libspe2 0.9a
dma.c
Go to the documentation of this file.
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