atsam: Add user defined RX/TX descriptor counts

This commit is contained in:
Alexander Krutwig
2016-07-25 15:11:07 +02:00
committed by Sebastian Huber
parent c51e6d915c
commit f6fdf2eb7b

View File

@@ -101,7 +101,6 @@
#define GMAC_PROM_ENABLE (1u << 4) #define GMAC_PROM_ENABLE (1u << 4)
/** RX Defines */ /** RX Defines */
#define GMAC_RX_BD_COUNT 8
#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_OFFSET (1u << 15)
@@ -109,7 +108,6 @@
#define GMAC_RX_SET_WRAP (1u << 1) #define GMAC_RX_SET_WRAP (1u << 1)
#define GMAC_RX_SET_USED (1u << 0) #define GMAC_RX_SET_USED (1u << 0)
/** TX Defines */ /** TX Defines */
#define GMAC_TX_BD_COUNT 128
#define GMAC_TX_SET_EOF (1u << 15) #define GMAC_TX_SET_EOF (1u << 15)
#define GMAC_TX_SET_WRAP (1u << 30) #define GMAC_TX_SET_WRAP (1u << 30)
#define GMAC_TX_SET_USED (1u << 31) #define GMAC_TX_SET_USED (1u << 31)
@@ -117,8 +115,9 @@
#define GMAC_DESCRIPTOR_ALIGNMENT 8 #define GMAC_DESCRIPTOR_ALIGNMENT 8
/** Events */ /** Events */
#define ATSAMV7_ETH_EVENT_INTERRUPT RTEMS_EVENT_1 #define ATSAMV7_ETH_RX_EVENT_INTERRUPT RTEMS_EVENT_1
#define ATSAMV7_ETH_START_TRANSMIT_EVENT RTEMS_EVENT_2 #define ATSAMV7_ETH_TX_EVENT_INTERRUPT RTEMS_EVENT_2
#define ATSAMV7_ETH_START_TRANSMIT_EVENT RTEMS_EVENT_3
#define ATSAMV7_ETH_RX_DATA_OFFSET 2 #define ATSAMV7_ETH_RX_DATA_OFFSET 2
@@ -136,6 +135,12 @@ typedef struct if_atsam_gmac {
uint8_t phy_address; uint8_t phy_address;
} if_atsam_gmac; } if_atsam_gmac;
typedef struct ring_buffer {
unsigned tx_bd_used;
unsigned tx_bd_free;
size_t length;
} ring_buffer;
/* /*
* Per-device data * Per-device data
*/ */
@@ -152,17 +157,19 @@ typedef struct if_atsam_softc {
rtems_vector_number interrupt_number; rtems_vector_number interrupt_number;
struct mbuf **rx_mbuf; struct mbuf **rx_mbuf;
struct mbuf **tx_mbuf; struct mbuf **tx_mbuf;
unsigned tx_bd_remove;
unsigned tx_bd_insert;
volatile sGmacTxDescriptor *tx_bd_base; volatile sGmacTxDescriptor *tx_bd_base;
uint32_t anlpar; uint32_t anlpar;
size_t rx_bd_fill_idx; size_t rx_bd_fill_idx;
size_t amount_rx_buf;
size_t amount_tx_buf;
ring_buffer tx_ring;
/* /*
* Statistics * Statistics
*/ */
unsigned rx_overrun_errors; unsigned rx_overrun_errors;
unsigned rx_interrupts; unsigned rx_interrupts;
unsigned tx_complete_int;
unsigned tx_tur_errors; unsigned tx_tur_errors;
unsigned tx_rlex_errors; unsigned tx_rlex_errors;
unsigned tx_tfc_errors; unsigned tx_tfc_errors;
@@ -182,13 +189,12 @@ static struct mbuf *if_atsam_new_mbuf(struct ifnet *ifp)
if ((m->m_flags & M_EXT) != 0) { if ((m->m_flags & M_EXT) != 0) {
m->m_pkthdr.rcvif = ifp; m->m_pkthdr.rcvif = ifp;
m->m_data = mtod(m, char *); m->m_data = mtod(m, char *);
rtems_cache_invalidate_multiple_data_lines(mtod(m, void *),
GMAC_RX_BUFFER_SIZE);
} else { } else {
m_free(m); m_free(m);
m = NULL; m = NULL;
} }
rtems_cache_invalidate_multiple_data_lines(mtod(m, void *),
GMAC_RX_BUFFER_SIZE);
} }
return (m); return (m);
} }
@@ -219,9 +225,7 @@ if_atsam_write_phy(Gmac *pHw, uint8_t PhyAddress, uint8_t Address,
uint32_t Value, uint32_t retry) uint32_t Value, uint32_t retry)
{ {
GMAC_PHYMaintain(pHw, PhyAddress, Address, 0, (uint16_t)Value); GMAC_PHYMaintain(pHw, PhyAddress, Address, 0, (uint16_t)Value);
TRACE_DEBUG(" Write Access\n\r");
if (if_atsam_wait_phy(pHw, retry) == 1) { if (if_atsam_wait_phy(pHw, retry) == 1) {
TRACE_ERROR("TimeOut WritePhy\n\r");
return (1); return (1);
} }
return (0); return (0);
@@ -232,10 +236,8 @@ static uint8_t
if_atsam_read_phy(Gmac *pHw, if_atsam_read_phy(Gmac *pHw,
uint8_t PhyAddress, uint8_t Address, uint32_t *pvalue, uint32_t retry) uint8_t PhyAddress, uint8_t Address, uint32_t *pvalue, uint32_t retry)
{ {
TRACE_DEBUG(" Read Access\n\r");
GMAC_PHYMaintain(pHw, PhyAddress, Address, 1, 0); GMAC_PHYMaintain(pHw, PhyAddress, Address, 1, 0);
if (if_atsam_wait_phy(pHw, retry) == 1) { if (if_atsam_wait_phy(pHw, retry) == 1) {
TRACE_ERROR("TimeOut ReadPhy\n\r");
return (1); return (1);
} }
*pvalue = GMAC_PHYData(pHw); *pvalue = GMAC_PHYData(pHw);
@@ -252,8 +254,6 @@ static void atsamv7_find_valid_phy(if_atsam_gmac *gmac_inst)
uint8_t rc; uint8_t rc;
uint8_t phy_address; uint8_t phy_address;
TRACE_DEBUG("GMACB_FindValidPhy\n\r");
phy_address = gmac_inst->phy_address; phy_address = gmac_inst->phy_address;
retry_max = gmac_inst->retries; retry_max = gmac_inst->retries;
@@ -270,24 +270,16 @@ static void atsamv7_find_valid_phy(if_atsam_gmac *gmac_inst)
rv = if_atsam_read_phy(pHw, phy_address, MII_PHYIDR1, rv = if_atsam_read_phy(pHw, phy_address, MII_PHYIDR1,
&value, retry_max); &value, retry_max);
if (rv == 0 && value != 0 && value >= 0xffff) { if (rv == 0 && value != 0 && value >= 0xffff) {
TRACE_DEBUG("_PHYID1 : 0x%X, addr: %d\n\r", value,
phy_address);
rc = phy_address; rc = phy_address;
break; break;
} else {
TRACE_ERROR("MACB PROBLEM\n\r");
} }
} }
if (rc != 0xFF) { if (rc != 0xFF) {
TRACE_DEBUG("** Valid PHY Found: %d\n\r", rc);
if_atsam_read_phy(pHw, phy_address, MII_PHYIDR1, &value, if_atsam_read_phy(pHw, phy_address, MII_PHYIDR1, &value,
retry_max); retry_max);
TRACE_DEBUG("_PHYID1R : 0x%X, addr: %d\n\r", value,
phy_address);
if_atsam_read_phy(pHw, phy_address, MII_PHYIDR2, &value, if_atsam_read_phy(pHw, phy_address, MII_PHYIDR2, &value,
retry_max); retry_max);
TRACE_DEBUG("_EMSR : 0x%X, addr: %d\n\r", value, phy_address);
gmac_inst->phy_address = phy_address; gmac_inst->phy_address = phy_address;
} }
} }
@@ -303,8 +295,6 @@ static uint8_t if_atsam_reset_phy(if_atsam_gmac *gmac_inst)
Gmac *pHw = gmac_inst->gGmacd.pHw; Gmac *pHw = gmac_inst->gGmacd.pHw;
TRACE_DEBUG(" GMACB_ResetPhy\n\r");
phy_address = gmac_inst->phy_address; phy_address = gmac_inst->phy_address;
retry_max = gmac_inst->retries; retry_max = gmac_inst->retries;
@@ -332,12 +322,9 @@ if_atsam_init_phy(if_atsam_gmac *gmac_inst, uint32_t mck,
Gmac *pHw = gmac_inst->gGmacd.pHw; Gmac *pHw = gmac_inst->gGmacd.pHw;
/* Perform RESET */ /* Perform RESET */
TRACE_DEBUG("RESET PHY\n\r");
if (pResetPins) { if (pResetPins) {
/* Configure PINS */ /* Configure PINS */
PIO_Configure(pResetPins, nbResetPins); PIO_Configure(pResetPins, nbResetPins);
TRACE_DEBUG(" Hard Reset of GMACD Phy\n\r");
PIO_Clear(pResetPins); PIO_Clear(pResetPins);
rtems_task_wake_after(1); rtems_task_wake_after(1);
PIO_Set(pResetPins); PIO_Set(pResetPins);
@@ -348,14 +335,10 @@ if_atsam_init_phy(if_atsam_gmac *gmac_inst, uint32_t mck,
rc = GMAC_SetMdcClock(pHw, mck); rc = GMAC_SetMdcClock(pHw, mck);
if (!rc) { if (!rc) {
TRACE_ERROR("No Valid MDC clock\n\r");
return (0); return (0);
} }
if_atsam_reset_phy(gmac_inst); if_atsam_reset_phy(gmac_inst);
} else {
TRACE_ERROR("PHY Reset Timeout\n\r");
} }
return (rc); return (rc);
} }
@@ -368,11 +351,7 @@ static int if_atsam_mdio_read(int phy, void *arg, unsigned reg, uint32_t *pval)
{ {
if_atsam_softc *sc = (if_atsam_softc *)arg; if_atsam_softc *sc = (if_atsam_softc *)arg;
TRACE_DEBUG("Mdio read\n\r");
TRACE_DEBUG("%i\n", phy);
if (!if_atsam_is_valid_phy(phy)) { if (!if_atsam_is_valid_phy(phy)) {
TRACE_ERROR("Mdio read invalid phy\n\r");
return (EINVAL); return (EINVAL);
} }
@@ -385,10 +364,7 @@ static int if_atsam_mdio_write(int phy, void *arg, unsigned reg, uint32_t pval)
{ {
if_atsam_softc *sc = (if_atsam_softc *)arg; if_atsam_softc *sc = (if_atsam_softc *)arg;
TRACE_DEBUG("Mdio write\n\r");
if (!if_atsam_is_valid_phy(phy)) { if (!if_atsam_is_valid_phy(phy)) {
TRACE_ERROR("Mdio write invalid phy\n\r");
return (EINVAL); return (EINVAL);
} }
@@ -414,10 +390,10 @@ static void if_atsam_interrupt_handler(void *arg)
/* Check receive interrupts */ /* Check receive interrupts */
if ((irq_status_val & GMAC_IER_ROVR) != 0) { if ((irq_status_val & GMAC_IER_ROVR) != 0) {
++sc->rx_overrun_errors; ++sc->rx_overrun_errors;
rx_event = ATSAMV7_ETH_EVENT_INTERRUPT; rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT;
} }
if ((irq_status_val & GMAC_IER_RCOMP) != 0) { if ((irq_status_val & GMAC_IER_RCOMP) != 0) {
rx_event = ATSAMV7_ETH_EVENT_INTERRUPT; rx_event = ATSAMV7_ETH_RX_EVENT_INTERRUPT;
} }
/* Send events to receive task and switch off rx interrupts */ /* Send events to receive task and switch off rx interrupts */
if (rx_event != 0) { if (rx_event != 0) {
@@ -428,23 +404,23 @@ static void if_atsam_interrupt_handler(void *arg)
} }
if ((irq_status_val & GMAC_IER_TUR) != 0) { if ((irq_status_val & GMAC_IER_TUR) != 0) {
++sc->tx_tur_errors; ++sc->tx_tur_errors;
tx_event = ATSAMV7_ETH_EVENT_INTERRUPT; tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
} }
if ((irq_status_val & GMAC_IER_RLEX) != 0) { if ((irq_status_val & GMAC_IER_RLEX) != 0) {
++sc->tx_rlex_errors; ++sc->tx_rlex_errors;
tx_event = ATSAMV7_ETH_EVENT_INTERRUPT; tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
} }
if ((irq_status_val & GMAC_IER_TFC) != 0) { if ((irq_status_val & GMAC_IER_TFC) != 0) {
++sc->tx_tfc_errors; ++sc->tx_tfc_errors;
tx_event = ATSAMV7_ETH_EVENT_INTERRUPT; tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
} }
if ((irq_status_val & GMAC_IER_HRESP) != 0) { if ((irq_status_val & GMAC_IER_HRESP) != 0) {
TRACE_DEBUG("Tx interrupts: %u\n", sc->tx_interrupts);
++sc->tx_hresp_errors; ++sc->tx_hresp_errors;
tx_event = ATSAMV7_ETH_EVENT_INTERRUPT; tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
} }
if ((irq_status_val & GMAC_IER_TCOMP) != 0) { if ((irq_status_val & GMAC_IER_TCOMP) != 0) {
tx_event = ATSAMV7_ETH_EVENT_INTERRUPT; ++sc->tx_complete_int;
tx_event = ATSAMV7_ETH_TX_EVENT_INTERRUPT;
} }
/* Send events to transmit task and switch off tx interrupts */ /* Send events to transmit task and switch off tx interrupts */
if (tx_event != 0) { if (tx_event != 0) {
@@ -454,14 +430,11 @@ static void if_atsam_interrupt_handler(void *arg)
(void)rtems_bsdnet_event_send(sc->tx_daemon_tid, tx_event); (void)rtems_bsdnet_event_send(sc->tx_daemon_tid, tx_event);
} }
} }
/* /*
* Receive daemon * Receive daemon
*/ */
static void if_atsam_rx_daemon(void *arg) static void if_atsam_rx_daemon(void *arg)
{ {
TRACE_DEBUG(" rx daemon\n\r");
if_atsam_softc *sc = (if_atsam_softc *)arg; if_atsam_softc *sc = (if_atsam_softc *)arg;
rtems_event_set events = 0; rtems_event_set events = 0;
void *rx_bd_base; void *rx_bd_base;
@@ -488,13 +461,13 @@ static void if_atsam_rx_daemon(void *arg)
/* Allocate memory space for buffer descriptor list */ /* Allocate memory space for buffer descriptor list */
rx_bd_base = rtems_cache_coherent_allocate( rx_bd_base = rtems_cache_coherent_allocate(
GMAC_RX_BD_COUNT * sizeof(sGmacRxDescriptor), sc->amount_rx_buf * sizeof(sGmacRxDescriptor),
GMAC_DESCRIPTOR_ALIGNMENT, 0); GMAC_DESCRIPTOR_ALIGNMENT, 0);
assert(rx_bd_base != NULL); assert(rx_bd_base != NULL);
buffer_desc = (sGmacRxDescriptor *)rx_bd_base; buffer_desc = (sGmacRxDescriptor *)rx_bd_base;
/* 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 < GMAC_RX_BD_COUNT; for (sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx < sc->amount_rx_buf;
++sc->rx_bd_fill_idx) { ++sc->rx_bd_fill_idx) {
m = if_atsam_new_mbuf(&sc->arpcom.ac_if); m = if_atsam_new_mbuf(&sc->arpcom.ac_if);
assert(m != NULL); assert(m != NULL);
@@ -502,7 +475,7 @@ static void if_atsam_rx_daemon(void *arg)
buffer_desc->addr.val = ((uint32_t)m->m_data) & buffer_desc->addr.val = ((uint32_t)m->m_data) &
GMAC_RX_BUF_DESC_ADDR_MASK; GMAC_RX_BUF_DESC_ADDR_MASK;
buffer_desc->status.val = 0; buffer_desc->status.val = 0;
if (sc->rx_bd_fill_idx == (GMAC_RX_BD_COUNT - 1)) { if (sc->rx_bd_fill_idx == (sc->amount_rx_buf - 1)) {
buffer_desc->addr.bm.bWrap = 1; buffer_desc->addr.bm.bWrap = 1;
} else { } else {
buffer_desc++; buffer_desc++;
@@ -518,11 +491,7 @@ static void if_atsam_rx_daemon(void *arg)
GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0); GMAC_SetRxQueue(pHw, (uint32_t)buffer_desc, 0);
/* Set address for address matching */ /* Set address for address matching */
TRACE_DEBUG("Connect the board to a host PC via an ethernet cable\n\r");
GMAC_SetAddress(pHw, 0, sc->GMacAddress); GMAC_SetAddress(pHw, 0, sc->GMacAddress);
TRACE_DEBUG("-- MAC %x:%x:%x:%x:%x:%x\n\r",
sc->GMacAddress[0], sc->GMacAddress[1], sc->GMacAddress[2],
sc->GMacAddress[3], sc->GMacAddress[4], sc->GMacAddress[5]);
/* Enable Receiving of data */ /* Enable Receiving of data */
GMAC_ReceiveEnable(pHw, 1); GMAC_ReceiveEnable(pHw, 1);
@@ -533,21 +502,16 @@ static void if_atsam_rx_daemon(void *arg)
sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx = 0;
while (true) { while (true) {
TRACE_DEBUG("Wait for receive event\n");
/* Wait for events */ /* Wait for events */
rtems_bsdnet_event_receive(ATSAMV7_ETH_EVENT_INTERRUPT, rtems_bsdnet_event_receive(ATSAMV7_ETH_RX_EVENT_INTERRUPT,
RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_EVENT_ANY | RTEMS_WAIT,
RTEMS_NO_TIMEOUT, &events); RTEMS_NO_TIMEOUT, &events);
TRACE_DEBUG("Receive event received\n");
/* /*
* Check for all packets with a set ownership bit * Check for all packets with a set ownership bit
*/ */
while (buffer_desc->addr.bm.bOwnership == 1) { while (buffer_desc->addr.bm.bOwnership == 1) {
if (buffer_desc->status.bm.bEof == 1) { if (buffer_desc->status.bm.bEof == 1) {
TRACE_DEBUG("Buffer Descriptor %i\n",
sc->rx_bd_fill_idx);
m = sc->rx_mbuf[sc->rx_bd_fill_idx]; m = sc->rx_mbuf[sc->rx_bd_fill_idx];
/* New mbuf for desc */ /* New mbuf for desc */
@@ -567,6 +531,9 @@ static void if_atsam_rx_daemon(void *arg)
m->m_data = (void *)(eh + 1); m->m_data = (void *)(eh + 1);
ether_input(&sc->arpcom.ac_if, eh, m); ether_input(&sc->arpcom.ac_if, eh, m);
m = n; m = n;
} else {
(void)rtems_bsdnet_event_send(
sc->tx_daemon_tid, ATSAMV7_ETH_START_TRANSMIT_EVENT);
} }
sc->rx_mbuf[sc->rx_bd_fill_idx] = m; sc->rx_mbuf[sc->rx_bd_fill_idx] = m;
tmp_rx_bd_address = (uint32_t)m->m_data & tmp_rx_bd_address = (uint32_t)m->m_data &
@@ -574,7 +541,7 @@ static void if_atsam_rx_daemon(void *arg)
/* Switch pointer to next buffer descriptor */ /* Switch pointer to next buffer descriptor */
if (sc->rx_bd_fill_idx == if (sc->rx_bd_fill_idx ==
(GMAC_RX_BD_COUNT - 1)) { (sc->amount_rx_buf - 1)) {
tmp_rx_bd_address |= GMAC_RX_SET_WRAP; tmp_rx_bd_address |= GMAC_RX_SET_WRAP;
sc->rx_bd_fill_idx = 0; sc->rx_bd_fill_idx = 0;
} else { } else {
@@ -597,15 +564,32 @@ static void if_atsam_rx_daemon(void *arg)
} }
} }
/* /*
* Update of current transmit buffer position. * Update of current transmit buffer position.
*/ */
static void if_atsam_tx_bd_pos_update(size_t *pos) static void if_atsam_tx_bd_pos_update(size_t *pos, size_t amount_tx_buf)
{ {
*pos = (*pos + 1) % GMAC_TX_BD_COUNT; *pos = (*pos + 1) % amount_tx_buf;
} }
/*
* Is RingBuffer empty
*/
static bool if_atsam_ring_buffer_empty(ring_buffer *ring_buffer)
{
return (ring_buffer->tx_bd_used == ring_buffer->tx_bd_free);
}
/*
* Is RingBuffer full
*/
static bool if_atsam_ring_buffer_full(ring_buffer *ring_buffer)
{
size_t tx_bd_used_next = ring_buffer->tx_bd_used;
if_atsam_tx_bd_pos_update(&tx_bd_used_next, ring_buffer->length);
return (tx_bd_used_next == ring_buffer->tx_bd_free);
}
/* /*
* Cleanup transmit file descriptors by freeing mbufs which are not needed any * Cleanup transmit file descriptors by freeing mbufs which are not needed any
@@ -617,17 +601,18 @@ static void if_atsam_tx_bd_cleanup(if_atsam_softc *sc)
volatile sGmacTxDescriptor *cur; volatile sGmacTxDescriptor *cur;
bool eof_needed = false; bool eof_needed = false;
while (sc->tx_bd_remove != sc->tx_bd_insert) { while (!if_atsam_ring_buffer_empty(&sc->tx_ring)){
cur = sc->tx_bd_base + sc->tx_bd_remove; cur = sc->tx_bd_base + sc->tx_ring.tx_bd_free;
if (((cur->status.bm.bUsed == 1) && if (((cur->status.bm.bUsed == 1) && !eof_needed) || eof_needed) {
!eof_needed) || eof_needed) {
eof_needed = true; eof_needed = true;
cur->status.val |= GMAC_TX_SET_USED; cur->status.val |= GMAC_TX_SET_USED;
m = sc->tx_mbuf[sc->tx_bd_remove]; m = sc->tx_mbuf[sc->tx_ring.tx_bd_free];
m_free(m); m_free(m);
if_atsam_tx_bd_pos_update(&sc->tx_bd_remove); sc->tx_mbuf[sc->tx_ring.tx_bd_free] = 0;
if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_free,
sc->tx_ring.length);
if (cur->status.bm.bLastBuffer) { if (cur->status.bm.bLastBuffer) {
break; eof_needed = false;
} }
} else { } else {
break; break;
@@ -635,56 +620,49 @@ static void if_atsam_tx_bd_cleanup(if_atsam_softc *sc)
} }
} }
/* /*
* Prepare Ethernet frame to start transmission. * Prepare Ethernet frame to start transmission.
*/ */
static void if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m) static bool if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m)
{ {
rtems_event_set events = 0;
volatile sGmacTxDescriptor *cur; volatile sGmacTxDescriptor *cur;
volatile sGmacTxDescriptor *start_packet_tx_bd = 0; volatile sGmacTxDescriptor *start_packet_tx_bd = 0;
int pos = 0; int pos = 0;
unsigned insert_next_pos;
uint32_t tmp_val = 0; uint32_t tmp_val = 0;
Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
bool success;
TRACE_DEBUG("TX Send Packet\n");
if_atsam_tx_bd_cleanup(sc); if_atsam_tx_bd_cleanup(sc);
/* Wait for interrupt in case no buffer descriptors are available */ /* Wait for interrupt in case no buffer descriptors are available */
/* Wait for events */ /* Wait for events */
while (true) { while (true) {
insert_next_pos = sc->tx_bd_insert; if (if_atsam_ring_buffer_full(&sc->tx_ring)) {
if_atsam_tx_bd_pos_update(&insert_next_pos);
if (sc->tx_bd_remove == insert_next_pos) {
/* Setup the interrupts for TX completion and errors */ /* Setup the interrupts for TX completion and errors */
GMAC_EnableIt(pHw, GMAC_INT_TX_BITS, 0); GMAC_EnableIt(pHw, GMAC_INT_TX_BITS, 0);
rtems_bsdnet_event_receive(ATSAMV7_ETH_EVENT_INTERRUPT, success = false;
RTEMS_EVENT_ANY | RTEMS_WAIT, break;
RTEMS_NO_TIMEOUT, &events);
if_atsam_tx_bd_cleanup(sc);
} }
/* /*
* Get current mbuf for data fill * Get current mbuf for data fill
*/ */
cur = &sc->tx_bd_base[sc->tx_bd_insert]; cur = &sc->tx_bd_base[sc->tx_ring.tx_bd_used];
/* Set the transfer data */ /* Set the transfer data */
rtems_cache_flush_multiple_data_lines(mtod(m, const void *), rtems_cache_flush_multiple_data_lines(mtod(m, const void *),
(size_t)m->m_len); (size_t)m->m_len);
if (m->m_len) { if (m->m_len) {
cur->addr = (uint32_t)(mtod(m, void *)); cur->addr = (uint32_t)(mtod(m, void *));
tmp_val = (uint32_t)m->m_len | GMAC_TX_SET_USED; tmp_val = (uint32_t)m->m_len | GMAC_TX_SET_USED;
if (sc->tx_bd_insert == (GMAC_TX_BD_COUNT - 1)) { if (sc->tx_ring.tx_bd_used == (sc->tx_ring.length - 1)) {
tmp_val |= GMAC_TX_SET_WRAP; tmp_val |= GMAC_TX_SET_WRAP;
} }
if (pos == 0) { if (pos == 0) {
start_packet_tx_bd = cur; start_packet_tx_bd = cur;
} }
sc->tx_mbuf[sc->tx_bd_insert] = m; sc->tx_mbuf[sc->tx_ring.tx_bd_used] = m;
m = m->m_next; m = m->m_next;
if_atsam_tx_bd_pos_update(&sc->tx_bd_insert); if_atsam_tx_bd_pos_update(&sc->tx_ring.tx_bd_used,
sc->tx_ring.length);
} else { } else {
/* Discard empty mbufs */ /* Discard empty mbufs */
m = m_free(m); m = m_free(m);
@@ -700,6 +678,9 @@ static void if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m)
_ARM_Data_synchronization_barrier(); _ARM_Data_synchronization_barrier();
cur->status.val = tmp_val; cur->status.val = tmp_val;
start_packet_tx_bd->status.val &= ~GMAC_TX_SET_USED; start_packet_tx_bd->status.val &= ~GMAC_TX_SET_USED;
_ARM_Data_synchronization_barrier();
GMAC_TransmissionStart(pHw);
success = true;
break; break;
} else { } else {
if (pos > 0) { if (pos > 0) {
@@ -709,6 +690,7 @@ static void if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m)
cur->status.val = tmp_val; cur->status.val = tmp_val;
} }
} }
return success;
} }
@@ -717,13 +699,13 @@ static void if_atsam_send_packet(if_atsam_softc *sc, struct mbuf *m)
*/ */
static void if_atsam_tx_daemon(void *arg) static void if_atsam_tx_daemon(void *arg)
{ {
TRACE_DEBUG(" tx daemon\n\r");
if_atsam_softc *sc = (if_atsam_softc *)arg; if_atsam_softc *sc = (if_atsam_softc *)arg;
rtems_event_set events = 0; rtems_event_set events = 0;
sGmacTxDescriptor *buffer_desc; sGmacTxDescriptor *buffer_desc;
int bd_number; int bd_number;
void *tx_bd_base; void *tx_bd_base;
struct mbuf *m; struct mbuf *m;
bool success;
Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
struct ifnet *ifp = &sc->arpcom.ac_if; struct ifnet *ifp = &sc->arpcom.ac_if;
@@ -744,16 +726,16 @@ static void if_atsam_tx_daemon(void *arg)
/* Allocate memory space for buffer descriptor list */ /* Allocate memory space for buffer descriptor list */
tx_bd_base = rtems_cache_coherent_allocate( tx_bd_base = rtems_cache_coherent_allocate(
GMAC_TX_BD_COUNT * sizeof(sGmacTxDescriptor), sc->amount_tx_buf * sizeof(sGmacTxDescriptor),
GMAC_DESCRIPTOR_ALIGNMENT, 0); GMAC_DESCRIPTOR_ALIGNMENT, 0);
assert(tx_bd_base != NULL); assert(tx_bd_base != NULL);
buffer_desc = (sGmacTxDescriptor *)tx_bd_base; buffer_desc = (sGmacTxDescriptor *)tx_bd_base;
/* Create descriptor list and mark as empty */ /* Create descriptor list and mark as empty */
for (bd_number = 0; bd_number < GMAC_TX_BD_COUNT; bd_number++) { for (bd_number = 0; bd_number < sc->amount_tx_buf; bd_number++) {
buffer_desc->addr = 0; buffer_desc->addr = 0;
buffer_desc->status.val = GMAC_TX_SET_USED; buffer_desc->status.val = GMAC_TX_SET_USED;
if (bd_number == (GMAC_TX_BD_COUNT - 1)) { if (bd_number == (sc->amount_tx_buf - 1)) {
buffer_desc->status.bm.bWrap = 1; buffer_desc->status.bm.bWrap = 1;
} else { } else {
buffer_desc++; buffer_desc++;
@@ -768,17 +750,14 @@ static void if_atsam_tx_daemon(void *arg)
GMAC_TransmitEnable(pHw, 1); GMAC_TransmitEnable(pHw, 1);
/* Set variables in context */ /* Set variables in context */
sc->tx_bd_remove = 0;
sc->tx_bd_insert = 0;
sc->tx_bd_base = tx_bd_base; sc->tx_bd_base = tx_bd_base;
while (true) { while (true) {
TRACE_DEBUG("Wait for TX Transmit Start Event\n");
/* Wait for events */ /* Wait for events */
rtems_bsdnet_event_receive(ATSAMV7_ETH_START_TRANSMIT_EVENT, rtems_bsdnet_event_receive(ATSAMV7_ETH_START_TRANSMIT_EVENT | ATSAMV7_ETH_TX_EVENT_INTERRUPT,
RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_EVENT_ANY | RTEMS_WAIT,
RTEMS_NO_TIMEOUT, &events); RTEMS_NO_TIMEOUT, &events);
TRACE_DEBUG("TX Transmit Event received\n"); //printf("TX Transmit Event received\n");
/* /*
* Send packets till queue is empty * Send packets till queue is empty
@@ -787,15 +766,17 @@ static void if_atsam_tx_daemon(void *arg)
/* /*
* Get the mbuf chain to transmit * Get the mbuf chain to transmit
*/ */
if_atsam_tx_bd_cleanup(sc);
IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
if (!m) { if (!m) {
ifp->if_flags &= ~IFF_OACTIVE;
break;
}
success = if_atsam_send_packet(sc, m);
if (!success){
break; break;
} }
if_atsam_send_packet(sc, m);
_ARM_Data_synchronization_barrier();
GMAC_TransmissionStart(pHw);
} }
ifp->if_flags &= ~IFF_OACTIVE;
} }
} }
@@ -807,8 +788,6 @@ static void if_atsam_enet_start(struct ifnet *ifp)
{ {
if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc; if_atsam_softc *sc = (if_atsam_softc *)ifp->if_softc;
TRACE_DEBUG(" in start\n\r");
ifp->if_flags |= IFF_OACTIVE; ifp->if_flags |= IFF_OACTIVE;
rtems_bsdnet_event_send(sc->tx_daemon_tid, rtems_bsdnet_event_send(sc->tx_daemon_tid,
ATSAMV7_ETH_START_TRANSMIT_EVENT); ATSAMV7_ETH_START_TRANSMIT_EVENT);
@@ -829,13 +808,10 @@ static void if_atsam_interface_watchdog(struct ifnet *ifp)
uint8_t phy = sc->Gmac_inst.phy_address; uint8_t phy = sc->Gmac_inst.phy_address;
uint32_t retries = sc->Gmac_inst.retries; uint32_t retries = sc->Gmac_inst.retries;
TRACE_DEBUG("Entered Watchdog\n\r");
if (if_atsam_read_phy(pHw, phy, MII_ANLPAR, &anlpar, retries)) { if (if_atsam_read_phy(pHw, phy, MII_ANLPAR, &anlpar, retries)) {
anlpar = 0; anlpar = 0;
} }
if (sc->anlpar != anlpar) { if (sc->anlpar != anlpar) {
TRACE_DEBUG("Entered Watchdog Loop\n\r");
/* Set up the GMAC link speed */ /* Set up the GMAC link speed */
if (anlpar & ANLPAR_TX_FD) { if (anlpar & ANLPAR_TX_FD) {
/* Set MII for 100BaseTx and Full Duplex */ /* Set MII for 100BaseTx and Full Duplex */
@@ -872,7 +848,6 @@ static void if_atsam_init(void *arg)
{ {
rtems_status_code status; rtems_status_code status;
TRACE_DEBUG(" in setup hardware\n\r");
if_atsam_softc *sc = (if_atsam_softc *)arg; if_atsam_softc *sc = (if_atsam_softc *)arg;
struct ifnet *ifp = &sc->arpcom.ac_if; struct ifnet *ifp = &sc->arpcom.ac_if;
uint32_t dmac_cfg = 0; uint32_t dmac_cfg = 0;
@@ -902,10 +877,8 @@ static void if_atsam_init(void *arg)
GMAC_EnableMdio(sc->Gmac_inst.gGmacd.pHw); GMAC_EnableMdio(sc->Gmac_inst.gGmacd.pHw);
/* PHY initialize */ /* PHY initialize */
if (!if_atsam_init_phy(&sc->Gmac_inst, BOARD_MCK, &gmacResetPin, 1, if_atsam_init_phy(&sc->Gmac_inst, BOARD_MCK, &gmacResetPin, 1,
gmacPins, PIO_LISTSIZE(gmacPins))) { gmacPins, PIO_LISTSIZE(gmacPins));
TRACE_ERROR("PHY Initialize ERROR!\n\r");
}
/* Find valid Phy */ /* Find valid Phy */
atsamv7_find_valid_phy(&sc->Gmac_inst); atsamv7_find_valid_phy(&sc->Gmac_inst);
@@ -933,9 +906,9 @@ static void if_atsam_init(void *arg)
/* /*
* Allocate mbuf pointers * Allocate mbuf pointers
*/ */
sc->rx_mbuf = malloc(GMAC_RX_BD_COUNT * sizeof *sc->rx_mbuf, sc->rx_mbuf = malloc(sc->amount_rx_buf * sizeof *sc->rx_mbuf,
M_MBUF, M_NOWAIT); M_MBUF, M_NOWAIT);
sc->tx_mbuf = malloc(GMAC_TX_BD_COUNT * sizeof *sc->rx_mbuf, sc->tx_mbuf = malloc(sc->amount_tx_buf * sizeof *sc->tx_mbuf,
M_MBUF, M_NOWAIT); M_MBUF, M_NOWAIT);
/* Install interrupt handler */ /* Install interrupt handler */
@@ -967,8 +940,6 @@ static void if_atsam_stop(struct if_atsam_softc *sc)
struct ifnet *ifp = &sc->arpcom.ac_if; struct ifnet *ifp = &sc->arpcom.ac_if;
Gmac *pHw = sc->Gmac_inst.gGmacd.pHw; Gmac *pHw = sc->Gmac_inst.gGmacd.pHw;
TRACE_DEBUG(" in stop\n\r");
ifp->if_flags &= ~IFF_RUNNING; ifp->if_flags &= ~IFF_RUNNING;
/* Disable MDIO interface and TX/RX */ /* Disable MDIO interface and TX/RX */
@@ -986,8 +957,6 @@ static void if_atsam_stats(struct if_atsam_softc *sc)
int media = 0; int media = 0;
Gmac *pHw; Gmac *pHw;
TRACE_DEBUG(" in stats\n\r");
media = (int)IFM_MAKEWORD(0, 0, 0, sc->Gmac_inst.phy_address); media = (int)IFM_MAKEWORD(0, 0, 0, sc->Gmac_inst.phy_address);
eno = rtems_mii_ioctl(&sc->mdio, sc, SIOCGIFMEDIA, &media); eno = rtems_mii_ioctl(&sc->mdio, sc, SIOCGIFMEDIA, &media);
@@ -1001,7 +970,12 @@ static void if_atsam_stats(struct if_atsam_softc *sc)
printf("\n** Context Statistics **\n"); printf("\n** Context Statistics **\n");
printf("Rx interrupts: %u\n", sc->rx_interrupts); printf("Rx interrupts: %u\n", sc->rx_interrupts);
printf("Tx interrupts: %u\n\n", sc->tx_interrupts); printf("Tx interrupts: %u\n", sc->tx_interrupts);
printf("Error Tur Tx interrupts: %u\n\n", sc->tx_tur_errors);
printf("Error Rlex Tx interrupts: %u\n\n", sc->tx_rlex_errors);
printf("Error Tfc Tx interrupts: %u\n\n", sc->tx_tfc_errors);
printf("Error Hresp Tx interrupts: %u\n\n", sc->tx_hresp_errors);
printf("Tx complete interrupts: %u\n\n", sc->tx_complete_int);
printf("\n** Statistics **\n"); printf("\n** Statistics **\n");
printf("Octets Transmitted Low: %lu\n", pHw->GMAC_OTLO); printf("Octets Transmitted Low: %lu\n", pHw->GMAC_OTLO);
printf("Octets Transmitted High: %lu\n", pHw->GMAC_OTHI); printf("Octets Transmitted High: %lu\n", pHw->GMAC_OTHI);
@@ -1164,17 +1138,13 @@ if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
int rv = 0; int rv = 0;
bool prom_enable; bool prom_enable;
TRACE_DEBUG(" in ioctl\n\r");
switch (command) { switch (command) {
case SIOCGIFMEDIA: case SIOCGIFMEDIA:
case SIOCSIFMEDIA: case SIOCSIFMEDIA:
TRACE_DEBUG("MEDIA\n");
rtems_mii_ioctl(&sc->mdio, sc, command, &ifr->ifr_media); rtems_mii_ioctl(&sc->mdio, sc, command, &ifr->ifr_media);
break; break;
case SIOCGIFADDR: case SIOCGIFADDR:
case SIOCSIFADDR: case SIOCSIFADDR:
TRACE_DEBUG("Address\n");
ether_ioctl(ifp, command, data); ether_ioctl(ifp, command, data);
break; break;
case SIOCSIFFLAGS: case SIOCSIFFLAGS:
@@ -1196,7 +1166,6 @@ if_atsam_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
case SIOCDELMULTI: case SIOCDELMULTI:
if_atsam_multicast_control(command == SIOCADDMULTI, ifr, sc); if_atsam_multicast_control(command == SIOCADDMULTI, ifr, sc);
case SIO_RTEMS_SHOW_STATS: case SIO_RTEMS_SHOW_STATS:
TRACE_DEBUG("SHOW STATS\n");
if_atsam_stats(sc); if_atsam_stats(sc);
break; break;
default: default:
@@ -1243,6 +1212,13 @@ static int if_atsam_driver_attach(struct rtems_bsdnet_ifconfig *config)
sc->mdio.mdio_w = if_atsam_mdio_write; sc->mdio.mdio_w = if_atsam_mdio_write;
sc->mdio.has_gmii = 1; sc->mdio.has_gmii = 1;
sc->amount_rx_buf = config->rbuf_count;
sc->amount_tx_buf = config->xbuf_count;
sc->tx_ring.tx_bd_used = 0;
sc->tx_ring.tx_bd_free = 0;
sc->tx_ring.length = sc->amount_tx_buf;
/* /*
* Set up network interface values * Set up network interface values
*/ */