📄 ctrl_rtl8019.c
字号:
if (nextpg1 != hdr.ph_nextpg) {
return NULL;
}
nextpg = nextpg1;
}
/*
* Check packet status. It should have set bit 0, but
* even without this bit packets seem to be OK.
*/
if (!drop && ((hdr.ph_status & 0x0E) == 0)) {
/*
* Allocate a NETBUF.
* Omit the fcs.
*/
count = hdr.ph_size - 4;
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, count, PBUF_POOL);
if (p != NULL ) {
/*
* Set remote dma byte count and
* start address. Don't read the
* header again.
*/
IOWR_CTRL_RTL8019_RBCR0(dev->base_addr,count);
IOWR_CTRL_RTL8019_RBCR1(dev->base_addr,count >> 8);
IOWR_CTRL_RTL8019_RSAR0(dev->base_addr,sizeof(struct nic_pkt_header));
IOWR_CTRL_RTL8019_RSAR1(dev->base_addr,bnry);
/*
* Perform the read.
*/
IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD0_MSK);
Delay16Cycles();
for(q = p; q != NULL; q = q->next)
{
NicRead(dev->base_addr,q->payload, q->len);
}
NicCompleteDma(dev->base_addr);
}
}
/*
* Set boundary register to the last page we read.
* This also drops packets with errors
*/
if (--nextpg < NIC_FIRST_RX_PAGE)
nextpg = NIC_STOP_PAGE - 1;
IOWR_CTRL_RTL8019_BNRY(dev->base_addr,nextpg);
return p;
}
/*!
* Load a packet into the nic's transmit ring buffer.
*
*
* param base NIC hardware base address.
* param nb Network buffer structure containing the packet to be sent.
* The structure must have been allocated by a previous
* call NutNetBufAlloc().
*
* return 0 on success, -1 in case of any errors. Errors
* will automatically release the network buffer
* structure.
*/
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
struct pbuf *q;
ctrl_rtl8019_if *dev = netif->state;
u_short i;
u_char padding = 0;
unsigned short int size;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_output ( %#x)\n",p));
size=0;
for(q = p; q != NULL; q = q->next)
{
size+=q->len;
}
/*
* Calculate the number of bytes to be send. Do not
* send packets larger than 1514 bytes.
*
* The previous version was wrong by specifying a maximum
* of 1518, because it didn't take the CRC into account,
* which is generated by the hardware and automatically
* appended. Thanks to Bengt Florin, who discovered this.
*/
if (size > 1514)
return -1;
/*
* The controller will not append pad bytes,
* so we have to do this.
*/
if (size < 60) {
padding = (u_char) (60 - p->tot_len);
size = 60;
}
/*
* Bengt Florin introduces polling mode for the transmitter. Be
* aware, that this may introduce other problems. If a high
* priority thread is waiting for the transmitter, it may hold
* the CPU for more than 1.2 milliseconds in worst cases.
*/
/*
while (NICINB(NIC_CR) & NIC_CR_TXP)
NutThreadYield();
*/
/* we don't want to be interrupted by NIC owerflow */
//irq_context=alt_irq_disable_all();
/*
* Set remote dma byte count
* and start address.
*/
IOWR_CTRL_RTL8019_RBCR0(dev->base_addr, size);
IOWR_CTRL_RTL8019_RBCR1(dev->base_addr, size >> 8);
IOWR_CTRL_RTL8019_RSAR0(dev->base_addr,0);
IOWR_CTRL_RTL8019_RSAR1(dev->base_addr,NIC_FIRST_TX_PAGE);
/*
* Peform the write.
*/
IOWR_CTRL_RTL8019_CR(dev->base_addr, CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD1_MSK);
/*
* Transfer the Ethernet frame.
*/
for(q = p; q != NULL; q = q->next)
{
NicWrite(dev->base_addr,q->payload, q->len);
}
/*
* Add pad bytes.
*/
for (i = 0; i < padding; i++)
IOWR_CTRL_RTL8019_DATA(dev->base_addr,0);
/*
* Complete remote dma.
*/
NicCompleteDma(dev->base_addr);
/*
* Number of bytes to be transmitted.
*/
IOWR_CTRL_RTL8019_TBCR0(dev->base_addr,(size & 0xff));
IOWR_CTRL_RTL8019_TBCR1(dev->base_addr,((size >> 8) & 0xff));
/*
* First page of packet to be transmitted.
*/
IOWR_CTRL_RTL8019_TPSR(dev->base_addr,NIC_FIRST_TX_PAGE);
/*
* Start transmission.
*/
IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_TXP_MSK | CTRL_RTL8019_CR_RD2_MSK);
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_ouptput () return OK\n"));
return 0;
}
/*
* \brief Handle NIC overflows.
*
* When a receiver buffer overflow occurs, the NIC will defer any subsequent
* action until properly restarted.
*
* This routine is called within interrupt context, which introduces a big
* problem. It waits for the last transmission to finish, which may take
* several milliseconds. Since Nut/OS 3.5, we do not support nested interrupts
* on AVR systems anymore. So this routine may now increase interrupt
* latency in an unacceptable way. The solution might be to handle overflows
* in the receiver thread.
*
* In any case, this routines needs a major redesign. But it has been
* tested in its current form to gracefully withstand ping floods. Thanks
* to Bengt Florin for contributing his code, which provides much more
* stability than its predecessor.
*/
u_char NicOverflow(ctrl_rtl8019_if *dev)
{
u_char cr;
u_char resend = 0;
u_char curr;
/*
* Wait for any transmission in progress. Save the command register,
* so we can later determine, if NIC transmitter has been interrupted.
* or reception in progress.
*/
while (IORD_CTRL_RTL8019_CR(dev->base_addr) & CTRL_RTL8019_CR_TXP_MSK);
cr = IORD_CTRL_RTL8019_CR(dev->base_addr);
/*
* Get the current page pointer. It points to the page where the NIC
* will start saving the next incoming packet.
*/
IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STP_MSK | CTRL_RTL8019_CR_RD2_MSK | CTRL_RTL8019_CR_PS0_MSK);
curr = IORD_CTRL_RTL8019_CURR(dev->base_addr);
IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STP_MSK | CTRL_RTL8019_CR_RD2_MSK);
/* Clear remote byte count register. */
IOWR_CTRL_RTL8019_RBCR0(dev->base_addr,0);
IOWR_CTRL_RTL8019_RBCR1(dev->base_addr,0);
/* Check for any incomplete transmission. */
if ((cr & CTRL_RTL8019_CR_TXP_MSK) && ((IORD_CTRL_RTL8019_ISR(dev->base_addr) & (CTRL_RTL8019_ISR_PTX_MSK | CTRL_RTL8019_ISR_TXE_MSK)) == 0))
{
resend = 1;
}
/* Enter loopback mode and restart the NIC. */
IOWR_CTRL_RTL8019_TCR(dev->base_addr,CTRL_RTL8019_TCR_LB0_MSK);
IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_RD2_MSK);
/*
* Discard all packets from the receiver buffer. Set boundary
* register to the last page we read.
*/
if (--curr < NIC_FIRST_RX_PAGE) {
curr = NIC_STOP_PAGE - 1;
}
IOWR_CTRL_RTL8019_BNRY(dev->base_addr,curr);
/* Switch from loopback to normal mode mode. */
IOWR_CTRL_RTL8019_TCR(dev->base_addr,0);
/* Re-invoke any interrupted transmission. */
if (resend) {
IOWR_CTRL_RTL8019_CR(dev->base_addr,CTRL_RTL8019_CR_STA_MSK | CTRL_RTL8019_CR_TXP_MSK | CTRL_RTL8019_CR_RD2_MSK);
}
/* Finally clear the overflow flag */
IOWR_CTRL_RTL8019_ISR(dev->base_addr,CTRL_RTL8019_ISR_OVW_MSK);
return resend;
}
/*
* \brief NIC interrupt entry.
*/
void ctrl_rtl8019_irq(void* context, alt_u32 interrupt)
{
u_char isr;
int rx_frame_errors;
int rx_crc_errors;
int rx_missed_errors;
ctrl_rtl8019_if *dev = (ctrl_rtl8019_if *)context;
isr = IORD_CTRL_RTL8019_ISR(dev->base_addr);
IOWR_CTRL_RTL8019_ISR(dev->base_addr,0xff);
/*
* Recover from receive buffer overflow. This may take some
* time, so we enable global interrupts but keep NIC
* interrupts disabled.
*/
if (isr & CTRL_RTL8019_ISR_OVW_MSK) {
NicOverflow(dev);
} else {
/*
* If this is a transmit interrupt, then a packet has been sent.
* So we can clear the transmitter busy flag and wake up the
* transmitter thread.
*/
if (isr & CTRL_RTL8019_ISR_TXE_MSK);
/*
* If this is a receive interrupt, then wake up the receiver
* thread.
*/
if (isr & CTRL_RTL8019_ISR_PRX_MSK){
sys_mbox_post(rx_mbox, &dev->lwip_dev_list.dev);
}
if (isr & CTRL_RTL8019_ISR_RXE_MSK) {
rx_frame_errors += IORD_CTRL_RTL8019_CNTR0(dev->base_addr);
rx_crc_errors += IORD_CTRL_RTL8019_CNTR1(dev->base_addr);
rx_missed_errors += IORD_CTRL_RTL8019_CNTR2(dev->base_addr);
}
}
}
/*-----------------------------------------------------------------------------------*
*
* ctrl_rtl8019_output():
*
* This function is called by the TCP/IP stack when an IP packet
* should be sent. It calls the function called low_level_output() to
* do the actuall transmission of the packet.
*
*
*-----------------------------------------------------------------------------------*/
static err_t
ctrl_rtl8019_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
{
err_t err;
ctrl_rtl8019_if* dev = (ctrl_rtl8019_if*)netif->state;
sys_sem_wait(dev->arp_semaphore);
/*
* resolve hardware address, then send (or queue) packet
* The code which updates the ARP tables does not appear to be thread safe
* so I've added a MUTEX around all calls to the arp code
*
*/
err = etharp_output(netif, ipaddr, p);
sys_sem_signal(dev->arp_semaphore);
return err;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -