libspe2 0.9a
|
00001 /* 00002 * libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS 00003 * Copyright (C) 2005 IBM Corp. 00004 * 00005 * This library is free software; you can redistribute it and/or modify it 00006 * under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation; either version 2.1 of the License, 00008 * or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, but 00011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 00012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00013 * License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this library; if not, write to the Free Software Foundation, 00017 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00018 */ 00019 00020 #include <errno.h> 00021 #include <fcntl.h> 00022 #include <stdio.h> 00023 #include <stdint.h> 00024 #include <string.h> 00025 #include <unistd.h> 00026 00027 #include <sys/poll.h> 00028 00029 #include "create.h" 00030 #include "dma.h" 00031 00032 static int spe_read_tag_status_block(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status); 00033 static int spe_read_tag_status_noblock(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status); 00034 00035 static int issue_mfc_command(spe_context_ptr_t spectx, unsigned lsa, void *ea, 00036 unsigned size, unsigned tag, unsigned tid, unsigned rid, 00037 enum mfc_cmd cmd) 00038 { 00039 int ret; 00040 00041 DEBUG_PRINTF("queuing DMA %x %lx %x %x %x %x %x\n", lsa, 00042 (unsigned long)ea, size, tag, tid, rid, (unsigned)cmd); 00043 00044 /* tag 16-31 are reserved by kernel */ 00045 if (tag > 0x0f || tid > 0xff || rid > 0xff) { 00046 errno = EINVAL; 00047 return -1; 00048 } 00049 00050 if (spectx->base_private->flags & SPE_MAP_PS) { 00051 volatile struct spe_mfc_command_area *cmd_area = 00052 spectx->base_private->mfc_mmap_base; 00053 unsigned int eal = (uintptr_t) ea & 0xFFFFFFFF; 00054 unsigned int eah = (unsigned long long)(uintptr_t) ea >> 32; 00055 _base_spe_context_lock(spectx, FD_MFC); 00056 spectx->base_private->active_tagmask |= 1 << tag; 00057 DEBUG_PRINTF("set active tagmask = 0x%04x, tag=%i\n",spectx->base_private->active_tagmask,tag); 00058 while ((cmd_area->MFC_QStatus & 0x0000FFFF) == 0) ; 00059 do { 00060 cmd_area->MFC_LSA = lsa; 00061 cmd_area->MFC_EAH = eah; 00062 cmd_area->MFC_EAL = eal; 00063 cmd_area->MFC_Size_Tag = (size << 16) | tag; 00064 cmd_area->MFC_ClassID_CMD = (tid << 24) | (rid << 16) | cmd; 00065 00066 ret = cmd_area->MFC_CMDStatus & 0x00000003; 00067 } while (ret); // at least one of the two bits is set 00068 _base_spe_context_unlock(spectx, FD_MFC); 00069 return 0; 00070 } 00071 else { 00072 int fd; 00073 fd = _base_spe_open_if_closed(spectx, FD_MFC, 0); 00074 if (fd != -1) { 00075 struct mfc_command_parameter_area parm = { 00076 .lsa = lsa, 00077 .ea = (unsigned long) ea, 00078 .size = size, 00079 .tag = tag, 00080 .class = (tid << 8) | rid, 00081 .cmd = cmd, 00082 }; 00083 ret = write(fd, &parm, sizeof (parm)); 00084 if ((ret < 0) && (errno != EIO)) { 00085 perror("spe_do_mfc_put: internal error"); 00086 } 00087 return ret < 0 ? -1 : 0; 00088 } 00089 } 00090 /* the kernel does not support DMA */ 00091 return 1; 00092 } 00093 00094 static int spe_do_mfc_put(spe_context_ptr_t spectx, unsigned src, void *dst, 00095 unsigned size, unsigned tag, unsigned tid, unsigned rid, 00096 enum mfc_cmd cmd) 00097 { 00098 int ret; 00099 ret = issue_mfc_command(spectx, src, dst, size, tag, tid, rid, cmd); 00100 if (ret <= 0) { 00101 return ret; 00102 } 00103 else { 00104 /* the kernel does not support DMA, so just copy directly */ 00105 memcpy(dst, spectx->base_private->mem_mmap_base + src, size); 00106 return 0; 00107 } 00108 } 00109 00110 static int spe_do_mfc_get(spe_context_ptr_t spectx, unsigned int dst, void *src, 00111 unsigned int size, unsigned int tag, unsigned tid, unsigned rid, 00112 enum mfc_cmd cmd) 00113 { 00114 int ret; 00115 ret = issue_mfc_command(spectx, dst, src, size, tag, tid, rid, cmd); 00116 if (ret <= 0) { 00117 return ret; 00118 } 00119 else { 00120 /* the kernel does not support DMA, so just copy directly */ 00121 memcpy(spectx->base_private->mem_mmap_base + dst, src, size); 00122 return 0; 00123 } 00124 } 00125 00126 int _base_spe_mfcio_put(spe_context_ptr_t spectx, 00127 unsigned int ls, 00128 void *ea, 00129 unsigned int size, 00130 unsigned int tag, 00131 unsigned int tid, 00132 unsigned int rid) 00133 { 00134 return spe_do_mfc_put(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_PUT); 00135 } 00136 00137 int _base_spe_mfcio_putb(spe_context_ptr_t spectx, 00138 unsigned int ls, 00139 void *ea, 00140 unsigned int size, 00141 unsigned int tag, 00142 unsigned int tid, 00143 unsigned int rid) 00144 { 00145 return spe_do_mfc_put(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_PUTB); 00146 } 00147 00148 int _base_spe_mfcio_putf(spe_context_ptr_t spectx, 00149 unsigned int ls, 00150 void *ea, 00151 unsigned int size, 00152 unsigned int tag, 00153 unsigned int tid, 00154 unsigned int rid) 00155 { 00156 return spe_do_mfc_put(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_PUTF); 00157 } 00158 00159 00160 int _base_spe_mfcio_get(spe_context_ptr_t spectx, 00161 unsigned int ls, 00162 void *ea, 00163 unsigned int size, 00164 unsigned int tag, 00165 unsigned int tid, 00166 unsigned int rid) 00167 { 00168 return spe_do_mfc_get(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_GET); 00169 } 00170 00171 int _base_spe_mfcio_getb(spe_context_ptr_t spectx, 00172 unsigned int ls, 00173 void *ea, 00174 unsigned int size, 00175 unsigned int tag, 00176 unsigned int tid, 00177 unsigned int rid) 00178 { 00179 return spe_do_mfc_get(spectx, ls, ea, size, tag, rid, rid, MFC_CMD_GETB); 00180 } 00181 00182 int _base_spe_mfcio_getf(spe_context_ptr_t spectx, 00183 unsigned int ls, 00184 void *ea, 00185 unsigned int size, 00186 unsigned int tag, 00187 unsigned int tid, 00188 unsigned int rid) 00189 { 00190 return spe_do_mfc_get(spectx, ls, ea, size, tag, tid, rid, MFC_CMD_GETF); 00191 } 00192 00193 static int spe_mfcio_tag_status_read_all(spe_context_ptr_t spectx, 00194 unsigned int mask, unsigned int *tag_status) 00195 { 00196 int fd; 00197 00198 if (spectx->base_private->flags & SPE_MAP_PS) { 00199 return spe_read_tag_status_block(spectx, mask, tag_status); 00200 } else { 00201 fd = _base_spe_open_if_closed(spectx, FD_MFC, 0); 00202 if (fd == -1) { 00203 return -1; 00204 } 00205 00206 if (fsync(fd) != 0) { 00207 return -1; 00208 } 00209 00210 return spe_read_tag_status_block(spectx, mask, tag_status); 00211 } 00212 } 00213 00214 static int spe_mfcio_tag_status_read_any(spe_context_ptr_t spectx, 00215 unsigned int mask, unsigned int *tag_status) 00216 { 00217 return spe_read_tag_status_block(spectx, mask, tag_status); 00218 } 00219 00220 static int spe_mfcio_tag_status_read_immediate(spe_context_ptr_t spectx, 00221 unsigned int mask, unsigned int *tag_status) 00222 { 00223 return spe_read_tag_status_noblock(spectx, mask, tag_status); 00224 } 00225 00226 00227 00228 /* MFC Read tag status functions 00229 * 00230 */ 00231 static int spe_read_tag_status_block(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status) 00232 { 00233 if (spectx->base_private->flags & SPE_MAP_PS) { 00234 volatile struct spe_mfc_command_area *cmd_area = 00235 spectx->base_private->mfc_mmap_base; 00236 _base_spe_context_lock(spectx, FD_MFC); 00237 cmd_area->Prxy_QueryMask = mask; 00238 __asm__ ("eieio"); 00239 do { 00240 *tag_status = cmd_area->Prxy_TagStatus; 00241 spectx->base_private->active_tagmask ^= *tag_status; 00242 DEBUG_PRINTF("unset active tagmask = 0x%04x, tag_status = 0x%04x\n", 00243 spectx->base_private->active_tagmask,*tag_status); 00244 } while (*tag_status ^ mask); 00245 _base_spe_context_unlock(spectx, FD_MFC); 00246 return 0; 00247 } else { 00248 int fd; 00249 fd = _base_spe_open_if_closed(spectx, FD_MFC, 0); 00250 if (fd == -1) { 00251 return -1; 00252 } 00253 00254 if (read(fd,tag_status,4) == 4) { 00255 return 0; 00256 } 00257 } 00258 return -1; 00259 } 00260 00261 static int spe_read_tag_status_noblock(spe_context_ptr_t spectx, unsigned int mask, unsigned int *tag_status) 00262 { 00263 unsigned int ret; 00264 00265 if (spectx->base_private->flags & SPE_MAP_PS) { 00266 volatile struct spe_mfc_command_area *cmd_area = 00267 spectx->base_private->mfc_mmap_base; 00268 00269 _base_spe_context_lock(spectx, FD_MFC); 00270 cmd_area->Prxy_QueryMask = mask; 00271 __asm__ ("eieio"); 00272 *tag_status = cmd_area->Prxy_TagStatus; 00273 spectx->base_private->active_tagmask ^= *tag_status; 00274 DEBUG_PRINTF("unset active tagmask = 0x%04x, tag_status = 0x%04x\n", 00275 spectx->base_private->active_tagmask,*tag_status); 00276 _base_spe_context_unlock(spectx, FD_MFC); 00277 return 0; 00278 } else { 00279 struct pollfd poll_fd; 00280 int fd; 00281 00282 fd = _base_spe_open_if_closed(spectx, FD_MFC, 0); 00283 if (fd == -1) { 00284 return -1; 00285 } 00286 00287 poll_fd.fd = fd; 00288 poll_fd.events = POLLIN; 00289 00290 ret = poll(&poll_fd, 1, 0); 00291 00292 if (ret < 0) 00293 return -1; 00294 00295 if (ret == 0 || !(poll_fd.revents & POLLIN)) { 00296 *tag_status = 0; 00297 return 0; 00298 } 00299 00300 if (read(fd,tag_status,4) == 4) { 00301 return 0; 00302 } 00303 } 00304 return -1; 00305 } 00306 00307 int _base_spe_mfcio_tag_status_read(spe_context_ptr_t spectx, unsigned int mask, unsigned int behavior, unsigned int *tag_status) 00308 { 00309 if ( mask != 0 ) { 00310 if (!(spectx->base_private->flags & SPE_MAP_PS)) 00311 mask = 0; 00312 } else { 00313 if ((spectx->base_private->flags & SPE_MAP_PS)) 00314 mask = spectx->base_private->active_tagmask; 00315 } 00316 00317 if (!tag_status) { 00318 errno = EINVAL; 00319 return -1; 00320 } 00321 00322 switch (behavior) { 00323 case SPE_TAG_ALL: 00324 return spe_mfcio_tag_status_read_all(spectx, mask, tag_status); 00325 case SPE_TAG_ANY: 00326 return spe_mfcio_tag_status_read_any(spectx, mask, tag_status); 00327 case SPE_TAG_IMMEDIATE: 00328 return spe_mfcio_tag_status_read_immediate(spectx, mask, tag_status); 00329 default: 00330 errno = EINVAL; 00331 return -1; 00332 } 00333 } 00334 00335 int _base_spe_mssync_start(spe_context_ptr_t spectx) 00336 { 00337 int ret, fd; 00338 unsigned int data = 1; /* Any value can be written here */ 00339 00340 volatile struct spe_mssync_area *mss_area = 00341 spectx->base_private->mssync_mmap_base; 00342 00343 if (spectx->base_private->flags & SPE_MAP_PS) { 00344 mss_area->MFC_MSSync = data; 00345 return 0; 00346 } else { 00347 fd = _base_spe_open_if_closed(spectx, FD_MSS, 0); 00348 if (fd != -1) { 00349 ret = write(fd, &data, sizeof (data)); 00350 if ((ret < 0) && (errno != EIO)) { 00351 perror("spe_mssync_start: internal error"); 00352 } 00353 return ret < 0 ? -1 : 0; 00354 } else 00355 return -1; 00356 } 00357 } 00358 00359 int _base_spe_mssync_status(spe_context_ptr_t spectx) 00360 { 00361 int ret, fd; 00362 unsigned int data; 00363 00364 volatile struct spe_mssync_area *mss_area = 00365 spectx->base_private->mssync_mmap_base; 00366 00367 if (spectx->base_private->flags & SPE_MAP_PS) { 00368 return mss_area->MFC_MSSync; 00369 } else { 00370 fd = _base_spe_open_if_closed(spectx, FD_MSS, 0); 00371 if (fd != -1) { 00372 ret = read(fd, &data, sizeof (data)); 00373 if ((ret < 0) && (errno != EIO)) { 00374 perror("spe_mssync_start: internal error"); 00375 } 00376 return ret < 0 ? -1 : data; 00377 } else 00378 return -1; 00379 } 00380 } 00381 00382