Skip to contentSkip to conversation

net: add driver for the NIC on Cell Blades

PATCH In review Arnd Bergmann 4 participants 8 messages Jun 28, 2005 – Jun 29, 2005

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

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
#1 lore raw

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__
maintainer Applied
#2 lore raw

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.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.

Applied, thanks a lot Arnd.

#3 lore raw
In reply to Arnd Bergmann

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....

#4 lore raw
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 <><
#5 lore raw
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

#6 lore raw
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_c
 	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);
 }
 
@@ -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_c
 	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);
 }
#7 lore raw
In reply to Arjan van de Ven
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