📄 c5471_ethernet.c
字号:
/* If the above function invocation resulted in data that should be * sent out on the network, the field d_len will set to a value > 0. * Send that data now if ESM has let go of the RX descriptor giving us * access rights to submit another Ethernet frame. */ if (dev->d_len > 0 && (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0) { uip_arp_out(dev); c5471_transmit(c5471); } } else if (BUF->type == HTONS(UIP_ETHTYPE_ARP)) { uip_arp_arpin(dev); /* If the above function invocation resulted in data that should be * sent out on the network, the field d_len will set to a value > 0. * Send that data now if ESM has let go of the RX descriptor giving us * access rights to submit another Ethernet frame. */ if (dev->d_len > 0 && (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0) { c5471_transmit(c5471); } } }#ifdef CONFIG_C5471_NET_STATS else { /* Increment the count of dropped packets */ ndbg("Too big! packetlen: %d\n", packetlen); c5471->c_rxdropped++; }#endif}/**************************************************************************** * Function: c5471_txstatus * * Description: * An interrupt was received indicating that the last TX packet(s) is done * * Parameters: * c5471 - Reference to the driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/#ifdef CONFIG_C5471_NET_STATSstatic void c5471_txstatus(struct c5471_driver_s *c5471){ uint32 desc = c5471->c_lastdescstart; uint32 txstatus; /* Walk that last packet we just sent to collect xmit status bits. */ txstatus = 0; if (c5471->c_lastdescstart && c5471->c_lastdescend) { for (;;) { txstatus |= (getreg32(desc) & EIM_RXDESC_STATUSMASK); if (desc == c5471->c_lastdescend) { break; } /* This packet is made up of several descriptors, find next one in chain. */ if (EIM_RXDESC_WRAP_NEXT & getreg32(c5471->c_rxcpudesc)) { /* Loop back around to base of descriptor queue. */ desc = getreg32(EIM_CPU_RXBA) + EIM_RAM_START; } else { desc += 2 * sizeof(uint32); } } } if (txstatus) { if ((txstatus & EIM_RXDESC_MISS) != 0) { c5471->c_txmiss++; nvdbg("c_txmiss: %d\n", c5471->c_txmiss); } if ((txstatus & EIM_RXDESC_VLAN) != 0) { c5471->c_txvlan++; nvdbg("c_txvlan: %d\n", c5471->c_txvlan); } if ((txstatus & EIM_RXDESC_LFRAME) != 0) { c5471->c_txlframe++; nvdbg("c_txlframe: %d\n", c5471->c_txlframe); } if ((txstatus & EIM_RXDESC_SFRAME) != 0) { c5471->c_txsframe++; nvdbg("c_txsframe: %d\n", c5471->c_txsframe); } if ((txstatus & EIM_RXDESC_CRCERROR) != 0) { c5471->c_txcrc++; nvdbg("c_txcrc: %d\n", c5471->c_txcrc); } if ((txstatus & EIM_RXDESC_OVERRUN) != 0) { c5471->c_txoverrun++; nvdbg("c_txoverrun: %d\n", c5471->c_txoverrun); } if ((txstatus & EIM_RXDESC_OVERRUN) != 0) { c5471->c_txalign++; nvdbg("c_txalign: %d\n", c5471->c_txalign); } }}#endif/**************************************************************************** * Function: c5471_txdone * * Description: * An interrupt was received indicating that the last TX packet(s) is done * * Parameters: * c5471 - Reference to the driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void c5471_txdone(struct c5471_driver_s *c5471){ /* If no further xmits are pending, then cancel the TX timeout */ wd_cancel(c5471->c_txtimeout); /* Then poll uIP for new XMIT data */ (void)uip_poll(&c5471->c_dev, c5471_uiptxpoll);}/**************************************************************************** * Function: c5471_interrupt * * Description: * Hardware interrupt handler * * Parameters: * irq - Number of the IRQ that generated the interrupt * context - Interrupt register state save info (architecture-specific) * * Returned Value: * OK on success * * Assumptions: * ****************************************************************************/static int c5471_interrupt(int irq, FAR void *context){#if CONFIG_C5471_NET_NINTERFACES == 1 register struct c5471_driver_s *c5471 = &g_c5471[0];#else# error "Additional logic needed to support multiple interfaces"#endif /* Get and clear interrupt status bits */ c5471->c_eimstatus = getreg32(EIM_STATUS); /* Handle interrupts according to status bit settings */ /* Check if we received an incoming packet, if so, call c5471_receive() */ if ((EIM_STATUS_CPU_TX & c5471->c_eimstatus) != 0) { /* An incoming packet has been received by the EIM from the network and * the interrupt associated with EIM's CPU TX queue has been asserted. It * is the EIM's CPU TX queue that we need to read from to get those * packets. We use this terminology to stay consistent with the Orion * documentation. */#ifdef CONFIG_C5471_NET_STATS /* Check for RX errors */ c5471_rxstatus(c5471);#endif /* Process the received packet */ c5471_receive(c5471); } /* Check is a packet transmission just completed. If so, call c5471_txdone */ if ((EIM_STATUS_CPU_RX & c5471->c_eimstatus) != 0) { /* An outgoing packet has been processed by the EIM and the interrupt * associated with EIM's CPU RX que has been asserted. It is the EIM's * CPU RX queue that we put packets on to send them *out*. TWe use this * terminology to stay consistent with the Orion documentation. */#ifdef CONFIG_C5471_NET_STATS /* Check for TX errors */ c5471_txstatus(c5471);#endif /* Handle the transmission done event */ c5471_txdone(c5471); } /* Enable Ethernet interrupts (perhaps excluding the TX done interrupt if * there are no pending transmissions. */ return OK;}/**************************************************************************** * Function: c5471_txtimeout * * Description: * Our TX watchdog timed out. Called from the timer interrupt handler. * The last TX never completed. Reset the hardware and start again. * * Parameters: * argc - The number of available arguments * arg - The first argument * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void c5471_txtimeout(int argc, uint32 arg, ...){ struct c5471_driver_s *c5471 = (struct c5471_driver_s *)arg; /* Increment statistics */#ifdef CONFIG_C5471_NET_STATS c5471->c_txtimeouts++; nvdbg("c_txtimeouts: %d\n", c5471->c_txtimeouts);#endif /* Then try to restart the hardware */ c5471_ifdown(&c5471->c_dev); c5471_ifup(&c5471->c_dev); /* Then poll uIP for new XMIT data */ (void)uip_poll(&c5471->c_dev, c5471_uiptxpoll);}/**************************************************************************** * Function: c5471_polltimer * * Description: * Periodic timer handler. Called from the timer interrupt handler. * * Parameters: * argc - The number of available arguments * arg - The first argument * * Returned Value: * None * * Assumptions: * ****************************************************************************/static void c5471_polltimer(int argc, uint32 arg, ...){ struct c5471_driver_s *c5471 = (struct c5471_driver_s *)arg; /* Check if the ESM has let go of the RX descriptor giving us access rights * to submit another Ethernet frame. */ if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0) { /* If so, update TCP timing states and poll uIP for new XMIT data */ (void)uip_timer(&c5471->c_dev, c5471_uiptxpoll, C5471_POLLHSEC); } /* Setup the watchdog poll timer again */ (void)wd_start(c5471->c_txpoll, C5471_WDDELAY, c5471_polltimer, 1, arg);}/**************************************************************************** * Function: c5471_ifup * * Description: * NuttX Callback: Bring up the Ethernet interface when an IP address is * provided * * Parameters: * dev - Reference to the NuttX driver state structure * * Returned Value: * None * * Assumptions: * The user has assigned a MAC to the driver * ****************************************************************************/static int c5471_ifup(struct uip_driver_s *dev){ struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private; volatile uint32 clearbits; ndbg("Bringing up: %d.%d.%d.%d\n", dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 ); /* Initilize Ethernet interface */ c5471_reset(c5471); /* Assign the MAC to the device */ c5471_macassign(c5471); /* Clear pending interrupts by reading the EIM status register */ clearbits = getreg32(EIM_STATUS); /* Enable interrupts going from EIM Module to Interrupt Module. */ putreg32(((getreg32(EIM_INTEN) | EIM_INTEN_CPU_TX|EIM_INTEN_CPU_RX)), EIM_INTEN); /* Next, go on-line. According to the C547X documentation the enables have to * occur in this order to insure proper operation; ESM first then the ENET. */ putreg32((getreg32(EIM_CTRL) | EIM_CTRL_ESM_EN), EIM_CTRL); /* enable ESM */ putreg32((getreg32(ENET0_MODE) | ENET_MODE_ENABLE), ENET0_MODE); /* enable ENET */ up_mdelay(100); /* Set and activate a timer process */ (void)wd_start(c5471->c_txpoll, C5471_WDDELAY, c5471_polltimer, 1, (uint32)c5471); /* Enable the Ethernet interrupt */ c5471->c_bifup = TRUE; up_enable_irq(C5471_IRQ_ETHER); return OK;}/**************************************************************************** * Function: c5471_ifdown * * Description: * NuttX Callback: Stop the interface. * * Parameters: * dev - Reference to the NuttX driver state structure * * Returned Value: * None * * Assumptions: * ****************************************************************************/static int c5471_ifdown(struct uip_driver_s *dev){ struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private; irqstate_t flags; ndbg("Stopping\n"); /* Disable the Ethernet interrupt */ flags = irqsave(); up_disable_irq(C5471_IRQ_ETHER); /* Disable interrupts going from EIM Module to Interrupt Module. */ putreg32((getreg32(EIM_INTEN) & ~(EIM_INTEN_CPU_TX|EIM_INTEN_CPU_RX)), EIM_INTEN); /* Disable ENET */ putreg32((getreg32(ENET0_MODE) & ~ENET_MODE_ENABLE), ENET0_MODE); /* disable ENET */ /* Disable ESM */ putreg32((getreg32(EIM_CTRL) & ~EIM_CTRL_ESM_EN), EIM_CTRL); /* disable ESM */ /* Cancel the TX poll timer and TX timeout timers */ wd_cancel(c5471->c_txpoll); wd_cancel(c5471->c_txtimeout); /* Reset the device */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -