From ccd13db67ea524d33b0db322bf3fd51f0e9779ec Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 20 Sep 2011 04:47:36 -0700 Subject: [PATCH 1/7] avoid mailbox overflow by sending a polling request to the tcpip thread --- drivers/net/rckemac.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/rckemac.c b/drivers/net/rckemac.c index 4d6d03e5..60c2f3a0 100644 --- a/drivers/net/rckemac.c +++ b/drivers/net/rckemac.c @@ -347,15 +347,18 @@ static void rckemacif_input(struct netif* netif, struct pbuf* p) case ETHTYPE_PPPOEDISC: case ETHTYPE_PPPOE: #endif /* PPPOE_SUPPORT */ - /* full packet send to tcpip_thread to process */ - if ((err = mynetif->input(p, mynetif)) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_input: IP input error %d\n", (int32_t) err)); - pbuf_free_callback(p); + /* + * This function is called in the context of the tcpip thread. + * Therefore, we are able to call directly the oinput functions + */ + err = ethernet_input(p, netif); + if (err != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_input: ethernet_input failed %d\n", err)); } break; default: - LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_input: invalid ethernet header: 0x%x\n", htons(ethhdr->type))); - pbuf_free_callback(p); + LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_input: invalid ethernet header 0x%x\n", htons(ethhdr->type))); + pbuf_free(p); break; } } @@ -500,6 +503,14 @@ rxDone: goto again; } +/* this function is called in the context of the tcpip thread */ +static void rckemacif_poll(void* ctx) +{ + unsigned int write_offset = (unsigned int) ctx; + + rckemacif_rx_handler(mynetif, write_offset); +} + static void rckemacif_handler(struct state* s) { unsigned int status, tmp; @@ -514,13 +525,13 @@ static void rckemacif_handler(struct state* s) return; } -nexttry: /* check for updated write offset */ write_offset = *((volatile unsigned int*) (rckemacif->rx_buffer)) & 0xFFFF; //write_offset = read_emac(rckemacif->num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_WRITE_OFFSET, rckemacif->core); if ((write_offset != 0) && (rckemacif->rx_read_offset != write_offset)) { - rckemacif_rx_handler(mynetif, write_offset); - goto nexttry; + if (tcpip_callback_with_block(rckemacif_poll, (void*) write_offset, 0) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_handler: unable to send a poll request to the tcpip thread\n")); + } } /* Set interrupt bit */ From 268ef4b37d1c34d1166543c224f22d9770571a55 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 20 Sep 2011 16:37:12 +0200 Subject: [PATCH 2/7] use nicer output messages --- kernel/netio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/netio.c b/kernel/netio.c index 35f57e45..4df88f8f 100644 --- a/kernel/netio.c +++ b/kernel/netio.c @@ -202,7 +202,7 @@ static int TCPServer(void* arg) { start = rdtsc(); - kprintf("\nReceiving from client, packet size %s ... ", PacketSize(ctl.data)); + kprintf("\nReceiving from client, packet size %s ... \n", PacketSize(ctl.data)); cBuffer[0] = 0; nData = 0; @@ -229,7 +229,7 @@ static int TCPServer(void* arg) } else if (ctl.cmd == CMD_S2C) { start = rdtsc(); - kprintf("\nSending to client, packet size %s ... ", PacketSize(ctl.data)); + kprintf("\nSending to client, packet size %s ... \n", PacketSize(ctl.data)); cBuffer[0] = 0; nData = 0; From e50b850cc0a8509eb4d8b61bcbbc0c812c9506b7 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 20 Sep 2011 16:37:38 +0200 Subject: [PATCH 3/7] remove typo --- drivers/net/rckemac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/rckemac.c b/drivers/net/rckemac.c index 60c2f3a0..6cb01ed3 100644 --- a/drivers/net/rckemac.c +++ b/drivers/net/rckemac.c @@ -349,7 +349,7 @@ static void rckemacif_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 oinput functions + * Therefore, we are able to call directly the input functions */ err = ethernet_input(p, netif); if (err != ERR_OK) { From d199ee059b1f70d234ba4a204462ec452836378e Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 20 Sep 2011 16:38:37 +0200 Subject: [PATCH 4/7] avoid mailbox overflow by sending a polling request to the tcpip thread --- drivers/net/rtl8139.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index fb1127db..7562a1ac 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -38,6 +38,7 @@ #define RX_BUF_LEN 8192 #define TX_BUF_LEN 4096 +#define MIN(a, b) (a) < (b) ? (a) : (b) board_t board_tbl[] = { @@ -131,15 +132,18 @@ static void rtl8139if_input(struct netif* netif, struct pbuf* p) case ETHTYPE_PPPOEDISC: case ETHTYPE_PPPOE: #endif /* PPPOE_SUPPORT */ - /* full packet send to tcpip_thread to process */ - err = mynetif->input(p, mynetif); + /* + * This function is called in the context of the tcpip thread. + * Therefore, we are able to call directly the input functions + */ + err = ethernet_input(p, netif); if (err != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_input: IP input error %d\n", (int32_t) err)); - pbuf_free_callback(p); + LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_input: ethernet_input failed %d\n", err)); } break; default: - pbuf_free_callback(p); + LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139_input: invalid ethernet header 0x%x\n", htons(ethhdr->type))); + pbuf_free(p); break; } } @@ -170,11 +174,13 @@ static void rtl_rx_inthandler(struct netif* netif) #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif - for (q=p, i=0; q!=NULL; q=q->next) { - memcpy((uint8_t*) q->payload + i, rtl8139if->rx_buffer + rtl8139if->rx_pos + i, q->len); - i += q->len; - } - rtl8139if->rx_pos = (rtl8139if->rx_pos + p->tot_len) % RX_BUF_LEN; + for (q=p; q!=NULL; q=q->next) { + i = MIN(q->len, RX_BUF_LEN - rtl8139if->rx_pos); + memcpy((uint8_t*) q->payload, rtl8139if->rx_buffer + rtl8139if->rx_pos, i); + if (i < q->len) // wrap around to end of RxBuffer + memcpy((uint8_t*) q->payload + i, rtl8139if->rx_buffer, q->len - i); + rtl8139if->rx_pos = (rtl8139if->rx_pos + q->len) % RX_BUF_LEN; + } #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif @@ -235,6 +241,14 @@ 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) { rtl1839if_t* rtl8139if = mynetif->state; @@ -246,7 +260,9 @@ static void rtl8139if_handler(struct state* s) break; if (isr_contents & ISR_ROK) { - rtl_rx_inthandler(mynetif); + 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")); + } outportw(rtl8139if->iobase + ISR, ISR_ROK); } @@ -291,7 +307,7 @@ err_t rtl8139if_init(struct netif* netif) memset(rtl8139if, 0, sizeof(rtl1839if_t)); /* allocate the receive buffer */ - rtl8139if->rx_buffer = mem_allocation(RX_BUF_LEN + 1500 /* MTU */ + 16 /* header size */, MAP_KERNEL_SPACE|MAP_NO_CACHE); + rtl8139if->rx_buffer = mem_allocation(RX_BUF_LEN + 16 /* header size */, MAP_KERNEL_SPACE|MAP_NO_CACHE); if (!(rtl8139if->rx_buffer)) { LWIP_DEBUGF(NETIF_DEBUG, ("rtl8139if_init: out of memory\n")); kfree(rtl8139if, sizeof(rtl1839if_t)); @@ -389,7 +405,7 @@ err_t rtl8139if_init(struct netif* netif) * APM - Accept Physical Match: Accept packets send to NIC's MAC address. * AAP - Accept All Packets. Accept all packets (run in promiscuous mode). */ - outportl(rtl8139if->iobase + RCR, RCR_MXDMA2|RCR_MXDMA1|RCR_WRAP|RCR_MXDMA0|RCR_AB|RCR_AM|RCR_APM|RCR_AAP); // The WRAP bit is set! + outportl(rtl8139if->iobase + RCR, RCR_MXDMA2|RCR_MXDMA1|RCR_MXDMA0|RCR_AB|RCR_AM|RCR_APM|RCR_AAP); // The WRAP bit isn't set! // set the transmit config register to // be the normal interframe gap time From 1ada6d15af121f9a41ba1d2d4b97f2c8c0cc9fda Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 20 Sep 2011 21:05:15 +0200 Subject: [PATCH 5/7] minor optimizations, avoiding mailbox overflow --- drivers/net/rtl8139.c | 56 +++++++++++++++++++++++++++---------------- drivers/net/rtl8139.h | 5 ++-- 2 files changed, 38 insertions(+), 23 deletions(-) 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; /* From 1fabe449dd69df3642cd898c7f5cb96d54d629bd Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 20 Sep 2011 13:05:49 -0700 Subject: [PATCH 6/7] minor performance improvements => reducing the number of interrupts --- drivers/net/rckemac.c | 18 ++++++++++++++---- drivers/net/rckemac.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/rckemac.c b/drivers/net/rckemac.c index 6cb01ed3..07b538ad 100644 --- a/drivers/net/rckemac.c +++ b/drivers/net/rckemac.c @@ -349,7 +349,7 @@ static void rckemacif_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) { @@ -501,6 +501,11 @@ rxDone: if (read_offset != write_offset) goto again; + + /* Enable eMAC interrupt */ + int tmp = *((volatile int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4)); + *((volatile int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4)) = tmp & ~(1 << rckemacif->num_emac); + rckemacif->polling = 0; } /* this function is called in the context of the tcpip thread */ @@ -528,8 +533,13 @@ static void rckemacif_handler(struct state* s) /* check for updated write offset */ write_offset = *((volatile unsigned int*) (rckemacif->rx_buffer)) & 0xFFFF; //write_offset = read_emac(rckemacif->num_emac, EMAC_RX_CONTROL + EMAC_RX_BUFFER_WRITE_OFFSET, rckemacif->core); - if ((write_offset != 0) && (rckemacif->rx_read_offset != write_offset)) { - if (tcpip_callback_with_block(rckemacif_poll, (void*) write_offset, 0) != ERR_OK) { + if ((write_offset != 0) && (rckemacif->rx_read_offset != write_offset) && !rckemacif->polling) { + if (tcpip_callback_with_block(rckemacif_poll, (void*) write_offset, 0) == ERR_OK) { + /* Maks eMAC interrupt */ + int tmp = *((volatile int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4)); + *((volatile int*) (FPGA_BASE + IRQ_MASK + rckemacif->core * 2 * 4)) = tmp | (1 << rckemacif->num_emac); + rckemacif->polling = 1; + } else { LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_handler: unable to send a poll request to the tcpip thread\n")); } } @@ -572,7 +582,7 @@ err_t rckemacif_init(struct netif* netif) LWIP_DEBUGF(NETIF_DEBUG, ("rckemacif_init: out of memory\n")); return ERR_MEM; } - memset(rckemacif, 0, sizeof(rckemacif_t)); + memset(rckemacif, 0x00, sizeof(rckemacif_t)); rckemacif->core = core; /* allocate the receive buffer */ diff --git a/drivers/net/rckemac.h b/drivers/net/rckemac.h index 2796f14d..f6710594 100644 --- a/drivers/net/rckemac.h +++ b/drivers/net/rckemac.h @@ -39,6 +39,7 @@ typedef struct rckemacif { void* irq_address; uint32_t core; uint32_t num_emac; + volatile uint8_t polling; } rckemacif_t; /* From 06a2b179786de7a310c907aa7414294d01fd3efe Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 20 Sep 2011 13:23:39 -0700 Subject: [PATCH 7/7] switch back to ticket lock --- include/metalsvm/spinlock.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/metalsvm/spinlock.h b/include/metalsvm/spinlock.h index bba4325a..a86bc603 100644 --- a/include/metalsvm/spinlock.h +++ b/include/metalsvm/spinlock.h @@ -80,7 +80,7 @@ inline static int spinlock_destroy(spinlock_t* s) { * - -EINVAL (-22) on failure */ inline static int spinlock_lock(spinlock_t* s) { - //int32_t ticket; + int32_t ticket; task_t* curr_task; if (BUILTIN_EXPECT(!s, 0)) @@ -92,7 +92,7 @@ inline static int spinlock_lock(spinlock_t* s) { return 0; } -#if 0 +#if 1 ticket = atomic_int32_inc(&s->queue); while(atomic_int32_read(&s->dequeue) != ticket) { NOP1; @@ -118,7 +118,7 @@ inline static int spinlock_unlock(spinlock_t* s) { s->counter--; if (!s->counter) { s->owner = MAX_TASKS; -#if 0 +#if 1 atomic_int32_inc(&s->dequeue); #else atomic_int32_set(&s->dequeue,1); @@ -172,7 +172,7 @@ inline static int spinlock_irqsave_destroy(spinlock_irqsave_t* s) { */ inline static int spinlock_irqsave_lock(spinlock_irqsave_t* s) { uint32_t flags; - //int32_t ticket; + int32_t ticket; if (BUILTIN_EXPECT(!s, 0)) return -EINVAL; @@ -183,7 +183,7 @@ inline static int spinlock_irqsave_lock(spinlock_irqsave_t* s) { return 0; } -#if 0 +#if 1 ticket = atomic_int32_inc(&s->queue); while (atomic_int32_read(&s->dequeue) != ticket) { NOP1; @@ -215,7 +215,7 @@ inline static int spinlock_irqsave_unlock(spinlock_irqsave_t* s) { flags = s->flags; s->coreid = (uint32_t) -1; s->flags = 0; -#if 0 +#if 1 atomic_int32_inc(&s->dequeue); #else atomic_int32_set(&s->dequeue,1);