From 62fc2b6a036e0a6804eb9b877e17993932157bb3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 6 May 2022 08:23:45 +0200 Subject: if_atsam: Optimize receive Do not use the interface mutex in the receive loop. Avoid multiple reads of DMA descriptor words. Use a compile-time constant for the receive DMA descriptor count to simplify calculations. Update #4652. --- rtemsbsd/sys/dev/atsam/if_atsam.c | 188 +++++++++++++++----------------------- 1 file changed, 72 insertions(+), 116 deletions(-) diff --git a/rtemsbsd/sys/dev/atsam/if_atsam.c b/rtemsbsd/sys/dev/atsam/if_atsam.c index 96895fc0..ef2b3401 100644 --- a/rtemsbsd/sys/dev/atsam/if_atsam.c +++ b/rtemsbsd/sys/dev/atsam/if_atsam.c @@ -95,26 +95,26 @@ /** RX Defines */ #define GMAC_RX_BUFFER_SIZE 1536 #define GMAC_RX_BUF_DESC_ADDR_MASK 0xFFFFFFFC -#define GMAC_RX_SET_OFFSET (1u << 15) -#define GMAC_RX_SET_USED_WRAP ((1u << 1) | (1u << 0)) -#define GMAC_RX_SET_WRAP (1u << 1) -#define GMAC_RX_SET_USED (1u << 0) #define GMAC_DESCRIPTOR_ALIGNMENT 8 /** Events */ #define ATSAMV7_ETH_RX_EVENT_INTERRUPT RTEMS_EVENT_1 -#define ATSAMV7_ETH_RX_DATA_OFFSET 2 - -#define WATCHDOG_TIMEOUT 5 - /* FIXME: Make these configurable */ #define MDIO_RETRIES 10 #define MDIO_PHY MII_PHY_ANY -#define RXBUF_COUNT 8 #define IGNORE_RX_ERR false +#define RX_DESC_LOG2 3 +#define RX_DESC_COUNT (1U << RX_DESC_LOG2) +#define RX_DESC_WRAP(idx) \ + ((((idx) + 1) & RX_DESC_COUNT) >> (RX_DESC_LOG2 - 1)) +RTEMS_STATIC_ASSERT(RX_DESC_WRAP(RX_DESC_COUNT - 1) == + GMAC_RX_WRAP_BIT, rx_desc_wrap); +RTEMS_STATIC_ASSERT(RX_DESC_WRAP(RX_DESC_COUNT - 2) == + 0, rx_desc_no_wrap); + #define TX_DESC_LOG2 6 #define TX_DESC_COUNT (1U << TX_DESC_LOG2) #define TX_DESC_WRAP(idx) \ @@ -137,6 +137,10 @@ struct if_atsam_tx_bds { volatile sGmacTxDescriptor bds[TX_DESC_COUNT]; }; +struct if_atsam_rx_bds { + volatile sGmacRxDescriptor bds[RX_DESC_COUNT]; +}; + /* * Per-device data */ @@ -152,12 +156,11 @@ typedef struct if_atsam_softc { size_t tx_idx_tail; struct if_atsam_tx_bds *tx; struct mbuf *tx_mbufs[TX_DESC_COUNT]; + struct if_atsam_rx_bds *rx; + struct mbuf *rx_mbufs[RX_DESC_COUNT]; uint8_t GMacAddress[6]; rtems_id rx_daemon_tid; rtems_vector_number interrupt_number; - struct mbuf **rx_mbuf; - size_t rx_bd_fill_idx; - size_t amount_rx_buf; struct callout tick_ch; /* @@ -242,27 +245,6 @@ static void if_atsam_poll_hw_stats(struct if_atsam_softc *sc); #define IF_ATSAM_UNLOCK(sc) mtx_unlock(&(sc)->mtx) -static void if_atsam_event_send(rtems_id task, rtems_event_set event) -{ - rtems_event_send(task, event); -} - - -static void if_atsam_event_receive(if_atsam_softc *sc, rtems_event_set in) -{ - rtems_event_set out; - - IF_ATSAM_UNLOCK(sc); - rtems_event_receive( - in, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &out - ); - IF_ATSAM_LOCK(sc); -} - - static struct mbuf *if_atsam_new_mbuf(struct ifnet *ifp) { struct mbuf *m; @@ -425,17 +407,17 @@ static void if_atsam_interrupt_handler(void *arg) /* Erase the interrupts for RX completion and errors */ pHw->GMAC_IDR = GMAC_IER_RCOMP | GMAC_IER_ROVR; - (void)if_atsam_event_send(sc->rx_daemon_tid, + (void)rtems_event_send(sc->rx_daemon_tid, ATSAMV7_ETH_RX_EVENT_INTERRUPT); } } -static void rx_update_mbuf(struct mbuf *m, - volatile sGmacRxDescriptor *buffer_desc) +static void +if_atsam_rx_update_mbuf(struct mbuf *m, uint32_t status) { int frame_len; - frame_len = (int) (buffer_desc->status.bm.len); + frame_len = (int)(status & GMAC_LENGTH_FRAME); m->m_data = mtod(m, char*)+ETHER_ALIGN; m->m_len = frame_len; @@ -443,7 +425,7 @@ static void rx_update_mbuf(struct mbuf *m, /* check checksum offload result */ m->m_pkthdr.csum_flags = 0; - switch (buffer_desc->status.bm.typeIDMatchOrCksumResult) { + switch ((status >> 22) & 0x3) { case GMAC_RXDESC_ST_CKSUM_RESULT_IP_CHECKED: m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID; m->m_pkthdr.csum_data = 0xffff; @@ -464,12 +446,12 @@ static void if_atsam_rx_daemon(void *arg) { if_atsam_softc *sc = (if_atsam_softc *)arg; struct ifnet *ifp = sc->ifp; - void *rx_bd_base; - struct mbuf *m; - struct mbuf *n; - volatile sGmacRxDescriptor *buffer_desc; - uint32_t tmp_rx_bd_address; + volatile sGmacRxDescriptor *base; + struct if_atsam_rx_bds *rx; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; + size_t idx; + struct mbuf **mbufs; + struct mbuf *m; IF_ATSAM_LOCK(sc); @@ -480,47 +462,37 @@ static void if_atsam_rx_daemon(void *arg) } /* Allocate memory space for priority queue descriptor list */ - rx_bd_base = rtems_cache_coherent_allocate(sizeof(sGmacRxDescriptor), + base = rtems_cache_coherent_allocate(sizeof(*base), GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(rx_bd_base != NULL); + assert(base != NULL); - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; - buffer_desc->addr.val = GMAC_RX_SET_USED_WRAP; - buffer_desc->status.val = 0; + base->addr.val = GMAC_RX_OWNERSHIP_BIT | GMAC_RX_WRAP_BIT; + base->status.val = 0; - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 1); - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 2); + GMAC_SetRxQueue(pHw, (uint32_t)base, 1); + GMAC_SetRxQueue(pHw, (uint32_t)base, 2); /* Allocate memory space for buffer descriptor list */ - rx_bd_base = rtems_cache_coherent_allocate( - sc->amount_rx_buf * sizeof(sGmacRxDescriptor), + rx = rtems_cache_coherent_allocate(sizeof(*rx), GMAC_DESCRIPTOR_ALIGNMENT, 0); - assert(rx_bd_base != NULL); - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; + assert(rx != NULL); + sc->rx = rx; + mbufs = &sc->rx_mbufs[0]; /* Create descriptor list and mark as empty */ - for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf; - ++sc->rx_bd_fill_idx) { + for (idx = 0; idx < RX_DESC_COUNT; ++idx) { m = if_atsam_new_mbuf(ifp); assert(m != NULL); - sc->rx_mbuf[sc->rx_bd_fill_idx] = m; - buffer_desc->addr.val = ((uint32_t)m->m_data) & - GMAC_RX_BUF_DESC_ADDR_MASK; - buffer_desc->status.val = 0; - if (sc->rx_bd_fill_idx == (sc->amount_rx_buf - 1)) { - buffer_desc->addr.bm.bWrap = 1; - } else { - buffer_desc++; - } + mbufs[idx] = m; + rx->bds[idx].addr.val = mtod(m, uint32_t) | RX_DESC_WRAP(idx); } - buffer_desc = (sGmacRxDescriptor *)rx_bd_base; /* Set 2 Byte Receive Buffer Offset */ - pHw->GMAC_NCFGR |= GMAC_RX_SET_OFFSET; + pHw->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(2); /* Write Buffer Queue Base Address Register */ GMAC_ReceiveEnable(pHw, 0); - GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0); + GMAC_SetRxQueue(pHw, (uint32_t)&rx->bds[0], 0); /* Set address for address matching */ GMAC_SetAddress(pHw, 0, sc->GMacAddress); @@ -528,58 +500,50 @@ static void if_atsam_rx_daemon(void *arg) /* Enable Receiving of data */ GMAC_ReceiveEnable(pHw, 1); - /* Setup the interrupts for RX completion and errors */ - GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); + IF_ATSAM_UNLOCK(sc); - sc->rx_bd_fill_idx = 0; + idx = 0; while (true) { - /* Wait for events */ - if_atsam_event_receive(sc, ATSAMV7_ETH_RX_EVENT_INTERRUPT); + rtems_event_set out; + + /* Enable RX interrupts */ + pHw->GMAC_IER = GMAC_IER_RCOMP | GMAC_IER_ROVR; + + (void) rtems_event_receive(ATSAMV7_ETH_RX_EVENT_INTERRUPT, + RTEMS_EVENT_ALL | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &out); + + while (true) { + uint32_t addr; + uint32_t status; + + addr = rx->bds[idx].addr.val; + if ((addr & GMAC_RX_OWNERSHIP_BIT) == 0) { + break; + } - /* - * Check for all packets with a set ownership bit - */ - while (buffer_desc->addr.bm.bOwnership == 1) { - if (buffer_desc->status.bm.bEof == 1) { - m = sc->rx_mbuf[sc->rx_bd_fill_idx]; + status = rx->bds[idx].status.val; + m = mbufs[idx]; + + if (__predict_true((status & GMAC_RX_EOF_BIT) != 0)) { + struct mbuf *n; - /* New mbuf for desc */ n = if_atsam_new_mbuf(ifp); if (n != NULL) { - rx_update_mbuf(m, buffer_desc); - - IF_ATSAM_UNLOCK(sc); - sc->ifp->if_input(ifp, m); - IF_ATSAM_LOCK(sc); + if_atsam_rx_update_mbuf(m, status); + (*ifp->if_input)(ifp, m); m = n; } - sc->rx_mbuf[sc->rx_bd_fill_idx] = m; - tmp_rx_bd_address = (uint32_t)m->m_data & - GMAC_RX_BUF_DESC_ADDR_MASK; - - /* Switch pointer to next buffer descriptor */ - if (sc->rx_bd_fill_idx == - (sc->amount_rx_buf - 1)) { - tmp_rx_bd_address |= GMAC_RX_SET_WRAP; - sc->rx_bd_fill_idx = 0; - } else { - ++sc->rx_bd_fill_idx; - } + } else { + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + } - /* - * Give ownership to GMAC for further processing - */ - tmp_rx_bd_address &= ~GMAC_RX_SET_USED; - _ARM_Data_synchronization_barrier(); - buffer_desc->addr.val = tmp_rx_bd_address; + mbufs[idx] = m; + rx->bds[idx].addr.val = mtod(m, uint32_t) | + RX_DESC_WRAP(idx); - buffer_desc = (sGmacRxDescriptor *)rx_bd_base - + sc->rx_bd_fill_idx; - } + idx = (idx + 1) % RX_DESC_COUNT; } - /* Setup the interrupts for RX completion and errors */ - GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0); } } @@ -944,12 +908,6 @@ if_atsam_init(if_atsam_softc *sc) GMAC_StatisticsWriteEnable(sc->Gmac_inst.gGmacd.pHw, 1); - /* - * Allocate mbuf pointers - */ - sc->rx_mbuf = malloc(sc->amount_rx_buf * sizeof *sc->rx_mbuf, - M_TEMP, M_WAITOK | M_ZERO); - /* Install interrupt handler */ status = rtems_interrupt_handler_install(sc->interrupt_number, "Ethernet", @@ -1417,8 +1375,6 @@ static int if_atsam_driver_attach(device_t dev) memcpy(sc->GMacAddress, eaddr, ETHER_ADDR_LEN); - sc->amount_rx_buf = RXBUF_COUNT; - /* Set Initial Link Speed */ sc->link_speed = GMAC_SPEED_100M; sc->link_duplex = GMAC_DUPLEX_FULL; -- cgit v1.2.3