Add IP1000A Driver into Kernel (2007/09/12)
Subsystems (3)
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
@@ -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.
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
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
@@ -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
@@ -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
@@ -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
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.
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.