From f49639e643e69ff233b14966b8d48541d2e17517 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 9 Jun 2006 11:58:36 -0700 Subject: [TG3]: Handle Sun onboard tg3 chips more correctly. Get rid of all the SUN_570X logic and instead: 1) Make sure MEMARB_ENABLE is set when we probe the SRAM for config information. If that is off we will get timeouts. 2) Always try to sync with the firmware, if there is no firmware running do not treat it as an error and instead just report it the first time we notice this condition. 3) If there is no valid SRAM signature, assume the device is onboard by setting TG3_FLAG_EEPROM_WRITE_PROT. Update driver version and release date. With help from Michael Chan and Fabio Massimo Di Nitto. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 144 ++++++++++++++++++------------------------------------ drivers/net/tg3.h | 3 +- 2 files changed, 50 insertions(+), 97 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 49ad60b7265..862c226dbbe 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.58" -#define DRV_MODULE_RELDATE "May 22, 2006" +#define DRV_MODULE_VERSION "3.59" +#define DRV_MODULE_RELDATE "June 8, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -4485,9 +4485,8 @@ static void tg3_disable_nvram_access(struct tg3 *tp) /* tp->lock is held. */ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind) { - if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) - tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, - NIC_SRAM_FIRMWARE_MBOX_MAGIC1); + tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, + NIC_SRAM_FIRMWARE_MBOX_MAGIC1); if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) { switch (kind) { @@ -4568,13 +4567,12 @@ static int tg3_chip_reset(struct tg3 *tp) void (*write_op)(struct tg3 *, u32, u32); int i; - if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) { - tg3_nvram_lock(tp); - /* No matching tg3_nvram_unlock() after this because - * chip reset below will undo the nvram lock. - */ - tp->nvram_lock_cnt = 0; - } + tg3_nvram_lock(tp); + + /* No matching tg3_nvram_unlock() after this because + * chip reset below will undo the nvram lock. + */ + tp->nvram_lock_cnt = 0; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || @@ -4727,20 +4725,25 @@ static int tg3_chip_reset(struct tg3 *tp) tw32_f(MAC_MODE, 0); udelay(40); - if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) { - /* Wait for firmware initialization to complete. */ - for (i = 0; i < 100000; i++) { - tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val); - if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1) - break; - udelay(10); - } - if (i >= 100000) { - printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, " - "firmware will not restart magic=%08x\n", - tp->dev->name, val); - return -ENODEV; - } + /* Wait for firmware initialization to complete. */ + for (i = 0; i < 100000; i++) { + tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val); + if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1) + break; + udelay(10); + } + + /* Chip might not be fitted with firmare. Some Sun onboard + * parts are configured like that. So don't signal the timeout + * of the above loop as an error, but do report the lack of + * running firmware once. + */ + if (i >= 100000 && + !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) { + tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED; + + printk(KERN_INFO PFX "%s: No firmware running.\n", + tp->dev->name); } if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && @@ -9075,9 +9078,6 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) { int j; - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) - return; - tw32_f(GRC_EEPROM_ADDR, (EEPROM_ADDR_FSM_RESET | (EEPROM_DEFAULT_CLOCK_PERIOD << @@ -9210,11 +9210,6 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) { int ret; - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { - printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n"); - return -EINVAL; - } - if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) return tg3_nvram_read_using_eeprom(tp, offset, val); @@ -9447,11 +9442,6 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) { int ret; - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { - printk(KERN_ERR PFX "Attempt to do nvram_write on Sun 570X\n"); - return -EINVAL; - } - if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & ~GRC_LCLCTRL_GPIO_OUTPUT1); @@ -9578,15 +9568,19 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); + /* The memory arbiter has to be enabled in order for SRAM accesses + * to succeed. Normally on powerup the tg3 chip firmware will make + * sure it is enabled, but other entities such as system netboot + * code might disable it. + */ + val = tr32(MEMARB_MODE); + tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE); + tp->phy_id = PHY_ID_INVALID; tp->led_ctrl = LED_CTRL_MODE_PHY_1; - /* Do not even try poking around in here on Sun parts. */ - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { - /* All SUN chips are built-in LOMs. */ - tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; - return; - } + /* Assume an onboard device by default. */ + tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { @@ -9686,6 +9680,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; + else + tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT; if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; @@ -9834,16 +9830,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp) int i; u32 magic; - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { - /* Sun decided not to put the necessary bits in the - * NVRAM of their onboard tg3 parts :( - */ - strcpy(tp->board_part_number, "Sun 570X"); - return; - } - if (tg3_nvram_read_swab(tp, 0x0, &magic)) - return; + goto out_not_found; if (magic == TG3_EEPROM_MAGIC) { for (i = 0; i < 256; i += 4) { @@ -9874,6 +9862,9 @@ static void __devinit tg3_read_partno(struct tg3 *tp) break; msleep(1); } + if (!(tmp16 & 0x8000)) + goto out_not_found; + pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA, &tmp); tmp = cpu_to_le32(tmp); @@ -9965,37 +9956,6 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) } } -#ifdef CONFIG_SPARC64 -static int __devinit tg3_is_sun_570X(struct tg3 *tp) -{ - struct pci_dev *pdev = tp->pdev; - struct pcidev_cookie *pcp = pdev->sysdata; - - if (pcp != NULL) { - int node = pcp->prom_node; - u32 venid; - int err; - - err = prom_getproperty(node, "subsystem-vendor-id", - (char *) &venid, sizeof(venid)); - if (err == 0 || err == -1) - return 0; - if (venid == PCI_VENDOR_ID_SUN) - return 1; - - /* TG3 chips onboard the SunBlade-2500 don't have the - * subsystem-vendor-id set to PCI_VENDOR_ID_SUN but they - * are distinguishable from non-Sun variants by being - * named "network" by the firmware. Non-Sun cards will - * show up as being named "ethernet". - */ - if (!strcmp(pcp->prom_name, "network")) - return 1; - } - return 0; -} -#endif - static int __devinit tg3_get_invariants(struct tg3 *tp) { static struct pci_device_id write_reorder_chipsets[] = { @@ -10012,11 +9972,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) u16 pci_cmd; int err; -#ifdef CONFIG_SPARC64 - if (tg3_is_sun_570X(tp)) - tp->tg3_flags2 |= TG3_FLG2_SUN_570X; -#endif - /* Force memory write invalidate off. If we leave it on, * then on 5700_BX chips we have to enable a workaround. * The workaround is to set the TG3PCI_DMA_RW_CTRL boundary @@ -10312,8 +10267,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->write32 == tg3_write_indirect_reg32 || ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) || - (tp->tg3_flags2 & TG3_FLG2_SUN_570X)) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701))) tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; /* Get eeprom hw config before calling tg3_set_power_state(). @@ -10594,8 +10548,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) #endif mac_offset = 0x7c; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && - !(tp->tg3_flags & TG3_FLG2_SUN_570X)) || + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID) mac_offset = 0xcc; @@ -10622,8 +10575,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) } if (!addr_ok) { /* Next, try NVRAM. */ - if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && - !tg3_nvram_read(tp, mac_offset + 0, &hi) && + if (!tg3_nvram_read(tp, mac_offset + 0, &hi) && !tg3_nvram_read(tp, mac_offset + 4, &lo)) { dev->dev_addr[0] = ((hi >> 16) & 0xff); dev->dev_addr[1] = ((hi >> 24) & 0xff); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 0e29b885d44..ff0faab94bd 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2184,7 +2184,7 @@ struct tg3 { #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; #define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_SUN_570X 0x00000002 +/* 0x00000002 available */ #define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004 #define TG3_FLG2_IS_5788 0x00000008 #define TG3_FLG2_MAX_RXPEND_64 0x00000010 @@ -2216,6 +2216,7 @@ struct tg3 { #define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2) #define TG3_FLG2_1SHOT_MSI 0x10000000 #define TG3_FLG2_PHY_JITTER_BUG 0x20000000 +#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 -- cgit v1.2.3 From d374c1c1281d6188a0d0676172b1c0e3de35c6e7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 12 Jun 2006 12:53:27 -0700 Subject: [sky2] Fix sky2 network driver suspend/resume This fixes two independent problems: it would not save the PCI state on suspend (and thus try to resume a nonexistent state on resume), and while shut off, if an interrupt happened on the same shared irq, the irq handler would react very badly to the interrupt status being an invalid all-ones state. Acked-by: Jeff Garzik Signed-off-by: Linus Torvalds --- drivers/net/sky2.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 959109609d8..6b87c7a5c90 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2183,6 +2183,9 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); + if (!~status) + return 0; + if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -3438,6 +3441,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) } } + pci_save_state(pdev); return sky2_set_power_state(hw, pci_choose_state(pdev, state)); } -- cgit v1.2.3 From 2ccc99b7b71976d15822ae7c41cd2ccda66d5076 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 13 Jun 2006 17:17:27 +0900 Subject: [PATCH] sky2: set_power_state should be void The set power state function is cleaner if it doesn't return anything. The only caller that could fail is in suspend() and it can check the argument there. Signed-off-by: Stephen Hemminger Signed-off-by: Linus Torvalds --- drivers/net/sky2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 6b87c7a5c90..765c8f06351 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -187,12 +187,11 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) return v; } -static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) +static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) { u16 power_control; u32 reg1; int vaux; - int ret = 0; pr_debug("sky2_set_power_state %d\n", state); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); @@ -275,12 +274,10 @@ static int sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) break; default: printk(KERN_ERR PFX "Unknown power state %d\n", state); - ret = -1; } sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - return ret; } static void sky2_phy_reset(struct sky2_hw *hw, unsigned port) @@ -3428,6 +3425,10 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) { struct sky2_hw *hw = pci_get_drvdata(pdev); int i; + pci_power_t pstate = pci_choose_state(pdev, state); + + if (!(pstate == PCI_D3hot || pstate == PCI_D3cold)) + return -EINVAL; for (i = 0; i < 2; i++) { struct net_device *dev = hw->dev[i]; @@ -3442,7 +3443,8 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) } pci_save_state(pdev); - return sky2_set_power_state(hw, pci_choose_state(pdev, state)); + sky2_set_power_state(hw, pstate); + return 0; } static int sky2_resume(struct pci_dev *pdev) @@ -3452,9 +3454,7 @@ static int sky2_resume(struct pci_dev *pdev) pci_restore_state(pdev); pci_enable_wake(pdev, PCI_D0, 0); - err = sky2_set_power_state(hw, PCI_D0); - if (err) - goto out; + sky2_set_power_state(hw, PCI_D0); err = sky2_reset(hw); if (err) -- cgit v1.2.3 From f05267e7dee58741a4feb20d0351706ec64bb0b5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 13 Jun 2006 17:17:28 +0900 Subject: [PATCH] sky2: don't hard code number of ports It is cleaner, to not loop over both ports if only one exists. Signed-off-by: Stephen Hemminger Signed-off-by: Linus Torvalds --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 765c8f06351..6ad676d2cbc 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3430,7 +3430,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) if (!(pstate == PCI_D3hot || pstate == PCI_D3cold)) return -EINVAL; - for (i = 0; i < 2; i++) { + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; if (dev) { @@ -3460,7 +3460,7 @@ static int sky2_resume(struct pci_dev *pdev) if (err) goto out; - for (i = 0; i < 2; i++) { + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; if (dev && netif_running(dev)) { netif_device_attach(dev); -- cgit v1.2.3 From 26ec43f132d1cf282124a020b2bb5310496c9132 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 13 Jun 2006 17:17:29 +0900 Subject: [PATCH] sky2: fix hotplug detect during poll If the poll routine detects no hardware available, it needs to dequeue it self from the network poll list. Linus didn't understand NAPI. Signed-off-by: Stephen Hemminger Signed-off-by: Linus Torvalds --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 6ad676d2cbc..b680e64ad2c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2181,7 +2181,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) u32 status = sky2_read32(hw, B0_Y2_SP_EISR); if (!~status) - return 0; + goto out; if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -2219,7 +2219,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) if (sky2_more_work(hw)) return 1; - +out: netif_rx_complete(dev0); sky2_read32(hw, B0_Y2_SP_LISR); -- cgit v1.2.3 From 8ab8fca2071cec559e4b77212cccffd150ce5ce7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 13 Jun 2006 17:17:30 +0900 Subject: [PATCH] sky2: save/restore base hardware irq during suspend/resume The hardware should be fully shut off during suspend, and the base irq mask restored during resume. Signed-off-by: Stephen Hemminger Signed-off-by: Linus Torvalds --- drivers/net/sky2.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b680e64ad2c..df899dcbd5b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3442,6 +3442,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) } } + sky2_write32(hw, B0_IMSK, 0); pci_save_state(pdev); sky2_set_power_state(hw, pstate); return 0; @@ -3460,6 +3461,8 @@ static int sky2_resume(struct pci_dev *pdev) if (err) goto out; + sky2_write32(hw, B0_IMSK, Y2_IS_BASE); + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; if (dev && netif_running(dev)) { -- cgit v1.2.3 From eb35cf60e462491249166182e3e755d3d5d91a28 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 13 Jun 2006 17:17:31 +0900 Subject: [PATCH] sky2: stop/start hardware idle timer on suspend/resume The resume bug was caused not by an early interrupt but because the idle timeout was not being stopped on suspend. Also disable hardware IRQ's on suspend. Will need to revisit this with hotplug? Signed-off-by: Stephen Hemminger Signed-off-by: Linus Torvalds --- drivers/net/sky2.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index df899dcbd5b..97fe95666f3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2161,6 +2161,13 @@ static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port, /* If idle then force a fake soft NAPI poll once a second * to work around cases where sharing an edge triggered interrupt. */ +static inline void sky2_idle_start(struct sky2_hw *hw) +{ + if (idle_timeout > 0) + mod_timer(&hw->idle_timer, + jiffies + msecs_to_jiffies(idle_timeout)); +} + static void sky2_idle(unsigned long arg) { struct sky2_hw *hw = (struct sky2_hw *) arg; @@ -3350,9 +3357,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, sky2_write32(hw, B0_IMSK, Y2_IS_BASE); setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); - if (idle_timeout > 0) - mod_timer(&hw->idle_timer, - jiffies + msecs_to_jiffies(idle_timeout)); + sky2_idle_start(hw); pci_set_drvdata(pdev, hw); @@ -3430,6 +3435,8 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) if (!(pstate == PCI_D3hot || pstate == PCI_D3cold)) return -EINVAL; + del_timer_sync(&hw->idle_timer); + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; @@ -3472,10 +3479,12 @@ static int sky2_resume(struct pci_dev *pdev) printk(KERN_ERR PFX "%s: could not up: %d\n", dev->name, err); dev_close(dev); - break; + goto out; } } } + + sky2_idle_start(hw); out: return err; } -- cgit v1.2.3