/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. * Copyright (C) 2005, 06 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2013 Imagination Technologies Ltd.
*/ #include <linux/kernel.h> #include <linux/fs.h> #include <linux/syscalls.h> #include <linux/moduleloader.h> #include <linux/atomic.h> #include <linux/sched/signal.h>
/* call when we have the address of the shared structure from the SP side. */ staticint rtlx_init(struct rtlx_info *rtlxi)
{ if (rtlxi->id != RTLX_ID) {
pr_err("no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id); return -ENOEXEC;
}
/* wake up any sleeping rtlx_open's */ for (i = 0; i < RTLX_CHANNELS; i++)
wake_up_interruptible(&channel_wqs[i].lx_queue);
}
void rtlx_stopping(int vpe)
{ int i;
sp_stopping = 1; for (i = 0; i < RTLX_CHANNELS; i++)
wake_up_interruptible(&channel_wqs[i].lx_queue);
}
int rtlx_open(int index, int can_sleep)
{ struct rtlx_info **p; struct rtlx_channel *chan; enum rtlx_state state; int ret = 0;
if (index >= RTLX_CHANNELS) {
pr_debug("rtlx_open index out of range\n"); return -ENOSYS;
}
if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
pr_debug("rtlx_open channel %d already opened\n", index);
ret = -EBUSY; goto out_fail;
}
if (rtlx == NULL) {
p = vpe_get_shared(aprp_cpu_index()); if (p == NULL) { if (can_sleep) {
ret = __wait_event_interruptible(
channel_wqs[index].lx_queue,
(p = vpe_get_shared(aprp_cpu_index()))); if (ret) goto out_fail;
} else {
pr_debug("No SP program loaded, and device opened with O_NONBLOCK\n");
ret = -ENOSYS; goto out_fail;
}
}
smp_rmb(); if (*p == NULL) { if (can_sleep) {
DEFINE_WAIT(wait);
for (;;) {
prepare_to_wait(
&channel_wqs[index].lx_queue,
&wait, TASK_INTERRUPTIBLE);
smp_rmb(); if (*p != NULL) break; if (!signal_pending(current)) {
schedule(); continue;
}
ret = -ERESTARTSYS; goto out_fail;
}
finish_wait(&channel_wqs[index].lx_queue,
&wait);
} else {
pr_err(" *vpe_get_shared is NULL. Has an SP program been loaded?\n");
ret = -ENOSYS; goto out_fail;
}
}
if ((unsignedint)*p < KSEG0) {
pr_warn("vpe_get_shared returned an invalid pointer maybe an error code %d\n",
(int)*p);
ret = -ENOSYS; goto out_fail;
}
ret = rtlx_init(*p); if (ret < 0) goto out_ret;
}
chan = &rtlx->channel[index];
state = xchg(&chan->lx_state, RTLX_STATE_OPENED); if (state == RTLX_STATE_OPENED) {
ret = -EBUSY; goto out_fail;
}
int rtlx_release(int index)
{ if (rtlx == NULL) {
pr_err("rtlx_release() with null rtlx\n"); return 0;
}
rtlx->channel[index].lx_state = RTLX_STATE_UNUSED; return 0;
}
unsignedint rtlx_read_poll(int index, int can_sleep)
{ struct rtlx_channel *chan;
if (rtlx == NULL) return 0;
chan = &rtlx->channel[index];
/* data available to read? */ if (chan->lx_read == chan->lx_write) { if (can_sleep) { int ret = __wait_event_interruptible(
channel_wqs[index].lx_queue,
(chan->lx_read != chan->lx_write) ||
sp_stopping); if (ret) return ret;
staticinlineint write_spacefree(int read, int write, int size)
{ if (read == write) { /* * Never fill the buffer completely, so indexes are always * equal if empty and only empty, or !equal if data available
*/ return size - 1;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.5Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.