mbox.c
Go to the documentation of this file.
/*
* libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
* Copyright (C) 2005 IBM Corp.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <unistd.h>
#include "create.h"
#include "mbox.h"
static __inline__ int _base_spe_out_mbox_read_ps(spe_context_ptr_t spectx,
unsigned int mbox_data[],
int count)
{
volatile struct spe_spu_control_area *cntl_area =
spectx->base_private->cntl_mmap_base;
int total;
int entries;
_base_spe_context_lock(spectx, FD_MBOX);
total = 0;
while (total < count) {
entries = cntl_area->SPU_Mbox_Stat & 0xFF;
if (entries == 0) break; // no entries
if (entries > count - total) entries = count - total; // don't read more than we need;
while(entries--) {
mbox_data[total] = cntl_area->SPU_Out_Mbox;
total ++;
}
}
_base_spe_context_unlock(spectx, FD_MBOX);
return total;
}
int _base_spe_out_mbox_read(spe_context_ptr_t spectx,
unsigned int mbox_data[],
int count)
{
int rc;
if (mbox_data == NULL || count < 1){
errno = EINVAL;
return -1;
}
if (spectx->base_private->flags & SPE_MAP_PS) {
rc = _base_spe_out_mbox_read_ps(spectx, mbox_data, count);
} else {
rc = read(_base_spe_open_if_closed(spectx,FD_MBOX, 0), mbox_data, count*4);
DEBUG_PRINTF("%s read rc: %d\n", __FUNCTION__, rc);
if (rc != -1) {
rc /= 4;
} else {
if (errno == EAGAIN ) { // no data ready to be read
errno = 0;
rc = 0;
}
}
}
return rc;
}
static __inline__ int _base_spe_in_mbox_write_ps(spe_context_ptr_t spectx,
unsigned int *mbox_data,
int count)
{
volatile struct spe_spu_control_area *cntl_area =
spectx->base_private->cntl_mmap_base;
int total = 0;
unsigned int *aux;
int space;
_base_spe_context_lock(spectx, FD_WBOX);
aux = mbox_data;
while (total < count) {
space = (cntl_area->SPU_Mbox_Stat >> 8) & 0xFF;
if (space == 0) break; // no space
if (space > count - total) space = count - total; // don't write more than we have
while (space --) {
cntl_area->SPU_In_Mbox = *aux++;
total++;
}
}
_base_spe_context_unlock(spectx, FD_WBOX);
return total;
}
int _base_spe_in_mbox_write(spe_context_ptr_t spectx,
unsigned int *mbox_data,
int count,
int behavior_flag)
{
int rc;
int total;
unsigned int *aux;
struct pollfd fds;
if (mbox_data == NULL || count < 1){
errno = EINVAL;
return -1;
}
switch (behavior_flag) {
case SPE_MBOX_ALL_BLOCKING: // write all, even if blocking
total = rc = 0;
if (spectx->base_private->flags & SPE_MAP_PS) {
do {
aux = mbox_data + total;
total += _base_spe_in_mbox_write_ps(spectx, aux, count - total);
if (total < count) { // we could not write everything, wait for space
fds.fd = _base_spe_open_if_closed(spectx, FD_WBOX, 0);
fds.events = POLLOUT;
rc = poll(&fds, 1, -1);
if (rc == -1 )
return -1;
}
} while (total < count);
} else {
while (total < 4*count) {
rc = write(_base_spe_open_if_closed(spectx,FD_WBOX, 0),
(const char *)mbox_data + total, 4*count - total);
if (rc == -1) {
break;
}
total += rc;
}
total /=4;
}
break;
case SPE_MBOX_ANY_BLOCKING: // write at least one, even if blocking
total = rc = 0;
if (spectx->base_private->flags & SPE_MAP_PS) {
do {
total = _base_spe_in_mbox_write_ps(spectx, mbox_data, count);
if (total == 0) { // we could not anything, wait for space
fds.fd = _base_spe_open_if_closed(spectx, FD_WBOX, 0);
fds.events = POLLOUT;
rc = poll(&fds, 1, -1);
if (rc == -1 )
return -1;
}
} while (total == 0);
} else {
rc = write(_base_spe_open_if_closed(spectx,FD_WBOX, 0), mbox_data, 4*count);
total = rc/4;
}
break;
case SPE_MBOX_ANY_NONBLOCKING: // only write, if non blocking
total = rc = 0;
// write directly if we map the PS else write via spufs
if (spectx->base_private->flags & SPE_MAP_PS) {
total = _base_spe_in_mbox_write_ps(spectx, mbox_data, count);
} else {
rc = write(_base_spe_open_if_closed(spectx,FD_WBOX_NB, 0), mbox_data, 4*count);
if (rc == -1 && errno == EAGAIN) {
rc = 0;
errno = 0;
}
total = rc/4;
}
break;
default:
errno = EINVAL;
return -1;
}
if (rc == -1) {
errno = EIO;
return -1;
}
return total;
}
int _base_spe_in_mbox_status(spe_context_ptr_t spectx)
{
int rc, ret;
volatile struct spe_spu_control_area *cntl_area =
spectx->base_private->cntl_mmap_base;
if (spectx->base_private->flags & SPE_MAP_PS) {
ret = (cntl_area->SPU_Mbox_Stat >> 8) & 0xFF;
} else {
rc = read(_base_spe_open_if_closed(spectx,FD_WBOX_STAT, 0), &ret, 4);
if (rc != 4)
ret = -1;
}
return ret;
}
int _base_spe_out_mbox_status(spe_context_ptr_t spectx)
{
int rc, ret;
volatile struct spe_spu_control_area *cntl_area =
spectx->base_private->cntl_mmap_base;
if (spectx->base_private->flags & SPE_MAP_PS) {
ret = cntl_area->SPU_Mbox_Stat & 0xFF;
} else {
rc = read(_base_spe_open_if_closed(spectx,FD_MBOX_STAT, 0), &ret, 4);
if (rc != 4)
ret = -1;
}
return ret;
}
int _base_spe_out_intr_mbox_status(spe_context_ptr_t spectx)
{
int rc, ret;
volatile struct spe_spu_control_area *cntl_area =
spectx->base_private->cntl_mmap_base;
if (spectx->base_private->flags & SPE_MAP_PS) {
ret = (cntl_area->SPU_Mbox_Stat >> 16) & 0xFF;
} else {
rc = read(_base_spe_open_if_closed(spectx,FD_IBOX_STAT, 0), &ret, 4);
if (rc != 4)
ret = -1;
}
return ret;
}
int _base_spe_out_intr_mbox_read(spe_context_ptr_t spectx,
unsigned int mbox_data[],
int count,
int behavior_flag)
{
int rc;
int total;
if (mbox_data == NULL || count < 1){
errno = EINVAL;
return -1;
}
switch (behavior_flag) {
case SPE_MBOX_ALL_BLOCKING: // read all, even if blocking
total = rc = 0;
while (total < 4*count) {
rc = read(_base_spe_open_if_closed(spectx,FD_IBOX, 0),
(char *)mbox_data + total, 4*count - total);
if (rc == -1) {
break;
}
total += rc;
}
break;
case SPE_MBOX_ANY_BLOCKING: // read at least one, even if blocking
total = rc = read(_base_spe_open_if_closed(spectx,FD_IBOX, 0), mbox_data, 4*count);
break;
case SPE_MBOX_ANY_NONBLOCKING: // only reaad, if non blocking
rc = read(_base_spe_open_if_closed(spectx,FD_IBOX_NB, 0), mbox_data, 4*count);
if (rc == -1 && errno == EAGAIN) {
rc = 0;
errno = 0;
}
total = rc;
break;
default:
errno = EINVAL;
return -1;
}
if (rc == -1) {
errno = EIO;
return -1;
}
return rc / 4;
}
int _base_spe_signal_write(spe_context_ptr_t spectx,
unsigned int signal_reg,
unsigned int data )
{
int rc;
if (spectx->base_private->flags & SPE_MAP_PS) {
if (signal_reg == SPE_SIG_NOTIFY_REG_1) {
spe_sig_notify_1_area_t *sig = spectx->base_private->signal1_mmap_base;
sig->SPU_Sig_Notify_1 = data;
} else if (signal_reg == SPE_SIG_NOTIFY_REG_2) {
spe_sig_notify_2_area_t *sig = spectx->base_private->signal2_mmap_base;
sig->SPU_Sig_Notify_2 = data;
} else {
errno = EINVAL;
return -1;
}
rc = 0;
} else {
if (signal_reg == SPE_SIG_NOTIFY_REG_1)
rc = write(_base_spe_open_if_closed(spectx,FD_SIG1, 0), &data, 4);
else if (signal_reg == SPE_SIG_NOTIFY_REG_2)
rc = write(_base_spe_open_if_closed(spectx,FD_SIG2, 0), &data, 4);
else {
errno = EINVAL;
return -1;
}
if (rc == 4)
rc = 0;
if (signal_reg == SPE_SIG_NOTIFY_REG_1)
_base_spe_close_if_open(spectx,FD_SIG1);
else if (signal_reg == SPE_SIG_NOTIFY_REG_2)
_base_spe_close_if_open(spectx,FD_SIG2);
}
return rc;
}