diff options
Diffstat (limited to 'gcell/src/lib/runtime/spu/gc_spu_jd_queue.c')
-rw-r--r-- | gcell/src/lib/runtime/spu/gc_spu_jd_queue.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/gcell/src/lib/runtime/spu/gc_spu_jd_queue.c b/gcell/src/lib/runtime/spu/gc_spu_jd_queue.c new file mode 100644 index 000000000..ba4a1b9d2 --- /dev/null +++ b/gcell/src/lib/runtime/spu/gc_spu_jd_queue.c @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "gc_jd_queue.h" +#include "mutex_lock.h" +#include "mutex_unlock.h" + +extern int gc_sys_tag; + +bool +gc_jd_queue_dequeue(gc_eaddr_t q, gc_eaddr_t *item_ea, gc_job_desc_t *item) +{ + gc_jd_queue_t local_q; + + // Before aquiring the lock, see if it's possible that there's + // something in the queue. Checking in this way makes it easier + // for the PPE to insert things, since we're not contending for + // the lock unless there is something in the queue. + + // copy in the queue structure + mfc_get(&local_q, q, sizeof(gc_jd_queue_t), gc_sys_tag, 0, 0); + mfc_write_tag_mask(1 << gc_sys_tag); // the tag we're interested in + mfc_read_tag_status_all(); // wait for DMA to complete + + if (local_q.head == 0){ // empty + return false; + } + + // When we peeked, head was non-zero. Now grab the + // lock and do it for real. + + _mutex_lock(q + offsetof(gc_jd_queue_t, mutex)); + + // copy in the queue structure + mfc_get(&local_q, q, sizeof(gc_jd_queue_t), gc_sys_tag, 0, 0); + mfc_write_tag_mask(1 << gc_sys_tag); // the tag we're interested in + mfc_read_tag_status_all(); // wait for DMA to complete + + if (local_q.head == 0){ // empty + _mutex_unlock(q + offsetof(gc_jd_queue_t, mutex)); + return false; + } + + // copy in job descriptor at head of queue + *item_ea = local_q.head; + mfc_get(item, local_q.head, sizeof(gc_job_desc_t), gc_sys_tag, 0, 0); + mfc_write_tag_mask(1 << gc_sys_tag); // the tag we're interested in + mfc_read_tag_status_all(); // wait for DMA to complete + + local_q.head = item->sys.next; + item->sys.next = 0; + if (local_q.head == 0) // now empty? + local_q.tail = 0; + + + // copy the queue structure back out + mfc_put(&local_q, q, sizeof(gc_jd_queue_t), gc_sys_tag, 0, 0); + mfc_write_tag_mask(1 << gc_sys_tag); // the tag we're interested in + mfc_read_tag_status_all(); // wait for DMA to complete + + // Q: FIXME do we need to order stores in EA or can we just clear the + // local copy of the mutex above and blast it out, removing the need + // for this explicit unlock? + // + // A: Manual says it's better to use an atomic op rather than + // a normal DMA, and that a putlluc is better than a putllc if + // you can use it. + + _mutex_unlock(q + offsetof(gc_jd_queue_t, mutex)); + return true; +} + + +void +gc_jd_queue_getllar(gc_eaddr_t q) +{ + // get reservation that includes the tail of the queue + gc_eaddr_t tail = q + offsetof(gc_jd_queue_t, tail); + + char _tmp[256]; + char *buf = (char *) ALIGN(_tmp, 128); // get cache-aligned buffer + + mfc_getllar(buf, ALIGN128_EA(tail), 0, 0); + spu_readch(MFC_RdAtomicStat); +} |