Index: linux-2.6.10-bk8-Netfilter/include/linux/skbuff.h =================================================================== --- linux-2.6.10-bk8-Netfilter.orig/include/linux/skbuff.h 2005-01-06 09:11:56.000000000 +1100 +++ linux-2.6.10-bk8-Netfilter/include/linux/skbuff.h 2005-01-07 13:37:18.000000000 +1100 @@ -339,6 +339,8 @@ return skb; } +struct sk_buff *dev_reuse_skb(struct sk_buff *skb); + /* * If users == 1, we are the only owner and are can avoid redundant * atomic change. Index: linux-2.6.10-bk8-Netfilter/drivers/net/8390.c =================================================================== --- linux-2.6.10-bk8-Netfilter.orig/drivers/net/8390.c 2005-01-06 09:11:33.000000000 +1100 +++ linux-2.6.10-bk8-Netfilter/drivers/net/8390.c 2005-01-07 14:49:23.960384408 +1100 @@ -644,6 +644,98 @@ netif_wake_queue(dev); } +/* Keep some pre-allocated ones, for speed. */ +#define SKB_RING_BUF_NUM 128 +struct skb_ring_buf +{ + unsigned int pos; + unsigned int hits, misses, fails; + struct sk_buff *skb[SKB_RING_BUF_NUM]; +}; + +static DEFINE_PER_CPU(struct skb_ring_buf, skb_ring_buf); + +static struct sk_buff *find_skb(struct net_device *dev) +{ + unsigned int i; + struct sk_buff *new; + struct skb_ring_buf *ring = &__get_cpu_var(skb_ring_buf); + + for (i = ring->pos; i < SKB_RING_BUF_NUM; i++) { + if (atomic_read(&ring->skb[i]->users) == 1 + && atomic_read(&skb_shinfo(ring->skb[i])->dataref) == 1) { + ring->pos = (ring->pos + 1) % SKB_RING_BUF_NUM; + ring->hits++; + return dev_reuse_skb(ring->skb[i]); + } + ring->misses++; + } + for (i = 0; i < ring->pos; i++) { + if (atomic_read(&ring->skb[i]->users) == 1 + && atomic_read(&skb_shinfo(ring->skb[i])->dataref) == 1) { + ring->pos = (ring->pos + 1) % SKB_RING_BUF_NUM; + ring->hits++; + return dev_reuse_skb(ring->skb[i]); + } + ring->misses++; + } + ring->fails++; + + if (net_ratelimit()) + printk("No skbs in ring: %i hits, %i fails, %i misses avg\n", + ring->hits, ring->fails, + ring->misses / (ring->hits+ring->fails)); + + new = dev_alloc_skb(1518+2); + if (!new) + return NULL; + + /* Reduce reference count of old one. */ + kfree_skb(ring->skb[i]); + ring->skb[i] = skb_get(new); + return new; +} + +static int fill_skb_ring(void) +{ + int cpu, cpu2, i; + + /* Already done? (hack) */ + if (__get_cpu_var(skb_ring_buf).skb[0]) + return 0; + + printk("8390: filling %i skbs in ring\n", SKB_RING_BUF_NUM); + for_each_cpu(cpu) { + for (i = 0; i < SKB_RING_BUF_NUM; i++) { + per_cpu(skb_ring_buf, cpu).skb[i] + = __dev_alloc_skb(1518+2, GFP_KERNEL); + if (!per_cpu(skb_ring_buf, cpu).skb[i]) + goto fail; + } + } + return 0; +fail: + while (--i >= 0) + kfree_skb(per_cpu(skb_ring_buf, cpu).skb[i]); + + for_each_cpu(cpu2) { + if (cpu2 == cpu) + break; + for (i = 0; i < SKB_RING_BUF_NUM; i++) + kfree_skb(per_cpu(skb_ring_buf, cpu2).skb[i]); + } + return -ENOMEM; +} + +static __exit void cleanup_skb_ring(void) +{ + int cpu, i; + + for_each_cpu(cpu) + for (i = 0; i < SKB_RING_BUF_NUM; i++) + kfree_skb(per_cpu(skb_ring_buf, cpu).skb[i]); +} + /** * ei_receive - receive some packets * @dev: network device with which receive will be run @@ -723,7 +815,12 @@ { struct sk_buff *skb; +#if 1 + skb = find_skb(dev); +#else skb = dev_alloc_skb(pkt_len+2); +#endif + if (skb == NULL) { if (ei_debug > 1) @@ -1034,6 +1131,9 @@ ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0)) : 0x48; + if (fill_skb_ring() != 0) + panic("Could not fill skb ring!"); + if(sizeof(struct e8390_pkt_hdr)!=4) panic("8390.c: header struct mispacked\n"); /* Follow National Semi's recommendations for initing the DP83902. */ @@ -1083,6 +1183,7 @@ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */ do_set_multicast_list(dev); /* (re)load the mcast table */ } + } /* Trigger a transmit start, assuming the length is valid. @@ -1121,11 +1222,12 @@ int init_module(void) { - return 0; + return fill_skb_ring(); } void cleanup_module(void) { + cleanup_skb_ring(); } #endif /* MODULE */ Index: linux-2.6.10-bk8-Netfilter/drivers/net/s2io.c =================================================================== --- linux-2.6.10-bk8-Netfilter.orig/drivers/net/s2io.c 2005-01-06 09:11:34.000000000 +1100 +++ linux-2.6.10-bk8-Netfilter/drivers/net/s2io.c 2005-01-07 15:14:01.034834960 +1100 @@ -1565,6 +1565,140 @@ } } +/* Keep some pre-allocated ones, for speed. */ +#define SKB_RING_BUF_NUM 128 +struct skb_ring_buf +{ + unsigned int pos; + unsigned int hits, misses, fails; + dma_addr_t addr[SKB_RING_BUF_NUM]; + struct sk_buff *skb[SKB_RING_BUF_NUM]; +}; + +static DEFINE_PER_CPU(struct skb_ring_buf, skb_ring_buf); + +/* FIXME: per-device. */ +static struct sk_buff *find_skb(struct pci_dev *pdev, u64 *addr) +{ + unsigned int i, size; + struct sk_buff *new; + struct skb_ring_buf *ring = &__get_cpu_var(skb_ring_buf); + + for (i = ring->pos; i < SKB_RING_BUF_NUM; i++) { + if (atomic_read(&ring->skb[i]->users) == 1 + && atomic_read(&skb_shinfo(ring->skb[i])->dataref) == 1) { + ring->pos = (ring->pos + 1) % SKB_RING_BUF_NUM; + ring->hits++; + *addr = ring->addr[i]; + return dev_reuse_skb(ring->skb[i]); + } + ring->misses++; + } + for (i = 0; i < ring->pos; i++) { + if (atomic_read(&ring->skb[i]->users) == 1 + && atomic_read(&skb_shinfo(ring->skb[i])->dataref) == 1) { + ring->pos = (ring->pos + 1) % SKB_RING_BUF_NUM; + ring->hits++; + *addr = ring->addr[i]; + return dev_reuse_skb(ring->skb[i]); + } + ring->misses++; + } + ring->fails++; + + if (net_ratelimit()) + printk("No skbs in ring: %i hits, %i fails, %i misses avg\n", + ring->hits, ring->fails, + ring->misses / (ring->hits+ring->fails)); + + if (i == SKB_RING_BUF_NUM) + i = 0; + + /* FIXME: dev->mtu not 1500 */ + size = 1500 + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + HEADER_SNAP_SIZE; + + new = dev_alloc_skb(size + NET_IP_ALIGN); + if (!new) + return NULL; + + /* Reduce reference count of old one. */ + kfree_skb(ring->skb[i]); + pci_unmap_single(pdev, ring->addr[i], size, PCI_DMA_FROMDEVICE); + + skb_reserve(new, NET_IP_ALIGN); + ring->addr[i] = pci_map_single(pdev, new->data, size, + PCI_DMA_FROMDEVICE); + ring->skb[i] = skb_get(new); + return new; +} + +static int fill_skb_ring(struct pci_dev *pdev) +{ + int cpu, cpu2, i, size; + + /* FIXME: dev->mtu not 1500 */ + size = 1500 + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + HEADER_SNAP_SIZE; + + /* Already done? (hack) */ + if (__get_cpu_var(skb_ring_buf).skb[0]) + return 0; + + printk("8390: filling %i skbs in ring\n", SKB_RING_BUF_NUM); + for_each_cpu(cpu) { + for (i = 0; i < SKB_RING_BUF_NUM; i++) { + per_cpu(skb_ring_buf, cpu).skb[i] + = __dev_alloc_skb(1518+2, GFP_KERNEL); + if (!per_cpu(skb_ring_buf, cpu).skb[i]) + goto fail; + per_cpu(skb_ring_buf, cpu).addr[i] + = pci_map_single(pdev, + per_cpu(skb_ring_buf, cpu) + .skb[i]->data, size, + PCI_DMA_FROMDEVICE); + } + } + return 0; +fail: + while (--i >= 0) { + pci_unmap_single(pdev, + per_cpu(skb_ring_buf, cpu).addr[i], + size, PCI_DMA_FROMDEVICE); + kfree_skb(per_cpu(skb_ring_buf, cpu).skb[i]); + } + + for_each_cpu(cpu2) { + if (cpu2 == cpu) + break; + for (i = 0; i < SKB_RING_BUF_NUM; i++) { + pci_unmap_single(pdev, + per_cpu(skb_ring_buf, cpu2).addr[i], + size, PCI_DMA_FROMDEVICE); + kfree_skb(per_cpu(skb_ring_buf, cpu2).skb[i]); + } + } + return -ENOMEM; +} + +static __exit void cleanup_skb_ring(struct pci_dev *pdev) +{ + int cpu, i, size; + + /* FIXME: dev->mtu not 1500 */ + size = 1500 + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + HEADER_SNAP_SIZE; + + for_each_cpu(cpu) { + for (i = 0; i < SKB_RING_BUF_NUM; i++) { + pci_unmap_single(pdev, + per_cpu(skb_ring_buf, cpu).addr[i], + size, PCI_DMA_FROMDEVICE); + kfree_skb(per_cpu(skb_ring_buf, cpu).skb[i]); + } + } +} + /** * fill_rx_buffers - Allocates the Rx side skbs * @nic: device private variable @@ -1719,8 +1853,13 @@ #endif #ifndef CONFIG_2BUFF_MODE +#if 0 skb = dev_alloc_skb(size + NET_IP_ALIGN); #else + memset(rxdp, 0, sizeof(RxD_t)); + skb = find_skb(nic->pdev, &rxdp->Buffer0_ptr); +#endif +#else skb = dev_alloc_skb(dev->mtu + ALIGN_SIZE + BUF0_LEN + 4); #endif if (!skb) { @@ -1729,10 +1868,13 @@ return -ENOMEM; } #ifndef CONFIG_2BUFF_MODE +#if 0 skb_reserve(skb, NET_IP_ALIGN); memset(rxdp, 0, sizeof(RxD_t)); rxdp->Buffer0_ptr = pci_map_single (nic->pdev, skb->data, size, PCI_DMA_FROMDEVICE); +#endif + rxdp->Control_2 &= (~MASK_BUFFER0_SIZE); rxdp->Control_2 |= SET_BUFFER0_SIZE(size); rxdp->Host_Control = (unsigned long) (skb); @@ -4261,6 +4403,8 @@ free_tx_buffers(sp); free_rx_buffers(sp); + cleanup_skb_ring(sp->pdev); + spin_unlock_irqrestore(&sp->tx_lock, flags); clear_bit(0, &(sp->link_state)); } @@ -4279,6 +4423,12 @@ return -ENODEV; } + if (fill_skb_ring(sp->pdev) != 0) { + s2io_reset(sp); + free_rx_buffers(sp); + return -ENOMEM; + } + /* * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks @@ -4290,6 +4440,7 @@ if ((ret = fill_rx_buffers(sp, i))) { DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", dev->name); + cleanup_skb_ring(sp->pdev); s2io_reset(sp); free_rx_buffers(sp); return -ENOMEM; @@ -4308,6 +4459,7 @@ if (start_nic(sp)) { DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name); tasklet_kill(&sp->task); + cleanup_skb_ring(sp->pdev); s2io_reset(sp); free_irq(dev->irq, dev); free_rx_buffers(sp); Index: linux-2.6.10-bk8-Netfilter/net/core/skbuff.c =================================================================== --- linux-2.6.10-bk8-Netfilter.orig/net/core/skbuff.c 2005-01-06 09:12:00.000000000 +1100 +++ linux-2.6.10-bk8-Netfilter/net/core/skbuff.c 2005-01-07 13:55:49.000000000 +1100 @@ -264,16 +264,7 @@ kmem_cache_free(skbuff_head_cache, skb); } -/** - * __kfree_skb - private function - * @skb: buffer - * - * Free an sk_buff. Release anything attached to the buffer. - * Clean the state. This is an internal helper function. Users should - * always call kfree_skb - */ - -void __kfree_skb(struct sk_buff *skb) +static void clean_skb(struct sk_buff *skb) { if (skb->list) { printk(KERN_WARNING "Warning: kfree_skb passed an skb still " @@ -305,7 +296,58 @@ skb->tc_classid = 0; #endif #endif +} + +/** + * dev_reuse_skb - prepare any skb for reuse + * @skb: buffer + * + * Clean the state of the buffer, but don't free the data. Increments + * reference count. Like dev_alloc_skb(). + */ +struct sk_buff *dev_reuse_skb(struct sk_buff *skb) +{ + BUG_ON(atomic_read(&skb->users) != 1); + BUG_ON(atomic_read(&skb_shinfo(skb)->dataref) != 1); + + clean_skb(skb); + + skb->dst = NULL; +#ifdef CONFIG_XFRM + skb->sp = NULL; +#endif + skb->destructor = NULL; +#ifdef CONFIG_NETFILTER + skb->nfct = NULL; +#ifdef CONFIG_BRIDGE_NETFILTER + skb->nf_bridge = NULL; +#endif +#endif + + skb->data = skb->tail = skb->head; + skb->len = 0; + + BUG_ON(skb_shinfo(skb)->nr_frags); + skb_shinfo(skb)->tso_size = 0; + skb_shinfo(skb)->tso_segs = 0; + skb_shinfo(skb)->frag_list = NULL; + + skb_reserve(skb, 16); + return skb_get(skb); +} + +/** + * __kfree_skb - private function + * @skb: buffer + * + * Free an sk_buff. Release anything attached to the buffer. + * Clean the state. This is an internal helper function. Users should + * always call kfree_skb + */ +void __kfree_skb(struct sk_buff *skb) +{ + clean_skb(skb); kfree_skbmem(skb); }