diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 7562a1ac..de5774e4 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -40,6 +40,17 @@ #define TX_BUF_LEN 4096 #define MIN(a, b) (a) < (b) ? (a) : (b) +/* + * To set the RTL8139 to accept only the Transmit OK (TOK) and Receive OK (ROK) + * interrupts, we would have the TOK and ROK bits of the IMR high and leave the + * rest low. That way when a TOK or ROK IRQ happens, it actually will go through + * and fire up an IRQ. + */ +#define INT_MASK (ISR_ROK|ISR_TOK|ISR_RXOVW|ISR_TER|ISR_RER) + +// Beside Receive OK (ROK) interrupt, this mask enable all other interrupts +#define INT_MASK_NO_ROK (ISR_TOK|ISR_RXOVW|ISR_TER|ISR_RER) + board_t board_tbl[] = { {"RealTek", "RealTek RTL8139", 0x10ec, 0x8139}, @@ -134,7 +145,7 @@ static void rtl8139if_input(struct netif* netif, struct pbuf* p) #endif /* PPPOE_SUPPORT */ /* * This function is called in the context of the tcpip thread. - * Therefore, we are able to call directly the input functions + * Therefore, we are able to call directly the input functions. */ err = ethernet_input(p, netif); if (err != ERR_OK) { @@ -207,6 +218,10 @@ static void rtl_rx_inthandler(struct netif* netif) cmd = inportb(rtl8139if->iobase + CR); } + + rtl8139if->polling = 0; + // enable all known interrupts + outportw(rtl8139if->iobase + IMR, INT_MASK); } static void rtl_tx_inthandler(struct netif* netif) @@ -244,9 +259,7 @@ static void rtl_tx_inthandler(struct netif* netif) /* this function is called in the context of the tcpip thread */ static void rtl8139if_poll(void* ctx) { - //uint32_t flag = irq_nested_disable(); rtl_rx_inthandler(mynetif); - //irq_nested_enable(flag); } static void rtl8139if_handler(struct state* s) @@ -254,38 +267,44 @@ static void rtl8139if_handler(struct state* s) rtl1839if_t* rtl8139if = mynetif->state; uint16_t isr_contents; + // disable all interrupts + outportw(rtl8139if->iobase + IMR, 0x00); + while (1) { isr_contents = inportw(rtl8139if->iobase + ISR); if (isr_contents == 0) break; - if (isr_contents & ISR_ROK) { - if (tcpip_callback_with_block(rtl8139if_poll, NULL, 0) != ERR_OK) { - //LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: unable to send a poll request to the tcpip thread\n")); + if ((isr_contents & ISR_ROK) && !rtl8139if->polling) { + if (tcpip_callback_with_block(rtl8139if_poll, NULL, 0) == ERR_OK) { + rtl8139if->polling = 1; + } else { + LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: unable to send a poll request to the tcpip thread\n")); } - outportw(rtl8139if->iobase + ISR, ISR_ROK); } - if (isr_contents & ISR_TOK) { + if (isr_contents & ISR_TOK) rtl_tx_inthandler(mynetif); - outportw(rtl8139if->iobase + ISR, ISR_TOK); - } if (isr_contents & ISR_RER) { LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: RX error detected!\n")); - outportw(rtl8139if->iobase + ISR, ISR_RER); } if (isr_contents & ISR_TER) { LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: TX error detected!\n")); - outportw(rtl8139if->iobase + ISR, ISR_TER); } if (isr_contents & ISR_RXOVW) { LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_handler: RX overflow detected!\n")); - outportw(rtl8139if->iobase + ISR, ISR_RXOVW); } + + outportw(rtl8139if->iobase + ISR, isr_contents & (ISR_RXOVW|ISR_TER|ISR_RER|ISR_TOK|ISR_ROK)); } + + if (rtl8139if->polling) // now, the tcpip thread will check for incoming messages + outportw(rtl8139if->iobase + IMR, INT_MASK_NO_ROK); + else + outportw(rtl8139if->iobase + IMR, INT_MASK); // enable interrupts } err_t rtl8139if_init(struct netif* netif) @@ -304,7 +323,7 @@ err_t rtl8139if_init(struct netif* netif) LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: out of memory\n")); return ERR_MEM; } - memset(rtl8139if, 0, sizeof(rtl1839if_t)); + memset(rtl8139if, 0x00, sizeof(rtl1839if_t)); /* allocate the receive buffer */ rtl8139if->rx_buffer = mem_allocation(RX_BUF_LEN + 16 /* header size */, MAP_KERNEL_SPACE|MAP_NO_CACHE); @@ -421,13 +440,8 @@ err_t rtl8139if_init(struct netif* netif) outportl(rtl8139if->iobase + TSAD2, virt_to_phys((size_t) rtl8139if->tx_buffer[2])); outportl(rtl8139if->iobase + TSAD3, virt_to_phys((size_t) rtl8139if->tx_buffer[3])); - /* - * To set the RTL8139 to accept only the Transmit OK (TOK) and Receive OK (ROK) - * interrupts, we would have the TOK and ROK bits of the IMR high and leave the - * rest low. That way when a TOK or ROK IRQ happens, it actually will go through - * and fire up an IRQ. - */ - outportw(rtl8139if->iobase + IMR, ISR_ROK|ISR_TOK|ISR_RXOVW|ISR_TER|ISR_RER); + // Enable all known interrupts by setting the interrupt mask. + outportw(rtl8139if->iobase + IMR, INT_MASK); outportw(rtl8139if->iobase + BMCR, BMCR_ANE); tmp16 = inportw(rtl8139if->iobase + BMCR); diff --git a/drivers/net/rtl8139.h b/drivers/net/rtl8139.h index 962f5232..d45966bc 100644 --- a/drivers/net/rtl8139.h +++ b/drivers/net/rtl8139.h @@ -148,8 +148,8 @@ // Bits in ISR indicate the status of the card #define ISR_SERR 0x8000 // System error interrupt #define ISR_TUN 0x4000 // time out interrupt -#define ISR__SWInt 0x100 // Software interrupt -#define ISR__TDU 0x80 // Tx Descriptor unavailable +#define ISR_SWInt 0x100 // Software interrupt +#define ISR_TDU 0x80 // Tx Descriptor unavailable #define ISR_FIFOOVW 0x40 // Rx Fifo overflow #define ISR_PUN 0x20 // Packet underrun/link change #define ISR_RXOVW 0x10 // Rx overflow/Rx Descriptor unavailable @@ -227,6 +227,7 @@ typedef struct rtl1839if { uint32_t tx_complete; uint16_t rx_pos; uint8_t tx_inuse[4]; + volatile uint8_t polling; } rtl1839if_t; /*