Subbject: spidernet: enable autonegotiate Following are the changes. -This patch enables auto-negotiation. -Loading firmware is done when spidernet_open() is called. -And this patch adds other several small changes for Celleb. -This patch is not tested on CellBlade. Signed-off-by: Kou Ishizaki Signed-off-by: Arnd Bergmann --- Dear everyone, This is the patch (besed on powerpc-git (2006-12-05)) for spidernet driver to work on Toshiba Cell reference set(Celleb). The reference set consists of Cell, 512MB memory, Super Companion Chip(SCC) and some peripherals such as HDD, GbE, etc. You can see brief explanation and picture of Cell reference set at following URLs. http://www.toshiba.co.jp/about/press/2005_09/pr2001.htm http://cell-industries.com/toshiba_announces.php This patch set is intended to be merged to 2.6.20. If you have any comment, please write to me. --- Index: linux-2.6/drivers/net/Kconfig =================================================================== --- linux-2.6.orig/drivers/net/Kconfig +++ linux-2.6/drivers/net/Kconfig @@ -2256,7 +2256,7 @@ config BNX2 config SPIDER_NET tristate "Spider Gigabit Ethernet driver" - depends on PCI && PPC_IBM_CELL_BLADE + depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) select FW_LOADER help This driver supports the Gigabit Ethernet chips present on the Index: linux-2.6/drivers/net/spider_net.h =================================================================== --- linux-2.6.orig/drivers/net/spider_net.h +++ linux-2.6/drivers/net/spider_net.h @@ -1,7 +1,8 @@ /* - * Network device driver for Cell Processor-Based Blade + * Network device driver for Cell Processor-Based Blade and Celleb platform * * (C) Copyright IBM Corp. 2005 + * (C) Copyright 2006 TOSHIBA CORPORATION * * Authors : Utz Bacher * Jens Osterkamp @@ -50,6 +51,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 #define SPIDER_NET_TX_TIMER (HZ/5) +#define SPIDER_NET_ANEG_TIMER (HZ*2) #define SPIDER_NET_RX_CSUM_DEFAULT 1 @@ -104,6 +106,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_GMACOPEMD 0x00000100 #define SPIDER_NET_GMACLENLMT 0x00000108 +#define SPIDER_NET_GMACST 0x00000110 #define SPIDER_NET_GMACINTEN 0x00000118 #define SPIDER_NET_GMACPHYCTRL 0x00000120 @@ -180,8 +183,8 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_IPSECINIT_VALUE 0x6f716f71 /* pause frames: automatic, no upper retransmission count */ -/* outside loopback mode: ETOMOD signal dont matter, not connected */ -#define SPIDER_NET_OPMODE_VALUE 0x00000063 +/* ETOMOD signal is brought to PHY reset. bit2 must be 1 in Celleb */ +#define SPIDER_NET_OPMODE_VALUE 0x00000067 /*#define SPIDER_NET_OPMODE_VALUE 0x001b0062*/ #define SPIDER_NET_LENLMT_VALUE 0x00000908 @@ -333,9 +336,12 @@ enum spider_net_int2_status { /* We rely on flagged descriptor interrupts */ #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) +#define SPIDER_NET_LINKINT ( 1 << SPIDER_NET_GMAC2INT ) + #define SPIDER_NET_ERRINT ( 0xffffffff & \ (~SPIDER_NET_TXINT) & \ - (~SPIDER_NET_RXINT) ) + (~SPIDER_NET_RXINT) & \ + (~SPIDER_NET_LINKINT) ) #define SPIDER_NET_GPREXEC 0x80000000 #define SPIDER_NET_GPRDAT_MASK 0x0000ffff @@ -447,6 +453,8 @@ struct spider_net_card { spinlock_t intmask_lock; struct tasklet_struct rxram_full_tl; + int aneg_count; + struct timer_list aneg_timer; struct timer_list tx_timer; struct work_struct tx_timeout_task; Index: linux-2.6/drivers/net/spider_net.c =================================================================== --- linux-2.6.orig/drivers/net/spider_net.c +++ linux-2.6/drivers/net/spider_net.c @@ -1,7 +1,8 @@ /* - * Network device driver for Cell Processor-Based Blade + * Network device driver for Cell Processor-Based Blade and Celleb platform * * (C) Copyright IBM Corp. 2005 + * (C) Copyright 2006 TOSHIBA CORPORATION * * Authors : Utz Bacher * Jens Osterkamp @@ -78,6 +79,8 @@ static struct pci_device_id spider_net_p MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl); +static int is1000 = 1; + /** * spider_net_read_reg - reads an SMMIO register of a card * @card: device structure @@ -165,6 +168,53 @@ spider_net_read_phy(struct net_device *n return readvalue; } +static void +spider_net_setup_aneg(struct spider_net_card *card, int is1000) +{ + struct mii_phy *phy = &card->phy; + u32 advertise = 0; + u16 bmcr, bmsr, ctrl1000, stat1000, estat; + + bmcr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMCR); + bmsr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); + ctrl1000 = spider_net_read_phy(card->netdev, phy->mii_id, MII_CTRL1000); + stat1000 = spider_net_read_phy(card->netdev, phy->mii_id, MII_STAT1000); + estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS); + + if (bmsr & BMSR_10HALF) + advertise |= ADVERTISE_10HALF; + if (bmsr & BMSR_10FULL) + advertise |= ADVERTISE_10FULL; + if (bmsr & BMSR_100HALF) + advertise |= ADVERTISE_100HALF; + if (bmsr & BMSR_100FULL) + advertise |= ADVERTISE_100FULL; + if (bmsr & BMSR_100BASE4) + advertise |= ADVERTISE_100BASE4; + + if (is1000) { + if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL)) { + advertise |= ADVERTISE_1000XFULL; + ctrl1000 |= ADVERTISE_1000FULL; + } + if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF)) { + advertise |= ADVERTISE_1000XHALF; + ctrl1000 |= ADVERTISE_1000HALF; + } + + spider_net_write_phy(card->netdev, phy->mii_id, + MII_CTRL1000, ctrl1000); + spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001); + + phy->def->ops->setup_aneg(phy, advertise); + } else { + spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0); + bmcr |= (BMCR_ANRESTART | BMCR_ANENABLE); + spider_net_write_phy(card->netdev, phy->mii_id, + MII_BMCR, bmcr); + } +} + /** * spider_net_rx_irq_off - switch off rx irq on this spider card * @card: device structure @@ -1227,6 +1277,31 @@ spider_net_set_mac(struct net_device *ne } /** + * spider_net_link_reset + * @netdev: net device structure + * + */ +static void +spider_net_link_reset(struct net_device *netdev) +{ + + struct spider_net_card *card=netdev_priv(netdev); + + del_timer_sync(&card->aneg_timer); + + spider_net_write_reg(card, SPIDER_NET_GMACST, + spider_net_read_reg(card, SPIDER_NET_GMACST)); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); + + mii_phy_probe(&card->phy, card->phy.mii_id); + spider_net_setup_aneg(card, is1000); + if (card->phy.def->phy_id) + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + else + pr_err("No phy is available\n"); +} + +/** * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt * @card: card structure * @@ -1356,8 +1431,8 @@ spider_net_handle_error_irq(struct spide switch (i) { case SPIDER_NET_GTMFLLINT: - if (netif_msg_intr(card) && net_ratelimit()) - pr_err("Spider TX RAM full\n"); + /* if (netif_msg_intr(card) && net_ratelimit()) + pr_err("Spider TX RAM full\n"); */ show_error = 0; break; case SPIDER_NET_GRFDFLLINT: /* fallthrough */ @@ -1497,6 +1572,9 @@ spider_net_interrupt(int irq, void *ptr) if (status_reg & SPIDER_NET_TXINT) netif_rx_schedule(netdev); + if (status_reg & SPIDER_NET_LINKINT) + spider_net_link_reset(netdev); + if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); @@ -1537,6 +1615,10 @@ spider_net_init_card(struct spider_net_c spider_net_write_reg(card, SPIDER_NET_CKRCTRL, SPIDER_NET_CKRCTRL_RUN_VALUE); + + spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, + spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4); + } /** @@ -1621,8 +1703,6 @@ spider_net_enable_card(struct spider_net spider_net_write_reg(card, SPIDER_NET_GMACLENLMT, SPIDER_NET_LENLMT_VALUE); - spider_net_write_reg(card, SPIDER_NET_GMACMODE, - SPIDER_NET_MACMODE_VALUE); spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, SPIDER_NET_OPMODE_VALUE); @@ -1638,6 +1718,7 @@ spider_net_enable_card(struct spider_net SPIDER_NET_GDTBSTA); } +static int spider_net_init_firmware(struct spider_net_card *); /** * spider_net_open - called upon ifonfig up * @netdev: interface device structure @@ -1655,6 +1736,16 @@ spider_net_open(struct net_device *netde int i, result; result = -ENOMEM; + if (spider_net_init_firmware(card)) + goto init_firmware_failed; + + spider_net_setup_aneg(card, is1000); + if (card->phy.def->phy_id) + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + else + pr_err("No phy is available\n"); + + if (spider_net_init_chain(card, &card->tx_chain, card->descr, card->num_tx_desc)) goto alloc_tx_failed; @@ -1699,9 +1790,60 @@ alloc_skbs_failed: alloc_rx_failed: spider_net_free_chain(card, &card->tx_chain); alloc_tx_failed: +init_firmware_failed: return result; } +static void spider_net_init_card(struct spider_net_card *); +/** + * spider_net_link_phy + * @data: used for pointer to card structure + * + */ +static void spider_net_link_phy(unsigned long data) +{ + struct spider_net_card *card = (struct spider_net_card *)data; + struct mii_phy *phy = &card->phy; + + if (card->aneg_count > 10) { + /* timeout */ + card->aneg_count = 0; + is1000 = !is1000; + goto re_setup; + } + + if (!(phy->def->ops->poll_link(phy))) { + card->aneg_count++; + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + return; + } + + phy->def->ops->read_link(phy); + + if (phy->speed == 1000 && !is1000) { + is1000 = 1; + goto re_setup; + } else if(phy->speed != 1000 && is1000) { + is1000 = 0; + goto re_setup; + } + + spider_net_write_reg(card, SPIDER_NET_GMACST, + spider_net_read_reg(card, SPIDER_NET_GMACST)); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4); + + pr_info("Found %s with %i Mbps, %s-duplex.\n", + phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half"); + + return; + +re_setup: + mii_phy_probe(phy, phy->mii_id); + spider_net_setup_aneg(card, is1000); + card->aneg_count = 0; + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); +} + /** * spider_net_setup_phy - setup PHY * @card: card structure @@ -1720,21 +1862,19 @@ spider_net_setup_phy(struct spider_net_c SPIDER_NET_DMASEL_VALUE); spider_net_write_reg(card, SPIDER_NET_GPCCTRL, SPIDER_NET_PHY_CTRL_VALUE); - phy->mii_id = 1; + phy->dev = card->netdev; phy->mdio_read = spider_net_read_phy; phy->mdio_write = spider_net_write_phy; - mii_phy_probe(phy, phy->mii_id); - - if (phy->def->ops->setup_forced) - phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL); - - phy->def->ops->enable_fiber(phy); - - phy->def->ops->read_link(phy); - pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, - phy->speed, phy->duplex==1 ? "Full" : "Half"); + for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) { + unsigned short id; + id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); + if (id != 0x0000 && id != 0xffff) { + mii_phy_probe(phy, phy->mii_id); + break; + } + } return 0; } @@ -1907,11 +2047,13 @@ spider_net_stop(struct net_device *netde netif_carrier_off(netdev); netif_stop_queue(netdev); del_timer_sync(&card->tx_timer); + del_timer_sync(&card->aneg_timer); /* disable/mask all interrupts */ spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0); spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); /* free_irq(netdev->irq, netdev);*/ free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev); @@ -1956,8 +2098,6 @@ spider_net_tx_timeout_task(struct work_s if (spider_net_setup_phy(card)) goto out; - if (spider_net_init_firmware(card)) - goto out; spider_net_open(netdev); spider_net_kick_tx_dma(card); @@ -2053,6 +2193,11 @@ spider_net_setup_netdev(struct spider_ne card->tx_timer.data = (unsigned long) card; netdev->irq = card->pdev->irq; + card->aneg_count = 0; + init_timer(&card->aneg_timer); + card->aneg_timer.function = spider_net_link_phy; + card->aneg_timer.data = (unsigned long) card; + card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; card->num_tx_desc = tx_descriptors; @@ -2231,10 +2376,6 @@ spider_net_probe(struct pci_dev *pdev, c if (err) goto out_undo_pci; - err = spider_net_init_firmware(card); - if (err) - goto out_undo_pci; - err = spider_net_setup_netdev(card); if (err) goto out_undo_pci;