net: add driver for the NIC on Cell Blades
Subsystems (3)
PATCH 1/1 net: add driver for the NIC on Cell Blades
This patch adds a driver for a new 1000 Mbit ethernet NIC. It is integrated on the south bridge that is used for our Cell Blades.
The code gets the MAC address from the Open Firmware device tree, so it won't compile on platforms other than ppc64.
This is the first public release, so I don't expect the first version to get merged, but I'd aim for integration within the 2.6.13 time frame.
From: Jens Osterkamp <[email protected]>
---
drivers/net/Kconfig | 6 drivers/net/Makefile | 2 drivers/net/spider_net.c | 2298 +++++++++++++++++++++++++++++++++++++++ drivers/net/spider_net.h | 469 +++++++ drivers/net/spider_net_ethtool.c | 107 + include/linux/pci_ids.h | 1 6 files changed, 2883 insertions(+)
drivers/net/Kconfig +6 -0
@@ -2042,6 +2042,12 @@ config BNX2 To compile this driver as a module, choose M here: the module will be called bnx2. This is recommended. +config SPIDER_NET + tristate "Spider Gigabit Ethernet driver" + depends on PCI && PPC_BPA + This driver supports the Gigabit Ethernet chips present on the + Cell Processor-Based Blades from IBM. + config GIANFAR tristate "Gianfar Ethernet" depends on 85xx || 83xx
drivers/net/Makefile +2 -0
@@ -52,6 +52,8 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o +spidernet-y += spider_net.o spider_net_ethtool.o sungem_phy.o +obj-$(CONFIG_SPIDER_NET) += spidernet.o obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SK98LIN) += sk98lin/
drivers/net/spider_net.c +2298 -0
2,298 lines not on this page · raw message
drivers/net/spider_net.h +469 -0
469 lines not on this page · raw message
drivers/net/spider_net_ethtool.c +107 -0
107 lines not on this page · raw message
include/linux/pci_ids.h +1 -0
@@ -1597,6 +1597,7 @@#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030#define PCI_DEVICE_ID_TOSHIBA_TX4927 0x0180#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108 +#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3#define PCI_VENDOR_ID_RICOH 0x1180#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
PATCH 1/1 net: add missing include to netdevice.h
linux/etherdevice.h can't be included standalone at the moment, which is required in order to sort the header files in the recommended alphabetic order. This patch fixes that and is needed to build spider_net.
include/linux/etherdevice.h +1 -0
@@ -25,6 +25,7 @@#define _LINUX_ETHERDEVICE_H#include <linux/if_ether.h> +#include <linux/netdevice.h> #include <linux/random.h> #ifdef __KERNEL__
Re: [PATCH] net: add missing include to netdevice.h
From: Arnd Bergmann <[email protected]>
Date: Tue, 28 Jun 2005 15:47:03 +0200
Quoted 5 lines
linux/etherdevice.hcan't be included standalone at the moment, which is required in order to sort the header files in the recommended alphabetic order. This patch fixes that and is needed to buildspider_net.Signed-off-by Arnd Bergmann <[email protected]>
Applied, thanks a lot Arnd.
drivers/net/spider_net.c line 128
Quoted 13 lines · Arnd Bergmann
drivers/net/spider_net.c +12
-0+static void +spider_net_rx_irq_off (struct spider_net_card *card) +{ +u32 regvalue; +unsigned long flags; + +spin_lock_irqsave (&card->intmask_lock, flags); + regvalue =spider_net_read_reg (card,SPIDER_NET_GHIINT0MSK ); + regvalue &= ~SPIDER_NET_RXINT ; +spider_net_write_reg (card,SPIDER_NET_GHIINT0MSK , regvalue); +spin_unlock_irqrestore (&card->intmask_lock, flags); +}
I think you have a PCI posting bug here....
Quoted 15 lines · Arjan van de Ven
drivers/net/spider_net.c line 128
Quoted 13 lines
drivers/net/spider_net.c +12
-0+static void +spider_net_rx_irq_off (struct spider_net_card *card) +{ + u32 regvalue; + unsigned long flags; + + spin_lock_irqsave(&card->intmask_lock, flags); + regvalue = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK); + regvalue &= ~SPIDER_NET_RXINT; + spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, regvalue); + spin_unlock_irqrestore(&card->intmask_lock, flags); +}I think you have a PCI posting bug here....
Could you be more specific? My guess would be that the 'sync' in writel takes care of this. Should there be an extra mmiowb() in here or are you referring to some other problem?
Arnd <><
Quoted 17 lines · Arnd Bergmann
Quoted 15 lines · Arjan van de Ven
drivers/net/spider_net.c line 128
Quoted 13 lines
drivers/net/spider_net.c +12
-0+static void +spider_net_rx_irq_off (struct spider_net_card *card) +{ +u32 regvalue; +unsigned long flags; + +spin_lock_irqsave (&card->intmask_lock, flags); + regvalue =spider_net_read_reg (card,SPIDER_NET_GHIINT0MSK ); + regvalue &= ~SPIDER_NET_RXINT ; +spider_net_write_reg (card,SPIDER_NET_GHIINT0MSK , regvalue); +spin_unlock_irqrestore (&card->intmask_lock, flags); +}I think you have a PCI posting bug here....
Quoted 3 lines
Could you be more specific? My guess would be that the 'sync' in writel takes care of this. Should there be an extra
mmiowb()in here or are you referring to some other problem?
different problem. the sync will get the byte out of the cpu. It won't get it out of the pci bridges...
In short, pci bridges are allowed to buffer (post) writes until data traffic in the other direction happens (eg readl() or dma).
In cases where you want your writel to hit the device instantly (and disabling irqs is generally one of those) you need to flush this posting cache with a dummy readl().
http://ftp.linux.org.uk/pub/linux/willy/patches/debug-write.diff
is a patch to simulate this behavior more agressive
Quoted 5 lines · Arjan van de Ven
different problem. the sync will get the byte out of the cpu. It won't get it out of the pci bridges...
In short, pci bridges are allowed to buffer (post) writes until data traffic in the other direction happens (eg
readl()or dma).
Ok, understood. This patch changes all io writes within a spinlock to use a checking version of spider_net_write_reg(). Jens, could you verify if these are the only places where you rely on the write making it to the chip and then (n)ack this patch?
Note that in our setup, we know that there are no PCI bridges involved because the device is not really PCI based but directly attached to the FlexIO port and just fakes a PCI-like config space.
drivers/net/spider_net.c +21 -4
@@ -109,6 +109,23 @@ spider_net_write_reg(struct spider_net_c }/** +* spider_net_write_reg_sync - writes to an SMMIO register of a card +* @card: device structure +* @reg: register to write to +* @value: value to write into the specified SMMIO register +* +* Unlike spider_net_write_reg, this will also make sure the +* data arrives on the card by reading the reg again. +*/ +static void +spider_net_write_reg_sync (struct spider_net_card *card,u32 reg,u32 value) +{ + value =cpu_to_le32 (value); +writel (value, card->regs + reg); + (void )readl (card->regs + reg); +} + +/** * spider_net_rx_irq_off - switch off rx irq on this spider card * @card: device structure *
@@ -123,7 +140,7 @@ spider_net_rx_irq_off(struct spider_net_spin_lock_irqsave (&card->intmask_lock, flags); regvalue =spider_net_read_reg (card,SPIDER_NET_GHIINT0MSK ); regvalue &= ~SPIDER_NET_RXINT ; -spider_net_write_reg (card,SPIDER_NET_GHIINT0MSK , regvalue); +spider_net_write_reg_sync (card,SPIDER_NET_GHIINT0MSK , regvalue);spin_unlock_irqrestore (&card->intmask_lock, flags); }
@@ -196,7 +213,7 @@ spider_net_rx_irq_on(struct spider_net_cspin_lock_irqsave (&card->intmask_lock, flags); regvalue =spider_net_read_reg (card,SPIDER_NET_GHIINT0MSK ); regvalue |=SPIDER_NET_RXINT ; -spider_net_write_reg (card,SPIDER_NET_GHIINT0MSK , regvalue); +spider_net_write_reg_sync (card,SPIDER_NET_GHIINT0MSK , regvalue);spin_unlock_irqrestore (&card->intmask_lock, flags); }
@@ -215,7 +232,7 @@ spider_net_tx_irq_off(struct spider_net_spin_lock_irqsave (&card->intmask_lock, flags); regvalue =spider_net_read_reg (card,SPIDER_NET_GHIINT0MSK ); regvalue &= ~SPIDER_NET_TXINT ; -spider_net_write_reg (card,SPIDER_NET_GHIINT0MSK , regvalue); +spider_net_write_reg_sync (card,SPIDER_NET_GHIINT0MSK , regvalue);spin_unlock_irqrestore (&card->intmask_lock, flags); }
@@ -234,7 +251,7 @@ spider_net_tx_irq_on(struct spider_net_cspin_lock_irqsave (&card->intmask_lock, flags); regvalue =spider_net_read_reg (card,SPIDER_NET_GHIINT0MSK ); regvalue |=SPIDER_NET_TXINT ; -spider_net_write_reg (card,SPIDER_NET_GHIINT0MSK , regvalue); +spider_net_write_reg_sync (card,SPIDER_NET_GHIINT0MSK , regvalue);spin_unlock_irqrestore (&card->intmask_lock, flags); }
Quoted 9 lines
Quoted 5 lines
Could you be more specific? My guess would be that the 'sync' in writel takes care of this. Should there be an extra
mmiowb()in here or are you referring to some other problem?different problem. the sync will get the byte out of the cpu. It won't get it out of the pci bridges...
Quoted 6 lines
In short, pci bridges are allowed to buffer (post) writes until data traffic in the other direction happens (eg
readl()or dma).In cases where you want your writel to hit the device instantly (and disabling irqs is generally one of those) you need to flush this posting cache with a dummy
readl().
As I keep repeating over and over again, nothing will guarantee that your interrupt is actually disabled here, not even a readl(). You _must_ make sure you are ready for a spurrious interrupt coming in, though in that case, the interrupt will probably be very short.
The thing is, interrupts (not MSIs tho, but the problem is still potentially there at the APIC level) are totally asynchronous to PCI transactions. By the time you readl() back (and thus flush your PCI posting buffers), or are approx. sure that the chip will have de-asserted it's IRQ line (oh well, that isn't even sure, it may take a few cycles depending on the HW you have there). But the IRQ may already have been "captured" by the PIC, or even by several layers of PICs. By the time the IRQ de-assertion propagates all the way to the CPU, you may already have taken it.
Since those PCI IRQs are level, hopefully, it will go down real soon (unless you have a misconfigured PIC along the chain), so it most cases, it's just a matter of ignoring it. If it's safe, just read your device IRQ status reg and your IRQ routine will "notice" that there is nothing to do. (Note that returning IRQ_NONE there may confuse the core, heh !). If it's not, then you need a local variable indicating that you did indeed mask interrupts, and that cause your handler to just bail out. It may get re-entered a couple of time, but ultimately, the IRQ will go down.
Ben