mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-07-26 08:18:14 +08:00
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.
This commit is contained in:
parent
2cb974fa20
commit
967613fbce
@ -95,26 +95,26 @@
|
|||||||
/** RX Defines */
|
/** RX Defines */
|
||||||
#define GMAC_RX_BUFFER_SIZE 1536
|
#define GMAC_RX_BUFFER_SIZE 1536
|
||||||
#define GMAC_RX_BUF_DESC_ADDR_MASK 0xFFFFFFFC
|
#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
|
#define GMAC_DESCRIPTOR_ALIGNMENT 8
|
||||||
|
|
||||||
/** Events */
|
/** Events */
|
||||||
#define ATSAMV7_ETH_RX_EVENT_INTERRUPT RTEMS_EVENT_1
|
#define ATSAMV7_ETH_RX_EVENT_INTERRUPT RTEMS_EVENT_1
|
||||||
|
|
||||||
#define ATSAMV7_ETH_RX_DATA_OFFSET 2
|
|
||||||
|
|
||||||
#define WATCHDOG_TIMEOUT 5
|
|
||||||
|
|
||||||
/* FIXME: Make these configurable */
|
/* FIXME: Make these configurable */
|
||||||
#define MDIO_RETRIES 10
|
#define MDIO_RETRIES 10
|
||||||
#define MDIO_PHY MII_PHY_ANY
|
#define MDIO_PHY MII_PHY_ANY
|
||||||
#define RXBUF_COUNT 8
|
|
||||||
#define IGNORE_RX_ERR false
|
#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_LOG2 6
|
||||||
#define TX_DESC_COUNT (1U << TX_DESC_LOG2)
|
#define TX_DESC_COUNT (1U << TX_DESC_LOG2)
|
||||||
#define TX_DESC_WRAP(idx) \
|
#define TX_DESC_WRAP(idx) \
|
||||||
@ -137,6 +137,10 @@ struct if_atsam_tx_bds {
|
|||||||
volatile sGmacTxDescriptor bds[TX_DESC_COUNT];
|
volatile sGmacTxDescriptor bds[TX_DESC_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct if_atsam_rx_bds {
|
||||||
|
volatile sGmacRxDescriptor bds[RX_DESC_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-device data
|
* Per-device data
|
||||||
*/
|
*/
|
||||||
@ -152,12 +156,11 @@ typedef struct if_atsam_softc {
|
|||||||
size_t tx_idx_tail;
|
size_t tx_idx_tail;
|
||||||
struct if_atsam_tx_bds *tx;
|
struct if_atsam_tx_bds *tx;
|
||||||
struct mbuf *tx_mbufs[TX_DESC_COUNT];
|
struct mbuf *tx_mbufs[TX_DESC_COUNT];
|
||||||
|
struct if_atsam_rx_bds *rx;
|
||||||
|
struct mbuf *rx_mbufs[RX_DESC_COUNT];
|
||||||
uint8_t GMacAddress[6];
|
uint8_t GMacAddress[6];
|
||||||
rtems_id rx_daemon_tid;
|
rtems_id rx_daemon_tid;
|
||||||
rtems_vector_number interrupt_number;
|
rtems_vector_number interrupt_number;
|
||||||
struct mbuf **rx_mbuf;
|
|
||||||
size_t rx_bd_fill_idx;
|
|
||||||
size_t amount_rx_buf;
|
|
||||||
struct callout tick_ch;
|
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)
|
#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)
|
static struct mbuf *if_atsam_new_mbuf(struct ifnet *ifp)
|
||||||
{
|
{
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
@ -425,17 +407,17 @@ static void if_atsam_interrupt_handler(void *arg)
|
|||||||
/* Erase the interrupts for RX completion and errors */
|
/* Erase the interrupts for RX completion and errors */
|
||||||
pHw->GMAC_IDR = GMAC_IER_RCOMP | GMAC_IER_ROVR;
|
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);
|
ATSAMV7_ETH_RX_EVENT_INTERRUPT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_update_mbuf(struct mbuf *m,
|
static void
|
||||||
volatile sGmacRxDescriptor *buffer_desc)
|
if_atsam_rx_update_mbuf(struct mbuf *m, uint32_t status)
|
||||||
{
|
{
|
||||||
int frame_len;
|
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_data = mtod(m, char*)+ETHER_ALIGN;
|
||||||
m->m_len = frame_len;
|
m->m_len = frame_len;
|
||||||
@ -443,7 +425,7 @@ static void rx_update_mbuf(struct mbuf *m,
|
|||||||
|
|
||||||
/* check checksum offload result */
|
/* check checksum offload result */
|
||||||
m->m_pkthdr.csum_flags = 0;
|
m->m_pkthdr.csum_flags = 0;
|
||||||
switch (buffer_desc->status.bm.typeIDMatchOrCksumResult) {
|
switch ((status >> 22) & 0x3) {
|
||||||
case GMAC_RXDESC_ST_CKSUM_RESULT_IP_CHECKED:
|
case GMAC_RXDESC_ST_CKSUM_RESULT_IP_CHECKED:
|
||||||
m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;
|
m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;
|
||||||
m->m_pkthdr.csum_data = 0xffff;
|
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;
|
if_atsam_softc *sc = (if_atsam_softc *)arg;
|
||||||
struct ifnet *ifp = sc->ifp;
|
struct ifnet *ifp = sc->ifp;
|
||||||
void *rx_bd_base;
|
volatile sGmacRxDescriptor *base;
|
||||||
struct mbuf *m;
|
struct if_atsam_rx_bds *rx;
|
||||||
struct mbuf *n;
|
|
||||||
volatile sGmacRxDescriptor *buffer_desc;
|
|
||||||
uint32_t tmp_rx_bd_address;
|
|
||||||
Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
|
Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
|
||||||
|
size_t idx;
|
||||||
|
struct mbuf **mbufs;
|
||||||
|
struct mbuf *m;
|
||||||
|
|
||||||
IF_ATSAM_LOCK(sc);
|
IF_ATSAM_LOCK(sc);
|
||||||
|
|
||||||
@ -480,47 +462,37 @@ static void if_atsam_rx_daemon(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate memory space for priority queue descriptor list */
|
/* 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);
|
GMAC_DESCRIPTOR_ALIGNMENT, 0);
|
||||||
assert(rx_bd_base != NULL);
|
assert(base != NULL);
|
||||||
|
|
||||||
buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
|
base->addr.val = GMAC_RX_OWNERSHIP_BIT | GMAC_RX_WRAP_BIT;
|
||||||
buffer_desc->addr.val = GMAC_RX_SET_USED_WRAP;
|
base->status.val = 0;
|
||||||
buffer_desc->status.val = 0;
|
|
||||||
|
|
||||||
GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 1);
|
GMAC_SetRxQueue(pHw, (uint32_t)base, 1);
|
||||||
GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 2);
|
GMAC_SetRxQueue(pHw, (uint32_t)base, 2);
|
||||||
|
|
||||||
/* Allocate memory space for buffer descriptor list */
|
/* Allocate memory space for buffer descriptor list */
|
||||||
rx_bd_base = rtems_cache_coherent_allocate(
|
rx = rtems_cache_coherent_allocate(sizeof(*rx),
|
||||||
sc->amount_rx_buf * sizeof(sGmacRxDescriptor),
|
|
||||||
GMAC_DESCRIPTOR_ALIGNMENT, 0);
|
GMAC_DESCRIPTOR_ALIGNMENT, 0);
|
||||||
assert(rx_bd_base != NULL);
|
assert(rx != NULL);
|
||||||
buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
|
sc->rx = rx;
|
||||||
|
mbufs = &sc->rx_mbufs[0];
|
||||||
|
|
||||||
/* Create descriptor list and mark as empty */
|
/* Create descriptor list and mark as empty */
|
||||||
for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf;
|
for (idx = 0; idx < RX_DESC_COUNT; ++idx) {
|
||||||
++sc->rx_bd_fill_idx) {
|
|
||||||
m = if_atsam_new_mbuf(ifp);
|
m = if_atsam_new_mbuf(ifp);
|
||||||
assert(m != NULL);
|
assert(m != NULL);
|
||||||
sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
|
mbufs[idx] = m;
|
||||||
buffer_desc->addr.val = ((uint32_t)m->m_data) &
|
rx->bds[idx].addr.val = mtod(m, uint32_t) | RX_DESC_WRAP(idx);
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
|
|
||||||
|
|
||||||
/* Set 2 Byte Receive Buffer Offset */
|
/* 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 */
|
/* Write Buffer Queue Base Address Register */
|
||||||
GMAC_ReceiveEnable(pHw, 0);
|
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 */
|
/* Set address for address matching */
|
||||||
GMAC_SetAddress(pHw, 0, sc->GMacAddress);
|
GMAC_SetAddress(pHw, 0, sc->GMacAddress);
|
||||||
@ -528,58 +500,50 @@ static void if_atsam_rx_daemon(void *arg)
|
|||||||
/* Enable Receiving of data */
|
/* Enable Receiving of data */
|
||||||
GMAC_ReceiveEnable(pHw, 1);
|
GMAC_ReceiveEnable(pHw, 1);
|
||||||
|
|
||||||
/* Setup the interrupts for RX completion and errors */
|
IF_ATSAM_UNLOCK(sc);
|
||||||
GMAC_EnableIt(pHw, GMAC_IER_RCOMP | GMAC_IER_ROVR, 0);
|
|
||||||
|
|
||||||
sc->rx_bd_fill_idx = 0;
|
idx = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Wait for events */
|
rtems_event_set out;
|
||||||
if_atsam_event_receive(sc, ATSAMV7_ETH_RX_EVENT_INTERRUPT);
|
|
||||||
|
|
||||||
/*
|
/* Enable RX interrupts */
|
||||||
* Check for all packets with a set ownership bit
|
pHw->GMAC_IER = GMAC_IER_RCOMP | GMAC_IER_ROVR;
|
||||||
*/
|
|
||||||
while (buffer_desc->addr.bm.bOwnership == 1) {
|
(void) rtems_event_receive(ATSAMV7_ETH_RX_EVENT_INTERRUPT,
|
||||||
if (buffer_desc->status.bm.bEof == 1) {
|
RTEMS_EVENT_ALL | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &out);
|
||||||
m = sc->rx_mbuf[sc->rx_bd_fill_idx];
|
|
||||||
|
while (true) {
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t status;
|
||||||
|
|
||||||
|
addr = rx->bds[idx].addr.val;
|
||||||
|
if ((addr & GMAC_RX_OWNERSHIP_BIT) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
n = if_atsam_new_mbuf(ifp);
|
||||||
if (n != NULL) {
|
if (n != NULL) {
|
||||||
rx_update_mbuf(m, buffer_desc);
|
if_atsam_rx_update_mbuf(m, status);
|
||||||
|
(*ifp->if_input)(ifp, m);
|
||||||
IF_ATSAM_UNLOCK(sc);
|
|
||||||
sc->ifp->if_input(ifp, m);
|
|
||||||
IF_ATSAM_LOCK(sc);
|
|
||||||
m = n;
|
m = n;
|
||||||
}
|
}
|
||||||
sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
|
} else {
|
||||||
tmp_rx_bd_address = (uint32_t)m->m_data &
|
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
buffer_desc = (sGmacRxDescriptor *)rx_bd_base
|
|
||||||
+ sc->rx_bd_fill_idx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mbufs[idx] = m;
|
||||||
|
rx->bds[idx].addr.val = mtod(m, uint32_t) |
|
||||||
|
RX_DESC_WRAP(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);
|
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 */
|
/* Install interrupt handler */
|
||||||
status = rtems_interrupt_handler_install(sc->interrupt_number,
|
status = rtems_interrupt_handler_install(sc->interrupt_number,
|
||||||
"Ethernet",
|
"Ethernet",
|
||||||
@ -1417,8 +1375,6 @@ static int if_atsam_driver_attach(device_t dev)
|
|||||||
|
|
||||||
memcpy(sc->GMacAddress, eaddr, ETHER_ADDR_LEN);
|
memcpy(sc->GMacAddress, eaddr, ETHER_ADDR_LEN);
|
||||||
|
|
||||||
sc->amount_rx_buf = RXBUF_COUNT;
|
|
||||||
|
|
||||||
/* Set Initial Link Speed */
|
/* Set Initial Link Speed */
|
||||||
sc->link_speed = GMAC_SPEED_100M;
|
sc->link_speed = GMAC_SPEED_100M;
|
||||||
sc->link_duplex = GMAC_DUPLEX_FULL;
|
sc->link_duplex = GMAC_DUPLEX_FULL;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user