* [PATCH 2.6.0-test9-bk6] r8169.c update for 8110S support from RTL 1.6 version @ 2003-11-17 4:08 Brad House 2003-11-18 4:39 ` r8169 and tg3 Jeff Garzik 0 siblings, 1 reply; 19+ messages in thread From: Brad House @ 2003-11-17 4:08 UTC (permalink / raw) To: netdev The current in-kernel version of the r8169 driver is v1.2 from RealTek. This is a patch against 2.6.0-test9-bk6 and later kernels that updates the driver to 1.6 from RealTek. Just small patches applied to it to port to 2.6 kernel, etc. It works with the 8110S chip found on many motherboards, especially x86_64 mobos. http://dev.gentoo.org/~brad_mssw/kernel_patches/2.6.0/genpatches-0.4/200_r8169-8110S-111203.patch Please CC me on any replies as I am not subscribed to the list. -Brad House brad_mssw@gentoo.org ^ permalink raw reply [flat|nested] 19+ messages in thread
* r8169 and tg3 2003-11-17 4:08 [PATCH 2.6.0-test9-bk6] r8169.c update for 8110S support from RTL 1.6 version Brad House @ 2003-11-18 4:39 ` Jeff Garzik 2003-11-18 4:51 ` Brad House ` (2 more replies) 0 siblings, 3 replies; 19+ messages in thread From: Jeff Garzik @ 2003-11-18 4:39 UTC (permalink / raw) To: Brad House; +Cc: netdev Brad House wrote: > The current in-kernel version of the r8169 driver is v1.2 > from RealTek. This is a patch against 2.6.0-test9-bk6 > and later kernels that updates the driver to 1.6 from RealTek. > Just small patches applied to it to port to 2.6 kernel, etc. > It works with the 8110S chip found on many motherboards, > especially x86_64 mobos. A bit of history... SiS sent me a driver for their gigabit chip, SIS190 (sis190.c). Full of PCI DMA bugs, alignment problems, and fun like that. After taking flak for merging it :) I fixed all those bugs. Fast forward a bit, I find out that sis190.c was copied from r8169.c, and modified a bit to work with SiS chips. I look at r8169.c, and find all those same bugs -- and the RealTek updates don't address any of that. So, what needs to happen is somebody needs to look at the sis190 changes that went in, and apply those same fixes to r8169. Two tangents, while I have your attention: 1) If you have problems with the tg3 driver, we need to get those bug reports and fix them. bcm5700 is not going to be merged into the kernel. Further, there was at least one serious x86-64 issue that was fixed in tg3, and we need to make sure users are testing that driver, not a non-standard driver with bugs of its own. 2) Please CC me on all net driver patches, since I am the dude that actually puts those patches into the kernel. Thanks, Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: r8169 and tg3 2003-11-18 4:39 ` r8169 and tg3 Jeff Garzik @ 2003-11-18 4:51 ` Brad House 2003-11-18 10:00 ` Jan Oravec 2003-11-18 12:58 ` Francois Romieu 2 siblings, 0 replies; 19+ messages in thread From: Brad House @ 2003-11-18 4:51 UTC (permalink / raw) To: Jeff Garzik; +Cc: Brad House, netdev Commenting below: > > So, what needs to happen is somebody needs to look at the sis190 changes > that went in, and apply those same fixes to r8169. Ok, cool. Didn't realize that, if you have a couple of references to those discussions or patches, that would be awesome (so I don't have to try to dig them up), otherwise, I'll research it some. I was also going to look into merging the big endian patches I saw posted earlier this month. > 1) If you have problems with the tg3 driver, we need to get those bug > reports and fix them. bcm5700 is not going to be merged into the > kernel. Further, there was at least one serious x86-64 issue that was > fixed in tg3, and we need to make sure users are testing that driver, > not a non-standard driver with bugs of its own. Ok, sounds like a plan. I'll get some testing on the latest tg3 driver then, have those been merged into 2.6.0-test9-bk21, or is there another patch I need to apply to my local tree (and in turn will be applied to Gentoo's tree)? > > 2) Please CC me on all net driver patches, since I am the dude that > actually puts those patches into the kernel. Cool, no problem. I just took over the amd64 port for Gentoo a couple months back, so I'm having to get into some stuff I haven't had to do before. But I'm starting to learn some of the kernel internals/driver infrastructure, so hopefully I'll be of some actual help in the near future, assuming my actual job doesn't get in the way ;) -Brad ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: r8169 and tg3 2003-11-18 4:39 ` r8169 and tg3 Jeff Garzik 2003-11-18 4:51 ` Brad House @ 2003-11-18 10:00 ` Jan Oravec 2003-11-18 11:01 ` David S. Miller 2003-11-18 12:58 ` Francois Romieu 2 siblings, 1 reply; 19+ messages in thread From: Jan Oravec @ 2003-11-18 10:00 UTC (permalink / raw) To: Jeff Garzik; +Cc: Brad House, netdev Hi Jeff, > 1) If you have problems with the tg3 driver, we need to get those bug > reports and fix them. bcm5700 is not going to be merged into the > kernel. Further, there was at least one serious x86-64 issue that was > fixed in tg3, and we need to make sure users are testing that driver, > not a non-standard driver with bugs of its own. So here is the bug report: I have a 4-port card with two Broadcom 5704 chips plugged into PCI-X 1 of Tyan S2880 motherboard (the onboard 5704's are disabled) with single Opteron 240 processor. When loading tg3 driver, this appears in dmesg: eth0: Tigon3 [partno(BCM95704A6) rev 2003 PHY(5704)] (PCIX:133MHz:64-bit) 10/100/1000BaseT Ethernet <MAC0> eth1: Tigon3 [partno(BCM95704A6) rev 2003 PHY(5704)] (PCIX:133MHz:64-bit) 10/100/1000BaseT Ethernet <MAC1> eth2: Tigon3 [partno(BCM95704A6) rev 2003 PHY(5704)] (PCIX:133MHz:64-bit) 10/100/1000BaseT Ethernet <MAC2> eth3: Tigon3 [partno(BCM95704A6) rev 2003 PHY(5704)] (PCIX:133MHz:64-bit) 10/100/1000BaseT Ethernet <MAC3> The IRQs of the ports are: eth0: IRQ 28 eth1: IRQ 28 eth2: IRQ 28 eth3: IRQ 30 When we try configure eth0 only or eth3 only, it works fine. When only eth1 or eth2 are configured, the 'RUNNING' flag of the interface is missing even if the cable is plugged thus card does not work. When we turn eth0 up, eth1 and eth2 starts working, but the latency of transfers is horrible. After some debugging I realized this: When inserting printk() into tg3_interrupt(): When one of eth0, eth3 are up, I get 10 interrups per second for them (I heard that it's some workaround for HW bug). When one of eth1, eth2 are up, I get no interrupt. When one of eth1, eth2 are up and eth0 is up, I get 10 interrupts per second for each of them, but I get no interrupts when data are received on eth1 or eth2. That explains the horrible latency like: 64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=10.0 ms 64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=9.00 ms 64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=8.00 ms 64 bytes from 10.0.0.1: icmp_seq=4 ttl=64 time=7.00 ms 64 bytes from 10.0.0.1: icmp_seq=5 ttl=64 time=6.00 ms 64 bytes from 10.0.0.1: icmp_seq=6 ttl=64 time=5.00 ms 64 bytes from 10.0.0.1: icmp_seq=7 ttl=64 time=4.00 ms 64 bytes from 10.0.0.1: icmp_seq=8 ttl=64 time=3.00 ms 64 bytes from 10.0.0.1: icmp_seq=9 ttl=64 time=2.00 ms 64 bytes from 10.0.0.1: icmp_seq=10 ttl=64 time=1.00 ms 64 bytes from 10.0.0.1: icmp_seq=11 ttl=64 time=99.9 ms 64 bytes from 10.0.0.1: icmp_seq=12 ttl=64 time=98.9 ms 64 bytes from 10.0.0.1: icmp_seq=13 ttl=64 time=97.9 ms 64 bytes from 10.0.0.1: icmp_seq=14 ttl=64 time=96.9 ms Also, I cannot see any interrupts in /proc/interrupts when I receive packets thru eth1/eth2. The problem is repeatable on other exactly same system. The NICs works fine on 32-bit architecture with 64-bit PCI-X. There are some reports that it works under 32-bit kernel on Opteron, but I have not tried this yet. The same problem appears with bcm5700 driver (except 10 ints/sec so the only way to make it partially work is to make traffic on eth0). If you need any details or have some suggestions what should I try, let me know. Thanks, Jan ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: r8169 and tg3 2003-11-18 10:00 ` Jan Oravec @ 2003-11-18 11:01 ` David S. Miller 0 siblings, 0 replies; 19+ messages in thread From: David S. Miller @ 2003-11-18 11:01 UTC (permalink / raw) To: Jan Oravec; +Cc: jgarzik, brad_mssw, netdev On Tue, 18 Nov 2003 11:00:01 +0100 Jan Oravec <jan.oravec@6com.sk> wrote: > The same problem appears with bcm5700 driver (except 10 ints/sec so the only > way to make it partially work is to make traffic on eth0). This smells of interrupt routing issues on this platform. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: r8169 and tg3 2003-11-18 4:39 ` r8169 and tg3 Jeff Garzik 2003-11-18 4:51 ` Brad House 2003-11-18 10:00 ` Jan Oravec @ 2003-11-18 12:58 ` Francois Romieu 2003-11-19 17:24 ` Jeff Garzik 2 siblings, 1 reply; 19+ messages in thread From: Francois Romieu @ 2003-11-18 12:58 UTC (permalink / raw) To: Jeff Garzik; +Cc: Brad House, netdev Jeff Garzik <jgarzik@pobox.com> : [...] > So, what needs to happen is somebody needs to look at the sis190 changes > that went in, and apply those same fixes to r8169. If no one objects, I can do for r8169 the same thing I did for sis190. Btw the DMA Rx/Tx rework is already in good shape (I rather like seeing Jeff improving (S)ATA than coming to copy over his RX and TX handling code :o) ). Anyway, the bk-commit patches which were related to sis190 are available at: http://www.fr.zoreil.com/people/francois/misc/sis190-rework.mbx -- Ueimor ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: r8169 and tg3 2003-11-18 12:58 ` Francois Romieu @ 2003-11-19 17:24 ` Jeff Garzik 2003-11-19 18:44 ` Robert Olsson 2003-11-20 0:00 ` [patches] 2.6.0-test9 - r8169 DMA API conversion Francois Romieu 0 siblings, 2 replies; 19+ messages in thread From: Jeff Garzik @ 2003-11-19 17:24 UTC (permalink / raw) To: Francois Romieu; +Cc: Brad House, netdev Francois Romieu wrote: > Jeff Garzik <jgarzik@pobox.com> : > [...] > >>So, what needs to happen is somebody needs to look at the sis190 changes >>that went in, and apply those same fixes to r8169. > > > If no one objects, I can do for r8169 the same thing I did for sis190. > Btw the DMA Rx/Tx rework is already in good shape (I rather like seeing > Jeff improving (S)ATA than coming to copy over his RX and TX handling > code :o) ). > > Anyway, the bk-commit patches which were related to sis190 are available at: > http://www.fr.zoreil.com/people/francois/misc/sis190-rework.mbx hehe. I certainly don't object... You probably want to look over the r8169 v1.6 that Brad posted a link to, since it does have some improved 8169 hardware support (modulo bugs, of course). Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: r8169 and tg3 2003-11-19 17:24 ` Jeff Garzik @ 2003-11-19 18:44 ` Robert Olsson 2003-11-20 0:00 ` [patches] 2.6.0-test9 - r8169 DMA API conversion Francois Romieu 1 sibling, 0 replies; 19+ messages in thread From: Robert Olsson @ 2003-11-19 18:44 UTC (permalink / raw) To: Jeff Garzik; +Cc: Francois Romieu, Brad House, netdev Jeff Garzik writes: > hehe. I certainly don't object... You probably want to look over the > r8169 v1.6 that Brad posted a link to, since it does have some improved > 8169 hardware support (modulo bugs, of course). Yes r8169 can be interesting... I played with it a bit from my head the sending performance was about 900 kpps (pktgen) and RX very OK too about 780 kpps with just dropping the skb instead of doing netif_receive. Cheers. --ro ^ permalink raw reply [flat|nested] 19+ messages in thread
* [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-19 17:24 ` Jeff Garzik 2003-11-19 18:44 ` Robert Olsson @ 2003-11-20 0:00 ` Francois Romieu 2003-11-20 0:08 ` Brad House 2003-11-21 0:36 ` Francois Romieu 1 sibling, 2 replies; 19+ messages in thread From: Francois Romieu @ 2003-11-20 0:00 UTC (permalink / raw) To: Jeff Garzik; +Cc: Brad House, netdev [-- Attachment #1: Type: text/plain, Size: 500 bytes --] Jeff Garzik <jgarzik@pobox.com> : [...] > hehe. I certainly don't object... You probably want to look over the > r8169 v1.6 that Brad posted a link to, since it does have some improved > 8169 hardware support (modulo bugs, of course). Ok, will do (hmmm... looks like a free ticket for "Whitespace attacks"). I have attached the usual DMA rework for: - the Tx descriptors; - the Rx process (with the original big Rx buffer removed). Feel free to comment/review. Next patch tomorrow. -- Ueimor [-- Attachment #2: r8169-dma-api-tx.patch --] [-- Type: text/plain, Size: 6675 bytes --] Conversion of Rx/Tx descriptors to consistent DMA: - use pci_alloc_consistent() for Rx/Tx descriptors in rtl8169_open() (balanced by pci_free_consistent() on error path as well as in rtl8169_close()); - removal of the fields {Rx/Tx}DescArrays in struct rtl8169_private as there is no need to store a non-256 bytes aligned address any more; - fix for rtl8169_open() leak when RxBufferRings allocation fails. Said allocation is pushed to rtl8169_init_ring() as part of an evil cunning plan. drivers/net/r8169.c | 99 +++++++++++++++++++++++++++------------------------- 1 files changed, 52 insertions(+), 47 deletions(-) diff -puN drivers/net/r8169.c~r8169-dma-api-tx drivers/net/r8169.c --- linux-2.6.0-test9/drivers/net/r8169.c~r8169-dma-api-tx 2003-11-19 20:30:09.000000000 +0100 +++ linux-2.6.0-test9-fr/drivers/net/r8169.c 2003-11-19 21:24:44.000000000 +0100 @@ -89,6 +89,8 @@ static int multicast_filter_limit = 32; #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ #define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ #define RX_BUF_SIZE 1536 /* Rx Buffer size */ +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) #define RTL_MIN_IO_SIZE 0x80 #define TX_TIMEOUT (6*HZ) @@ -280,10 +282,10 @@ struct rtl8169_private { unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ unsigned long dirty_tx; - unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */ - unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */ struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ + dma_addr_t TxPhyAddr; + dma_addr_t RxPhyAddr; unsigned char *RxBufferRings; /* Index of Rx Buffer */ unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ @@ -297,7 +299,7 @@ static int rtl8169_open(struct net_devic static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static void rtl8169_init_ring(struct net_device *dev); +static int rtl8169_init_ring(struct net_device *dev); static void rtl8169_hw_start(struct net_device *dev); static int rtl8169_close(struct net_device *dev); static void rtl8169_set_rx_mode(struct net_device *dev); @@ -654,52 +656,48 @@ static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; int retval; - u8 diff; - u32 TxPhyAddr, RxPhyAddr; retval = request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev); - if (retval) { - return retval; - } + if (retval < 0) + goto out; - tp->TxDescArrays = - kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL); - // Tx Desscriptor needs 256 bytes alignment; - TxPhyAddr = virt_to_bus(tp->TxDescArrays); - diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8)); - TxPhyAddr += diff; - tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff); - - tp->RxDescArrays = - kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL); - // Rx Desscriptor needs 256 bytes alignment; - RxPhyAddr = virt_to_bus(tp->RxDescArrays); - diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8)); - RxPhyAddr += diff; - tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff); + retval = -ENOMEM; - if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) { - printk(KERN_INFO - "Allocate RxDescArray or TxDescArray failed\n"); - free_irq(dev->irq, dev); - if (tp->TxDescArrays) - kfree(tp->TxDescArrays); - if (tp->RxDescArrays) - kfree(tp->RxDescArrays); - return -ENOMEM; - } - tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); - if (tp->RxBufferRings == NULL) { - printk(KERN_INFO "Allocate RxBufferRing failed\n"); - } + /* + * Rx and Tx desscriptors needs 256 bytes alignment. + * pci_alloc_consistent provides more. + */ + tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, + &tp->TxPhyAddr); + if (!tp->TxDescArray) + goto err_free_irq; + + tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, + &tp->RxPhyAddr); + if (!tp->RxDescArray) + goto err_free_tx; + + retval = rtl8169_init_ring(dev); + if (retval < 0) + goto err_free_rx; - rtl8169_init_ring(dev); rtl8169_hw_start(dev); - return 0; +out: + return retval; +err_free_rx: + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); +err_free_tx: + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); +err_free_irq: + free_irq(dev->irq, dev); + goto out; } static void @@ -739,8 +737,8 @@ rtl8169_hw_start(struct net_device *dev) tp->cur_rx = 0; - RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray)); - RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray)); + RTL_W32(TxDescStartAddr, tp->TxPhyAddr); + RTL_W32(RxDescStartAddr, tp->RxPhyAddr); RTL_W8(Cfg9346, Cfg9346_Lock); udelay(10); @@ -758,12 +756,17 @@ rtl8169_hw_start(struct net_device *dev) } -static void -rtl8169_init_ring(struct net_device *dev) +static int rtl8169_init_ring(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; int i; + tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); + if (tp->RxBufferRings == NULL) { + printk(KERN_INFO "Allocate RxBufferRing failed\n"); + return -ENOMEM; + } + tp->cur_rx = 0; tp->cur_tx = 0; tp->dirty_tx = 0; @@ -783,6 +786,7 @@ rtl8169_init_ring(struct net_device *dev tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]); tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]); } + return 0; } static void @@ -1026,6 +1030,7 @@ static int rtl8169_close(struct net_device *dev) { struct rtl8169_private *tp = dev->priv; + struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; int i; @@ -1049,10 +1054,10 @@ rtl8169_close(struct net_device *dev) free_irq(dev->irq, dev); rtl8169_tx_clear(tp); - kfree(tp->TxDescArrays); - kfree(tp->RxDescArrays); - tp->TxDescArrays = NULL; - tp->RxDescArrays = NULL; + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, + tp->RxPhyAddr); + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, + tp->TxPhyAddr); tp->TxDescArray = NULL; tp->RxDescArray = NULL; kfree(tp->RxBufferRings); _ [-- Attachment #3: r8169-dma-api-data-buffers.patch --] [-- Type: text/plain, Size: 10696 bytes --] Conversion of Rx data buffers to PCI DMA - endianness is kept in a fscked state as it is in the original code (will be adressed in a later patch); - rtl8169_rx_clear() walks the buffer ring and releases the allocated data buffers. It needs to be used in two places: - rtl8169_init_ring() failure path; - normal device release (i.e. rtl8169_close); - rtl8169_free_rx_skb() releases a Rx data buffer. Mostly an helper for rtl8169_rx_clear(). As such it must: - unmap the memory area; - release the skb; - prevent the ring descriptor from being used again; - rtl8169_alloc_rx_skb() prepares a Rx data buffer for use. As such it must: - allocate an skb; - map the memory area; - reflect the changes in the ring descriptor. This function is balanced by rtl8169_free_rx_skb(). - rtl8169_unmap_rx() simply helps with the 80-columns limit. - rtl8169_rx_fill() walks a given range of the buffer ring and try to turn any descriptor into a ready to use one. It returns the count of modified descriptors and exits if an allocation fails. It can be seen as balanced by rtl8169_rx_clear(). Motivation: - partially abstract the (usually big) piece of code for the refill logic at the end of the Rx interrupt; - factorize the refill logic and the initial ring setup. - simple conversion of rtl8169_rx_interrupt() without rx_copybreak (will be adressed in a later patch). drivers/net/r8169.c | 235 +++++++++++++++++++++++++++++++++++----------------- 1 files changed, 161 insertions(+), 74 deletions(-) diff -puN drivers/net/r8169.c~r8169-dma-api-data-buffers drivers/net/r8169.c --- linux-2.6.0-test9/drivers/net/r8169.c~r8169-dma-api-data-buffers 2003-11-19 21:26:45.000000000 +0100 +++ linux-2.6.0-test9-fr/drivers/net/r8169.c 2003-11-20 00:45:00.000000000 +0100 @@ -279,15 +279,15 @@ struct rtl8169_private { struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ int chipset; - unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ - unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ - unsigned long dirty_tx; + u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ + u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ + u32 dirty_rx; + u32 dirty_tx; struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ dma_addr_t TxPhyAddr; dma_addr_t RxPhyAddr; - unsigned char *RxBufferRings; /* Index of Rx Buffer */ - unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ + struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ }; @@ -756,37 +756,119 @@ rtl8169_hw_start(struct net_device *dev) } -static int rtl8169_init_ring(struct net_device *dev) +static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) +{ + desc->buf_addr = 0xdeadbeef; + desc->status = EORbit; +} + +static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct RxDesc *desc) +{ + pci_unmap_single(pdev, desc->buf_addr, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(*sk_buff); + *sk_buff = NULL; + rtl8169_make_unusable_by_asic(desc); +} + +static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping) +{ + desc->buf_addr = mapping; + desc->status = OWNbit + RX_BUF_SIZE; +} + +static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev, + struct sk_buff **sk_buff, struct RxDesc *desc) +{ + struct sk_buff *skb; + dma_addr_t mapping; + int ret = 0; + + skb = dev_alloc_skb(RX_BUF_SIZE); + if (!skb) + goto err_out; + + skb->dev = dev; + skb_reserve(skb, 2); + *sk_buff = skb; + + mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + + rtl8169_give_to_asic(desc, mapping); + +out: + return ret; + +err_out: + ret = -ENOMEM; + rtl8169_make_unusable_by_asic(desc); + goto out; +} + +static void rtl8169_rx_clear(struct rtl8169_private *tp) { - struct rtl8169_private *tp = dev->priv; int i; - tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); - if (tp->RxBufferRings == NULL) { - printk(KERN_INFO "Allocate RxBufferRing failed\n"); - return -ENOMEM; + for (i = 0; i < NUM_RX_DESC; i++) { + if (tp->Rx_skbuff[i]) { + rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + } } +} - tp->cur_rx = 0; - tp->cur_tx = 0; - tp->dirty_tx = 0; +static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, + u32 start, u32 end) +{ + u32 cur; + + for (cur = start; end - start > 0; cur++) { + int ret, i = cur % NUM_RX_DESC; + + if (tp->Rx_skbuff[i]) + continue; + + ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i, + tp->RxDescArray + i); + if (ret < 0) + break; + } + return cur - start; +} + +static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc) +{ + desc->status |= EORbit; +} + +static inline void rtl8169_unmark_as_last_descriptor(struct RxDesc *desc) +{ + desc->status &= ~EORbit; +} + +static int rtl8169_init_ring(struct net_device *dev) +{ + struct rtl8169_private *tp = dev->priv; + + tp->cur_rx = tp->dirty_rx = 0; + tp->cur_tx = tp->dirty_tx = 0; memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc)); memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc)); - for (i = 0; i < NUM_TX_DESC; i++) { - tp->Tx_skbuff[i] = NULL; - } - for (i = 0; i < NUM_RX_DESC; i++) { - if (i == (NUM_RX_DESC - 1)) - tp->RxDescArray[i].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE; + memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *)); + memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); + + if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) + goto err_out; + + rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); - tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]); - tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]); - } return 0; + +err_out: + rtl8169_rx_clear(tp); + return -ENOMEM; } static void @@ -906,70 +988,77 @@ rtl8169_tx_interrupt(struct net_device * } } +static inline void rtl8169_unmap_rx(struct pci_dev *pdev, struct RxDesc *desc) +{ + pci_dma_sync_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); +} + static void rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr) { - int cur_rx; - struct sk_buff *skb; - int pkt_size = 0; + int cur_rx, delta; assert(dev != NULL); assert(tp != NULL); assert(ioaddr != NULL); - cur_rx = tp->cur_rx; + cur_rx = tp->cur_rx % RX_BUF_SIZE; while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) { + u32 status = tp->RxDescArray[cur_rx].status; - if (tp->RxDescArray[cur_rx].status & RxRES) { + if (status & RxRES) { printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); tp->stats.rx_errors++; - if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT)) + if (status & (RxRWT | RxRUNT)) tp->stats.rx_length_errors++; - if (tp->RxDescArray[cur_rx].status & RxCRC) + if (status & RxCRC) tp->stats.rx_crc_errors++; } else { - pkt_size = - (int) (tp->RxDescArray[cur_rx]. - status & 0x00001FFF) - 4; - skb = dev_alloc_skb(pkt_size + 2); - if (skb != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); // 16 byte align the IP fields. // - eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], - pkt_size, 0); - skb_put(skb, pkt_size); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - if (cur_rx == (NUM_RX_DESC - 1)) - tp->RxDescArray[cur_rx].status = - (OWNbit | EORbit) + RX_BUF_SIZE; - else - tp->RxDescArray[cur_rx].status = - OWNbit + RX_BUF_SIZE; - - tp->RxDescArray[cur_rx].buf_addr = - virt_to_bus(tp->RxBufferRing[cur_rx]); - dev->last_rx = jiffies; - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; - } else { - printk(KERN_WARNING - "%s: Memory squeeze, deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; - } - } + struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; + int pkt_size = (status & 0x00001FFF) - 4; + + rtl8169_unmap_rx(tp->pci_dev, tp->RxDescArray + cur_rx); + + skb_put(skb, pkt_size); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); - cur_rx = (cur_rx + 1) % NUM_RX_DESC; + tp->Rx_skbuff[cur_rx] = NULL; + dev->last_rx = jiffies; + tp->stats.rx_bytes += pkt_size; + tp->stats.rx_packets++; + } + + tp->cur_rx++; + cur_rx = tp->cur_rx % NUM_RX_DESC; } - tp->cur_rx = cur_rx; + delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); + if (delta > 0) { + u32 old_last = (tp->dirty_rx - 1) % NUM_RX_DESC; + + tp->dirty_rx += delta; + rtl8169_mark_as_last_descriptor(tp->RxDescArray + + (tp->dirty_rx - 1)%NUM_RX_DESC); + rtl8169_unmark_as_last_descriptor(tp->RxDescArray + old_last); + } else if (delta < 0) + printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); + + /* + * FIXME: until there is periodic timer to try and refill the ring, + * a temporary shortage may definitely kill the Rx process. + * - disable the asic to try and avoid an overflow and kick it again + * after refill ? + * - how do others driver handle this condition (Uh oh...). + */ + if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) + printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); } /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -1032,7 +1121,6 @@ rtl8169_close(struct net_device *dev) struct rtl8169_private *tp = dev->priv; struct pci_dev *pdev = tp->pci_dev; void *ioaddr = tp->mmio_addr; - int i; netif_stop_queue(dev); @@ -1054,16 +1142,15 @@ rtl8169_close(struct net_device *dev) free_irq(dev->irq, dev); rtl8169_tx_clear(tp); + + rtl8169_rx_clear(tp); + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, tp->RxPhyAddr); pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, tp->TxPhyAddr); tp->TxDescArray = NULL; tp->RxDescArray = NULL; - kfree(tp->RxBufferRings); - for (i = 0; i < NUM_RX_DESC; i++) { - tp->RxBufferRing[i] = NULL; - } return 0; } _ ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 0:00 ` [patches] 2.6.0-test9 - r8169 DMA API conversion Francois Romieu @ 2003-11-20 0:08 ` Brad House 2003-11-20 0:45 ` Francois Romieu 2003-11-21 0:36 ` Francois Romieu 1 sibling, 1 reply; 19+ messages in thread From: Brad House @ 2003-11-20 0:08 UTC (permalink / raw) To: Francois Romieu; +Cc: Jeff Garzik, Brad House, netdev Just because I'm way to lazy to actually look, is this against the original r8169, or my patch from the v1.6 driver ?? -Brad Francois Romieu wrote: > Jeff Garzik <jgarzik@pobox.com> : > [...] > >>hehe. I certainly don't object... You probably want to look over the >>r8169 v1.6 that Brad posted a link to, since it does have some improved >>8169 hardware support (modulo bugs, of course). > > > Ok, will do (hmmm... looks like a free ticket for "Whitespace attacks"). > > I have attached the usual DMA rework for: > - the Tx descriptors; > - the Rx process (with the original big Rx buffer removed). > > Feel free to comment/review. Next patch tomorrow. > > -- > Ueimor > > > ------------------------------------------------------------------------ > > > Conversion of Rx/Tx descriptors to consistent DMA: > - use pci_alloc_consistent() for Rx/Tx descriptors in rtl8169_open() > (balanced by pci_free_consistent() on error path as well as in > rtl8169_close()); > - removal of the fields {Rx/Tx}DescArrays in struct rtl8169_private > as there is no need to store a non-256 bytes aligned address any more; > - fix for rtl8169_open() leak when RxBufferRings allocation fails. > Said allocation is pushed to rtl8169_init_ring() as part of an evil > cunning plan. > > > drivers/net/r8169.c | 99 +++++++++++++++++++++++++++------------------------- > 1 files changed, 52 insertions(+), 47 deletions(-) > > diff -puN drivers/net/r8169.c~r8169-dma-api-tx drivers/net/r8169.c > --- linux-2.6.0-test9/drivers/net/r8169.c~r8169-dma-api-tx 2003-11-19 20:30:09.000000000 +0100 > +++ linux-2.6.0-test9-fr/drivers/net/r8169.c 2003-11-19 21:24:44.000000000 +0100 > @@ -89,6 +89,8 @@ static int multicast_filter_limit = 32; > #define NUM_TX_DESC 64 /* Number of Tx descriptor registers */ > #define NUM_RX_DESC 64 /* Number of Rx descriptor registers */ > #define RX_BUF_SIZE 1536 /* Rx Buffer size */ > +#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) > +#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) > > #define RTL_MIN_IO_SIZE 0x80 > #define TX_TIMEOUT (6*HZ) > @@ -280,10 +282,10 @@ struct rtl8169_private { > unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ > unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ > unsigned long dirty_tx; > - unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */ > - unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */ > struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ > struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ > + dma_addr_t TxPhyAddr; > + dma_addr_t RxPhyAddr; > unsigned char *RxBufferRings; /* Index of Rx Buffer */ > unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ > struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ > @@ -297,7 +299,7 @@ static int rtl8169_open(struct net_devic > static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); > static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, > struct pt_regs *regs); > -static void rtl8169_init_ring(struct net_device *dev); > +static int rtl8169_init_ring(struct net_device *dev); > static void rtl8169_hw_start(struct net_device *dev); > static int rtl8169_close(struct net_device *dev); > static void rtl8169_set_rx_mode(struct net_device *dev); > @@ -654,52 +656,48 @@ static int > rtl8169_open(struct net_device *dev) > { > struct rtl8169_private *tp = dev->priv; > + struct pci_dev *pdev = tp->pci_dev; > int retval; > - u8 diff; > - u32 TxPhyAddr, RxPhyAddr; > > retval = > request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev); > - if (retval) { > - return retval; > - } > + if (retval < 0) > + goto out; > > - tp->TxDescArrays = > - kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL); > - // Tx Desscriptor needs 256 bytes alignment; > - TxPhyAddr = virt_to_bus(tp->TxDescArrays); > - diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8)); > - TxPhyAddr += diff; > - tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff); > - > - tp->RxDescArrays = > - kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL); > - // Rx Desscriptor needs 256 bytes alignment; > - RxPhyAddr = virt_to_bus(tp->RxDescArrays); > - diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8)); > - RxPhyAddr += diff; > - tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff); > + retval = -ENOMEM; > > - if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) { > - printk(KERN_INFO > - "Allocate RxDescArray or TxDescArray failed\n"); > - free_irq(dev->irq, dev); > - if (tp->TxDescArrays) > - kfree(tp->TxDescArrays); > - if (tp->RxDescArrays) > - kfree(tp->RxDescArrays); > - return -ENOMEM; > - } > - tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); > - if (tp->RxBufferRings == NULL) { > - printk(KERN_INFO "Allocate RxBufferRing failed\n"); > - } > + /* > + * Rx and Tx desscriptors needs 256 bytes alignment. > + * pci_alloc_consistent provides more. > + */ > + tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES, > + &tp->TxPhyAddr); > + if (!tp->TxDescArray) > + goto err_free_irq; > + > + tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES, > + &tp->RxPhyAddr); > + if (!tp->RxDescArray) > + goto err_free_tx; > + > + retval = rtl8169_init_ring(dev); > + if (retval < 0) > + goto err_free_rx; > > - rtl8169_init_ring(dev); > rtl8169_hw_start(dev); > > - return 0; > +out: > + return retval; > > +err_free_rx: > + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, > + tp->RxPhyAddr); > +err_free_tx: > + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, > + tp->TxPhyAddr); > +err_free_irq: > + free_irq(dev->irq, dev); > + goto out; > } > > static void > @@ -739,8 +737,8 @@ rtl8169_hw_start(struct net_device *dev) > > tp->cur_rx = 0; > > - RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray)); > - RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray)); > + RTL_W32(TxDescStartAddr, tp->TxPhyAddr); > + RTL_W32(RxDescStartAddr, tp->RxPhyAddr); > RTL_W8(Cfg9346, Cfg9346_Lock); > udelay(10); > > @@ -758,12 +756,17 @@ rtl8169_hw_start(struct net_device *dev) > > } > > -static void > -rtl8169_init_ring(struct net_device *dev) > +static int rtl8169_init_ring(struct net_device *dev) > { > struct rtl8169_private *tp = dev->priv; > int i; > > + tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); > + if (tp->RxBufferRings == NULL) { > + printk(KERN_INFO "Allocate RxBufferRing failed\n"); > + return -ENOMEM; > + } > + > tp->cur_rx = 0; > tp->cur_tx = 0; > tp->dirty_tx = 0; > @@ -783,6 +786,7 @@ rtl8169_init_ring(struct net_device *dev > tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]); > tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]); > } > + return 0; > } > > static void > @@ -1026,6 +1030,7 @@ static int > rtl8169_close(struct net_device *dev) > { > struct rtl8169_private *tp = dev->priv; > + struct pci_dev *pdev = tp->pci_dev; > void *ioaddr = tp->mmio_addr; > int i; > > @@ -1049,10 +1054,10 @@ rtl8169_close(struct net_device *dev) > free_irq(dev->irq, dev); > > rtl8169_tx_clear(tp); > - kfree(tp->TxDescArrays); > - kfree(tp->RxDescArrays); > - tp->TxDescArrays = NULL; > - tp->RxDescArrays = NULL; > + pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, > + tp->RxPhyAddr); > + pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, > + tp->TxPhyAddr); > tp->TxDescArray = NULL; > tp->RxDescArray = NULL; > kfree(tp->RxBufferRings); > > _ > > > ------------------------------------------------------------------------ > > > Conversion of Rx data buffers to PCI DMA > - endianness is kept in a fscked state as it is in the original code > (will be adressed in a later patch); > - rtl8169_rx_clear() walks the buffer ring and releases the allocated > data buffers. It needs to be used in two places: > - rtl8169_init_ring() failure path; > - normal device release (i.e. rtl8169_close); > - rtl8169_free_rx_skb() releases a Rx data buffer. Mostly an helper > for rtl8169_rx_clear(). As such it must: > - unmap the memory area; > - release the skb; > - prevent the ring descriptor from being used again; > - rtl8169_alloc_rx_skb() prepares a Rx data buffer for use. > As such it must: > - allocate an skb; > - map the memory area; > - reflect the changes in the ring descriptor. > This function is balanced by rtl8169_free_rx_skb(). > - rtl8169_unmap_rx() simply helps with the 80-columns limit. > - rtl8169_rx_fill() walks a given range of the buffer ring and > try to turn any descriptor into a ready to use one. It returns the > count of modified descriptors and exits if an allocation fails. > It can be seen as balanced by rtl8169_rx_clear(). Motivation: > - partially abstract the (usually big) piece of code for the refill > logic at the end of the Rx interrupt; > - factorize the refill logic and the initial ring setup. > - simple conversion of rtl8169_rx_interrupt() without rx_copybreak > (will be adressed in a later patch). > > > drivers/net/r8169.c | 235 +++++++++++++++++++++++++++++++++++----------------- > 1 files changed, 161 insertions(+), 74 deletions(-) > > diff -puN drivers/net/r8169.c~r8169-dma-api-data-buffers drivers/net/r8169.c > --- linux-2.6.0-test9/drivers/net/r8169.c~r8169-dma-api-data-buffers 2003-11-19 21:26:45.000000000 +0100 > +++ linux-2.6.0-test9-fr/drivers/net/r8169.c 2003-11-20 00:45:00.000000000 +0100 > @@ -279,15 +279,15 @@ struct rtl8169_private { > struct net_device_stats stats; /* statistics of net device */ > spinlock_t lock; /* spin lock flag */ > int chipset; > - unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ > - unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ > - unsigned long dirty_tx; > + u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ > + u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ > + u32 dirty_rx; > + u32 dirty_tx; > struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */ > struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */ > dma_addr_t TxPhyAddr; > dma_addr_t RxPhyAddr; > - unsigned char *RxBufferRings; /* Index of Rx Buffer */ > - unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */ > + struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ > struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */ > }; > > @@ -756,37 +756,119 @@ rtl8169_hw_start(struct net_device *dev) > > } > > -static int rtl8169_init_ring(struct net_device *dev) > +static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc) > +{ > + desc->buf_addr = 0xdeadbeef; > + desc->status = EORbit; > +} > + > +static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, > + struct RxDesc *desc) > +{ > + pci_unmap_single(pdev, desc->buf_addr, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); > + dev_kfree_skb(*sk_buff); > + *sk_buff = NULL; > + rtl8169_make_unusable_by_asic(desc); > +} > + > +static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping) > +{ > + desc->buf_addr = mapping; > + desc->status = OWNbit + RX_BUF_SIZE; > +} > + > +static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev, > + struct sk_buff **sk_buff, struct RxDesc *desc) > +{ > + struct sk_buff *skb; > + dma_addr_t mapping; > + int ret = 0; > + > + skb = dev_alloc_skb(RX_BUF_SIZE); > + if (!skb) > + goto err_out; > + > + skb->dev = dev; > + skb_reserve(skb, 2); > + *sk_buff = skb; > + > + mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE, > + PCI_DMA_FROMDEVICE); > + > + rtl8169_give_to_asic(desc, mapping); > + > +out: > + return ret; > + > +err_out: > + ret = -ENOMEM; > + rtl8169_make_unusable_by_asic(desc); > + goto out; > +} > + > +static void rtl8169_rx_clear(struct rtl8169_private *tp) > { > - struct rtl8169_private *tp = dev->priv; > int i; > > - tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL); > - if (tp->RxBufferRings == NULL) { > - printk(KERN_INFO "Allocate RxBufferRing failed\n"); > - return -ENOMEM; > + for (i = 0; i < NUM_RX_DESC; i++) { > + if (tp->Rx_skbuff[i]) { > + rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, > + tp->RxDescArray + i); > + } > } > +} > > - tp->cur_rx = 0; > - tp->cur_tx = 0; > - tp->dirty_tx = 0; > +static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev, > + u32 start, u32 end) > +{ > + u32 cur; > + > + for (cur = start; end - start > 0; cur++) { > + int ret, i = cur % NUM_RX_DESC; > + > + if (tp->Rx_skbuff[i]) > + continue; > + > + ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i, > + tp->RxDescArray + i); > + if (ret < 0) > + break; > + } > + return cur - start; > +} > + > +static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc) > +{ > + desc->status |= EORbit; > +} > + > +static inline void rtl8169_unmark_as_last_descriptor(struct RxDesc *desc) > +{ > + desc->status &= ~EORbit; > +} > + > +static int rtl8169_init_ring(struct net_device *dev) > +{ > + struct rtl8169_private *tp = dev->priv; > + > + tp->cur_rx = tp->dirty_rx = 0; > + tp->cur_tx = tp->dirty_tx = 0; > memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc)); > memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc)); > > - for (i = 0; i < NUM_TX_DESC; i++) { > - tp->Tx_skbuff[i] = NULL; > - } > - for (i = 0; i < NUM_RX_DESC; i++) { > - if (i == (NUM_RX_DESC - 1)) > - tp->RxDescArray[i].status = > - (OWNbit | EORbit) + RX_BUF_SIZE; > - else > - tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE; > + memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *)); > + memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); > + > + if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) > + goto err_out; > + > + rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); > > - tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]); > - tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]); > - } > return 0; > + > +err_out: > + rtl8169_rx_clear(tp); > + return -ENOMEM; > } > > static void > @@ -906,70 +988,77 @@ rtl8169_tx_interrupt(struct net_device * > } > } > > +static inline void rtl8169_unmap_rx(struct pci_dev *pdev, struct RxDesc *desc) > +{ > + pci_dma_sync_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, > + PCI_DMA_FROMDEVICE); > + pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, > + PCI_DMA_FROMDEVICE); > +} > + > static void > rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, > void *ioaddr) > { > - int cur_rx; > - struct sk_buff *skb; > - int pkt_size = 0; > + int cur_rx, delta; > > assert(dev != NULL); > assert(tp != NULL); > assert(ioaddr != NULL); > > - cur_rx = tp->cur_rx; > + cur_rx = tp->cur_rx % RX_BUF_SIZE; > > while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) { > + u32 status = tp->RxDescArray[cur_rx].status; > > - if (tp->RxDescArray[cur_rx].status & RxRES) { > + if (status & RxRES) { > printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); > tp->stats.rx_errors++; > - if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT)) > + if (status & (RxRWT | RxRUNT)) > tp->stats.rx_length_errors++; > - if (tp->RxDescArray[cur_rx].status & RxCRC) > + if (status & RxCRC) > tp->stats.rx_crc_errors++; > } else { > - pkt_size = > - (int) (tp->RxDescArray[cur_rx]. > - status & 0x00001FFF) - 4; > - skb = dev_alloc_skb(pkt_size + 2); > - if (skb != NULL) { > - skb->dev = dev; > - skb_reserve(skb, 2); // 16 byte align the IP fields. // > - eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], > - pkt_size, 0); > - skb_put(skb, pkt_size); > - skb->protocol = eth_type_trans(skb, dev); > - netif_rx(skb); > - > - if (cur_rx == (NUM_RX_DESC - 1)) > - tp->RxDescArray[cur_rx].status = > - (OWNbit | EORbit) + RX_BUF_SIZE; > - else > - tp->RxDescArray[cur_rx].status = > - OWNbit + RX_BUF_SIZE; > - > - tp->RxDescArray[cur_rx].buf_addr = > - virt_to_bus(tp->RxBufferRing[cur_rx]); > - dev->last_rx = jiffies; > - tp->stats.rx_bytes += pkt_size; > - tp->stats.rx_packets++; > - } else { > - printk(KERN_WARNING > - "%s: Memory squeeze, deferring packet.\n", > - dev->name); > - /* We should check that some rx space is free. > - If not, free one and mark stats->rx_dropped++. */ > - tp->stats.rx_dropped++; > - } > - } > + struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; > + int pkt_size = (status & 0x00001FFF) - 4; > + > + rtl8169_unmap_rx(tp->pci_dev, tp->RxDescArray + cur_rx); > + > + skb_put(skb, pkt_size); > + skb->protocol = eth_type_trans(skb, dev); > + netif_rx(skb); > > - cur_rx = (cur_rx + 1) % NUM_RX_DESC; > + tp->Rx_skbuff[cur_rx] = NULL; > > + dev->last_rx = jiffies; > + tp->stats.rx_bytes += pkt_size; > + tp->stats.rx_packets++; > + } > + > + tp->cur_rx++; > + cur_rx = tp->cur_rx % NUM_RX_DESC; > } > > - tp->cur_rx = cur_rx; > + delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); > + if (delta > 0) { > + u32 old_last = (tp->dirty_rx - 1) % NUM_RX_DESC; > + > + tp->dirty_rx += delta; > + rtl8169_mark_as_last_descriptor(tp->RxDescArray + > + (tp->dirty_rx - 1)%NUM_RX_DESC); > + rtl8169_unmark_as_last_descriptor(tp->RxDescArray + old_last); > + } else if (delta < 0) > + printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name); > + > + /* > + * FIXME: until there is periodic timer to try and refill the ring, > + * a temporary shortage may definitely kill the Rx process. > + * - disable the asic to try and avoid an overflow and kick it again > + * after refill ? > + * - how do others driver handle this condition (Uh oh...). > + */ > + if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx) > + printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name); > } > > /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ > @@ -1032,7 +1121,6 @@ rtl8169_close(struct net_device *dev) > struct rtl8169_private *tp = dev->priv; > struct pci_dev *pdev = tp->pci_dev; > void *ioaddr = tp->mmio_addr; > - int i; > > netif_stop_queue(dev); > > @@ -1054,16 +1142,15 @@ rtl8169_close(struct net_device *dev) > free_irq(dev->irq, dev); > > rtl8169_tx_clear(tp); > + > + rtl8169_rx_clear(tp); > + > pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray, > tp->RxPhyAddr); > pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray, > tp->TxPhyAddr); > tp->TxDescArray = NULL; > tp->RxDescArray = NULL; > - kfree(tp->RxBufferRings); > - for (i = 0; i < NUM_RX_DESC; i++) { > - tp->RxBufferRing[i] = NULL; > - } > > return 0; > } > > _ ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 0:08 ` Brad House @ 2003-11-20 0:45 ` Francois Romieu 2003-11-20 0:59 ` Brad House 0 siblings, 1 reply; 19+ messages in thread From: Francois Romieu @ 2003-11-20 0:45 UTC (permalink / raw) To: Brad House; +Cc: Jeff Garzik, Brad House, netdev Brad House <brad@mcve.com> : > Just because I'm way to lazy to actually look, is this > against the original r8169, or my patch from the v1.6 > driver ?? It is against the original r8169. Once finished, it should look like: - first cut at dma api conversion (today) - remaining bits of dma api conversion (tomorrow) - rx_copybreak (tomorrow) - your changes (week-end) - big-endian fixes (week-end) Each part divided in reasonably small patches to ease the test/review process. -- Ueimor ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 0:45 ` Francois Romieu @ 2003-11-20 0:59 ` Brad House 2003-11-20 1:34 ` Andre Tomt 2003-11-20 1:36 ` Jeff Garzik 0 siblings, 2 replies; 19+ messages in thread From: Brad House @ 2003-11-20 0:59 UTC (permalink / raw) To: Francois Romieu; +Cc: Jeff Garzik, Brad House, netdev any reason why it's not against the v1.6 ? the current driver is missing support for the 8110S chip (or at least it doesn't seem to work at all), so you're cutting out all the chips on the mobos out there. Haven't looked to see if it's just a PCI ID or other functionality, but since the V1.2 is from realtek that's in the official kernel, it would make sense to use the 1.6 patch.... I suppose I could do it, but it would take me much more time simply because I'm not familiar with the changes you're making. -Brad Francois Romieu wrote: > Brad House <brad@mcve.com> : > >>Just because I'm way to lazy to actually look, is this >>against the original r8169, or my patch from the v1.6 >>driver ?? > > > It is against the original r8169. Once finished, it should look like: > - first cut at dma api conversion (today) > - remaining bits of dma api conversion (tomorrow) > - rx_copybreak (tomorrow) > - your changes (week-end) > - big-endian fixes (week-end) > > Each part divided in reasonably small patches to ease the test/review process. > > -- > Ueimor > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 0:59 ` Brad House @ 2003-11-20 1:34 ` Andre Tomt 2003-11-20 1:35 ` Brad House 2003-11-20 1:36 ` Jeff Garzik 1 sibling, 1 reply; 19+ messages in thread From: Andre Tomt @ 2003-11-20 1:34 UTC (permalink / raw) To: netdev; +Cc: Francois Romieu, Jeff Garzik, Brad House, Brad House On Thu, 2003-11-20 at 01:59, Brad House wrote: > any reason why it's not against the v1.6 ? I think you misunderstood. If I intepret the list correctly, the 1.6 changes are in that list (as "your changes (week-end)".) > the current driver is missing support for the > 8110S chip (or at least it doesn't seem to work at all), > so you're cutting out all the chips on the mobos out there. > Haven't looked to see if it's just a PCI ID or other functionality, > but since the V1.2 is from realtek that's in the official > kernel, it would make sense to use the 1.6 patch.... IIRC, the realtek one got cleaned up a great deal before entering mainline, both bug-fixes and coding style cleanups. Your patch may revert a lot of that work (I havn't looked at it closely.) Also the changelog differs for the 1.2 entry between the two versions, indicating just this. Lets take one step at a time ;-) > > It is against the original r8169. Once finished, it should look like: > > - first cut at dma api conversion (today) > > - remaining bits of dma api conversion (tomorrow) > > - rx_copybreak (tomorrow) > > - your changes (week-end) > > - big-endian fixes (week-end) > > > > Each part divided in reasonably small patches to ease the test/review process. -- Mvh, André Tomt andre@tomt.net ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 1:34 ` Andre Tomt @ 2003-11-20 1:35 ` Brad House 2003-11-20 1:36 ` Brad House 0 siblings, 1 reply; 19+ messages in thread From: Brad House @ 2003-11-20 1:35 UTC (permalink / raw) To: Andre Tomt; +Cc: netdev, Francois Romieu, Jeff Garzik, Brad House yes, I definately misunderstood then ... sorry ;) I'll just apply the patches to my version and see what happens ;) -Brad Andre Tomt wrote: > On Thu, 2003-11-20 at 01:59, Brad House wrote: > >>any reason why it's not against the v1.6 ? > > > I think you misunderstood. If I intepret the list correctly, the 1.6 > changes are in that list (as "your changes (week-end)".) > > >>the current driver is missing support for the >>8110S chip (or at least it doesn't seem to work at all), >>so you're cutting out all the chips on the mobos out there. >>Haven't looked to see if it's just a PCI ID or other functionality, >>but since the V1.2 is from realtek that's in the official >>kernel, it would make sense to use the 1.6 patch.... > > > IIRC, the realtek one got cleaned up a great deal before entering > mainline, both bug-fixes and coding style cleanups. Your patch may > revert a lot of that work (I havn't looked at it closely.) Also the > changelog differs for the 1.2 entry between the two versions, indicating > just this. > > Lets take one step at a time ;-) > > >>>It is against the original r8169. Once finished, it should look like: >>>- first cut at dma api conversion (today) >>>- remaining bits of dma api conversion (tomorrow) >>>- rx_copybreak (tomorrow) >>>- your changes (week-end) >>>- big-endian fixes (week-end) >>> >>>Each part divided in reasonably small patches to ease the test/review process. > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 1:35 ` Brad House @ 2003-11-20 1:36 ` Brad House 0 siblings, 0 replies; 19+ messages in thread From: Brad House @ 2003-11-20 1:36 UTC (permalink / raw) To: Brad House; +Cc: Andre Tomt, netdev, Francois Romieu, Jeff Garzik, Brad House ok, misunderstood again ... geez .... now I get it ... he'll apply the 1.6 patch this weekend ... _sigh_ I really must be brain dead today. -Brad Brad House wrote: > yes, I definately misunderstood then ... > sorry ;) > I'll just apply the patches to my version and see what happens ;) > > -Brad > > Andre Tomt wrote: > >> On Thu, 2003-11-20 at 01:59, Brad House wrote: >> >>> any reason why it's not against the v1.6 ? >> >> >> >> I think you misunderstood. If I intepret the list correctly, the 1.6 >> changes are in that list (as "your changes (week-end)".) >> >> >>> the current driver is missing support for the >>> 8110S chip (or at least it doesn't seem to work at all), >>> so you're cutting out all the chips on the mobos out there. >>> Haven't looked to see if it's just a PCI ID or other functionality, >>> but since the V1.2 is from realtek that's in the official >>> kernel, it would make sense to use the 1.6 patch.... >> >> >> >> IIRC, the realtek one got cleaned up a great deal before entering >> mainline, both bug-fixes and coding style cleanups. Your patch may >> revert a lot of that work (I havn't looked at it closely.) Also the >> changelog differs for the 1.2 entry between the two versions, indicating >> just this. >> >> Lets take one step at a time ;-) >> >> >>>> It is against the original r8169. Once finished, it should look like: >>>> - first cut at dma api conversion (today) >>>> - remaining bits of dma api conversion (tomorrow) >>>> - rx_copybreak (tomorrow) >>>> - your changes (week-end) >>>> - big-endian fixes (week-end) >>>> >>>> Each part divided in reasonably small patches to ease the >>>> test/review process. >> >> >> > > > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 0:59 ` Brad House 2003-11-20 1:34 ` Andre Tomt @ 2003-11-20 1:36 ` Jeff Garzik 1 sibling, 0 replies; 19+ messages in thread From: Jeff Garzik @ 2003-11-20 1:36 UTC (permalink / raw) To: Brad House; +Cc: Francois Romieu, Brad House, netdev Brad House wrote: > any reason why it's not against the v1.6 ? > the current driver is missing support for the > 8110S chip (or at least it doesn't seem to work at all), > so you're cutting out all the chips on the mobos out there. > Haven't looked to see if it's just a PCI ID or other functionality, > but since the V1.2 is from realtek that's in the official > kernel, it would make sense to use the 1.6 patch.... > > I suppose I could do it, but it would take me much > more time simply because I'm not familiar with the > changes you're making. He's doing the work, and he included 1.6 in his list of changes... looks like everybody will be happy :) Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-20 0:00 ` [patches] 2.6.0-test9 - r8169 DMA API conversion Francois Romieu 2003-11-20 0:08 ` Brad House @ 2003-11-21 0:36 ` Francois Romieu 2003-11-21 1:38 ` Jeff Garzik 1 sibling, 1 reply; 19+ messages in thread From: Francois Romieu @ 2003-11-21 0:36 UTC (permalink / raw) To: netdev; +Cc: Jeff Garzik, Brad House [-- Attachment #1: Type: text/plain, Size: 300 bytes --] Francois Romieu <romieu@fr.zoreil.com> : [...] > Feel free to comment/review. Next patch tomorrow. The attached patches apply on top of yesterday's ones: r8169-start-xmit-fixes.patch r8169-dma-api-tx-buffers.patch r8169-rx_copybreak.patch Bugs apart, there shouldn't be anything subtle. -- Ueimor [-- Attachment #2: r8169-start-xmit-fixes.patch --] [-- Type: text/plain, Size: 2087 bytes --] rtl8169_start_xmit fixes: - it forgot to update stats if the skb couldn't be expanded; - it didn't free it either if the descriptor was not available; - move the spin_unlock nearer of the exit point instead of duplicating it in the new branch. drivers/net/r8169.c | 31 ++++++++++++++++++------------- 1 files changed, 18 insertions(+), 13 deletions(-) diff -puN drivers/net/r8169.c~r8169-start-xmit-fixes drivers/net/r8169.c --- linux-2.6.0-test9/drivers/net/r8169.c~r8169-start-xmit-fixes 2003-11-21 01:08:38.000000000 +0100 +++ linux-2.6.0-test9-fr/drivers/net/r8169.c 2003-11-21 01:08:38.000000000 +0100 @@ -918,11 +918,13 @@ rtl8169_start_xmit(struct sk_buff *skb, struct rtl8169_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry = tp->cur_tx % NUM_TX_DESC; + u32 len = skb->len; - if (skb->len < ETH_ZLEN) { + if (unlikely(skb->len < ETH_ZLEN)) { skb = skb_padto(skb, ETH_ZLEN); - if (skb == NULL) - return 0; + if (!skb) + goto err_update_stats; + len = ETH_ZLEN; } spin_lock_irq(&tp->lock); @@ -930,29 +932,32 @@ rtl8169_start_xmit(struct sk_buff *skb, if ((tp->TxDescArray[entry].status & OWNbit) == 0) { tp->Tx_skbuff[entry] = skb; tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data); - if (entry != (NUM_TX_DESC - 1)) - tp->TxDescArray[entry].status = - (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ? - skb->len : ETH_ZLEN); - else - tp->TxDescArray[entry].status = - (OWNbit | EORbit | FSbit | LSbit) | - ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN); + tp->TxDescArray[entry].status = OWNbit | FSbit | LSbit | len | + (EORbit * !((entry + 1) % NUM_TX_DESC)); + RTL_W8(TxPoll, 0x40); //set polling bit dev->trans_start = jiffies; tp->cur_tx++; - } + } else + goto err_drop; - spin_unlock_irq(&tp->lock); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) { netif_stop_queue(dev); } +out: + spin_unlock_irq(&tp->lock); return 0; + +err_drop: + dev_kfree_skb(skb); +err_update_stats: + tp->stats.tx_dropped++; + goto out; } static void _ [-- Attachment #3: r8169-dma-api-tx-buffers.patch --] [-- Type: text/plain, Size: 2533 bytes --] Conversion of Tx data buffers to PCI DMA: - endianness is kept in a fscked state as it is in the original code (will be adressed in a later patch); - buf_addr of an unmapped descriptor is always set to the same value (cf rtl8169_unmap_tx_skb); - nothing fancy, really. drivers/net/r8169.c | 36 +++++++++++++++++++++++++++++------- 1 files changed, 29 insertions(+), 7 deletions(-) diff -puN drivers/net/r8169.c~r8169-dma-api-tx-buffers drivers/net/r8169.c --- linux-2.6.0-test9/drivers/net/r8169.c~r8169-dma-api-tx-buffers 2003-11-21 01:08:42.000000000 +0100 +++ linux-2.6.0-test9-fr/drivers/net/r8169.c 2003-11-21 01:08:42.000000000 +0100 @@ -871,6 +871,17 @@ err_out: return -ENOMEM; } +static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct TxDesc *desc) +{ + u32 len = sk_buff[0]->len; + + pci_unmap_single(pdev, desc->buf_addr, len < ETH_ZLEN ? ETH_ZLEN : len, + PCI_DMA_TODEVICE); + desc->buf_addr = 0x00; + *sk_buff = NULL; +} + static void rtl8169_tx_clear(struct rtl8169_private *tp) { @@ -878,9 +889,12 @@ rtl8169_tx_clear(struct rtl8169_private tp->cur_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) { - if (tp->Tx_skbuff[i] != NULL) { - dev_kfree_skb(tp->Tx_skbuff[i]); - tp->Tx_skbuff[i] = NULL; + struct sk_buff *skb = tp->Tx_skbuff[i]; + + if (skb) { + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + i, + tp->TxDescArray + i); + dev_kfree_skb(skb); tp->stats.tx_dropped++; } } @@ -930,8 +944,13 @@ rtl8169_start_xmit(struct sk_buff *skb, spin_lock_irq(&tp->lock); if ((tp->TxDescArray[entry].status & OWNbit) == 0) { + dma_addr_t mapping; + + mapping = pci_map_single(tp->pci_dev, skb->data, len, + PCI_DMA_TODEVICE); + tp->Tx_skbuff[entry] = skb; - tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data); + tp->TxDescArray[entry].buf_addr = mapping; tp->TxDescArray[entry].status = OWNbit | FSbit | LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC)); @@ -976,9 +995,12 @@ rtl8169_tx_interrupt(struct net_device * while (tx_left > 0) { if ((tp->TxDescArray[entry].status & OWNbit) == 0) { - dev_kfree_skb_irq(tp-> - Tx_skbuff[dirty_tx % NUM_TX_DESC]); - tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL; + int cur = dirty_tx % NUM_TX_DESC; + struct sk_buff *skb = tp->Tx_skbuff[cur]; + + rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + cur, + tp->TxDescArray + cur); + dev_kfree_skb_irq(skb); tp->stats.tx_packets++; dirty_tx++; tx_left--; _ [-- Attachment #4: r8169-rx_copybreak.patch --] [-- Type: text/plain, Size: 3154 bytes --] Rx copybreak for small packets. - removal of rtl8169_unmap_rx() (unneeded as for now). drivers/net/r8169.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 39 insertions(+), 8 deletions(-) diff -puN drivers/net/r8169.c~r8169-rx_copybreak drivers/net/r8169.c --- linux-2.6.0-test9/drivers/net/r8169.c~r8169-rx_copybreak 2003-11-21 01:08:46.000000000 +0100 +++ linux-2.6.0-test9-fr/drivers/net/r8169.c 2003-11-21 01:08:46.000000000 +0100 @@ -116,6 +116,8 @@ static struct pci_device_id rtl8169_pci_ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); +static int rx_copybreak = 200; + enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ @@ -294,6 +296,7 @@ struct rtl8169_private { MODULE_AUTHOR("Realtek"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_copybreak, "i"); static int rtl8169_open(struct net_device *dev); static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -771,6 +774,11 @@ static void rtl8169_free_rx_skb(struct p rtl8169_make_unusable_by_asic(desc); } +static inline void rtl8169_return_to_asic(struct RxDesc *desc) +{ + desc->status |= OWNbit + RX_BUF_SIZE; +} + static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping) { desc->buf_addr = mapping; @@ -1015,12 +1023,26 @@ rtl8169_tx_interrupt(struct net_device * } } -static inline void rtl8169_unmap_rx(struct pci_dev *pdev, struct RxDesc *desc) +static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, + struct RxDesc *desc, + struct net_device *dev) { - pci_dma_sync_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); - pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_size + 2); + if (skb) { + skb->dev = dev; + skb_reserve(skb, 2); + eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0); + *sk_buff = skb; + rtl8169_return_to_asic(desc); + ret = 0; + } + } + return ret; } static void @@ -1046,17 +1068,26 @@ rtl8169_rx_interrupt(struct net_device * if (status & RxCRC) tp->stats.rx_crc_errors++; } else { + struct RxDesc *desc = tp->RxDescArray + cur_rx; struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; int pkt_size = (status & 0x00001FFF) - 4; - rtl8169_unmap_rx(tp->pci_dev, tp->RxDescArray + cur_rx); + pci_dma_sync_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + + if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) { + pci_unmap_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + tp->Rx_skbuff[cur_rx] = NULL; + } skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - tp->Rx_skbuff[cur_rx] = NULL; - dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; _ ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-21 0:36 ` Francois Romieu @ 2003-11-21 1:38 ` Jeff Garzik 2003-11-21 23:20 ` Francois Romieu 0 siblings, 1 reply; 19+ messages in thread From: Jeff Garzik @ 2003-11-21 1:38 UTC (permalink / raw) To: Francois Romieu; +Cc: netdev, Brad House The rx_copybreak didn't apply, but everything else did. Thanks much. Just posted a new net-drivers-2.5-exp patch, to which you may sync with. Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [patches] 2.6.0-test9 - r8169 DMA API conversion 2003-11-21 1:38 ` Jeff Garzik @ 2003-11-21 23:20 ` Francois Romieu 0 siblings, 0 replies; 19+ messages in thread From: Francois Romieu @ 2003-11-21 23:20 UTC (permalink / raw) To: Jeff Garzik; +Cc: netdev [-- Attachment #1: Type: text/plain, Size: 302 bytes --] Jeff Garzik <jgarzik@pobox.com> : > The rx_copybreak didn't apply, but everything else did. Thanks much. Oops, I forgot there was an extra MODULE_LICENSE() in net-drivers-2.5-exp. > Just posted a new net-drivers-2.5-exp patch, to which you may sync with. Updated rx_copybreak attached. -- Ueimor [-- Attachment #2: r8169-rx_copybreak.patch --] [-- Type: text/plain, Size: 3137 bytes --] Rx copybreak for small packets. - removal of rtl8169_unmap_rx() (unneeded as for now). drivers/net/r8169.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 39 insertions(+), 8 deletions(-) diff -puN drivers/net/r8169.c~r8169-rx_copybreak drivers/net/r8169.c --- linux-2.6.0-test9-bk24-netdrvr-exp3/drivers/net/r8169.c~r8169-rx_copybreak 2003-11-22 00:14:22.000000000 +0100 +++ linux-2.6.0-test9-bk24-netdrvr-exp3-fr/drivers/net/r8169.c 2003-11-22 00:14:37.000000000 +0100 @@ -116,6 +116,8 @@ static struct pci_device_id rtl8169_pci_ MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl); +static int rx_copybreak = 200; + enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ @@ -294,6 +296,7 @@ struct rtl8169_private { MODULE_AUTHOR("Realtek"); MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver"); MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_copybreak, "i"); MODULE_LICENSE("GPL"); static int rtl8169_open(struct net_device *dev); @@ -772,6 +775,11 @@ static void rtl8169_free_rx_skb(struct p rtl8169_make_unusable_by_asic(desc); } +static inline void rtl8169_return_to_asic(struct RxDesc *desc) +{ + desc->status |= OWNbit + RX_BUF_SIZE; +} + static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping) { desc->buf_addr = mapping; @@ -1016,12 +1024,26 @@ rtl8169_tx_interrupt(struct net_device * } } -static inline void rtl8169_unmap_rx(struct pci_dev *pdev, struct RxDesc *desc) +static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, + struct RxDesc *desc, + struct net_device *dev) { - pci_dma_sync_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); - pci_unmap_single(pdev, le32_to_cpu(desc->buf_addr), RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_size + 2); + if (skb) { + skb->dev = dev; + skb_reserve(skb, 2); + eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0); + *sk_buff = skb; + rtl8169_return_to_asic(desc); + ret = 0; + } + } + return ret; } static void @@ -1047,17 +1069,26 @@ rtl8169_rx_interrupt(struct net_device * if (status & RxCRC) tp->stats.rx_crc_errors++; } else { + struct RxDesc *desc = tp->RxDescArray + cur_rx; struct sk_buff *skb = tp->Rx_skbuff[cur_rx]; int pkt_size = (status & 0x00001FFF) - 4; - rtl8169_unmap_rx(tp->pci_dev, tp->RxDescArray + cur_rx); + pci_dma_sync_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + + if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) { + pci_unmap_single(tp->pci_dev, + le32_to_cpu(desc->buf_addr), + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); + tp->Rx_skbuff[cur_rx] = NULL; + } skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - tp->Rx_skbuff[cur_rx] = NULL; - dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; _ ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2003-11-21 23:20 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2003-11-17 4:08 [PATCH 2.6.0-test9-bk6] r8169.c update for 8110S support from RTL 1.6 version Brad House 2003-11-18 4:39 ` r8169 and tg3 Jeff Garzik 2003-11-18 4:51 ` Brad House 2003-11-18 10:00 ` Jan Oravec 2003-11-18 11:01 ` David S. Miller 2003-11-18 12:58 ` Francois Romieu 2003-11-19 17:24 ` Jeff Garzik 2003-11-19 18:44 ` Robert Olsson 2003-11-20 0:00 ` [patches] 2.6.0-test9 - r8169 DMA API conversion Francois Romieu 2003-11-20 0:08 ` Brad House 2003-11-20 0:45 ` Francois Romieu 2003-11-20 0:59 ` Brad House 2003-11-20 1:34 ` Andre Tomt 2003-11-20 1:35 ` Brad House 2003-11-20 1:36 ` Brad House 2003-11-20 1:36 ` Jeff Garzik 2003-11-21 0:36 ` Francois Romieu 2003-11-21 1:38 ` Jeff Garzik 2003-11-21 23:20 ` Francois Romieu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).