/** * This function with either place the packet into the Stellaris transmit fifo, * or will place the packet in the interface PBUF Queue for subsequent * transmission when the transmitter becomes idle. * * @param netif the lwip network interface structure for this ethernetif * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * */ static err_t low_level_output(struct netif *netif, struct pbuf *p) { err_t status; // Bump the reference count on the pbuf to prevent it from being // freed till we are done with it. pbuf_ref(p); // Prevent from simultaneously writing to ETH TX FIFO xSemaphoreTake(ETHTxAccessMutex[0], ( portTickType ) portMAX_DELAY); // If Semaphore was given previously -> take it while (xSemaphoreTake(ETHTxBinSemaphore[0], ( portTickType ) 0) == pdTRUE) ; // If the transmitter is idle, send the pbuf now. if (((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0)) { // Send packet via eth controller status = low_level_transmit(netif, p); } else { LWIP_DEBUGF(CORTEX_DEBUG, ("low_level_output: Ethernet transmitter busy\n")); // Enable generating transmit interrupt for eth. controller EthernetIntEnable(ETH_BASE, ETH_INT_TX); // Waiting for finishing transmitting from interrupt routine xSemaphoreTake(ETHTxBinSemaphore[0], ( portTickType ) portMAX_DELAY); // Send packet via eth controller status = low_level_transmit(netif, p); // Disable generating transmit interrupt for eth. controller EthernetIntDisable(ETH_BASE, ETH_INT_TX); } // Release mutex xSemaphoreGive(ETHTxAccessMutex[0]); //pf vTaskDelay(10 / portTICK_RATE_MS); pbuf_free(p); return status; }
/*..........................................................................*/ void eth_driver_write(void) { if ((ETH->TR & MAC_TR_NEWTX) == 0) { /* TX fifo empty? */ struct pbuf *p = l_txq.get(); if (p != NULL) { /* pbuf found in the queue? */ low_level_transmit(p); pbuf_free(p); /* free the pbuf, lwIP knows nothing of it */ } } }
/** * Process tx and rx packets at the low-level interrupt. * * Should be called from the Stellaris Ethernet Interrupt Handler. This * function will read packets from the Stellaris Ethernet fifo and place them * into a pbuf queue. If the transmitter is idle and there is at least one packet * on the transmit queue, it will place it in the transmit fifo and start the * transmitter. * */ void stellarisif_interrupt(struct netif *netif) { struct ethernetif *ethernetif; struct pbuf *p; /* setup pointer to the if state data */ ethernetif = netif->state; /** * Process the transmit and receive queues as long as there is receive * data available * */ p = low_level_receive(netif); while(p != NULL) { /* Add the rx packet to the rx queue */ if(!enqueue_packet(p, ðernetif->rxq)) { /* Could not place the packet on the queue, bail out. */ pbuf_free(p); break; } /* Check if TX fifo is empty and packet available */ if((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0) { p = dequeue_packet(ðernetif->txq); if(p != NULL) { low_level_transmit(netif, p); } } /* Read another packet from the RX fifo */ p = low_level_receive(netif); } /* One more check of the transmit queue/fifo */ if((HWREG(ETH_BASE + MAC_O_TR) & MAC_TR_NEWTX) == 0) { p = dequeue_packet(ðernetif->txq); if(p != NULL) { low_level_transmit(netif, p); } } }
/** * This function with either place the packet into the Stellaris transmit fifo, * or will place the packet in the interface PBUF Queue for subsequent * transmission when the transmitter becomes idle. * * @param netif the lwip network interface structure for this ethernetif * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * */ static err_t low_level_output(struct netif *netif, struct pbuf *p) { LWIP_DRIVER_DATA* drv_data = (LWIP_DRIVER_DATA*)netif; MAC_Type* mac = (MAC_Type*)netif->state; SYS_ARCH_DECL_PROTECT(lev); /** * This entire function must run within a "critical section" to preserve * the integrity of the transmit pbuf queue. * */ SYS_ARCH_PROTECT(lev); /** * Bump the reference count on the pbuf to prevent it from being * freed till we are done with it. * */ pbuf_ref(p); /** * If the transmitter is idle, and there is nothing on the queue, * send the pbuf now. * */ if (PBUF_QUEUE_EMPTY(&drv_data->txq) && ((mac->MACTR & MAC_TR_NEWTX) == 0)) { low_level_transmit(netif, p); } /* Otherwise place the pbuf on the transmit queue. */ else { /* Add to transmit packet queue */ if (!enqueue_packet(p, &drv_data->txq)) { /* if no room on the queue, free the pbuf reference and return error. */ pbuf_free(p); SYS_ARCH_UNPROTECT(lev); return (ERR_MEM); } } /* Return to prior interrupt state and return. */ SYS_ARCH_UNPROTECT(lev); return (ERR_OK); }
/* * This function will either write the pbuf into the Stellaris TX FIFO, * or will put the packet in the TX queue of pbufs for subsequent * transmission when the transmitter becomes idle. * * @param netif the lwip network interface structure for this ethernetif * @param p the pbuf to send * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * */ static err_t ethernetif_output(struct netif *netif, struct pbuf *p) { if (l_txq.isEmpty() && /* nothing in the TX queue? */ ((ETH->TR & MAC_TR_NEWTX) == 0)) /* TX empty? */ { low_level_transmit(p); /* send the pbuf right away */ /* the pbuf will be freed by the lwIP code */ } else { /* otherwise post the pbuf to the transmit queue */ if (l_txq.put(p)) { /*could the TX queue take the pbuf? */ pbuf_ref(p); /* reference the pbuf to spare it from freeing */ } else { /* no room in the queue */ /* the pbuf will be freed by the lwIP code */ return ERR_MEM; } } return ERR_OK; }
/*..........................................................................*/ void eth_driver_read(void) { struct pbuf *p = low_level_receive(); if (p != NULL) { /* new packet received into the pbuf? */ if (ethernet_input(p, &l_netif) != ERR_OK) { /* pbuf not handled? */ LWIP_DEBUGF(NETIF_DEBUG, ("eth_driver_input: input error\n")); pbuf_free(p); /* free the pbuf */ } /* try to output a packet if TX fifo is empty and pbuf is available */ if ((ETH->TR & MAC_TR_NEWTX) == 0) { p = l_txq.get(); if (p != NULL) { low_level_transmit(p); pbuf_free(p); /* free the pbuf, lwIP knows nothing of it */ } } } ETH->IM |= ETH_INT_RX; /* re-enable the RX interrupt */ }