|
|
|
@@ -13,36 +13,66 @@
|
|
|
|
#define IFNAME0 'e'
|
|
|
|
#define IFNAME0 'e'
|
|
|
|
#define IFNAME1 'n'
|
|
|
|
#define IFNAME1 'n'
|
|
|
|
|
|
|
|
|
|
|
|
#define ETH_RXBUFNB 4
|
|
|
|
#define ETH_RX_BUF_COUNT 4
|
|
|
|
#define ETH_TXBUFNB 1
|
|
|
|
#define ETH_TX_BUF_COUNT 2
|
|
|
|
#define ETH_RX_BUF_SZE ETH_MAX_PACKET_SIZE
|
|
|
|
/* buf size should be at least ETH_MAX_PACKET_SIZE */
|
|
|
|
#define ETH_TX_BUF_SZE ETH_MAX_PACKET_SIZE
|
|
|
|
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
|
|
|
|
|
|
|
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
|
|
|
volatile uint32_t head; // producer idx: next free slot to write to
|
|
|
|
|
|
|
|
volatile uint32_t tail; // consumer idx: next slot to be txed
|
|
|
|
|
|
|
|
volatile bool is_full; // for N=1 size
|
|
|
|
|
|
|
|
} tx_queue_t;
|
|
|
|
|
|
|
|
|
|
|
|
struct ethernetif {
|
|
|
|
struct ethernetif {
|
|
|
|
ETH_DMADESCTypeDef* DMARxDescToGet;
|
|
|
|
ETH_DMADESCTypeDef* rx_desc_head; // next desc to be filled by DMA
|
|
|
|
ETH_DMADESCTypeDef* DMARxDescToRead;
|
|
|
|
ETH_DMADESCTypeDef* rx_desc_tail; // next desc to be read by CPU
|
|
|
|
ETH_DMADESCTypeDef* DMATxDescToSet;
|
|
|
|
tx_queue_t tx_q;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
__attribute__((aligned(4))) ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB];
|
|
|
|
__attribute__((aligned(4))) ETH_DMADESCTypeDef g_dma_rx_descs[ETH_RX_BUF_COUNT];
|
|
|
|
__attribute__((aligned(4))) ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB];
|
|
|
|
__attribute__((aligned(4))) ETH_DMADESCTypeDef g_dma_tx_descs[ETH_TX_BUF_COUNT];
|
|
|
|
__attribute__((aligned(4))) uint8_t MACRxBuf[ETH_RXBUFNB * ETH_RX_BUF_SZE];
|
|
|
|
__attribute__((
|
|
|
|
__attribute__((aligned(4))) uint8_t MACTxBuf[ETH_TXBUFNB * ETH_TX_BUF_SZE];
|
|
|
|
aligned(4))) uint8_t g_mac_rx_bufs[ETH_RX_BUF_COUNT * ETH_RX_BUF_SIZE];
|
|
|
|
|
|
|
|
__attribute__((
|
|
|
|
|
|
|
|
aligned(4))) uint8_t g_mac_tx_bufs[ETH_TX_BUF_COUNT * ETH_TX_BUF_SIZE];
|
|
|
|
|
|
|
|
|
|
|
|
static volatile bool g_link_interrupt_flag = false;
|
|
|
|
static struct ethernetif g_eth_state;
|
|
|
|
static struct ethernetif eth_state;
|
|
|
|
static volatile bool g_link_irq_flag = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline void tx_queue_init(tx_queue_t* q) {
|
|
|
|
|
|
|
|
q->head = 0;
|
|
|
|
|
|
|
|
q->tail = 0;
|
|
|
|
|
|
|
|
q->is_full = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline bool tx_queue_is_empty(const tx_queue_t* q) {
|
|
|
|
|
|
|
|
return !q->is_full && (q->head == q->tail);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool tx_queue_is_full(const tx_queue_t* q) { return q->is_full; }
|
|
|
|
|
|
|
|
static inline void tx_queue_produce(tx_queue_t* q) {
|
|
|
|
|
|
|
|
q->head = (q->head + 1) % ETH_TX_BUF_COUNT;
|
|
|
|
|
|
|
|
if (q->head == q->tail) {
|
|
|
|
|
|
|
|
q->is_full = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void tx_queue_consume(tx_queue_t* q) {
|
|
|
|
|
|
|
|
q->is_full = false;
|
|
|
|
|
|
|
|
q->tail = (q->tail + 1) % ETH_TX_BUF_COUNT;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void low_level_init(struct netif* netif);
|
|
|
|
static void low_level_init(struct netif* netif);
|
|
|
|
static err_t low_level_output(struct netif* netif, struct pbuf* p);
|
|
|
|
static err_t low_level_output(struct netif* netif, struct pbuf* p);
|
|
|
|
static struct pbuf* low_level_input(struct netif* netif);
|
|
|
|
static struct pbuf* low_level_input(struct netif* netif);
|
|
|
|
void WritePHYReg(uint8_t reg_add, uint16_t reg_val);
|
|
|
|
void phy_write_reg(uint8_t reg_add, uint16_t reg_val);
|
|
|
|
uint16_t ReadPHYReg(uint8_t reg_add);
|
|
|
|
uint16_t phy_read_reg(uint8_t reg_add);
|
|
|
|
|
|
|
|
|
|
|
|
static void eth_get_mac_in_uc(uint8_t* mac) {
|
|
|
|
static void eth_get_mac_addr(uint8_t* mac) {
|
|
|
|
// Mac is backwards.
|
|
|
|
// Mac is backwards.
|
|
|
|
const uint8_t* macaddr = (const uint8_t*)(ROM_CFG_USERADR_ID + 5);
|
|
|
|
const uint8_t* macaddr_src = (const uint8_t*)(ROM_CFG_USERADR_ID + 5);
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
mac[i] = *(macaddr--);
|
|
|
|
mac[i] = *(macaddr_src--);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -51,7 +81,7 @@ err_t ethernetif_init(struct netif* netif) {
|
|
|
|
netif->hostname = "lwip-ch32";
|
|
|
|
netif->hostname = "lwip-ch32";
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
netif->state = ð_state;
|
|
|
|
netif->state = &g_eth_state;
|
|
|
|
netif->name[0] = IFNAME0;
|
|
|
|
netif->name[0] = IFNAME0;
|
|
|
|
netif->name[1] = IFNAME1;
|
|
|
|
netif->name[1] = IFNAME1;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -61,7 +91,7 @@ err_t ethernetif_init(struct netif* netif) {
|
|
|
|
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 10000000); // 10Mbps
|
|
|
|
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 10000000); // 10Mbps
|
|
|
|
|
|
|
|
|
|
|
|
netif->hwaddr_len = ETH_HWADDR_LEN;
|
|
|
|
netif->hwaddr_len = ETH_HWADDR_LEN;
|
|
|
|
eth_get_mac_in_uc(netif->hwaddr);
|
|
|
|
eth_get_mac_addr(netif->hwaddr);
|
|
|
|
|
|
|
|
|
|
|
|
printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0],
|
|
|
|
printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", netif->hwaddr[0],
|
|
|
|
netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4],
|
|
|
|
netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4],
|
|
|
|
@@ -104,32 +134,34 @@ static void low_level_init(struct netif* netif) {
|
|
|
|
ETH10M->ECON2 = RB_ETH_ECON2_DEFAULT;
|
|
|
|
ETH10M->ECON2 = RB_ETH_ECON2_DEFAULT;
|
|
|
|
|
|
|
|
|
|
|
|
// init TX descriptors
|
|
|
|
// init TX descriptors
|
|
|
|
ethernetif->DMATxDescToSet = DMATxDscrTab;
|
|
|
|
tx_queue_init(ðernetif->tx_q);
|
|
|
|
for (int i = 0; i < ETH_TXBUFNB; i++) {
|
|
|
|
for (int i = 0; i < ETH_TX_BUF_COUNT; i++) {
|
|
|
|
DMATxDscrTab[i].Status = 0;
|
|
|
|
g_dma_tx_descs[i].Status = 0;
|
|
|
|
DMATxDscrTab[i].Buffer1Addr = (uint32_t)&MACTxBuf[i * ETH_TX_BUF_SZE];
|
|
|
|
g_dma_tx_descs[i].Buffer1Addr =
|
|
|
|
DMATxDscrTab[i].Buffer2NextDescAddr =
|
|
|
|
(uint32_t)&g_mac_tx_bufs[i * ETH_TX_BUF_SIZE];
|
|
|
|
(uint32_t)&DMATxDscrTab[(i + 1) % ETH_TXBUFNB];
|
|
|
|
g_dma_tx_descs[i].Buffer2NextDescAddr =
|
|
|
|
|
|
|
|
(uint32_t)&g_dma_tx_descs[(i + 1) % ETH_TX_BUF_COUNT];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// init RX descriptors
|
|
|
|
// init RX descriptors
|
|
|
|
ethernetif->DMARxDescToGet = DMARxDscrTab;
|
|
|
|
ethernetif->rx_desc_head = g_dma_rx_descs;
|
|
|
|
ethernetif->DMARxDescToRead = DMARxDscrTab;
|
|
|
|
ethernetif->rx_desc_tail = g_dma_rx_descs;
|
|
|
|
for (int i = 0; i < ETH_RXBUFNB; i++) {
|
|
|
|
for (int i = 0; i < ETH_RX_BUF_COUNT; i++) {
|
|
|
|
DMARxDscrTab[i].Status = ETH_DMARxDesc_OWN;
|
|
|
|
g_dma_rx_descs[i].Status = ETH_DMARxDesc_OWN;
|
|
|
|
DMARxDscrTab[i].Buffer1Addr = (uint32_t)&MACRxBuf[i * ETH_RX_BUF_SZE];
|
|
|
|
g_dma_rx_descs[i].Buffer1Addr =
|
|
|
|
DMARxDscrTab[i].Buffer2NextDescAddr =
|
|
|
|
(uint32_t)&g_mac_rx_bufs[i * ETH_RX_BUF_SIZE];
|
|
|
|
(uint32_t)&DMARxDscrTab[(i + 1) % ETH_RXBUFNB];
|
|
|
|
g_dma_rx_descs[i].Buffer2NextDescAddr =
|
|
|
|
|
|
|
|
(uint32_t)&g_dma_rx_descs[(i + 1) % ETH_RX_BUF_COUNT];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// set RX buffer start and enable receiver
|
|
|
|
// set RX buffer start and enable receiver
|
|
|
|
ETH10M->ERXST = ethernetif->DMARxDescToGet->Buffer1Addr;
|
|
|
|
ETH10M->ERXST = ethernetif->rx_desc_head->Buffer1Addr;
|
|
|
|
ETH10M->ECON1 = RB_ETH_ECON1_RXEN;
|
|
|
|
ETH10M->ECON1 = RB_ETH_ECON1_RXEN;
|
|
|
|
|
|
|
|
|
|
|
|
WritePHYReg(PHY_BMCR, PHY_BMCR_RESET);
|
|
|
|
phy_write_reg(PHY_BMCR, PHY_BMCR_RESET);
|
|
|
|
Delay_Ms(200);
|
|
|
|
Delay_Ms(200);
|
|
|
|
|
|
|
|
|
|
|
|
WritePHYReg(PHY_BMCR, PHY_BMCR_FULL_DUPLEX);
|
|
|
|
phy_write_reg(PHY_BMCR, PHY_BMCR_FULL_DUPLEX);
|
|
|
|
|
|
|
|
|
|
|
|
ETH10M->EIR = 0xFF; // clear all interrupt flags
|
|
|
|
ETH10M->EIR = 0xFF; // clear all interrupt flags
|
|
|
|
ETH10M->EIE = RB_ETH_EIE_INTIE | RB_ETH_EIE_RXIE | RB_ETH_EIE_TXIE |
|
|
|
|
ETH10M->EIE = RB_ETH_EIE_INTIE | RB_ETH_EIE_RXIE | RB_ETH_EIE_TXIE |
|
|
|
|
@@ -139,31 +171,67 @@ static void low_level_init(struct netif* netif) {
|
|
|
|
NVIC_EnableIRQ(ETH_IRQn);
|
|
|
|
NVIC_EnableIRQ(ETH_IRQn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static err_t low_level_output(struct netif* netif, struct pbuf* p) {
|
|
|
|
static void tx_start_if_possible(void) {
|
|
|
|
(void)netif;
|
|
|
|
// if TXRTS bit is set, MAC is busy sending a packet
|
|
|
|
|
|
|
|
if (ETH10M->ECON1 & RB_ETH_ECON1_TXRTS) {
|
|
|
|
if (DMATxDscrTab[0].Status & ETH_DMATxDesc_OWN) {
|
|
|
|
return;
|
|
|
|
LINK_STATS_INC(link.drop);
|
|
|
|
|
|
|
|
return ERR_BUF;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ethernetif* ethernetif = &g_eth_state;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tx_queue_is_empty(ðernetif->tx_q)) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get descriptor for the next packet to send
|
|
|
|
|
|
|
|
uint32_t idx = ethernetif->tx_q.tail;
|
|
|
|
|
|
|
|
ETH_DMADESCTypeDef* dma_desc = &g_dma_tx_descs[idx];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t len = dma_desc->Status;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// tell MAC which buffer to send
|
|
|
|
|
|
|
|
ETH10M->ETXLN = len;
|
|
|
|
|
|
|
|
ETH10M->ETXST = dma_desc->Buffer1Addr;
|
|
|
|
|
|
|
|
// start tx
|
|
|
|
|
|
|
|
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static err_t low_level_output(struct netif* netif, struct pbuf* p) {
|
|
|
|
|
|
|
|
struct ethernetif* ethernetif = netif->state;
|
|
|
|
|
|
|
|
err_t errval = ERR_OK;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NVIC_DisableIRQ(ETH_IRQn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tx_queue_is_full(ðernetif->tx_q)) {
|
|
|
|
|
|
|
|
// queue full, drop pkt
|
|
|
|
|
|
|
|
errval = ERR_BUF;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
uint32_t current_idx = ethernetif->tx_q.head;
|
|
|
|
|
|
|
|
uint8_t* tx_buf_ptr = (uint8_t*)g_dma_tx_descs[current_idx].Buffer1Addr;
|
|
|
|
uint32_t len = 0;
|
|
|
|
uint32_t len = 0;
|
|
|
|
uint8_t* tx_buf_ptr = (uint8_t*)DMATxDscrTab[0].Buffer1Addr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
|
|
|
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
|
|
|
memcpy(&tx_buf_ptr[len], q->payload, q->len);
|
|
|
|
memcpy(&tx_buf_ptr[len], q->payload, q->len);
|
|
|
|
len += q->len;
|
|
|
|
len += q->len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ETH10M->ETXLN = len;
|
|
|
|
g_dma_tx_descs[current_idx].Status = len;
|
|
|
|
ETH10M->ETXST = (uint32_t)tx_buf_ptr;
|
|
|
|
|
|
|
|
DMATxDscrTab[0].Status |= ETH_DMATxDesc_OWN;
|
|
|
|
tx_queue_produce(ðernetif->tx_q);
|
|
|
|
ETH10M->ECON1 |= RB_ETH_ECON1_TXRTS;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LINK_STATS_INC(link.xmit);
|
|
|
|
LINK_STATS_INC(link.xmit);
|
|
|
|
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, len);
|
|
|
|
MIB2_STATS_NETIF_ADD(netif, ifoutoctets, len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ERR_OK;
|
|
|
|
tx_start_if_possible();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NVIC_EnableIRQ(ETH_IRQn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (errval == ERR_BUF) {
|
|
|
|
|
|
|
|
LINK_STATS_INC(link.drop);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return errval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct pbuf* low_level_input(struct netif* netif) {
|
|
|
|
static struct pbuf* low_level_input(struct netif* netif) {
|
|
|
|
@@ -171,16 +239,16 @@ static struct pbuf* low_level_input(struct netif* netif) {
|
|
|
|
struct pbuf* p = NULL;
|
|
|
|
struct pbuf* p = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
// if OWN bit is set, it's still owned by DMA and no packet rdy
|
|
|
|
// if OWN bit is set, it's still owned by DMA and no packet rdy
|
|
|
|
if (ethernetif->DMARxDescToRead->Status & ETH_DMARxDesc_OWN) {
|
|
|
|
if (ethernetif->rx_desc_tail->Status & ETH_DMARxDesc_OWN) {
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// packet ready
|
|
|
|
// packet ready
|
|
|
|
uint32_t len = (ethernetif->DMARxDescToRead->Status & ETH_DMARxDesc_FL) >> 16;
|
|
|
|
uint32_t len = (ethernetif->rx_desc_tail->Status & ETH_DMARxDesc_FL) >> 16;
|
|
|
|
|
|
|
|
|
|
|
|
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
|
|
|
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
|
|
|
if (p != NULL) {
|
|
|
|
if (p != NULL) {
|
|
|
|
uint8_t* buffer = (uint8_t*)ethernetif->DMARxDescToRead->Buffer1Addr;
|
|
|
|
uint8_t* buffer = (uint8_t*)ethernetif->rx_desc_tail->Buffer1Addr;
|
|
|
|
uint32_t offset = 0;
|
|
|
|
uint32_t offset = 0;
|
|
|
|
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
|
|
|
for (struct pbuf* q = p; q != NULL; q = q->next) {
|
|
|
|
memcpy(q->payload, buffer + offset, q->len);
|
|
|
|
memcpy(q->payload, buffer + offset, q->len);
|
|
|
|
@@ -193,10 +261,10 @@ static struct pbuf* low_level_input(struct netif* netif) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// give buffer back to DMA
|
|
|
|
// give buffer back to DMA
|
|
|
|
ethernetif->DMARxDescToRead->Status = ETH_DMARxDesc_OWN;
|
|
|
|
ethernetif->rx_desc_tail->Status = ETH_DMARxDesc_OWN;
|
|
|
|
// advance read pointer to the next descriptor in the ring
|
|
|
|
// advance read pointer to the next descriptor in the ring
|
|
|
|
ethernetif->DMARxDescToRead =
|
|
|
|
ethernetif->rx_desc_tail =
|
|
|
|
(ETH_DMADESCTypeDef*)ethernetif->DMARxDescToRead->Buffer2NextDescAddr;
|
|
|
|
(ETH_DMADESCTypeDef*)ethernetif->rx_desc_tail->Buffer2NextDescAddr;
|
|
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -211,12 +279,12 @@ void ethernetif_input(struct netif* netif) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ethernetif_link_poll(struct netif* netif) {
|
|
|
|
void ethernetif_link_poll(struct netif* netif) {
|
|
|
|
if (!g_link_interrupt_flag) return;
|
|
|
|
if (!g_link_irq_flag) return;
|
|
|
|
g_link_interrupt_flag = false;
|
|
|
|
g_link_irq_flag = false;
|
|
|
|
|
|
|
|
|
|
|
|
// supposedly, first read latches link status 2nd get cur val
|
|
|
|
// supposedly, first read latches link status 2nd get cur val
|
|
|
|
(void)ReadPHYReg(PHY_BMSR);
|
|
|
|
(void)phy_read_reg(PHY_BMSR);
|
|
|
|
uint16_t bmsr = ReadPHYReg(PHY_BMSR);
|
|
|
|
uint16_t bmsr = phy_read_reg(PHY_BMSR);
|
|
|
|
|
|
|
|
|
|
|
|
if (bmsr & PHY_BMSR_LINK_STATUS) {
|
|
|
|
if (bmsr & PHY_BMSR_LINK_STATUS) {
|
|
|
|
if (!netif_is_link_up(netif)) {
|
|
|
|
if (!netif_is_link_up(netif)) {
|
|
|
|
@@ -233,62 +301,70 @@ void ethernetif_link_poll(struct netif* netif) {
|
|
|
|
void ETH_IRQHandler(void) __attribute__((interrupt)) __attribute__((used));
|
|
|
|
void ETH_IRQHandler(void) __attribute__((interrupt)) __attribute__((used));
|
|
|
|
void ETH_IRQHandler(void) {
|
|
|
|
void ETH_IRQHandler(void) {
|
|
|
|
uint32_t flags = ETH10M->EIR;
|
|
|
|
uint32_t flags = ETH10M->EIR;
|
|
|
|
struct ethernetif* ethernetif = ð_state;
|
|
|
|
struct ethernetif* ethernetif = &g_eth_state;
|
|
|
|
|
|
|
|
|
|
|
|
if (flags & RB_ETH_EIR_RXIF) {
|
|
|
|
if (flags & RB_ETH_EIR_RXIF) {
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_RXIF;
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_RXIF;
|
|
|
|
|
|
|
|
|
|
|
|
// descriptor should be owned by DMA
|
|
|
|
// descriptor should be owned by DMA
|
|
|
|
if (ethernetif->DMARxDescToGet->Status & ETH_DMARxDesc_OWN) {
|
|
|
|
if (ethernetif->rx_desc_head->Status & ETH_DMARxDesc_OWN) {
|
|
|
|
ETH_DMADESCTypeDef* next_desc =
|
|
|
|
ETH_DMADESCTypeDef* next_desc =
|
|
|
|
(ETH_DMADESCTypeDef*)ethernetif->DMARxDescToGet->Buffer2NextDescAddr;
|
|
|
|
(ETH_DMADESCTypeDef*)ethernetif->rx_desc_head->Buffer2NextDescAddr;
|
|
|
|
|
|
|
|
|
|
|
|
// if next descriptor OWN bit is 0, ring is full and we must drop
|
|
|
|
// if next descriptor OWN bit is 0, ring is full and we must drop
|
|
|
|
if (!(next_desc->Status & ETH_DMARxDesc_OWN)) {
|
|
|
|
if (!(next_desc->Status & ETH_DMARxDesc_OWN)) {
|
|
|
|
LINK_STATS_INC(link.drop);
|
|
|
|
LINK_STATS_INC(link.drop);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// process and re-arm
|
|
|
|
// process and re-arm
|
|
|
|
ethernetif->DMARxDescToGet->Status &= ~ETH_DMARxDesc_OWN;
|
|
|
|
ethernetif->rx_desc_head->Status &= ~ETH_DMARxDesc_OWN;
|
|
|
|
// write packet len into status field for CPU
|
|
|
|
// write packet len into status field for CPU
|
|
|
|
ethernetif->DMARxDescToGet->Status |=
|
|
|
|
ethernetif->rx_desc_head->Status |=
|
|
|
|
(ETH_DMARxDesc_FS | ETH_DMARxDesc_LS | (ETH10M->ERXLN << 16));
|
|
|
|
(ETH_DMARxDesc_FS | ETH_DMARxDesc_LS | (ETH10M->ERXLN << 16));
|
|
|
|
// advance descripotor ptr
|
|
|
|
// advance descripotor ptr
|
|
|
|
ethernetif->DMARxDescToGet = next_desc;
|
|
|
|
ethernetif->rx_desc_head = next_desc;
|
|
|
|
// re-arm receiver with new emtpy buf
|
|
|
|
// re-arm receiver with new emtpy buf
|
|
|
|
ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr;
|
|
|
|
ETH10M->ERXST = (uint32_t)ethernetif->rx_desc_head->Buffer1Addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (flags & RB_ETH_EIR_TXIF) {
|
|
|
|
if (flags & RB_ETH_EIR_TXIF) {
|
|
|
|
DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN;
|
|
|
|
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_TXIF;
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_TXIF;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!tx_queue_is_empty(ðernetif->tx_q)) {
|
|
|
|
|
|
|
|
tx_queue_consume(ðernetif->tx_q);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tx_start_if_possible();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (flags & RB_ETH_EIR_TXERIF) {
|
|
|
|
if (flags & RB_ETH_EIR_TXERIF) {
|
|
|
|
DMATxDscrTab[0].Status &= ~ETH_DMATxDesc_OWN;
|
|
|
|
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_TXERIF;
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_TXERIF;
|
|
|
|
LINK_STATS_INC(link.err);
|
|
|
|
LINK_STATS_INC(link.err);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!tx_queue_is_empty(ðernetif->tx_q)) {
|
|
|
|
|
|
|
|
tx_queue_consume(ðernetif->tx_q);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tx_start_if_possible();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (flags & RB_ETH_EIR_RXERIF) {
|
|
|
|
if (flags & RB_ETH_EIR_RXERIF) {
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_RXERIF;
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_RXERIF;
|
|
|
|
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN;
|
|
|
|
ETH10M->ECON1 |= RB_ETH_ECON1_RXEN; // re-enable receiver
|
|
|
|
LINK_STATS_INC(link.err);
|
|
|
|
LINK_STATS_INC(link.err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (flags & RB_ETH_EIR_LINKIF) {
|
|
|
|
if (flags & RB_ETH_EIR_LINKIF) {
|
|
|
|
g_link_interrupt_flag = true;
|
|
|
|
g_link_irq_flag = true;
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_LINKIF;
|
|
|
|
ETH10M->EIR = RB_ETH_EIR_LINKIF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void WritePHYReg(uint8_t reg_add, uint16_t reg_val) {
|
|
|
|
void phy_write_reg(uint8_t reg_add, uint16_t reg_val) {
|
|
|
|
R32_ETH_MIWR = (reg_add & RB_ETH_MIREGADR_MASK) | RB_ETH_MIWR_MIIWR |
|
|
|
|
R32_ETH_MIWR = (reg_add & RB_ETH_MIREGADR_MASK) | RB_ETH_MIWR_MIIWR |
|
|
|
|
(reg_val << RB_ETH_MIWR_DATA_SHIFT);
|
|
|
|
(reg_val << RB_ETH_MIWR_DATA_SHIFT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t ReadPHYReg(uint8_t reg_add) {
|
|
|
|
uint16_t phy_read_reg(uint8_t reg_add) {
|
|
|
|
ETH10M->MIERGADR = reg_add;
|
|
|
|
ETH10M->MIERGADR = reg_add;
|
|
|
|
return ETH10M->MIRD;
|
|
|
|
return ETH10M->MIRD;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|