libspe2 0.9a
mbox.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 <poll.h>
00023 #include <stdio.h>
00024 #include <unistd.h>
00025 
00026 #include "create.h"
00027 #include "mbox.h"
00028 
00034 static __inline__ int _base_spe_out_mbox_read_ps(spe_context_ptr_t spectx,
00035                         unsigned int mbox_data[], 
00036                         int count)
00037 {
00038         volatile struct spe_spu_control_area *cntl_area =
00039                 spectx->base_private->cntl_mmap_base;
00040         int total;
00041         int entries;
00042 
00043         _base_spe_context_lock(spectx, FD_MBOX);
00044         total = 0;
00045         while (total < count) {
00046                 entries = cntl_area->SPU_Mbox_Stat & 0xFF;
00047                 if (entries == 0) break;  // no entries
00048                 if (entries > count - total) entries = count - total; // don't read more than we need;
00049                 while(entries--) {
00050                         mbox_data[total] = cntl_area->SPU_Out_Mbox;
00051                         total ++;
00052                 }
00053         }
00054         _base_spe_context_unlock(spectx, FD_MBOX);
00055         return total;
00056 }
00057 
00058 int _base_spe_out_mbox_read(spe_context_ptr_t spectx, 
00059                         unsigned int mbox_data[], 
00060                         int count)
00061 {
00062         int rc;
00063 
00064         if (mbox_data == NULL || count < 1){
00065                 errno = EINVAL;
00066                 return -1;
00067         }
00068 
00069         if (spectx->base_private->flags & SPE_MAP_PS) {
00070                 rc = _base_spe_out_mbox_read_ps(spectx, mbox_data, count);
00071         } else {
00072                 rc = read(_base_spe_open_if_closed(spectx,FD_MBOX, 0), mbox_data, count*4);
00073                 DEBUG_PRINTF("%s read rc: %d\n", __FUNCTION__, rc);
00074                 if (rc != -1) {
00075                         rc /= 4;
00076                 } else {
00077                         if (errno == EAGAIN ) { // no data ready to be read
00078                                 errno = 0;
00079                                 rc = 0;
00080                         }
00081                 }
00082         }
00083         return rc;
00084 }
00085 
00086 static __inline__ int _base_spe_in_mbox_write_ps(spe_context_ptr_t spectx,
00087                         unsigned int *mbox_data, 
00088                         int count)
00089 {
00090         volatile struct spe_spu_control_area *cntl_area =
00091                 spectx->base_private->cntl_mmap_base;
00092         int total = 0;
00093         unsigned int *aux;
00094         int space;
00095 
00096         _base_spe_context_lock(spectx, FD_WBOX);
00097         aux = mbox_data;
00098         while (total < count) {
00099                 space = (cntl_area->SPU_Mbox_Stat >> 8) & 0xFF;
00100                 if (space == 0) break;  // no space
00101                 if (space > count - total) space = count - total; // don't write more than we have
00102                 while  (space --) {
00103                         cntl_area->SPU_In_Mbox = *aux++;
00104                         total++;
00105                 }
00106         }
00107         _base_spe_context_unlock(spectx, FD_WBOX);
00108 
00109         return total;
00110 }
00111 
00112 int _base_spe_in_mbox_write(spe_context_ptr_t spectx, 
00113                         unsigned int *mbox_data, 
00114                         int count, 
00115                         int behavior_flag)
00116 {
00117         int rc;
00118         int total;
00119         unsigned int *aux;
00120         struct pollfd fds;
00121 
00122         if (mbox_data == NULL || count < 1){
00123                 errno = EINVAL;
00124                 return -1;
00125         }
00126 
00127         switch (behavior_flag) {
00128         case SPE_MBOX_ALL_BLOCKING: // write all, even if blocking
00129                 total = rc = 0;
00130                 if (spectx->base_private->flags & SPE_MAP_PS) {
00131                         do {
00132                                 aux = mbox_data + total;
00133                                 total += _base_spe_in_mbox_write_ps(spectx, aux, count - total);
00134                                 if (total < count) { // we could not write everything, wait for space
00135                                         fds.fd = _base_spe_open_if_closed(spectx, FD_WBOX, 0);
00136                                         fds.events = POLLOUT;
00137                                         rc = poll(&fds, 1, -1);
00138                                         if (rc == -1 ) 
00139                                                 return -1;
00140                                 }
00141                         } while (total < count);
00142                 } else {
00143                         while (total < 4*count) {
00144                                 rc = write(_base_spe_open_if_closed(spectx,FD_WBOX, 0),
00145                                            (const char *)mbox_data + total, 4*count - total);
00146                                 if (rc == -1) {
00147                                         break;
00148                                 }
00149                                 total += rc;
00150                         }
00151                         total /=4;
00152                 }
00153                 break;
00154 
00155         case  SPE_MBOX_ANY_BLOCKING: // write at least one, even if blocking
00156                 total = rc = 0;
00157                 if (spectx->base_private->flags & SPE_MAP_PS) {
00158                         do {
00159                                 total = _base_spe_in_mbox_write_ps(spectx, mbox_data, count);
00160                                 if (total == 0) { // we could not anything, wait for space
00161                                         fds.fd = _base_spe_open_if_closed(spectx, FD_WBOX, 0);
00162                                         fds.events = POLLOUT;
00163                                         rc = poll(&fds, 1, -1);
00164                                         if (rc == -1 ) 
00165                                                 return -1;
00166                                 }
00167                         } while (total == 0);
00168                 } else {
00169                         rc = write(_base_spe_open_if_closed(spectx,FD_WBOX, 0), mbox_data, 4*count);
00170                         total = rc/4;
00171                 }
00172                 break;
00173 
00174         case  SPE_MBOX_ANY_NONBLOCKING: // only write, if non blocking
00175                 total = rc = 0;
00176                 // write directly if we map the PS else write via spufs
00177                 if (spectx->base_private->flags & SPE_MAP_PS) {
00178                         total = _base_spe_in_mbox_write_ps(spectx, mbox_data, count);
00179                 } else { 
00180                         rc = write(_base_spe_open_if_closed(spectx,FD_WBOX_NB, 0), mbox_data, 4*count);
00181                         if (rc == -1 && errno == EAGAIN) {
00182                                 rc = 0;
00183                                 errno = 0;
00184                         }
00185                         total = rc/4;
00186                 }
00187                 break;
00188 
00189         default:
00190                 errno = EINVAL;
00191                 return -1;
00192         }
00193 
00194         if (rc == -1) {
00195                 errno = EIO;
00196                 return -1;
00197         }
00198 
00199         return total;
00200 }
00201 
00202 int _base_spe_in_mbox_status(spe_context_ptr_t spectx)
00203 {
00204         int rc, ret;
00205         volatile struct spe_spu_control_area *cntl_area =
00206                 spectx->base_private->cntl_mmap_base;
00207 
00208         if (spectx->base_private->flags & SPE_MAP_PS) {
00209                 ret = (cntl_area->SPU_Mbox_Stat >> 8) & 0xFF;
00210         } else {
00211                 rc = read(_base_spe_open_if_closed(spectx,FD_WBOX_STAT, 0), &ret, 4);
00212                 if (rc != 4)
00213                         ret = -1;
00214         }
00215 
00216         return ret;
00217         
00218 }
00219 
00220 int _base_spe_out_mbox_status(spe_context_ptr_t spectx)
00221 {
00222         int rc, ret;
00223         volatile struct spe_spu_control_area *cntl_area =
00224                 spectx->base_private->cntl_mmap_base;
00225 
00226         if (spectx->base_private->flags & SPE_MAP_PS) {
00227                 ret = cntl_area->SPU_Mbox_Stat & 0xFF;
00228         } else {
00229                 rc = read(_base_spe_open_if_closed(spectx,FD_MBOX_STAT, 0), &ret, 4);
00230                 if (rc != 4)
00231                         ret = -1;
00232         }
00233 
00234         return ret;
00235         
00236 }
00237 
00238 int _base_spe_out_intr_mbox_status(spe_context_ptr_t spectx)
00239 {
00240         int rc, ret;
00241         volatile struct spe_spu_control_area *cntl_area =
00242                 spectx->base_private->cntl_mmap_base;
00243 
00244         if (spectx->base_private->flags & SPE_MAP_PS) {
00245                 ret = (cntl_area->SPU_Mbox_Stat >> 16) & 0xFF;
00246         } else {
00247                 rc = read(_base_spe_open_if_closed(spectx,FD_IBOX_STAT, 0), &ret, 4);
00248                 if (rc != 4)
00249                         ret = -1;
00250 
00251         }
00252         return ret;
00253 }
00254 
00255 int _base_spe_out_intr_mbox_read(spe_context_ptr_t spectx, 
00256                         unsigned int mbox_data[], 
00257                         int count, 
00258                         int behavior_flag)
00259 {
00260         int rc;
00261         int total;
00262 
00263         if (mbox_data == NULL || count < 1){
00264                 errno = EINVAL;
00265                 return -1;
00266         }
00267 
00268         switch (behavior_flag) {
00269         case SPE_MBOX_ALL_BLOCKING: // read all, even if blocking
00270                 total = rc = 0;
00271                 while (total < 4*count) {
00272                         rc = read(_base_spe_open_if_closed(spectx,FD_IBOX, 0),
00273                                   (char *)mbox_data + total, 4*count - total);
00274                         if (rc == -1) {
00275                                 break;
00276                         }
00277                         total += rc;
00278                 }
00279                 break;
00280 
00281         case  SPE_MBOX_ANY_BLOCKING: // read at least one, even if blocking
00282                 total = rc = read(_base_spe_open_if_closed(spectx,FD_IBOX, 0), mbox_data, 4*count);
00283                 break;
00284 
00285         case  SPE_MBOX_ANY_NONBLOCKING: // only reaad, if non blocking
00286                 rc = read(_base_spe_open_if_closed(spectx,FD_IBOX_NB, 0), mbox_data, 4*count);
00287                 if (rc == -1 && errno == EAGAIN) {
00288                         rc = 0;
00289                         errno = 0;
00290                 }
00291                 total = rc;
00292                 break;
00293 
00294         default:
00295                 errno = EINVAL;
00296                 return -1;
00297         }
00298 
00299         if (rc == -1) {
00300                 errno = EIO;
00301                 return -1;
00302         }
00303 
00304         return rc / 4;
00305 }
00306 
00307 int _base_spe_signal_write(spe_context_ptr_t spectx, 
00308                         unsigned int signal_reg, 
00309                         unsigned int data )
00310 {
00311         int rc;
00312 
00313         if (spectx->base_private->flags & SPE_MAP_PS) {
00314                 if (signal_reg == SPE_SIG_NOTIFY_REG_1) {
00315                         spe_sig_notify_1_area_t *sig = spectx->base_private->signal1_mmap_base;
00316 
00317                         sig->SPU_Sig_Notify_1 = data;
00318                 } else if (signal_reg == SPE_SIG_NOTIFY_REG_2) {
00319                         spe_sig_notify_2_area_t *sig = spectx->base_private->signal2_mmap_base;
00320 
00321                         sig->SPU_Sig_Notify_2 = data;
00322                 } else {
00323                         errno = EINVAL;
00324                         return -1;
00325                 }
00326                 rc = 0;
00327         } else {
00328                 if (signal_reg == SPE_SIG_NOTIFY_REG_1)
00329                         rc = write(_base_spe_open_if_closed(spectx,FD_SIG1, 0), &data, 4);
00330                 else if (signal_reg == SPE_SIG_NOTIFY_REG_2)
00331                         rc = write(_base_spe_open_if_closed(spectx,FD_SIG2, 0), &data, 4);
00332                 else {
00333                         errno = EINVAL;
00334                         return -1;
00335                 }
00336                 
00337                 if (rc == 4)
00338                         rc = 0;
00339         
00340                 if (signal_reg == SPE_SIG_NOTIFY_REG_1)
00341                         _base_spe_close_if_open(spectx,FD_SIG1);
00342                 else if (signal_reg == SPE_SIG_NOTIFY_REG_2)
00343                         _base_spe_close_if_open(spectx,FD_SIG2);
00344         }
00345 
00346         return rc;
00347 }
00348 
00349 
00350