X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Fnet%2Fsky2.c;h=a2070db725c903ced2fae8079cf71fd2ae32d182;hb=8ac98ce17cf318f6ceb1eb88053917001f5ca60a;hp=24cfb6275d9b37a39cd021a45a00f1c7951fc886;hpb=0b776eb5426752d4e53354ac89e3710d857e09a7;p=linux-2.6-omap-h63xx.git diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 24cfb6275d9..a2070db725c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -52,7 +52,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.19" +#define DRV_VERSION "1.20" #define PFX DRV_NAME " " /* @@ -121,6 +121,7 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4357) }, /* 88E8042 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */ @@ -134,6 +135,7 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436C) }, /* 88E8072 */ { 0 } }; @@ -156,7 +158,7 @@ static const char *yukon2_name[] = { static void sky2_set_multicast(struct net_device *dev); -/* Access to external PHY */ +/* Access to PHY via serial interconnect */ static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val) { int i; @@ -166,13 +168,22 @@ static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val) GM_SMI_CT_PHY_AD(PHY_ADDR_MARV) | GM_SMI_CT_REG_AD(reg)); for (i = 0; i < PHY_RETRIES; i++) { - if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) + u16 ctrl = gma_read16(hw, port, GM_SMI_CTRL); + if (ctrl == 0xffff) + goto io_error; + + if (!(ctrl & GM_SMI_CT_BUSY)) return 0; - udelay(1); + + udelay(10); } - printk(KERN_WARNING PFX "%s: phy write timeout\n", hw->dev[port]->name); + dev_warn(&hw->pdev->dev,"%s: phy write timeout\n", hw->dev[port]->name); return -ETIMEDOUT; + +io_error: + dev_err(&hw->pdev->dev, "%s: phy I/O error\n", hw->dev[port]->name); + return -EIO; } static int __gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg, u16 *val) @@ -183,23 +194,29 @@ static int __gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg, u16 *val) | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); for (i = 0; i < PHY_RETRIES; i++) { - if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) { + u16 ctrl = gma_read16(hw, port, GM_SMI_CTRL); + if (ctrl == 0xffff) + goto io_error; + + if (ctrl & GM_SMI_CT_RD_VAL) { *val = gma_read16(hw, port, GM_SMI_DATA); return 0; } - udelay(1); + udelay(10); } + dev_warn(&hw->pdev->dev, "%s: phy read timeout\n", hw->dev[port]->name); return -ETIMEDOUT; +io_error: + dev_err(&hw->pdev->dev, "%s: phy I/O error\n", hw->dev[port]->name); + return -EIO; } -static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) +static inline u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) { u16 v; - - if (__gm_phy_read(hw, port, reg, &v) != 0) - printk(KERN_WARNING PFX "%s: phy read timeout\n", hw->dev[port]->name); + __gm_phy_read(hw, port, reg, &v); return v; } @@ -273,8 +290,6 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) /* disable all GMAC IRQ's */ sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0); - /* disable PHY IRQs */ - gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */ gma_write16(hw, port, GM_MC_ADDR_H2, 0); @@ -1805,29 +1820,6 @@ static void sky2_link_up(struct sky2_port *sky2) sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF); - if (hw->flags & SKY2_HW_NEWER_PHY) { - u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); - u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */ - - switch(sky2->speed) { - case SPEED_10: - led |= PHY_M_LEDC_INIT_CTRL(7); - break; - - case SPEED_100: - led |= PHY_M_LEDC_STA1_CTRL(7); - break; - - case SPEED_1000: - led |= PHY_M_LEDC_STA0_CTRL(7); - break; - } - - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, led); - gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); - } - if (netif_msg_link(sky2)) printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", @@ -2247,20 +2239,26 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) do { struct sky2_port *sky2; struct sky2_status_le *le = hw->st_le + hw->st_idx; - unsigned port = le->css & CSS_LINK_BIT; + unsigned port; struct net_device *dev; struct sk_buff *skb; u32 status; u16 length; + u8 opcode = le->opcode; + + if (!(opcode & HW_OWNER)) + break; hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE); + port = le->css & CSS_LINK_BIT; dev = hw->dev[port]; sky2 = netdev_priv(dev); length = le16_to_cpu(le->length); status = le32_to_cpu(le->status); - switch (le->opcode & ~HW_OWNER) { + le->opcode = 0; + switch (opcode & ~HW_OWNER) { case OP_RXSTAT: ++rx[port]; skb = sky2_receive(dev, length, status); @@ -2353,7 +2351,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) default: if (net_ratelimit()) printk(KERN_WARNING PFX - "unknown status opcode 0x%x\n", le->opcode); + "unknown status opcode 0x%x\n", opcode); } } while (hw->st_idx != idx); @@ -2439,13 +2437,26 @@ static void sky2_hw_intr(struct sky2_hw *hw) if (status & Y2_IS_PCI_EXP) { /* PCI-Express uncorrectable Error occurred */ - int pos = pci_find_aer_capability(hw->pdev); + int aer = pci_find_aer_capability(hw->pdev); u32 err; - pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_STATUS, &err); + if (aer) { + pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, + &err); + pci_cleanup_aer_uncorrect_error_status(pdev); + } else { + /* Either AER not configured, or not working + * because of bad MMCONFIG, so just do recover + * manually. + */ + err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS); + sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS, + 0xfffffffful); + } + if (net_ratelimit()) dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err); - pci_cleanup_aer_uncorrect_error_status(pdev); + } if (status & Y2_HWE_L1_MASK) @@ -2791,6 +2802,9 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_RST_SET); sky2_write8(hw, B0_CTST, CS_RST_CLR); + /* allow writes to PCI config */ + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + /* clear PCI errors, if any */ pci_read_config_word(pdev, PCI_STATUS, &status); status |= PCI_STATUS_ERROR_BITS; @@ -2800,9 +2814,18 @@ static void sky2_reset(struct sky2_hw *hw) cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (cap) { - /* Check for advanced error reporting */ - pci_cleanup_aer_uncorrect_error_status(pdev); - pci_cleanup_aer_correct_error_status(pdev); + if (pci_find_aer_capability(pdev)) { + /* Check for advanced error reporting */ + pci_cleanup_aer_uncorrect_error_status(pdev); + pci_cleanup_aer_correct_error_status(pdev); + } else { + dev_warn(&pdev->dev, + "PCI Express Advanced Error Reporting" + " not configured or MMCONFIG problem?\n"); + + sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS, + 0xfffffffful); + } /* If error bit is stuck on ignore it */ if (sky2_read32(hw, B0_HWE_ISRC) & Y2_IS_PCI_EXP) @@ -3974,7 +3997,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->tx_timeout = sky2_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; #ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sky2_netpoll; + if (port == 0) + dev->poll_controller = sky2_netpoll; #endif sky2 = netdev_priv(dev); @@ -4271,7 +4295,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev) del_timer_sync(&hw->watchdog_timer); cancel_work_sync(&hw->restart_work); - for (i = hw->ports; i >= 0; --i) + for (i = hw->ports-1; i >= 0; --i) unregister_netdev(hw->dev[i]); sky2_write32(hw, B0_IMSK, 0); @@ -4289,7 +4313,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); - for (i = hw->ports; i >= 0; --i) + for (i = hw->ports-1; i >= 0; --i) free_netdev(hw->dev[i]); iounmap(hw->regs);