[PATCH 18/44] leon, grspw_pkt: support for reading tx/rx DMA queue
Daniel Hellstrom
daniel at gaisler.com
Fri Mar 3 14:56:51 UTC 2017
* Add support for reading the GRSPW TX/RX descriptor counters
directly.
* Add semaphore lock to counters to avoid couters being out
of sync
* This makes it possible for the user in polling mode to check
the amount of work before entering RX/TX descriptor table
processing.
---
c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h | 4 +-
c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c | 76 +++++++++++++++++++++--
2 files changed, 74 insertions(+), 6 deletions(-)
diff --git a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
index 9a2a440..1bab68b 100644
--- a/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
+++ b/c/src/lib/libbsp/sparc/shared/include/grspw_pkt.h
@@ -481,7 +481,7 @@ extern int grspw_dma_tx_send(void *c, int opts, struct grspw_list *pkts, int cou
extern int grspw_dma_tx_reclaim(void *c, int opts, struct grspw_list *pkts, int *count);
/* Get current number of Packets in respective TX Queue. */
-extern void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent);
+extern void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent, int *hw);
#define GRSPW_OP_AND 0
#define GRSPW_OP_OR 1
@@ -553,7 +553,7 @@ extern int grspw_dma_rx_recv(void *c, int opts, struct grspw_list *pkts, int *co
extern int grspw_dma_rx_prepare(void *c, int opts, struct grspw_list *pkts, int count);
/* Get current number of Packets in respective RX Queue. */
-extern void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv);
+extern void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv, int *hw);
/* Block until recv_cnt or more packets are Queued in RECV Q, op (AND or OR),
* ready_cnt or fewer packet buffers are available in the "READY and Scheduled" Q,
diff --git a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
index 066d30f..048f7d1 100644
--- a/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
+++ b/c/src/lib/libbsp/sparc/shared/spw/grspw_pkt.c
@@ -334,6 +334,8 @@ struct grspw_txbd {
/* GRSPW Constants */
#define GRSPW_TXBD_NR 64 /* Maximum number of TX Descriptors */
#define GRSPW_RXBD_NR 128 /* Maximum number of RX Descriptors */
+#define GRSPW_TXBD_SIZE 16 /* Size in bytes of one TX descriptor */
+#define GRSPW_RXBD_SIZE 8 /* Size in bytes of one RX descriptor */
#define BDTAB_SIZE 0x400 /* BD Table Size (RX or TX) */
#define BDTAB_ALIGN 0x400 /* BD Table Alignment Requirement */
@@ -1894,16 +1896,49 @@ int grspw_dma_tx_reclaim(void *c, int opts, struct grspw_list *pkts, int *count)
return (~started) & 1; /* signal DMA has been stopped */
}
-void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent)
+void grspw_dma_tx_count(void *c, int *send, int *sched, int *sent, int *hw)
{
struct grspw_dma_priv *dma = c;
+ int sched_cnt, diff;
+ unsigned int hwbd;
+ struct grspw_txbd *tailbd;
+
+ /* Take device lock - Wait until we get semaphore.
+ * The lock is taken so that the counters are in sync with each other
+ * and that DMA descriptor table and tx_ring_tail is not being updated
+ * during HW counter processing in this function.
+ */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return;
if (send)
*send = dma->send_cnt;
+ sched_cnt = dma->tx_sched_cnt;
if (sched)
- *sched = dma->tx_sched_cnt;
+ *sched = sched_cnt;
if (sent)
*sent = dma->sent_cnt;
+ if (hw) {
+ /* Calculate number of descriptors (processed by HW) between
+ * HW pointer and oldest SW pointer.
+ */
+ hwbd = REG_READ(&dma->regs->txdesc);
+ tailbd = dma->tx_ring_tail->bd;
+ diff = ((hwbd - (unsigned int)tailbd) / GRSPW_TXBD_SIZE) &
+ (GRSPW_TXBD_NR - 1);
+ /* Handle special case when HW and SW pointers are equal
+ * because all TX descriptors have been processed by HW.
+ */
+ if ((diff == 0) && (sched_cnt == GRSPW_TXBD_NR) &&
+ ((BD_READ(&tailbd->ctrl) & GRSPW_TXBD_EN) == 0)) {
+ diff = GRSPW_TXBD_NR;
+ }
+ *hw = diff;
+ }
+
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
}
static inline int grspw_tx_wait_eval(struct grspw_dma_priv *dma)
@@ -2108,16 +2143,49 @@ out:
return ret;
}
-void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv)
+void grspw_dma_rx_count(void *c, int *ready, int *sched, int *recv, int *hw)
{
struct grspw_dma_priv *dma = c;
+ int sched_cnt, diff;
+ unsigned int hwbd;
+ struct grspw_rxbd *tailbd;
+
+ /* Take device lock - Wait until we get semaphore.
+ * The lock is taken so that the counters are in sync with each other
+ * and that DMA descriptor table and rx_ring_tail is not being updated
+ * during HW counter processing in this function.
+ */
+ if (rtems_semaphore_obtain(dma->sem_dma, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
+ != RTEMS_SUCCESSFUL)
+ return;
if (ready)
*ready = dma->ready_cnt;
+ sched_cnt = dma->rx_sched_cnt;
if (sched)
- *sched = dma->rx_sched_cnt;
+ *sched = sched_cnt;
if (recv)
*recv = dma->recv_cnt;
+ if (hw) {
+ /* Calculate number of descriptors (processed by HW) between
+ * HW pointer and oldest SW pointer.
+ */
+ hwbd = REG_READ(&dma->regs->rxdesc);
+ tailbd = dma->rx_ring_tail->bd;
+ diff = ((hwbd - (unsigned int)tailbd) / GRSPW_RXBD_SIZE) &
+ (GRSPW_RXBD_NR - 1);
+ /* Handle special case when HW and SW pointers are equal
+ * because all RX descriptors have been processed by HW.
+ */
+ if ((diff == 0) && (sched_cnt == GRSPW_RXBD_NR) &&
+ ((BD_READ(&tailbd->ctrl) & GRSPW_RXBD_EN) == 0)) {
+ diff = GRSPW_RXBD_NR;
+ }
+ *hw = diff;
+ }
+
+ /* Unlock DMA channel */
+ rtems_semaphore_release(dma->sem_dma);
}
static inline int grspw_rx_wait_eval(struct grspw_dma_priv *dma)
--
2.7.4
More information about the devel
mailing list