NAPI-ized tulip patch against 2.4.20-rc1
Subsystems (3)
Here is a patch that makes Tulip support NAPI. The vast bulk of these changes come from Robert Olsson's ftp site, I just pieced them together.
It works good on my 4-port Tulip NICs, better than the default driver at least (no, I never tried the old HW-Mitigation option).
This patch will also make use of Robert's skb-recycle patch if it's been applied, but through #ifdef magic, it should also work w/out that....
Enjoy,
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 1 line · Ben Greear
Here is a patch that makes Tulip support NAPI. The vast bulk of these
Blech...I actually attached it this time...
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
drivers/net/tulip/interrupt.c +288 -199
@@ -1,4 +1,4 @@ -/* +/* -*-linux-c-*- drivers/net/tulip/interrupt.c Maintained by Jeff Garzik <[email protected]>
@@ -23,9 +23,14 @@int tulip_rx_copybreak;unsigned int tulip_max_interrupt_work; -#ifdef CONFIG_NET_HW_FLOWCONTROL +#ifdef CONFIG_NET_SKB_RECYCLING +int tulip_recycle (struct sk_buff *skb); +#endif +#ifdef USE_MITIGATION #define MIT_SIZE 15 +#define MIT_TABLE 15/* We use 0 or max */ +unsigned int mit_table[MIT_SIZE +1 ] = {/* CRS11 21143 hardware Mitigation Control Interrupt
@@ -99,16 +104,28 @@return refilled; } +void oom_timer (unsigned long data) +{ +struct net_device *dev = (struct net_device *)data; +netif_rx_schedule (dev); +} + -static int tulip_rx (struct net_device *dev) +int tulip_poll (struct net_device *dev,int *budget) {struct tulip_private *tp = (struct tulip_private *)dev->priv;int entry = tp->cur_rx %RX_RING_SIZE ; -int rx_work_limit = tp->dirty_rx +RX_RING_SIZE - tp->cur_rx; +int rx_work_limit = *budget;int received =0 ; -#ifdef CONFIG_NET_HW_FLOWCONTROL -int drop =0 , mit_sel =0 ; +#ifdef EXTRA_STATS + tp->stats_poll_starts++; +#endif + +if (rx_work_limit > dev->quota) + rx_work_limit = dev->quota; + +#ifdef USE_MITIGATION /* that one buffer is needed for mit activation; or might be a bug in the ring buffer code; check later -- JHS*/
@@ -118,177 +135,266 @@if (tulip_debug >4 )printk (KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n" , entry, - tp->rx_ring[entry].status); -/* If we own the next entry, it is a new packet. Send it up. */ -while ( ! (tp->rx_ring[entry].status &cpu_to_le32 (DescOwned))) { -s32 status =le32_to_cpu (tp->rx_ring[entry].status); - -if (tulip_debug >5 ) -printk (KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n" , - dev->name, entry, status); -if (--rx_work_limit <0 ) -break ; -if ((status &0x38008300 ) !=0x0300 ) { -if ((status &0x38000300 ) !=0x0300 ) { -/* Ingore earlier buffers. */ -if ((status &0xffff ) !=0x7fff ) { -if (tulip_debug >1 ) -printk (KERN_WARNING "%s: Oversized Ethernet frame " -"spanned multiple buffers, status %8.8x!\n" , - dev->name, status); - tp->stats.rx_length_errors++; - } - }else if (status & RxDescFatalErr) { + tp->rx_ring[entry].status); + + +do { +/* Acknowledge current RX interrupt sources. */ +outl ((RxIntr | RxNoBuf), dev->base_addr +CSR5 ); + + +/* If we own the next entry, it is a new packet. Send it up. */ +while ( ! (tp->rx_ring[entry].status &cpu_to_le32 (DescOwned))) { +s32 status =le32_to_cpu (tp->rx_ring[entry].status); + + +if (tp->dirty_rx +RX_RING_SIZE == tp->cur_rx) +break ; + +if (tulip_debug >5 ) +printk (KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n" , + dev->name, entry, status); +if (--rx_work_limit <0 ) + goto not_done; + +if ((status &0x38008300 ) !=0x0300 ) { +if ((status &0x38000300 ) !=0x0300 ) { +/* Ignore earlier buffers. */ +if ((status &0xffff ) !=0x7fff ) { +if (tulip_debug >1 ) +printk (KERN_WARNING "%s: Oversized Ethernet frame " +"spanned multiple buffers, status %8.8x!\n" , + dev->name, status); + tp->stats.rx_length_errors++; + } + }else if (status & RxDescFatalErr) {/* There was a fatal error. */ -if (tulip_debug >2 ) -printk (KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n" , - dev->name, status); - tp->stats.rx_errors++;/* end of a packet.*/ -if (status &0x0890 ) tp->stats.rx_length_errors++; -if (status &0x0004 ) tp->stats.rx_frame_errors++; -if (status &0x0002 ) tp->stats.rx_crc_errors++; -if (status &0x0001 ) tp->stats.rx_fifo_errors++; - } - }else { -/* Omit the four octet CRC from the length. */ -short pkt_len = ((status >>16 ) &0x7ff ) -4 ; -struct sk_buff *skb; +if (tulip_debug >2 ) +printk (KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n" , + dev->name, status); + tp->stats.rx_errors++;/* end of a packet.*/ +if (status &0x0890 ) tp->stats.rx_length_errors++; +if (status &0x0004 ) tp->stats.rx_frame_errors++; +if (status &0x0002 ) tp->stats.rx_crc_errors++; +if (status &0x0001 ) tp->stats.rx_fifo_errors++; + } + }else { +/* Omit the four octet CRC from the length. */ +short pkt_len = ((status >>16 ) &0x7ff ) -4 ; +struct sk_buff *skb =NULL ;#ifndef final_version -if (pkt_len >1518 ) { -printk (KERN_WARNING "%s: Bogus packet size of %d (%#x).\n" , - dev->name, pkt_len, pkt_len); - pkt_len =1518 ; - tp->stats.rx_length_errors++; - } +if (pkt_len >1518 ) { +printk (KERN_WARNING "%s: Bogus packet size of %d (%#x).\n" , + dev->name, pkt_len, pkt_len); + pkt_len =1518 ; + tp->stats.rx_length_errors++; + }#endif -#ifdef CONFIG_NET_HW_FLOWCONTROL - drop =atomic_read (&netdev_dropping); -if (drop) - goto throttle; -#endif -/* Check if the packet is long enough to accept without copying -to a minimally-sized skbuff. */ -if (pkt_len < tulip_rx_copybreak - && (skb =dev_alloc_skb (pkt_len +2 )) !=NULL ) { - skb->dev = dev; -skb_reserve (skb,2 );/* 16 byte align the IP header */ -pci_dma_sync_single (tp->pdev, - tp->rx_buffers[entry].mapping, - pkt_len,PCI_DMA_FROMDEVICE ); +/* Check if the packet is long enough to accept without copying +to a minimally-sized skbuff. */ +#ifdef CONFIG_NET_SKB_RECYCLING +if (pkt_len < tulip_rx_copybreak) { +/* Allocate an skb from our private queue if possible */ + skb =skb_dequeue (&(tp->tulip_recycle[smp_processor_id ()].list)); +if (skb) { +skb_headerinit (skb,NULL ,0 );/* clean state */ + + skb->data = skb->head; + skb->tail = skb->head; + skb->len =0 ; + } + } +#endif +if ((pkt_len < tulip_rx_copybreak) + && ((skb !=NULL ) + || ((skb =dev_alloc_skb (pkt_len +2 )) !=NULL ))) { + skb->dev = dev; +skb_reserve (skb,2 );/* 16 byte align the IP header */ +pci_dma_sync_single (tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len,PCI_DMA_FROMDEVICE );#if ! defined(__alpha__) -eth_copy_and_sum (skb, tp->rx_buffers[entry].skb->tail, - pkt_len,0 ); -skb_put (skb, pkt_len); +eth_copy_and_sum (skb, tp->rx_buffers[entry].skb->tail, + pkt_len,0 ); +skb_put (skb, pkt_len);#else -memcpy (skb_put (skb, pkt_len), - tp->rx_buffers[entry].skb->tail, - pkt_len); -#endif - }else {/* Pass up the skb already on the Rx ring. */ -char *temp =skb_put (skb = tp->rx_buffers[entry].skb, - pkt_len); +memcpy (skb_put (skb, pkt_len), + tp->rx_buffers[entry].skb->tail, + pkt_len); +#endif +#ifdef CONFIG_NET_SKB_RECYCLING + skb->tag =smp_processor_id (); + tp->cnt[skb->tag]++; + skb->recycle_dev = dev; + skb->recycle_dev->skb_recycle = tulip_recycle; +#endif + }else {/* Pass up the skb already on the Rx ring. */ +char *temp =skb_put (skb = tp->rx_buffers[entry].skb, + pkt_len);#ifndef final_version -if (tp->rx_buffers[entry].mapping != -le32_to_cpu (tp->rx_ring[entry].buffer1)) { -printk (KERN_ERR "%s: Internal fault: The skbuff addresses " -"do not match in tulip_rx: %08x vs. %08x %p / %p.\n" , - dev->name, -le32_to_cpu (tp->rx_ring[entry].buffer1), - tp->rx_buffers[entry].mapping, - skb->head, temp); - } +if (tp->rx_buffers[entry].mapping != +le32_to_cpu (tp->rx_ring[entry].buffer1)) { +printk (KERN_ERR "%s: Internal fault: The skbuff addresses " +"do not match in tulip_rx: %08x vs. %08x %p / %p.\n" , + dev->name, +le32_to_cpu (tp->rx_ring[entry].buffer1), + tp->rx_buffers[entry].mapping, + skb->head, temp); + }#endif -pci_unmap_single (tp->pdev, tp->rx_buffers[entry].mapping, -PKT_BUF_SZ ,PCI_DMA_FROMDEVICE ); +pci_unmap_single (tp->pdev, tp->rx_buffers[entry].mapping, +PKT_BUF_SZ ,PCI_DMA_FROMDEVICE ); - tp->rx_buffers[entry].skb =NULL ; - tp->rx_buffers[entry].mapping =0 ; - } - skb->protocol =eth_type_trans (skb, dev); -#ifdef CONFIG_NET_HW_FLOWCONTROL - mit_sel = -#endif -netif_rx (skb); - -#ifdef CONFIG_NET_HW_FLOWCONTROL -switch (mit_sel) { -case NET_RX_SUCCESS : -case NET_RX_CN_LOW : -case NET_RX_CN_MOD : -break ; - -case NET_RX_CN_HIGH : - rx_work_limit -=NET_RX_CN_HIGH ;/* additional*/ -break ; -case NET_RX_DROP : - rx_work_limit =-1 ; -break ; -default : -printk ("unknown feedback return code %d\n" , mit_sel); -break ; - } + tp->rx_buffers[entry].skb =NULL ; + tp->rx_buffers[entry].mapping =0 ; + } + skb->protocol =eth_type_trans (skb, dev); - drop =atomic_read (&netdev_dropping); -if (drop) { -throttle: - rx_work_limit =-1 ; - mit_sel =NET_RX_DROP ; - -if (tp->fc_bit) { -long ioaddr = dev->base_addr; - -/* disable Rx & RxNoBuf ints. */ -outl (tulip_tbl[tp->chip_id].valid_intrs&RX_A_NBF_STOP , ioaddr +CSR7 ); -set_bit (tp->fc_bit, &netdev_fc_xoff); - } - } +netif_receive_skb (skb); + + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + received++; +#ifdef EXTRA_STATS + tp->stats_poll_pkts++; +#ifdef USE_MITIGATION +if (tp->mit_on) tp->stats_poll_pkts_mit++; +#endif #endif - dev->last_rx = jiffies; - tp->stats.rx_packets++; - tp->stats.rx_bytes += pkt_len; + entry = (++tp->cur_rx) %RX_RING_SIZE ; +if (tp->cur_rx - tp->dirty_rx >RX_RING_SIZE /4 ) +tulip_refill_rx (dev); + } - received++; - entry = (++tp->cur_rx) %RX_RING_SIZE ; - } -#ifdef CONFIG_NET_HW_FLOWCONTROL + +/* New ack strategy... irq does not ack Rx any longer +hopefully this helps */ + +/* Really bad things can happen here... If new packet arrives +* and an irq arrives (tx or just due to occasionally unset +* mask), it will be acked by irq handler, but new thread +* is not scheduled. It is major hole in design. +* No idea how to fix this if "playing with fire" will fail +* tomorrow (night 011029). If it will not fail, we won +* finally: amount of IO did not increase at all. */ + }while ((inl (dev->base_addr +CSR5 ) & RxIntr)); + +/* done: */ + +#ifdef USE_MITIGATION /* We use this simplistic scheme for IM. It's proven by real life installations. We can have IM enabled -continuesly but this would cause unnecessary latency. -Unfortunely we can't use all the NET_RX_* feedback here. -This would turn on IM for devices that is not contributing -to backlog congestion with unnecessary latency. +continuesly but this would cause unnecessary latency. +Unfortunely we can't use all the NET_RX_* feedback here. +This would turn on IM for devices that is not contributing +to backlog congestion with unnecessary latency. We monitor the the device RX-ring and have: HW Interrupt Mitigation either ON or OFF. -ON: More then 1 pkt received (per intr.) OR we are dropping +ON: More then 1 pkt received (per intr.) OR we are dropping OFF: Only 1 pkt received - +Note. We only use min and max (0, 15) settings from mit_table */ if ( tp->flags &HAS_INTR_MITIGATION ) { -if ((received >1 || mit_sel ==NET_RX_DROP ) - && tp->mit_sel !=15 ) { - tp->mit_sel =15 ; - tp->mit_change =1 ;/* Force IM change */ +if ( received >1 ) { +if ( ! tp->mit_on ) { + tp->mit_on =1 ; +outl (mit_table[MIT_TABLE ], dev->base_addr +CSR11 ); + } } -if ((received <=1 && mit_sel !=NET_RX_DROP ) && tp->mit_sel !=0 ) { - tp->mit_sel =0 ; - tp->mit_change =1 ;/* Force IM change */ +else { +if ( tp->mit_on ) { + tp->mit_on =0 ; +outl (0 , dev->base_addr +CSR11 ); + } } } -return RX_RING_SIZE +1 ;/* maxrx+1 */ -#else -return received;#endif + + dev->quota -= received; + *budget -= received; + +tulip_refill_rx (dev); + +/* If RX ring is not full we are out of memory. */ +if (tp->rx_buffers[tp->dirty_rx %RX_RING_SIZE ].skb ==NULL ) goto oom; + +#ifdef EXTRA_STATS +if ((inl (dev->base_addr +CSR5 ) & RxIntr)) tp->stats_poll_exit_done_rx_pending++; + tp->stats_poll_exit_done++; +#endif + +/* Remove us from polling list and enable RX intr. */ + +netif_rx_complete (dev); +outl (tulip_tbl[tp->chip_id].valid_intrs, dev->base_addr+CSR7 ); + +/* The last op happens after poll completion. Which means the following: +* 1. it can race with disabling irqs in irq handler +* 2. it can race with dise/enabling irqs in other poll threads +* 3. if an irq raised after beginning loop, it will be immediately +* triggered here. +* +* Summarizing: the logic results in some redundant irqs both +* due to races in masking and due to too late acking of already +* processed irqs. But it must not result in losing events. +*/ + +return 0 ; + +not_done: +if (!received) { +#ifdef EXTRA_STATS + tp->stats_poll_zero_rx++; +#endif +/* received = dev->quota; Why existed? --Ben */ /* Not to happen */ + } +else { + dev->quota -= received; + *budget -= received; + } + +if (tp->cur_rx - tp->dirty_rx >RX_RING_SIZE /2 || + tp->rx_buffers[tp->dirty_rx %RX_RING_SIZE ].skb ==NULL ) +tulip_refill_rx (dev); + +if (tp->rx_buffers[tp->dirty_rx %RX_RING_SIZE ].skb ==NULL ) goto oom; + +#ifdef EXTRA_STATS + tp->stats_poll_exit_not_done++; +#endif +return 1 ; + + +oom:/* Executed with RX ints disabled */ +printk ("ERROR: tulip: Hit OOM trying to refill rx buffer.\n" ); + +/* Start timer, stop polling, but do not enable rx interrupts. */ +mod_timer (&tp->oom_timer, jiffies+1 ); + +/* Think: timer_pending() was an explicit signature of bug. +* Timer can be pending now but fired and completed +* before we did netif_rx_complete(). See? We would lose it. */ + +/* remove ourselves from the polling list */ +netif_rx_complete (dev); + +#ifdef EXTRA_STATS + tp->stats_poll_exit_oom++; +#endif +return 0 ; }static inline void phy_interrupt (struct net_device *dev)
@@ -319,7 +425,6 @@struct tulip_private *tp = (struct tulip_private *)dev->priv;long ioaddr = dev->base_addr;int csr5; -int entry;int missed;int rx =0 ;int tx =0 ;
@@ -327,6 +432,7 @@int maxrx =RX_RING_SIZE ;int maxtx =TX_RING_SIZE ;int maxoi =TX_RING_SIZE ; +int rxd =0 ;unsigned int work_count = tulip_max_interrupt_work;/* Let's see whether the interrupt really is for us */
@@ -341,21 +447,32 @@ tp->nir++; do { - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(csr5 & 0x0001ffff, ioaddr + CSR5); +#ifdef EXTRA_STATS + if(!rxd) + record_interrupt_cause(dev, csr5); + else + record_interrupt_cause(dev, csr5& 0x0001ff3f); +#endif + if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { + rxd++; + /* Mask RX intrs and add the device to poll list. */ + outl(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); + netif_rx_schedule(dev); + + if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) + break; + } + + /* Acknowledge the interrupt sources we handle here ASAP + the poll function does Rx and RxNoBuf acking */ + + outl(csr5 & 0x0001ff3f, ioaddr + CSR5); + if (tulip_debug > 4) printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", - dev->name, csr5, inl(dev->base_addr + CSR5)); - - if (csr5 & (RxIntr | RxNoBuf)) { -#ifdef CONFIG_NET_HW_FLOWCONTROL - if ((!tp->fc_bit) || - (!test_bit(tp->fc_bit, &netdev_fc_xoff))) -#endif - rx += tulip_rx(dev); - tulip_refill_rx(dev); - } + dev->name, csr5, inl(dev->base_addr + CSR5)); + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { unsigned int dirty_tx;
@@ -457,15 +574,8 @@ }if (csr5 & RxDied) {/* Missed a Rx frame. */ tp->stats.rx_missed_errors +=inl (ioaddr +CSR8 ) &0xffff ; -#ifdef CONFIG_NET_HW_FLOWCONTROL -if (tp->fc_bit && !test_bit (tp->fc_bit, &netdev_fc_xoff)) { - tp->stats.rx_errors++; -tulip_start_rxtx (tp); - } -#else tp->stats.rx_errors++;tulip_start_rxtx (tp); -#endif }/* * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this
@@ -499,10 +609,6 @@if (tulip_debug >2 )printk (KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n" , dev->name, csr5); -#ifdef CONFIG_NET_HW_FLOWCONTROL -if (tp->fc_bit && (test_bit (tp->fc_bit, &netdev_fc_xoff))) -if (net_ratelimit ())printk ("BUG!! enabling interupt when FC off (timerintr.) \n" ); -#endif outl (tulip_tbl[tp->chip_id].valid_intrs, ioaddr +CSR7 ); tp->ttimer =0 ; oi++;
@@ -515,11 +621,8 @@/* Acknowledge all interrupt sources. */ outl (0x8001ffff , ioaddr +CSR5 );if (tp->flags &HAS_INTR_MITIGATION ) { -#ifdef CONFIG_NET_HW_FLOWCONTROL -if (tp->mit_change) { -outl (mit_table[tp->mit_sel], ioaddr +CSR11 ); - tp->mit_change =0 ; - } +#ifdef USE_MITIGATION +outl (mit_table[MIT_TABLE ], ioaddr +CSR11 );#else /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/
@@ -532,10 +635,8 @@ }else {/* Mask all interrupting sources, set timer to re-enable. */ -#ifndef CONFIG_NET_HW_FLOWCONTROL outl (((~csr5) &0x0001ebef ) | AbnormalIntr | TimerInt, ioaddr +CSR7 );outl (0x0012 , ioaddr +CSR11 ); -#endif }break ; }
@@ -545,30 +646,18 @@break ; csr5 =inl (ioaddr +CSR5 ); - }while ((csr5 & (NormalIntr|AbnormalIntr)) !=0 ); - -tulip_refill_rx (dev); - -/* check if the card is in suspend mode */ - entry = tp->dirty_rx %RX_RING_SIZE ; -if (tp->rx_buffers[entry].skb ==NULL ) { -if (tulip_debug >1 ) -printk (KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n" , dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); -if (tp->chip_id ==LC82C168 ) { -outl (0x00 , ioaddr +CSR7 ); -mod_timer (&tp->timer,RUN_AT (HZ /50 )); - }else { -if (tp->ttimer ==0 || (inl (ioaddr +CSR11 ) &0xffff ) ==0 ) { -if (tulip_debug >1 ) -printk (KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n" , dev->name, tp->nir); -outl (tulip_tbl[tp->chip_id].valid_intrs | TimerInt, - ioaddr +CSR7 ); -outl (TimerInt, ioaddr +CSR5 ); -outl (12 , ioaddr +CSR11 ); - tp->ttimer =1 ; - } - } - } +if (rxd) + csr5 &= ~RxPollInt; + }while ((csr5 & (TxNoBuf | + TxDied | + TxIntr | + TimerInt | +/* Abnormal intr. */ + RxDied | + TxFIFOUnderflow | + TxJabber | + TPLnkFail | + SytemError )) !=0 );if ((missed =inl (ioaddr +CSR8 ) &0x1ffff )) { tp->stats.rx_dropped += missed &0x10000 ?0x10000 : missed;
drivers/net/tulip/tulip_core.c +106 -38
237 lines not on this page · raw message
drivers/net/tulip/tulip.h +74 -2
135 lines not on this page · raw message
Quoted 9 lines · Ben Greear
Here is a patch that makes Tulip support NAPI. The vast bulk of these changes come from Robert Olsson's ftp site, I just pieced them together.
It works good on my 4-port Tulip NICs, better than the default driver at least (no, I never tried the old HW-Mitigation option).
This patch will also make use of Robert's skb-recycle patch if it's been applied, but through #ifdef magic, it should also work w/out that....
Hello!
Well skb recycling is "research" and should be used to challange to vm/slab people to start with... And I guess you will get objections about the extra stats as well.
I see you increased the RX-ring to 1024 pkts.
Did you really see any improvement with this?
Also I would be interested if you have any numbers for recycling patch?
Jamal and I spent some days after OLS to test and tune but it wasn't to promising at that time but it's reworked now.
Cheers.
--ro
Quoted 11 lines · Robert Olsson
Quoted 9 lines · Ben Greear
Here is a patch that makes Tulip support NAPI. The vast bulk of these changes come from Robert Olsson's ftp site, I just pieced them together.
It works good on my 4-port Tulip NICs, better than the default driver at least (no, I never tried the old HW-Mitigation option).
This patch will also make use of Robert's skb-recycle patch if it's been applied, but through #ifdef magic, it should also work w/out that....
Quoted 5 lines
Hello!
Well skb recycling is "research" and should be used to challange to vm/slab people to start with... And I guess you will get objections about the extra stats as well.
The stats stuff is #ifdef'd out, as is the skb-recycling stuff.
Quoted 3 lines
I see you increased the RX-ring to 1024 pkts.
Did you really see any improvement with this?
It helped drop fewer packets when running 4 ports at 92Mbps+ However, the difference between that and 512 is not large. I would really like to make that size adjustable at module load time and/or runtime, but I'm not sure how easy that would be.
Imagine being able to crank up your receive buffers when running at very high speeds (and/or when you start dropping packets). At lower speeds, shrink things down and free up resources....
Quoted 1 line
Also I would be interested if you have any numbers for recycling patch?
I still need to do some comparisons with that being the only difference. I do know that it does not appear to hurt anything, but it's also possible that it doesn't really help. Since under normal circumstances there are enough buffers to be allocated with GFP_ATOMIC, I believe that it will take long statistical runs to determine if this really helps. I do like very much the fact that it actually gives me something deterministic to tune though, so I'll keep it for that reason if nothing else.
Quoted 2 lines
Jamal and I spent some days after OLS to test and tune but it wasn't to promising at that time but it's reworked now.
Were you testing SMP or uni-processor? I've been doing the tulip testing on a single processor P-IV system.
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 5 lines · Ben Greear
Quoted 2 lines
I see you increased the RX-ring to 1024 pkts.
Did you really see any improvement with this?It helped drop fewer packets when running 4 ports at 92Mbps+ However, the difference between that and 512 is not large.
Using 512 Rx buffers at 100Mbps seem like a pretty silly default.
Quoted 2 lines
I would really like to make that size adjustable at module load time and/or runtime, but I'm not sure how easy that would be.
It's trivial for many (but not all) drivers.
I've been considering doing that with my driver release. There is no longer a CPU cycle cost issue with ring-wrapping on an arbitrary ring size.
Quoted 3 lines
Imagine being able to crank up your receive buffers when running at very high speeds (and/or when you start dropping packets). At lower speeds, shrink things down and free up resources....
Being that dynamic involves writing code and extensive testing with all of the different chips.
The trivial case is a module option that sets a variable replacing RX_RING_SIZE / TX_RING_SIZE..
The passed-in value shouldn't be used directly:
- many drivers have upper and lower bounds
- the size can only be changed when the rings are initialized, which occurs when the interface starts.
- users thinking "if 32 is good, 32000 is better"
Quoted 1 line
Quoted 1 line
Also I would be interested if you have any numbers for recycling patch?
interest++
Signature · 4 lines
Donald Becker [email protected] Scyld Computing Corporation http://www.scyld.com 410 Severn Ave. Suite 210 Scyld Beowulf cluster system Annapolis MD 21403 410-990-9993
Quoted 10 lines · Donald Becker
Quoted 4 lines · Ben Greear
Quoted 1 line
I see you increased the RX-ring to 1024 pkts. Did you really see any improvement with this?
It helped drop fewer packets when running 4 ports at 92Mbps+ However, the difference between that and 512 is not large.
Using 512 Rx buffers at 100Mbps seem like a pretty silly default.
I'm open to suggestions. However, I am running 4 or 8 ports simultaneously, on a single processor machine, so w/out large receive buffers, I drop packets horribly. If there is some magic number you think will be better than others, I'll be happy to try it and report results...
Quoted 6 lines
The trivial case is a module option that sets a variable replacing
RX_RING_SIZE/TX_RING_SIZE..
The passed-in value shouldn't be used directly:
- many drivers have upper and lower bounds
- the size can only be changed when the rings are initialized, which occurs when the interface starts.
So, adjusting the ring size would require stopping and starting the NIC? Is that a full bounce (including auto-negotiation)?
Quoted 1 line
- users thinking "if 32 is good, 32000 is better"
The sad truth is, most NICs/drivers do not perform at high speeds w/out hacking them in various ways. Where to lay the blame (VM, shitty hardware, etc) is debatable, but it doesn't change the results. I do know that 1024 is better than 32 for high speeds on muliple ports, on my NICs.
Thanks,
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 9 lines · Ben Greear
Quoted 6 lines
The trivial case is a module option that sets a variable replacing
RX_RING_SIZE/TX_RING_SIZE..
The passed-in value shouldn't be used directly:
- many drivers have upper and lower bounds
- the size can only be changed when the rings are initialized, which occurs when the interface starts.So, adjusting the ring size would require stopping and starting the NIC? Is that a full bounce (including auto-negotiation)?
Most chips do not require bouncing the link when the interface is cycled down/up. That's not to say that some drivers don't reset the link -- it's easier for the driver writer to write the code that way, and doing the link reset can mask other problems.
Quoted 7 lines
Quoted 1 line
- users thinking "if 32 is good, 32000 is better"
The sad truth is, most NICs/drivers do not perform at high speeds w/out hacking them in various ways. Where to lay the blame (VM, shitty hardware, etc) is debatable, but it doesn't change the results. I do know that 1024 is better than 32 for high speeds on muliple ports, on my NICs.
I can see that changing the parameters is a quick, ad hoc solution. This list should focus on identifying the problems, rather than just patching in work-arounds.
Signature · 4 lines
Donald Becker [email protected] Scyld Computing Corporation http://www.scyld.com 410 Severn Ave. Suite 210 Scyld Beowulf cluster system Annapolis MD 21403 410-990-9993
Here's an update of the tulip-NAPI and skb-recycle patches. I made some changes to get it to compile and work when the RECYCLE define in skbuff.h was not enabled.
I also got some test runs in. Nothing really conclusive.
Test setup: Phobos 4-port NIC in each P-IV 1.8Ghz machine 32/33 PCI bus. Kernel 2.4.20-rc1 + my patches. NICs connected to each other over CX cables. Sending 4k 1514 byte packets per second, send + receive. (48Mbps or so) RX ring size is 1024 for all of these tests. No significant errors reported by the driver. I don't know where these dropped packets go..no counter seems to be catching them.
I sent 1 million packets (or very close to that) on every interface (received the same, mostly)
Without SKB-Recycle:
dropped 339 out of 1Million, repeated test twice, numbers very similar. When packets do drop, they drop on all interfaces in bursts of 10-150, generally. Latency was about .3ms
With SKB-Recycle (300 pkt hot-list)
dropped 230, 500, and 180 in consecutive runs. They also drop in bursts. The middle run may be bad luck...don't know.
Latency was about .3ms
While typing, I ran a longer test. Dropped about 1600 out of 4 million.
So, I think I can't draw too much from any of this. The bottleneck and/or problem seems to lie elsewhere. I will work on testing various rx-buffer sizes tomorrow...
Enjoy,
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
include/linux/skbuff.h +47 -0
@@ -14,6 +14,8 @@#ifndef _LINUX_SKBUFF_H#define _LINUX_SKBUFF_H +#define CONFIG_NET_SKB_RECYCLING +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h>
@@ -25,6 +27,7 @@#include <linux/spinlock.h> #include <linux/mm.h> #include <linux/highmem.h> +#include <linux/if_packet.h> /* PACKET_HOST */ #define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALIGNABLE_SKB /* Ditto 8) */
@@ -194,6 +197,11 @@unsigned char *end;/* End pointer */ void (*destructor)(struct sk_buff *);/* Destruct function */ +#ifdef CONFIG_NET_SKB_RECYCLING +struct net_device *recycle_dev;/* Device we arrived on */ +int tag;/* Device private tag. */ +#endif +#ifdef CONFIG_NETFILTER /* Can be used for communication between hooks. */ unsigned long nfmark;
@@ -1109,6 +1117,45 @@#endif } + +/* +* Slab constructor for a skb head. +*/ +static inline void skb_headerinit (void *p,kmem_cache_t *cache, +unsigned long flags) +{ +struct sk_buff *skb = p; + + skb->next =NULL ; + skb->prev =NULL ; + skb->list =NULL ; + skb->sk =NULL ; + skb->stamp.tv_sec=0 ;/* No idea about time */ + skb->dev =NULL ; + skb->dst =NULL ; +memset (skb->cb,0 ,sizeof (skb->cb)); + skb->pkt_type =PACKET_HOST ;/* Default type */ + skb->ip_summed =0 ; + skb->priority =0 ; + skb->security =0 ;/* By default packets are insecure */ + skb->destructor =NULL ; + +#ifdef CONFIG_NET_SKB_RECYCLING + skb->recycle_dev =0 ; +#endif + +#ifdef CONFIG_NETFILTER + skb->nfmark = skb->nfcache =0 ; + skb->nfct =NULL ; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug =0 ; +#endif +#endif +#ifdef CONFIG_NET_SCHED + skb->tc_index =0 ; +#endif +} +#define skb_queue_walk (queue, skb) \ for (skb = (queue)->next; \ (skb != (struct sk_buff *)(queue)); \
net/core/skbuff.c +15 -36
75 lines not on this page · raw message
Documentation/networking/skb_recycling.txt +186 -0
186 lines not on this page · raw message
drivers/net/tulip/interrupt.c +288 -199
604 lines not on this page · raw message
drivers/net/tulip/tulip_core.c +105 -38
236 lines not on this page · raw message
drivers/net/tulip/tulip.h +74 -2
135 lines not on this page · raw message
Quoted 22 lines · Ben Greear
Here's an update of the tulip-NAPI and skb-recycle patches. I made some changes to get it to compile and work when the RECYCLE define in
skbuff.hwas not enabled.I also got some test runs in. Nothing really conclusive.
Test setup: Phobos 4-port NIC in each P-IV 1.8Ghz machine 32/33 PCI bus. Kernel 2.4.20-rc1 + my patches. NICs connected to each other over CX cables. Sending 4k 1514 byte packets per second, send + receive. (48Mbps or so) RX ring size is 1024 for all of these tests. No significant errors reported by the driver. I don't know where these dropped packets go..no counter seems to be catching them.
I sent 1 million packets (or very close to that) on every interface (received the same, mostly)
Without SKB-Recycle:
dropped 339 out of 1Million, repeated test twice, numbers very similar. When packets do drop, they drop on all interfaces in bursts of 10-150, generally. Latency was about .3ms
Quoted 6 lines
With SKB-Recycle (300 pkt hot-list)
dropped 230, 500, and 180 in consecutive runs. They also drop in bursts. The middle run may be bad luck...don't know.
Latency was about .3ms
While typing, I ran a longer test. Dropped about 1600 out of 4 million.
Trash the machines harder. Try using smaller packets;
cheers,
jamal
Quoted 1 line · jamal
Trash the machines harder. Try using smaller packets;
They are already dropping packets, I thought I'd try to get a slower run to work cleanly before trying something faster. Precision is more important to me than absolute throughput at this point.
Initial run with 256 sized rx-ring (and skb-recycle) shows better performance (than with 1024 rx-ring)
Sent 6-mil packets (same setup as before), dropped 750 or so. One NIC has dropped 2000 in one direction and 1325 in the other though...
An over-night run with 1024 rx-ring passed 152mil packets, dropped 75k or so.
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 6 lines · [email protected] writes:
Quoted 1 line · jamal
Trash the machines harder. Try using smaller packets;
They are already dropping packets, I thought I'd try to get a slower run to work cleanly before trying something faster. Precision is more important to me than absolute throughput at this point.
If you need excessive buffering this gives latency and jitter which is considered bad for network protocols and worse for test equipment.
Quoted 2 lines
Initial run with 256 sized rx-ring (and skb-recycle) shows better performance (than with 1024 rx-ring)
Packet size? Expect eventual effects when there is very high pressure on the packet memory system.
Cheers.
--ro
Quoted 11 lines · Robert Olsson
Quoted 6 lines · [email protected] writes:
Quoted 1 line · jamal
Trash the machines harder. Try using smaller packets;
They are already dropping packets, I thought I'd try to get a slower run to work cleanly before trying something faster. Precision is more important to me than absolute throughput at this point.
If you need excessive buffering this gives latency and jitter which is considered bad for network protocols and worse for test equipment.
It depends on the goals of the test, but I agree in principle :)
Quoted 6 lines
Quoted 3 lines
Initial run with 256 sized rx-ring (and skb-recycle) shows better performance (than with 1024 rx-ring)
Packet size? Expect eventual effects when there is very high pressure on the packet memory system.
Packet size has been 1514 for all my recent tests.
For an extended 256 rx-ring run (4kpps send + rcv, 1514 byte packet, 4 ports), I see about 9k dropped packets per 55 million sent & received.
Ben
Quoted 5 lines
Cheers.
--ro
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 5 lines · Ben Greear
Here's an update of the tulip-NAPI and skb-recycle patches. I made some changes to get it to compile and work when the RECYCLE define in
skbuff.hwas not enabled.
Quoted 8 lines
I also got some test runs in. Nothing really conclusive.
Test setup: Phobos 4-port NIC in each P-IV 1.8Ghz machine 32/33 PCI bus. Kernel 2.4.20-rc1 + my patches. NICs connected to each other over CX cables. Sending 4k 1514 byte packets per second, send + receive. (48Mbps or so) RX ring size is 1024 for all of these tests. No significant errors reported by the driver. I don't know where these dropped packets go..no counter seems to be catching them.
I changed to use smaller packets 757 bytes long, and to send/receive twice as many (8kpps). Still running at 50Mbps or so.
rx-ring is 256, still using skb-recycling with 300 skb hotlist.
Out of 57 million sent, dropped about 24k packets. I also see about 3k of Rx-Drops on each interface. No other significant errors reported by the driver....
Any ideas for what to try next? What about upping the skb-hotlist to 1024 or so? Maybe also pre-load it with buffers to make it less likely we'll run low? (Rx-Drops means it could not allocate a buffer, right?)
Enjoy,
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 4 lines · Ben Greear
Any ideas for what to try next? What about upping the skb-hotlist to 1024 or so? Maybe also pre-load it with buffers to make it less likely we'll run low? (Rx-Drops means it could not allocate a buffer, right?)
You seem to be using that patch of yours where you route to yourself? Well, since you are up for it:
- try with two ports only; eth0->eth1 and vary then vary RX ring {32, 64,128,256,512,1024}
- send at least 1 minute worth of data at wire rate
a) small packets 64 bytes
b) repeat with MTU sized packets
Repeat above with eth0->eth1, eth2->eth3
also try where machine is a router and you have a source/sink host
cheers,
jamal
Quoted 11 lines · jamal
Quoted 4 lines · Ben Greear
Any ideas for what to try next? What about upping the skb-hotlist to 1024 or so? Maybe also pre-load it with buffers to make it less likely we'll run low? (Rx-Drops means it could not allocate a buffer, right?)
You seem to be using that patch of yours where you route to yourself?
I'm using pktgen for this to take as much of the stack out of the question as possible, and I'm using two machines for these latest tests.
Quoted 4 lines
Well, since you are up for it:
- try with two ports only;eth0->eth1and vary then vary RX ring {32, 64,128,256,512,1024}
- send at least 1 minute worth of data at wire rate
Unfortunately, it seems I need 15 or 30 minutes to make an accurate judgement. For one reason or another, I drop bursts of packets every 2-5 minutes.
Quoted 2 lines
a) small packets 64 bytes
b) repeat with MTU sized packets
I'll try some of those variations today. From more tweaking, it appears that a good skb_hotlist is around 1k, a good ring size is 512 (1024 is not much better, still dropping packets in small bursts), weight of 32 or 64 is good.
It also seems that the max_work_at_interrupt setting in the tulip driver is irrelevant when using NAPI (weight trumps it)... I increased it above weight, it helped slightly I think.
Found some more bugs in my skb-recycle patch, I had forgotten to use it for filling the ring. If anyone is interested in an updated patch, let me know. Otherwise, I'll save the bits :)
With settings like these, I ran 294 million pkts, dropped about 90k (up to 150k on one interface). Had about 30k dropped packets, don't know where the other 60k went.
Quoted 4 lines
Repeat above with
eth0->eth1,eth2->eth3also try where machine is a router and you have a source/sink host
I'm trying to keep the stacks out of it for now...but can do that test later...
Quoted 3 lines
cheers,
jamal
Thanks for the suggestions!
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 4 lines · Donald Becker
I can see that changing the parameters is a quick, ad hoc solution. This list should focus on identifying the problems, rather than just patching in work-arounds.
Well said.
Tuning the receive ring is still a mystery; what i have noticed is that depending on the number of NICs on the system, the most optimal value varies. Typically, extremely large or small values are bad.
cheers,
jamal
Quoted 11 lines · Ben Greear
Quoted 2 lines
I see you increased the RX-ring to 1024 pkts.
Did you really see any improvement with this?It helped drop fewer packets when running 4 ports at 92Mbps+ However, the difference between that and 512 is not large. I would really like to make that size adjustable at module load time and/or runtime, but I'm not sure how easy that would be.
Imagine being able to crank up your receive buffers when running at very high speeds (and/or when you start dropping packets). At lower speeds, shrink things down and free up resources....
I still doubt ;-)
With e1000 I played with various settings for RX-buffers rather recently when the 82544 increased the number of available buffers from 256 to 4096.
And I guess my test looks a bit like yours... Injecting an "overload" of packets. I found was 256 buffers was the optimum. Approximative of course.
Quoted 2 lines
Were you testing SMP or uni-processor? I've been doing the tulip testing on a single processor P-IV system.
We tested both at that time but it's rewritten now...
And as you saw for SMP with recycle it is easy to feed the recycled skb back to CPU were it was created/processed.
So kfree/skb_headerinit "should" cause less cache bouncing. Still we need to pollute one cache line to find the CPU "owner". I posted some of numbers here time ago but it would be nice to verify with CPU's performance counters.
Cheers.
--ro
Quoted 9 lines · Robert Olsson
Ben Greear writes:
I still doubt ;-)
With e1000 I played with various settings for RX-buffers rather recently when the 82544 increased the number of available buffers from 256 to 4096.
And I guess my test looks a bit like yours... Injecting an "overload" of packets. I found was 256 buffers was the optimum. Approximative of course.
It's possible that it is a particular issue with my NICs (Old Phobos 4-port). Phobos folks said the bridge chipset has errata that make it un-suitable for high speeds. And something about a memory divide-by-four error. It may be that the extra buffers help hide the hardware defects in some manner. I was, for instance, seeing cases where packets just dissappeared...and no error counters were being bumped.
With the latest kernel drivers, the 570tx NIC seems to have trouble autonegotiating full-duplex again, so I have not been testing with it lately (I think it uses the same bridge chipset anyway.)
I will try changing around those numbers again now that I have a baseline to work from.
Quoted 2 lines
And as you saw for SMP with recycle it is easy to feed the recycled skb back to CPU were it was created/processed.
Yes, I can see how that would be useful on SMP, so there may be less gain for single-proc systems. I actually am pretty fuzzy on cache-line optimizations and the like...
Thanks,
Ben
Signature · 3 lines
Ben Greear <[email protected]> <Ben_Greear AT excite.com> President of Candela Technologies Inc http://www.candelatech.com ScryMUD: http://scry.wanfear.com http://scry.wanfear.com/~greear
Quoted 4 lines · Robert Olsson
Well skb recycling is "research" and should be used to challange to vm/slab people to start with... And I guess you will get objections about the extra stats as well.
It's ok for syncing with current kernel driver i suppose. The patch that should be considered for merging really is:
http://www.cyberus.ca/~hadi/patches/tulip-2419-napi-nifd.gz
which looks suspiciouly similar to his patch if you remove the experimental stuff.
Quoted 9 lines
I see you increased the RX-ring to 1024 pkts.
Did you really see any improvement with this?Also I would be interested if you have any numbers for recycling patch?
Jamal and I spent some days after OLS to test and tune but it wasn't to promising at that time but it's reworked now.
I think the numbers we saw were upto 20% increase with uniprocessor (AMD 1Gig) and about 5% increase with dual SMP(PII-450s). In the case of SMP, we concluded that the slab was screwing us.
In any case, this WIP ...
cheers,
jamal