Skip to contentSkip to conversation

Add IP1000A Driver into Kernel (2007/09/12)

PATCH In review Jesse Huang 3 participants 4 messages Sep 14, 2007 – Sep 15, 2007

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

PATCH 1/1 Add IP1000A Driver into Kernel (2007/09/12)

From: Jesse Huang <[email protected]>

Change Logs: Add IP1000A Driver to kernel tree.

---

 MAINTAINERS       |   10 
 drivers/net/ipg.c | 2329 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ipg.h |  856 +++++++++++++++++++
 3 files changed, 3195 insertions(+), 0 deletions(-)
 create mode 100755 drivers/net/ipg.c
 create mode 100755 drivers/net/ipg.h

339cdb53f4106d822dcda34b12bd10f0ba965de1

MAINTAINERS +10 -0
index df40a4e..a1ff6fe 100644
@@ -1988,6 +1988,16 @@ P:	Juanjo Ciarlante
 M:	[email protected]
 S:	Maintained
 
+IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER
+P:	Francois Romieu
+M:	[email protected]
+P:	Sorbica Shieh 
+M:	[email protected]
+P:	Jesse Huang
+M:	[email protected]
+L:	[email protected]
+S:	Maintained
+
 IPATH DRIVER:
 P:	Bryan O'Sullivan
 M:	[email protected]
drivers/net/ipg.c new file +2329 -0

2,329 lines not on this page · raw message

drivers/net/ipg.h new file +856 -0

655 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
1.3.GIT

Part of the diff is not shown here. View the raw message.

#1 lore raw

Jesse Huang <[email protected]> :
[...]

Quoted 1 line

Change Logs: Add IP1000A Driver to kernel tree.

It misses the needed Kconfig, Makefile and pci_ids changes from Stefan Lippers-Hollmann.

Signature · 1 line
Ueimor
#2 lore raw

PATCH 1/1 ipg: add IP1000A driver to kernel tree

---
 MAINTAINERS             |   10 +
 drivers/net/Kconfig     |    9 +
 drivers/net/Makefile    |    1 +
 drivers/net/ipg.c       | 2329 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ipg.h       |  856 +++++++++++++++++
 include/linux/pci_ids.h |    2 +
 6 files changed, 3207 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/ipg.c
 create mode 100644 drivers/net/ipg.h
MAINTAINERS +10 -0
index 9c54a5e..1ad90e8 100644
@@ -2075,6 +2075,16 @@ P:	Juanjo Ciarlante
 M:	[email protected]
 S:	Maintained
 
+IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER
+P:	Francois Romieu
+M:	[email protected]
+P:	Sorbica Shieh
+M:	[email protected]
+P:	Jesse Huang
+M:	[email protected]
+L:	[email protected]
+S:	Maintained
+
 IPATH DRIVER:
 P:	Arthur Jones
 M:	[email protected]
drivers/net/Kconfig +9 -0
index 5b9e17b..3462d07 100644
@@ -159,6 +159,15 @@ config NET_SB1000
 
 	  If you don't have this card, of course say N.
 
+config IP1000
+       tristate "IP1000 Gigabit Ethernet support"
+       depends on PCI && EXPERIMENTAL
+       ---help---
+         This driver supports IP1000 gigabit Ethernet cards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ipg.  This is recommended.
+
 source "drivers/net/arcnet/Kconfig"
 
 source "drivers/net/phy/Kconfig"
drivers/net/Makefile +1 -0
index e684212..eccd0eb 100644
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
+obj-$(CONFIG_IP1000) += ipg.o
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_CHELSIO_T1) += chelsio/
 obj-$(CONFIG_CHELSIO_T3) += cxgb3/
drivers/net/ipg.c new file +2327 -0

2,327 lines not on this page · raw message

drivers/net/ipg.h new file +856 -0

635 lines not on this page · raw message

include/linux/pci_ids.h +2 -0
index 55f307f..c9c24dd 100644

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Signature · 1 line
1.5.2.4

Part of the diff is not shown here. View the raw message.

#3 lore raw

Re: [PATCH] ipg: add IP1000A driver to kernel tree

Quoted 15 lines · On Fri, 14 Sep 2007 23:21:05 +0200 Francois Romieu <[email protected]> wrote:

...

drivers/net/ipg.c new file +13 -0
+
+static void ipg_dump_tfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+	u32 offset;
+
+	IPG_DEBUG_MSG("_dump_tfdlist\n");
+
+	printk(KERN_INFO "tx_current         = %2.2x\n", sp->tx_current);
+	printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
+	printk(KERN_INFO "TFDList start address = %16.16lx\n",

drivers/net/ipg.c line 134

Quoted 10 lines
drivers/net/ipg.c new file +10 -0
+	       (unsigned long) sp->txd_map);
+	printk(KERN_INFO "TFDListPtr register   = %8.8x%8.8x\n",
+	       ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].next_desc);
+
+		offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;

Is the u32 cast safe here on all architectures?

Quoted 31 lines
drivers/net/ipg.c new file +28 -0
+		printk(KERN_INFO "%2.2x %4.4x TFC        = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].tfc);
+		offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x frag_info   = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].frag_info);
+	}
+}
 
...
 
+static int mdio_read(struct net_device * dev, int phy_id, int phy_reg)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	/*
+	 * The GMII mangement frame structure for a read is as follows:
+	 *
+	 * |Preamble|st|op|phyad|regad|ta|      data      |idle|
+	 * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
+	 *
+	 * <32 1s> = 32 consecutive logic 1 values
+	 * A = bit of Physical Layer device address (MSB first)
+	 * R = bit of register address (MSB first)
+	 * z = High impedance state
+	 * D = bit of read data (MSB first)
+	 *
+	 * Transmission order is 'Preamble' field first, bits transmitted
+	 * left to right (first to last).
+	 */
+	struct {
+		u32 field;
+		unsigned int len;

drivers/net/ipg.c line 216

Quoted 10 lines
drivers/net/ipg.c new file +10 -0
+	} p[] = {
+		{ GMII_PREAMBLE,	32 },	/* Preamble */
+		{ GMII_ST,		2  },	/* ST */
+		{ GMII_READ,		2  },	/* OP */
+		{ phy_id,		5  },	/* PHYAD */
+		{ phy_reg,		5  },	/* REGAD */
+		{ 0x0000,		2  },	/* TA */
+		{ 0x0000,		16 },	/* DATA */
+		{ 0x0000,		1  }	/* IDLE */
+	};

This will be built on the stack at runtime.

Quoted 36 lines
drivers/net/ipg.c new file +36 -0
+	unsigned int i, j;
+	u8 polarity, data;
+
+	polarity  = ipg_r8(PHY_CTRL);
+	polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+	/* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+	for (j = 0; j < 5; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			/* For each variable length field, the MSB must be
+			 * transmitted first. Rotate through the field bits,
+			 * starting with the MSB, and move each bit into the
+			 * the 1st (2^1) bit position (this is the bit position
+			 * corresponding to the MgmtData bit of the PhyCtrl
+			 * register for the IPG).
+			 *
+			 * Example: ST = 01;
+			 *
+			 *          First write a '0' to bit 1 of the PhyCtrl
+			 *          register, then write a '1' to bit 1 of the
+			 *          PhyCtrl register.
+			 *
+			 * To do this, right shift the MSB of ST by the value:
+			 * [field length - 1 - #ST bits already written]
+			 * then left shift this result by 1.
+			 */
+			data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
+			data &= IPG_PC_MGMTDATA;
+			data |= polarity | IPG_PC_MGMTDIR;
+
+			ipg_drive_phy_ctl_low_high(ioaddr, data);
+		}
+	}
+
+	send_three_state(ioaddr, polarity);
+

drivers/net/ipg.c line 262

Quoted 10 lines
drivers/net/ipg.c new file +10 -0
+	read_phy_bit(ioaddr, polarity);
+
+	/*
+	 * For a read cycle, the bits for the next two fields (TA and
+	 * DATA) are driven by the PHY (the IPG reads these bits).
+	 */
+	for (i = 0; i < p[6].len; i++) {
+		p[6].field |=
+		    (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
+	}

Simply because we're using p[6] as a temporary variable.

This can be tightened up.

Quoted 34 lines
drivers/net/ipg.c new file +34 -0
+	send_three_state(ioaddr, polarity);
+	send_three_state(ioaddr, polarity);
+	send_three_state(ioaddr, polarity);
+	send_end(ioaddr, polarity);
+
+	/* Return the value of the DATA field. */
+	return p[6].field;
+}
+
+/*
+ * Write to a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	/*
+	 * The GMII mangement frame structure for a read is as follows:
+	 *
+	 * |Preamble|st|op|phyad|regad|ta|      data      |idle|
+	 * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
+	 *
+	 * <32 1s> = 32 consecutive logic 1 values
+	 * A = bit of Physical Layer device address (MSB first)
+	 * R = bit of register address (MSB first)
+	 * z = High impedance state
+	 * D = bit of write data (MSB first)
+	 *
+	 * Transmission order is 'Preamble' field first, bits transmitted
+	 * left to right (first to last).
+	 */
+	struct {
+		u32 field;
+		unsigned int len;

drivers/net/ipg.c line 307

Quoted 10 lines
drivers/net/ipg.c new file +10 -0
+	} p[] = {
+		{ GMII_PREAMBLE,	32 },	/* Preamble */
+		{ GMII_ST,		2  },	/* ST */
+		{ GMII_WRITE,		2  },	/* OP */
+		{ phy_id,		5  },	/* PHYAD */
+		{ phy_reg,		5  },	/* REGAD */
+		{ 0x0002,		2  },	/* TA */
+		{ val & 0xffff,		16 },	/* DATA */
+		{ 0x0000,		1  }	/* IDLE */
+	};

similar here

Quoted 35 lines
drivers/net/ipg.c new file +35 -0
+	unsigned int i, j;
+	u8 polarity, data;
+
+	polarity  = ipg_r8(PHY_CTRL);
+	polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+	/* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+	for (j = 0; j < 7; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			/* For each variable length field, the MSB must be
+			 * transmitted first. Rotate through the field bits,
+			 * starting with the MSB, and move each bit into the
+			 * the 1st (2^1) bit position (this is the bit position
+			 * corresponding to the MgmtData bit of the PhyCtrl
+			 * register for the IPG).
+			 *
+			 * Example: ST = 01;
+			 *
+			 *          First write a '0' to bit 1 of the PhyCtrl
+			 *          register, then write a '1' to bit 1 of the
+			 *          PhyCtrl register.
+			 *
+			 * To do this, right shift the MSB of ST by the value:
+			 * [field length - 1 - #ST bits already written]
+			 * then left shift this result by 1.
+			 */
+			data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
+			data &= IPG_PC_MGMTDATA;
+			data |= polarity | IPG_PC_MGMTDIR;
+
+			ipg_drive_phy_ctl_low_high(ioaddr, data);
+		}
+	}
+
+	/* The last cycle is a tri-state, so read from the PHY. */

drivers/net/ipg.c line 352

Quoted 10 lines
drivers/net/ipg.c new file +10 -0
+	for (j = 7; j < 8; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
+
+			p[j].field |= ((ipg_r8(PHY_CTRL) &
+				IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i);
+
+			ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
+		}
+	}

although it might be tricky to avoid

Quoted 15 lines
drivers/net/ipg.c new file +12 -0
+}
+
 
...
 
+static int ipg_reset(struct net_device *dev, u32 resetflags)
+{
+	/* Assert functional resets via the IPG AsicCtrl
+	 * register as specified by the 'resetflags' input
+	 * parameter.
+	 */
+	void __iomem *ioaddr = ipg_ioaddr(dev);	//JES20040127EEPROM:
+	unsigned int timeout_count = 0;
+
+	IPG_DEBUG_MSG("_reset\n");

drivers/net/ipg.c line 409

Quoted 10 lines
drivers/net/ipg.c new file +10 -0
+
+	ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
+
+	/* Delay added to account for problem with 10Mbps reset. */
+	mdelay(IPG_AC_RESETWAIT);
+
+	while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
+		mdelay(IPG_AC_RESETWAIT);
+		if (++timeout_count > IPG_AC_RESET_TIMEOUT)
+			return -ETIME;

Is ETIME an appropriate errno here? Zillions of drivers use it, but I think it's for posix timers or something like that?

Quoted 10 lines
drivers/net/ipg.c new file +9 -0
+	}
+	/* Set LED Mode in Asic Control JES20040127EEPROM */
+	ipg_set_led_mode(dev);
+
+	/* Set PHYSet Register Value JES20040127EEPROM */
+	ipg_set_phy_set(dev);
+	return 0;
+}
+
Quoted 2 lines

[vast amounts trimmed]

Attention span expired, sorry. ETIME.