From: Mark Brown Aculab E1/T1 PMXc cPCI carrier card cards present a natsemi on the cPCI bus wired up in a non-standard fashion. This patch provides support in the natsemi driver for these cards by implementing a quirk mechanism and using that to configure appropriate settings for the card: forcing 100M full duplex, having a large EEPROM and using the MII port while ignoring PHYs. Signed-off-by: Mark Brown Cc: Tim Hockin Cc: Jeff Garzik Signed-off-by: Andrew Morton --- drivers/net/natsemi.c | 94 ++++++++++++++++++++++++-------------- include/linux/pci_ids.h | 1 2 files changed, 61 insertions(+), 34 deletions(-) diff -puN drivers/net/natsemi.c~natsemi-add-quirks-for-aculab-e1-t1-pmxc-cpci-carrier-cards drivers/net/natsemi.c --- devel/drivers/net/natsemi.c~natsemi-add-quirks-for-aculab-e1-t1-pmxc-cpci-carrier-cards 2006-03-16 02:07:40.000000000 -0800 +++ devel-akpm/drivers/net/natsemi.c 2006-03-16 02:07:40.000000000 -0800 @@ -226,7 +226,6 @@ static int full_duplex[MAX_UNITS]; NATSEMI_PG1_NREGS) #define NATSEMI_REGS_VER 1 /* v1 added RFDR registers */ #define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32)) -#define NATSEMI_DEF_EEPROM_SIZE 24 /* 12 16-bit values */ /* Buffer sizes: * The nic writes 32-bit values, even if the upper bytes of @@ -344,12 +343,14 @@ None characterised. -enum pcistuff { +enum natsemi_quirks { PCI_USES_IO = 0x01, PCI_USES_MEM = 0x02, PCI_USES_MASTER = 0x04, PCI_ADDR0 = 0x08, PCI_ADDR1 = 0x10, + MEDIA_FORCE_100FD = 0x20, + MEDIA_IGNORE_PHY = 0x40, }; /* MMIO operations required */ @@ -367,17 +368,21 @@ enum pcistuff { #define MII_FX_SEL 0x0001 /* 100BASE-FX (fiber) */ #define MII_EN_SCRM 0x0004 /* enable scrambler (tp) */ - /* array of board data directly indexed by pci_tbl[x].driver_data */ static const struct { const char *name; unsigned long flags; + int quirks; + int eeprom_size; } natsemi_pci_info[] __devinitdata = { - { "NatSemi DP8381[56]", PCI_IOTYPE }, + { "NatSemi DP8381[56]", PCI_IOTYPE, 0, 24 }, + { "Aculab E1/T1 PMXc cPCI carrier card", PCI_IOTYPE, + MEDIA_FORCE_100FD | MEDIA_IGNORE_PHY, 128 }, }; static struct pci_device_id natsemi_pci_tbl[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_VENDOR_ID_ACULAB, PCI_SUBDEVICE_ID_ACULAB_174, 0, 0, 1 }, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl); @@ -815,6 +820,39 @@ static void move_int_phy(struct net_devi udelay(1); } +static void __devinit natsemi_init_media (struct net_device *dev) +{ + struct netdev_private *np = netdev_priv(dev); + u32 tmp; + + tmp = mdio_read(dev, MII_BMCR); + np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10; + np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF; + np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE; + np->advertising= mdio_read(dev, MII_ADVERTISE); + + if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL + && netif_msg_probe(np)) { + printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s " + "10%s %s duplex.\n", + pci_name(np->pci_dev), + (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)? + "enabled, advertise" : "disabled, force", + (np->advertising & + (ADVERTISE_100FULL|ADVERTISE_100HALF))? + "0" : "", + (np->advertising & + (ADVERTISE_100FULL|ADVERTISE_10FULL))? + "full" : "half"); + } + if (netif_msg_probe(np)) + printk(KERN_INFO + "natsemi %s: Transceiver status %#04x advertising %#04x.\n", + pci_name(np->pci_dev), mdio_read(dev, MII_BMSR), + np->advertising); + +} + static int __devinit natsemi_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -894,17 +932,21 @@ static int __devinit natsemi_probe1 (str np->msg_enable = (debug >= 0) ? (1<hands_off = 0; np->intr_status = 0; - np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE; + np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size; option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; if (dev->mem_start) option = dev->mem_start; /* Ignore the PHY status? */ - if (option & 0x400) { + if (natsemi_pci_info[chip_idx].quirks & MEDIA_IGNORE_PHY) { np->ignore_phy = 1; } else { - np->ignore_phy = 0; + if (option & 0x400) { + np->ignore_phy = 1; + } else { + np->ignore_phy = 0; + } } /* Initial port: @@ -936,6 +978,12 @@ static int __devinit natsemi_probe1 (str np->phy_addr_external = PHY_ADDR_INTERNAL; } + /* Apply any speed quirks. */ + if (natsemi_pci_info[chip_idx].quirks & MEDIA_FORCE_100FD) { + np->speed = 100; + np->duplex = 1; + } + /* The lower four bits are the media type. */ if (option) { if (option & 0x200) @@ -974,32 +1022,10 @@ static int __devinit natsemi_probe1 (str else netif_carrier_off(dev); - /* get the initial settings from hardware */ - tmp = mdio_read(dev, MII_BMCR); - np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10; - np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF; - np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE; - np->advertising= mdio_read(dev, MII_ADVERTISE); - - if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL - && netif_msg_probe(np)) { - printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s " - "10%s %s duplex.\n", - pci_name(np->pci_dev), - (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)? - "enabled, advertise" : "disabled, force", - (np->advertising & - (ADVERTISE_100FULL|ADVERTISE_100HALF))? - "0" : "", - (np->advertising & - (ADVERTISE_100FULL|ADVERTISE_10FULL))? - "full" : "half"); - } - if (netif_msg_probe(np)) - printk(KERN_INFO - "natsemi %s: Transceiver status %#04x advertising %#04x.\n", - pci_name(np->pci_dev), mdio_read(dev, MII_BMSR), - np->advertising); + /* get the initial settings from hardware if we don't have any + * already */ + if (!np->speed) + natsemi_init_media(dev); /* save the silicon revision for later querying */ np->srr = readl(ioaddr + SiliconRev); diff -puN include/linux/pci_ids.h~natsemi-add-quirks-for-aculab-e1-t1-pmxc-cpci-carrier-cards include/linux/pci_ids.h --- devel/include/linux/pci_ids.h~natsemi-add-quirks-for-aculab-e1-t1-pmxc-cpci-carrier-cards 2006-03-16 02:07:40.000000000 -0800 +++ devel-akpm/include/linux/pci_ids.h 2006-03-16 02:07:40.000000000 -0800 @@ -1616,6 +1616,7 @@ #define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018 #define PCI_VENDOR_ID_ACULAB 0x12d9 +#define PCI_SUBDEVICE_ID_ACULAB_174 0x000c #define PCI_SUBVENDOR_ID_CHASE_PCIFAST 0x12E0 #define PCI_SUBDEVICE_ID_CHASE_PCIFAST4 0x0031 _