diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/tg3.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 1625 |
1 files changed, 825 insertions, 800 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index a1f2e0fed78b..7b71387cf93c 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -4,7 +4,7 @@ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) * Copyright (C) 2004 Sun Microsystems Inc. - * Copyright (C) 2005-2011 Broadcom Corporation. + * Copyright (C) 2005-2012 Broadcom Corporation. * * Firmware is: * Derived from proprietary unpublished source code, @@ -89,10 +89,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 122 +#define TG3_MIN_NUM 123 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "December 7, 2011" +#define DRV_MODULE_RELDATE "March 21, 2012" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1 @@ -204,6 +204,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define TG3_RAW_IP_ALIGN 2 #define TG3_FW_UPDATE_TIMEOUT_SEC 5 +#define TG3_FW_UPDATE_FREQ_SEC (TG3_FW_UPDATE_TIMEOUT_SEC / 2) #define FIRMWARE_TG3 "tigon/tg3.bin" #define FIRMWARE_TG3TSO "tigon/tg3_tso.bin" @@ -1453,33 +1454,23 @@ static void tg3_wait_for_event_ack(struct tg3 *tp) } /* tp->lock is held. */ -static void tg3_ump_link_report(struct tg3 *tp) +static void tg3_phy_gather_ump_data(struct tg3 *tp, u32 *data) { - u32 reg; - u32 val; - - if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF)) - return; - - tg3_wait_for_event_ack(tp); - - tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE); - - tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14); + u32 reg, val; val = 0; if (!tg3_readphy(tp, MII_BMCR, ®)) val = reg << 16; if (!tg3_readphy(tp, MII_BMSR, ®)) val |= (reg & 0xffff); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val); + *data++ = val; val = 0; if (!tg3_readphy(tp, MII_ADVERTISE, ®)) val = reg << 16; if (!tg3_readphy(tp, MII_LPA, ®)) val |= (reg & 0xffff); - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val); + *data++ = val; val = 0; if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) { @@ -1488,13 +1479,33 @@ static void tg3_ump_link_report(struct tg3 *tp) if (!tg3_readphy(tp, MII_STAT1000, ®)) val |= (reg & 0xffff); } - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val); + *data++ = val; if (!tg3_readphy(tp, MII_PHYADDR, ®)) val = reg << 16; else val = 0; - tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val); + *data++ = val; +} + +/* tp->lock is held. */ +static void tg3_ump_link_report(struct tg3 *tp) +{ + u32 data[4]; + + if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF)) + return; + + tg3_phy_gather_ump_data(tp, data); + + tg3_wait_for_event_ack(tp); + + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x0, data[0]); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x4, data[1]); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0x8, data[2]); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 0xc, data[3]); tg3_generate_fw_event(tp); } @@ -1809,13 +1820,13 @@ static void tg3_adjust_link(struct net_device *dev) (6 << TX_LENGTHS_IPG_SHIFT) | (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); - if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) || - (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) || + if (phydev->link != tp->old_link || phydev->speed != tp->link_config.active_speed || phydev->duplex != tp->link_config.active_duplex || oldflowctrl != tp->link_config.active_flowctrl) linkmesg = 1; + tp->old_link = phydev->link; tp->link_config.active_speed = phydev->speed; tp->link_config.active_duplex = phydev->duplex; @@ -1884,10 +1895,10 @@ static void tg3_phy_start(struct tg3 *tp) if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER; - phydev->speed = tp->link_config.orig_speed; - phydev->duplex = tp->link_config.orig_duplex; - phydev->autoneg = tp->link_config.orig_autoneg; - phydev->advertising = tp->link_config.orig_advertising; + phydev->speed = tp->link_config.speed; + phydev->duplex = tp->link_config.duplex; + phydev->autoneg = tp->link_config.autoneg; + phydev->advertising = tp->link_config.advertising; } phy_start(phydev); @@ -2709,9 +2720,6 @@ static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed) return 0; } -static int tg3_setup_phy(struct tg3 *, int); -static int tg3_halt_cpu(struct tg3 *, u32); - static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) { u32 val; @@ -2978,6 +2986,259 @@ static int tg3_nvram_read_be32(struct tg3 *tp, u32 offset, __be32 *val) return res; } +static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp, + u32 offset, u32 len, u8 *buf) +{ + int i, j, rc = 0; + u32 val; + + for (i = 0; i < len; i += 4) { + u32 addr; + __be32 data; + + addr = offset + i; + + memcpy(&data, buf + i, 4); + + /* + * The SEEPROM interface expects the data to always be opposite + * the native endian format. We accomplish this by reversing + * all the operations that would have been performed on the + * data from a call to tg3_nvram_read_be32(). + */ + tw32(GRC_EEPROM_DATA, swab32(be32_to_cpu(data))); + + val = tr32(GRC_EEPROM_ADDR); + tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE); + + val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK | + EEPROM_ADDR_READ); + tw32(GRC_EEPROM_ADDR, val | + (0 << EEPROM_ADDR_DEVID_SHIFT) | + (addr & EEPROM_ADDR_ADDR_MASK) | + EEPROM_ADDR_START | + EEPROM_ADDR_WRITE); + + for (j = 0; j < 1000; j++) { + val = tr32(GRC_EEPROM_ADDR); + + if (val & EEPROM_ADDR_COMPLETE) + break; + msleep(1); + } + if (!(val & EEPROM_ADDR_COMPLETE)) { + rc = -EBUSY; + break; + } + } + + return rc; +} + +/* offset and length are dword aligned */ +static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len, + u8 *buf) +{ + int ret = 0; + u32 pagesize = tp->nvram_pagesize; + u32 pagemask = pagesize - 1; + u32 nvram_cmd; + u8 *tmp; + + tmp = kmalloc(pagesize, GFP_KERNEL); + if (tmp == NULL) + return -ENOMEM; + + while (len) { + int j; + u32 phy_addr, page_off, size; + + phy_addr = offset & ~pagemask; + + for (j = 0; j < pagesize; j += 4) { + ret = tg3_nvram_read_be32(tp, phy_addr + j, + (__be32 *) (tmp + j)); + if (ret) + break; + } + if (ret) + break; + + page_off = offset & pagemask; + size = pagesize; + if (len < size) + size = len; + + len -= size; + + memcpy(tmp + page_off, buf, size); + + offset = offset + (pagesize - page_off); + + tg3_enable_nvram_access(tp); + + /* + * Before we can erase the flash page, we need + * to issue a special "write enable" command. + */ + nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE; + + if (tg3_nvram_exec_cmd(tp, nvram_cmd)) + break; + + /* Erase the target page */ + tw32(NVRAM_ADDR, phy_addr); + + nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR | + NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE; + + if (tg3_nvram_exec_cmd(tp, nvram_cmd)) + break; + + /* Issue another write enable to start the write. */ + nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE; + + if (tg3_nvram_exec_cmd(tp, nvram_cmd)) + break; + + for (j = 0; j < pagesize; j += 4) { + __be32 data; + + data = *((__be32 *) (tmp + j)); + + tw32(NVRAM_WRDATA, be32_to_cpu(data)); + + tw32(NVRAM_ADDR, phy_addr + j); + + nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | + NVRAM_CMD_WR; + + if (j == 0) + nvram_cmd |= NVRAM_CMD_FIRST; + else if (j == (pagesize - 4)) + nvram_cmd |= NVRAM_CMD_LAST; + + ret = tg3_nvram_exec_cmd(tp, nvram_cmd); + if (ret) + break; + } + if (ret) + break; + } + + nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE; + tg3_nvram_exec_cmd(tp, nvram_cmd); + + kfree(tmp); + + return ret; +} + +/* offset and length are dword aligned */ +static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, + u8 *buf) +{ + int i, ret = 0; + + for (i = 0; i < len; i += 4, offset += 4) { + u32 page_off, phy_addr, nvram_cmd; + __be32 data; + + memcpy(&data, buf + i, 4); + tw32(NVRAM_WRDATA, be32_to_cpu(data)); + + page_off = offset % tp->nvram_pagesize; + + phy_addr = tg3_nvram_phys_addr(tp, offset); + + nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR; + + if (page_off == 0 || i == 0) + nvram_cmd |= NVRAM_CMD_FIRST; + if (page_off == (tp->nvram_pagesize - 4)) + nvram_cmd |= NVRAM_CMD_LAST; + + if (i == (len - 4)) + nvram_cmd |= NVRAM_CMD_LAST; + + if ((nvram_cmd & NVRAM_CMD_FIRST) || + !tg3_flag(tp, FLASH) || + !tg3_flag(tp, 57765_PLUS)) + tw32(NVRAM_ADDR, phy_addr); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && + !tg3_flag(tp, 5755_PLUS) && + (tp->nvram_jedecnum == JEDEC_ST) && + (nvram_cmd & NVRAM_CMD_FIRST)) { + u32 cmd; + + cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE; + ret = tg3_nvram_exec_cmd(tp, cmd); + if (ret) + break; + } + if (!tg3_flag(tp, FLASH)) { + /* We always do complete word writes to eeprom. */ + nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST); + } + + ret = tg3_nvram_exec_cmd(tp, nvram_cmd); + if (ret) + break; + } + return ret; +} + +/* offset and length are dword aligned */ +static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) +{ + int ret; + + if (tg3_flag(tp, EEPROM_WRITE_PROT)) { + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & + ~GRC_LCLCTRL_GPIO_OUTPUT1); + udelay(40); + } + + if (!tg3_flag(tp, NVRAM)) { + ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf); + } else { + u32 grc_mode; + + ret = tg3_nvram_lock(tp); + if (ret) + return ret; + + tg3_enable_nvram_access(tp); + if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) + tw32(NVRAM_WRITE1, 0x406); + + grc_mode = tr32(GRC_MODE); + tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE); + + if (tg3_flag(tp, NVRAM_BUFFERED) || !tg3_flag(tp, FLASH)) { + ret = tg3_nvram_write_block_buffered(tp, offset, len, + buf); + } else { + ret = tg3_nvram_write_block_unbuffered(tp, offset, len, + buf); + } + + grc_mode = tr32(GRC_MODE); + tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE); + + tg3_disable_nvram_access(tp); + tg3_nvram_unlock(tp); + } + + if (tg3_flag(tp, EEPROM_WRITE_PROT)) { + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); + udelay(40); + } + + return ret; +} + #define RX_CPU_SCRATCH_BASE 0x30000 #define RX_CPU_SCRATCH_SIZE 0x04000 #define TX_CPU_SCRATCH_BASE 0x34000 @@ -3264,6 +3525,8 @@ static int tg3_power_up(struct tg3 *tp) return err; } +static int tg3_setup_phy(struct tg3 *, int); + static int tg3_power_down_prepare(struct tg3 *tp) { u32 misc_host_ctrl; @@ -3302,10 +3565,10 @@ static int tg3_power_down_prepare(struct tg3 *tp) tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER; - tp->link_config.orig_speed = phydev->speed; - tp->link_config.orig_duplex = phydev->duplex; - tp->link_config.orig_autoneg = phydev->autoneg; - tp->link_config.orig_advertising = phydev->advertising; + tp->link_config.speed = phydev->speed; + tp->link_config.duplex = phydev->duplex; + tp->link_config.autoneg = phydev->autoneg; + tp->link_config.advertising = phydev->advertising; advertising = ADVERTISED_TP | ADVERTISED_Pause | @@ -3338,19 +3601,11 @@ static int tg3_power_down_prepare(struct tg3 *tp) } else { do_low_power = true; - if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) { + if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER; - tp->link_config.orig_speed = tp->link_config.speed; - tp->link_config.orig_duplex = tp->link_config.duplex; - tp->link_config.orig_autoneg = tp->link_config.autoneg; - } - if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) { - tp->link_config.speed = SPEED_10; - tp->link_config.duplex = DUPLEX_HALF; - tp->link_config.autoneg = AUTONEG_ENABLE; + if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) tg3_setup_phy(tp, 0); - } } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { @@ -3559,8 +3814,8 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 DUPLEX_HALF; break; } - *speed = SPEED_INVALID; - *duplex = DUPLEX_INVALID; + *speed = SPEED_UNKNOWN; + *duplex = DUPLEX_UNKNOWN; break; } } @@ -3640,51 +3895,33 @@ done: static void tg3_phy_copper_begin(struct tg3 *tp) { - u32 new_adv; - int i; + if (tp->link_config.autoneg == AUTONEG_ENABLE || + (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) { + u32 adv, fc; - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { - new_adv = ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full; - if (tg3_flag(tp, WOL_SPEED_100MB)) - new_adv |= ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full; - - tg3_phy_autoneg_cfg(tp, new_adv, - FLOW_CTRL_TX | FLOW_CTRL_RX); - } else if (tp->link_config.speed == SPEED_INVALID) { - if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) - tp->link_config.advertising &= - ~(ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full); + if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { + adv = ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full; + if (tg3_flag(tp, WOL_SPEED_100MB)) + adv |= ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full; - tg3_phy_autoneg_cfg(tp, tp->link_config.advertising, - tp->link_config.flowctrl); - } else { - /* Asking for a specific link mode. */ - if (tp->link_config.speed == SPEED_1000) { - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv = ADVERTISED_1000baseT_Full; - else - new_adv = ADVERTISED_1000baseT_Half; - } else if (tp->link_config.speed == SPEED_100) { - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv = ADVERTISED_100baseT_Full; - else - new_adv = ADVERTISED_100baseT_Half; + fc = FLOW_CTRL_TX | FLOW_CTRL_RX; } else { - if (tp->link_config.duplex == DUPLEX_FULL) - new_adv = ADVERTISED_10baseT_Full; - else - new_adv = ADVERTISED_10baseT_Half; + adv = tp->link_config.advertising; + if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) + adv &= ~(ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full); + + fc = tp->link_config.flowctrl; } - tg3_phy_autoneg_cfg(tp, new_adv, - tp->link_config.flowctrl); - } + tg3_phy_autoneg_cfg(tp, adv, fc); - if (tp->link_config.autoneg == AUTONEG_DISABLE && - tp->link_config.speed != SPEED_INVALID) { + tg3_writephy(tp, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART); + } else { + int i; u32 bmcr, orig_bmcr; tp->link_config.active_speed = tp->link_config.speed; @@ -3726,9 +3963,6 @@ static void tg3_phy_copper_begin(struct tg3 *tp) tg3_writephy(tp, MII_BMCR, bmcr); udelay(40); } - } else { - tg3_writephy(tp, MII_BMCR, - BMCR_ANENABLE | BMCR_ANRESTART); } } @@ -3778,7 +4012,16 @@ static bool tg3_phy_copper_an_config_ok(struct tg3 *tp, u32 *lcladv) if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl)) return false; - tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL); + if (tgtadv && + (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) { + tgtadv |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; + tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL | + CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER); + } else { + tg3_ctrl &= (ADVERTISE_1000HALF | ADVERTISE_1000FULL); + } + if (tg3_ctrl != tgtadv) return false; } @@ -3909,8 +4152,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) } current_link_up = 0; - current_speed = SPEED_INVALID; - current_duplex = DUPLEX_INVALID; + current_speed = SPEED_UNKNOWN; + current_duplex = DUPLEX_UNKNOWN; tp->phy_flags &= ~TG3_PHYFLG_MDIX_STATE; tp->link_config.rmt_adv = 0; @@ -4806,8 +5049,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) LED_CTRL_LNKLED_OVERRIDE | LED_CTRL_1000MBPS_ON)); } else { - tp->link_config.active_speed = SPEED_INVALID; - tp->link_config.active_duplex = DUPLEX_INVALID; + tp->link_config.active_speed = SPEED_UNKNOWN; + tp->link_config.active_duplex = DUPLEX_UNKNOWN; tw32(MAC_LED_CTRL, (tp->led_ctrl | LED_CTRL_LNKLED_OVERRIDE | LED_CTRL_TRAFFIC_OVERRIDE)); @@ -4855,8 +5098,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) tg3_phy_reset(tp); current_link_up = 0; - current_speed = SPEED_INVALID; - current_duplex = DUPLEX_INVALID; + current_speed = SPEED_UNKNOWN; + current_duplex = DUPLEX_UNKNOWN; tp->link_config.rmt_adv = 0; err |= tg3_readphy(tp, MII_BMSR, &bmsr); @@ -5352,7 +5595,7 @@ static void tg3_tx(struct tg3_napi *tnapi) } } - netdev_completed_queue(tp->dev, pkts_compl, bytes_compl); + netdev_tx_completed_queue(txq, pkts_compl, bytes_compl); tnapi->tx_cons = sw_idx; @@ -5685,6 +5928,9 @@ next_pkt_nopost: /* Refill RX ring(s). */ if (!tg3_flag(tp, ENABLE_RSS)) { + /* Sync BD data before updating mailbox */ + wmb(); + if (work_mask & RXD_OPAQUE_RING_STD) { tpr->rx_std_prod_idx = std_prod_idx & tp->rx_std_ring_mask; @@ -5707,8 +5953,10 @@ next_pkt_nopost: tpr->rx_std_prod_idx = std_prod_idx & tp->rx_std_ring_mask; tpr->rx_jmb_prod_idx = jmb_prod_idx & tp->rx_jmb_ring_mask; - if (tnapi != &tp->napi[1]) + if (tnapi != &tp->napi[1]) { + tp->rx_refill = true; napi_schedule(&tp->napi[1].napi); + } } return received; @@ -5888,6 +6136,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) u32 std_prod_idx = dpr->rx_std_prod_idx; u32 jmb_prod_idx = dpr->rx_jmb_prod_idx; + tp->rx_refill = false; for (i = 1; i < tp->irq_cnt; i++) err |= tg3_rx_prodring_xfer(tp, dpr, &tp->napi[i].prodring); @@ -5921,6 +6170,7 @@ static inline void tg3_reset_task_cancel(struct tg3 *tp) { cancel_work_sync(&tp->reset_task); tg3_flag_clear(tp, RESET_TASK_PENDING); + tg3_flag_clear(tp, TX_RECOVERY_PENDING); } static int tg3_poll_msix(struct napi_struct *napi, int budget) @@ -5950,9 +6200,25 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) /* check for RX/TX work to do */ if (likely(sblk->idx[0].tx_consumer == tnapi->tx_cons && *(tnapi->rx_rcb_prod_idx) == tnapi->rx_rcb_ptr)) { + + /* This test here is not race free, but will reduce + * the number of interrupts by looping again. + */ + if (tnapi == &tp->napi[1] && tp->rx_refill) + continue; + napi_complete(napi); /* Reenable interrupts. */ tw32_mailbox(tnapi->int_mbox, tnapi->last_tag << 24); + + /* This test here is synchronized by napi_schedule() + * and napi_complete() to close the race condition. + */ + if (unlikely(tnapi == &tp->napi[1] && tp->rx_refill)) { + tw32(HOSTCC_MODE, tp->coalesce_mode | + HOSTCC_MODE_ENABLE | + tnapi->coal_now); + } mmiowb(); break; } @@ -6292,33 +6558,6 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id) return IRQ_RETVAL(0); } -static int tg3_init_hw(struct tg3 *, int); -static int tg3_halt(struct tg3 *, int, int); - -/* Restart hardware after configuration changes, self-test, etc. - * Invoked with tp->lock held. - */ -static int tg3_restart_hw(struct tg3 *tp, int reset_phy) - __releases(tp->lock) - __acquires(tp->lock) -{ - int err; - - err = tg3_init_hw(tp, reset_phy); - if (err) { - netdev_err(tp->dev, - "Failed to re-initialize device, aborting\n"); - tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - tg3_full_unlock(tp); - del_timer_sync(&tp->timer); - tp->irq_sync = 0; - tg3_napi_enable(tp); - dev_close(tp->dev); - tg3_full_lock(tp, 0); - } - return err; -} - #ifdef CONFIG_NET_POLL_CONTROLLER static void tg3_poll_controller(struct net_device *dev) { @@ -6330,50 +6569,6 @@ static void tg3_poll_controller(struct net_device *dev) } #endif -static void tg3_reset_task(struct work_struct *work) -{ - struct tg3 *tp = container_of(work, struct tg3, reset_task); - int err; - - tg3_full_lock(tp, 0); - - if (!netif_running(tp->dev)) { - tg3_flag_clear(tp, RESET_TASK_PENDING); - tg3_full_unlock(tp); - return; - } - - tg3_full_unlock(tp); - - tg3_phy_stop(tp); - - tg3_netif_stop(tp); - - tg3_full_lock(tp, 1); - - if (tg3_flag(tp, TX_RECOVERY_PENDING)) { - tp->write32_tx_mbox = tg3_write32_tx_mbox; - tp->write32_rx_mbox = tg3_write_flush_reg32; - tg3_flag_set(tp, MBOX_WRITE_REORDER); - tg3_flag_clear(tp, TX_RECOVERY_PENDING); - } - - tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); - err = tg3_init_hw(tp, 1); - if (err) - goto out; - - tg3_netif_start(tp); - -out: - tg3_full_unlock(tp); - - if (!err) - tg3_phy_start(tp); - - tg3_flag_clear(tp, RESET_TASK_PENDING); -} - static void tg3_tx_timeout(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -6745,7 +6940,6 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0), mss, vlan)) { would_hit_hwbug = 1; - /* Now loop through additional data fragments, and queue them. */ } else if (skb_shinfo(skb)->nr_frags > 0) { u32 tmp_mss = mss; @@ -6754,6 +6948,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) !tg3_flag(tp, HW_TSO_3)) tmp_mss = 0; + /* Now loop through additional data + * fragments, and queue them. + */ last = skb_shinfo(skb)->nr_frags - 1; for (i = 0; i <= last; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; @@ -6793,7 +6990,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } skb_tx_timestamp(skb); - netdev_sent_queue(tp->dev, skb->len); + netdev_tx_sent_queue(txq, skb->len); + + /* Sync BD data before updating mailbox */ + wmb(); /* Packets are ready, update Tx producer idx local and on card. */ tw32_tx_mbox(tnapi->prodmbox, entry); @@ -6993,66 +7193,6 @@ static int tg3_set_features(struct net_device *dev, netdev_features_t features) return 0; } -static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, - int new_mtu) -{ - dev->mtu = new_mtu; - - if (new_mtu > ETH_DATA_LEN) { - if (tg3_flag(tp, 5780_CLASS)) { - netdev_update_features(dev); - tg3_flag_clear(tp, TSO_CAPABLE); - } else { - tg3_flag_set(tp, JUMBO_RING_ENABLE); - } - } else { - if (tg3_flag(tp, 5780_CLASS)) { - tg3_flag_set(tp, TSO_CAPABLE); - netdev_update_features(dev); - } - tg3_flag_clear(tp, JUMBO_RING_ENABLE); - } -} - -static int tg3_change_mtu(struct net_device *dev, int new_mtu) -{ - struct tg3 *tp = netdev_priv(dev); - int err; - - if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp)) - return -EINVAL; - - if (!netif_running(dev)) { - /* We'll just catch it later when the - * device is up'd. - */ - tg3_set_mtu(dev, tp, new_mtu); - return 0; - } - - tg3_phy_stop(tp); - - tg3_netif_stop(tp); - - tg3_full_lock(tp, 1); - - tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - - tg3_set_mtu(dev, tp, new_mtu); - - err = tg3_restart_hw(tp, 0); - - if (!err) - tg3_netif_start(tp); - - tg3_full_unlock(tp); - - if (!err) - tg3_phy_start(tp); - - return err; -} - static void tg3_rx_prodring_free(struct tg3 *tp, struct tg3_rx_prodring_set *tpr) { @@ -7275,8 +7415,8 @@ static void tg3_free_rings(struct tg3 *tp) dev_kfree_skb_any(skb); } + netdev_tx_reset_queue(netdev_get_tx_queue(tp->dev, j)); } - netdev_reset_queue(tp->dev); } /* Initialize tx/rx rings for packet processing. @@ -7886,10 +8026,8 @@ static int tg3_chip_reset(struct tg3 *tp) return 0; } -static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *, - struct rtnl_link_stats64 *); -static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *, - struct tg3_ethtool_stats *); +static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *); +static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *); /* tp->lock is held. */ static int tg3_halt(struct tg3 *tp, int kind, int silent) @@ -7910,7 +8048,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent) if (tp->hw_stats) { /* Save the stats across chip resets... */ - tg3_get_stats64(tp->dev, &tp->net_stats_prev), + tg3_get_nstats(tp, &tp->net_stats_prev); tg3_get_estats(tp, &tp->estats_prev); /* And make sure the next sample is new data */ @@ -7930,7 +8068,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) int err = 0, skip_mac_1 = 0; if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; + return -EADDRNOTAVAIL; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); @@ -7978,7 +8116,6 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr, nic_addr); } -static void __tg3_set_rx_mode(struct net_device *); static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) { int i; @@ -8215,6 +8352,93 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp) tw32(JMB_REPLENISH_LWM, bdcache_maxcnt); } +static inline u32 calc_crc(unsigned char *buf, int len) +{ + u32 reg; + u32 tmp; + int j, k; + + reg = 0xffffffff; + + for (j = 0; j < len; j++) { + reg ^= buf[j]; + + for (k = 0; k < 8; k++) { + tmp = reg & 0x01; + + reg >>= 1; + + if (tmp) + reg ^= 0xedb88320; + } + } + + return ~reg; +} + +static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all) +{ + /* accept or reject all multicast frames */ + tw32(MAC_HASH_REG_0, accept_all ? 0xffffffff : 0); + tw32(MAC_HASH_REG_1, accept_all ? 0xffffffff : 0); + tw32(MAC_HASH_REG_2, accept_all ? 0xffffffff : 0); + tw32(MAC_HASH_REG_3, accept_all ? 0xffffffff : 0); +} + +static void __tg3_set_rx_mode(struct net_device *dev) +{ + struct tg3 *tp = netdev_priv(dev); + u32 rx_mode; + + rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC | + RX_MODE_KEEP_VLAN_TAG); + +#if !defined(CONFIG_VLAN_8021Q) && !defined(CONFIG_VLAN_8021Q_MODULE) + /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG + * flag clear. + */ + if (!tg3_flag(tp, ENABLE_ASF)) + rx_mode |= RX_MODE_KEEP_VLAN_TAG; +#endif + + if (dev->flags & IFF_PROMISC) { + /* Promiscuous mode. */ + rx_mode |= RX_MODE_PROMISC; + } else if (dev->flags & IFF_ALLMULTI) { + /* Accept all multicast. */ + tg3_set_multi(tp, 1); + } else if (netdev_mc_empty(dev)) { + /* Reject all multicast. */ + tg3_set_multi(tp, 0); + } else { + /* Accept one or more multicast(s). */ + struct netdev_hw_addr *ha; + u32 mc_filter[4] = { 0, }; + u32 regidx; + u32 bit; + u32 crc; + + netdev_for_each_mc_addr(ha, dev) { + crc = calc_crc(ha->addr, ETH_ALEN); + bit = ~crc & 0x7f; + regidx = (bit & 0x60) >> 5; + bit &= 0x1f; + mc_filter[regidx] |= (1 << bit); + } + + tw32(MAC_HASH_REG_0, mc_filter[0]); + tw32(MAC_HASH_REG_1, mc_filter[1]); + tw32(MAC_HASH_REG_2, mc_filter[2]); + tw32(MAC_HASH_REG_3, mc_filter[3]); + } + + if (rx_mode != tp->rx_mode) { + tp->rx_mode = rx_mode; + tw32_f(MAC_RX_MODE, rx_mode); + udelay(10); + } +} + static void tg3_rss_init_dflt_indir_tbl(struct tg3 *tp) { int i; @@ -8690,9 +8914,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (tg3_flag(tp, PCI_EXPRESS)) rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766) - rdmac_mode |= RDMAC_MODE_JMB_2K_MMRR; - if (tg3_flag(tp, HW_TSO_1) || tg3_flag(tp, HW_TSO_2) || tg3_flag(tp, HW_TSO_3)) @@ -9039,12 +9260,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } if (!tg3_flag(tp, USE_PHYLIB)) { - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { + if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER; - tp->link_config.speed = tp->link_config.orig_speed; - tp->link_config.duplex = tp->link_config.orig_duplex; - tp->link_config.autoneg = tp->link_config.orig_autoneg; - } err = tg3_setup_phy(tp, 0); if (err) @@ -9347,6 +9564,108 @@ restart_timer: add_timer(&tp->timer); } +static void __devinit tg3_timer_init(struct tg3 *tp) +{ + if (tg3_flag(tp, TAGGED_STATUS) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + !tg3_flag(tp, 57765_CLASS)) + tp->timer_offset = HZ; + else + tp->timer_offset = HZ / 10; + + BUG_ON(tp->timer_offset > HZ); + + tp->timer_multiplier = (HZ / tp->timer_offset); + tp->asf_multiplier = (HZ / tp->timer_offset) * + TG3_FW_UPDATE_FREQ_SEC; + + init_timer(&tp->timer); + tp->timer.data = (unsigned long) tp; + tp->timer.function = tg3_timer; +} + +static void tg3_timer_start(struct tg3 *tp) +{ + tp->asf_counter = tp->asf_multiplier; + tp->timer_counter = tp->timer_multiplier; + + tp->timer.expires = jiffies + tp->timer_offset; + add_timer(&tp->timer); +} + +static void tg3_timer_stop(struct tg3 *tp) +{ + del_timer_sync(&tp->timer); +} + +/* Restart hardware after configuration changes, self-test, etc. + * Invoked with tp->lock held. + */ +static int tg3_restart_hw(struct tg3 *tp, int reset_phy) + __releases(tp->lock) + __acquires(tp->lock) +{ + int err; + + err = tg3_init_hw(tp, reset_phy); + if (err) { + netdev_err(tp->dev, + "Failed to re-initialize device, aborting\n"); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + tg3_full_unlock(tp); + tg3_timer_stop(tp); + tp->irq_sync = 0; + tg3_napi_enable(tp); + dev_close(tp->dev); + tg3_full_lock(tp, 0); + } + return err; +} + +static void tg3_reset_task(struct work_struct *work) +{ + struct tg3 *tp = container_of(work, struct tg3, reset_task); + int err; + + tg3_full_lock(tp, 0); + + if (!netif_running(tp->dev)) { + tg3_flag_clear(tp, RESET_TASK_PENDING); + tg3_full_unlock(tp); + return; + } + + tg3_full_unlock(tp); + + tg3_phy_stop(tp); + + tg3_netif_stop(tp); + + tg3_full_lock(tp, 1); + + if (tg3_flag(tp, TX_RECOVERY_PENDING)) { + tp->write32_tx_mbox = tg3_write32_tx_mbox; + tp->write32_rx_mbox = tg3_write_flush_reg32; + tg3_flag_set(tp, MBOX_WRITE_REORDER); + tg3_flag_clear(tp, TX_RECOVERY_PENDING); + } + + tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); + err = tg3_init_hw(tp, 1); + if (err) + goto out; + + tg3_netif_start(tp); + +out: + tg3_full_unlock(tp); + + if (!err) + tg3_phy_start(tp); + + tg3_flag_clear(tp, RESET_TASK_PENDING); +} + static int tg3_request_irq(struct tg3 *tp, int irq_num) { irq_handler_t fn; @@ -9401,7 +9720,7 @@ static int tg3_test_interrupt(struct tg3 *tp) } err = request_irq(tnapi->irq_vec, tg3_test_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, tnapi); + IRQF_SHARED, dev->name, tnapi); if (err) return err; @@ -9712,24 +10031,6 @@ static int tg3_open(struct net_device *dev) if (err) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); - } else { - if (tg3_flag(tp, TAGGED_STATUS) && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && - !tg3_flag(tp, 57765_CLASS)) - tp->timer_offset = HZ; - else - tp->timer_offset = HZ / 10; - - BUG_ON(tp->timer_offset > HZ); - tp->timer_counter = tp->timer_multiplier = - (HZ / tp->timer_offset); - tp->asf_counter = tp->asf_multiplier = - ((HZ / tp->timer_offset) * 2); - - init_timer(&tp->timer); - tp->timer.expires = jiffies + tp->timer_offset; - tp->timer.data = (unsigned long) tp; - tp->timer.function = tg3_timer; } tg3_full_unlock(tp); @@ -9761,7 +10062,7 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); - add_timer(&tp->timer); + tg3_timer_start(tp); tg3_flag_set(tp, INIT_COMPLETE); tg3_enable_ints(tp); @@ -9806,7 +10107,7 @@ static int tg3_close(struct net_device *dev) netif_tx_stop_all_queues(dev); - del_timer_sync(&tp->timer); + tg3_timer_stop(tp); tg3_phy_stop(tp); @@ -9847,7 +10148,7 @@ static inline u64 get_stat64(tg3_stat64_t *val) return ((u64)val->high << 32) | ((u64)val->low); } -static u64 calc_crc_errors(struct tg3 *tp) +static u64 tg3_calc_crc_errors(struct tg3 *tp) { struct tg3_hw_stats *hw_stats = tp->hw_stats; @@ -9856,14 +10157,12 @@ static u64 calc_crc_errors(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { u32 val; - spin_lock_bh(&tp->lock); if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) { tg3_writephy(tp, MII_TG3_TEST1, val | MII_TG3_TEST1_CRC_EN); tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &val); } else val = 0; - spin_unlock_bh(&tp->lock); tp->phy_crc_errors += val; @@ -9877,15 +10176,11 @@ static u64 calc_crc_errors(struct tg3 *tp) estats->member = old_estats->member + \ get_stat64(&hw_stats->member) -static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp, - struct tg3_ethtool_stats *estats) +static void tg3_get_estats(struct tg3 *tp, struct tg3_ethtool_stats *estats) { struct tg3_ethtool_stats *old_estats = &tp->estats_prev; struct tg3_hw_stats *hw_stats = tp->hw_stats; - if (!hw_stats) - return old_estats; - ESTAT_ADD(rx_octets); ESTAT_ADD(rx_fragments); ESTAT_ADD(rx_ucast_packets); @@ -9963,20 +10258,13 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp, ESTAT_ADD(nic_tx_threshold_hit); ESTAT_ADD(mbuf_lwm_thresh_hit); - - return estats; } -static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *stats) +static void tg3_get_nstats(struct tg3 *tp, struct rtnl_link_stats64 *stats) { - struct tg3 *tp = netdev_priv(dev); struct rtnl_link_stats64 *old_stats = &tp->net_stats_prev; struct tg3_hw_stats *hw_stats = tp->hw_stats; - if (!hw_stats) - return old_stats; - stats->rx_packets = old_stats->rx_packets + get_stat64(&hw_stats->rx_ucast_packets) + get_stat64(&hw_stats->rx_mcast_packets) + @@ -10019,114 +10307,13 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, get_stat64(&hw_stats->tx_carrier_sense_errors); stats->rx_crc_errors = old_stats->rx_crc_errors + - calc_crc_errors(tp); + tg3_calc_crc_errors(tp); stats->rx_missed_errors = old_stats->rx_missed_errors + get_stat64(&hw_stats->rx_discards); stats->rx_dropped = tp->rx_dropped; stats->tx_dropped = tp->tx_dropped; - - return stats; -} - -static inline u32 calc_crc(unsigned char *buf, int len) -{ - u32 reg; - u32 tmp; - int j, k; - - reg = 0xffffffff; - - for (j = 0; j < len; j++) { - reg ^= buf[j]; - - for (k = 0; k < 8; k++) { - tmp = reg & 0x01; - - reg >>= 1; - - if (tmp) - reg ^= 0xedb88320; - } - } - - return ~reg; -} - -static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all) -{ - /* accept or reject all multicast frames */ - tw32(MAC_HASH_REG_0, accept_all ? 0xffffffff : 0); - tw32(MAC_HASH_REG_1, accept_all ? 0xffffffff : 0); - tw32(MAC_HASH_REG_2, accept_all ? 0xffffffff : 0); - tw32(MAC_HASH_REG_3, accept_all ? 0xffffffff : 0); -} - -static void __tg3_set_rx_mode(struct net_device *dev) -{ - struct tg3 *tp = netdev_priv(dev); - u32 rx_mode; - - rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC | - RX_MODE_KEEP_VLAN_TAG); - -#if !defined(CONFIG_VLAN_8021Q) && !defined(CONFIG_VLAN_8021Q_MODULE) - /* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG - * flag clear. - */ - if (!tg3_flag(tp, ENABLE_ASF)) - rx_mode |= RX_MODE_KEEP_VLAN_TAG; -#endif - - if (dev->flags & IFF_PROMISC) { - /* Promiscuous mode. */ - rx_mode |= RX_MODE_PROMISC; - } else if (dev->flags & IFF_ALLMULTI) { - /* Accept all multicast. */ - tg3_set_multi(tp, 1); - } else if (netdev_mc_empty(dev)) { - /* Reject all multicast. */ - tg3_set_multi(tp, 0); - } else { - /* Accept one or more multicast(s). */ - struct netdev_hw_addr *ha; - u32 mc_filter[4] = { 0, }; - u32 regidx; - u32 bit; - u32 crc; - - netdev_for_each_mc_addr(ha, dev) { - crc = calc_crc(ha->addr, ETH_ALEN); - bit = ~crc & 0x7f; - regidx = (bit & 0x60) >> 5; - bit &= 0x1f; - mc_filter[regidx] |= (1 << bit); - } - - tw32(MAC_HASH_REG_0, mc_filter[0]); - tw32(MAC_HASH_REG_1, mc_filter[1]); - tw32(MAC_HASH_REG_2, mc_filter[2]); - tw32(MAC_HASH_REG_3, mc_filter[3]); - } - - if (rx_mode != tp->rx_mode) { - tp->rx_mode = rx_mode; - tw32_f(MAC_RX_MODE, rx_mode); - udelay(10); - } -} - -static void tg3_set_rx_mode(struct net_device *dev) -{ - struct tg3 *tp = netdev_priv(dev); - - if (!netif_running(dev)) - return; - - tg3_full_lock(tp, 0); - __tg3_set_rx_mode(dev); - tg3_full_unlock(tp); } static int tg3_get_regs_len(struct net_device *dev) @@ -10223,8 +10410,6 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, return 0; } -static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf); - static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct tg3 *tp = netdev_priv(dev); @@ -10338,8 +10523,8 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->eth_tp_mdix = ETH_TP_MDI; } } else { - ethtool_cmd_speed_set(cmd, SPEED_INVALID); - cmd->duplex = DUPLEX_INVALID; + ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); + cmd->duplex = DUPLEX_UNKNOWN; cmd->eth_tp_mdix = ETH_TP_MDI_INVALID; } cmd->phy_address = tp->phy_addr; @@ -10421,18 +10606,14 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (cmd->autoneg == AUTONEG_ENABLE) { tp->link_config.advertising = (cmd->advertising | ADVERTISED_Autoneg); - tp->link_config.speed = SPEED_INVALID; - tp->link_config.duplex = DUPLEX_INVALID; + tp->link_config.speed = SPEED_UNKNOWN; + tp->link_config.duplex = DUPLEX_UNKNOWN; } else { tp->link_config.advertising = 0; tp->link_config.speed = speed; tp->link_config.duplex = cmd->duplex; } - tp->link_config.orig_speed = tp->link_config.speed; - tp->link_config.orig_duplex = tp->link_config.duplex; - tp->link_config.orig_autoneg = tp->link_config.autoneg; - if (netif_running(dev)) tg3_setup_phy(tp, 1); @@ -10679,10 +10860,10 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam if (!epause->autoneg) tg3_setup_flow_control(tp, 0, 0); } else { - tp->link_config.orig_advertising &= + tp->link_config.advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); - tp->link_config.orig_advertising |= newadv; + tp->link_config.advertising |= newadv; } } else { int irq_sync = 0; @@ -10859,7 +11040,10 @@ static void tg3_get_ethtool_stats(struct net_device *dev, { struct tg3 *tp = netdev_priv(dev); - tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats); + if (tp->hw_stats) + tg3_get_estats(tp, (struct tg3_ethtool_stats *)tmp_stats); + else + memset(tmp_stats, 0, sizeof(struct tg3_ethtool_stats)); } static __be32 *tg3_vpd_readblock(struct tg3 *tp, u32 *vpdlen) @@ -11568,6 +11752,10 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback) } else { num_pkts = 1; data_off = ETH_HLEN; + + if (tg3_flag(tp, USE_JUMBO_BDFLAG) && + tx_len > VLAN_ETH_FRAME_LEN) + base_flags |= TXD_FLAG_JMB_PKT; } for (i = data_off; i < tx_len; i++) @@ -11600,6 +11788,9 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback) tnapi->tx_prod++; + /* Sync BD data before updating mailbox */ + wmb(); + tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod); tr32_mailbox(tnapi->prodmbox); @@ -11698,6 +11889,10 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk) { int err = -EIO; u32 eee_cap; + u32 jmb_pkt_sz = 9000; + + if (tp->dma_limit) + jmb_pkt_sz = tp->dma_limit - ETH_HLEN; eee_cap = tp->phy_flags & TG3_PHYFLG_EEE_CAP; tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP; @@ -11741,7 +11936,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk) data[0] |= TG3_STD_LOOPBACK_FAILED; if (tg3_flag(tp, JUMBO_RING_ENABLE) && - tg3_run_loopback(tp, 9000 + ETH_HLEN, false)) + tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false)) data[0] |= TG3_JMB_LOOPBACK_FAILED; tg3_mac_loopback(tp, false); @@ -11766,7 +11961,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk) tg3_run_loopback(tp, ETH_FRAME_LEN, true)) data[1] |= TG3_TSO_LOOPBACK_FAILED; if (tg3_flag(tp, JUMBO_RING_ENABLE) && - tg3_run_loopback(tp, 9000 + ETH_HLEN, false)) + tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false)) data[1] |= TG3_JMB_LOOPBACK_FAILED; if (do_extlpbk) { @@ -11784,7 +11979,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk) tg3_run_loopback(tp, ETH_FRAME_LEN, true)) data[2] |= TG3_TSO_LOOPBACK_FAILED; if (tg3_flag(tp, JUMBO_RING_ENABLE) && - tg3_run_loopback(tp, 9000 + ETH_HLEN, false)) + tg3_run_loopback(tp, jmb_pkt_sz + ETH_HLEN, false)) data[2] |= TG3_JMB_LOOPBACK_FAILED; } @@ -12040,6 +12235,117 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_rxfh_indir = tg3_set_rxfh_indir, }; +static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + struct tg3 *tp = netdev_priv(dev); + + if (!tp->hw_stats) + return &tp->net_stats_prev; + + spin_lock_bh(&tp->lock); + tg3_get_nstats(tp, stats); + spin_unlock_bh(&tp->lock); + + return stats; +} + +static void tg3_set_rx_mode(struct net_device *dev) +{ + struct tg3 *tp = netdev_priv(dev); + + if (!netif_running(dev)) + return; + + tg3_full_lock(tp, 0); + __tg3_set_rx_mode(dev); + tg3_full_unlock(tp); +} + +static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, + int new_mtu) +{ + dev->mtu = new_mtu; + + if (new_mtu > ETH_DATA_LEN) { + if (tg3_flag(tp, 5780_CLASS)) { + netdev_update_features(dev); + tg3_flag_clear(tp, TSO_CAPABLE); + } else { + tg3_flag_set(tp, JUMBO_RING_ENABLE); + } + } else { + if (tg3_flag(tp, 5780_CLASS)) { + tg3_flag_set(tp, TSO_CAPABLE); + netdev_update_features(dev); + } + tg3_flag_clear(tp, JUMBO_RING_ENABLE); + } +} + +static int tg3_change_mtu(struct net_device *dev, int new_mtu) +{ + struct tg3 *tp = netdev_priv(dev); + int err, reset_phy = 0; + + if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp)) + return -EINVAL; + + if (!netif_running(dev)) { + /* We'll just catch it later when the + * device is up'd. + */ + tg3_set_mtu(dev, tp, new_mtu); + return 0; + } + + tg3_phy_stop(tp); + + tg3_netif_stop(tp); + + tg3_full_lock(tp, 1); + + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + + tg3_set_mtu(dev, tp, new_mtu); + + /* Reset PHY, otherwise the read DMA engine will be in a mode that + * breaks all requests to 256 bytes. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766) + reset_phy = 1; + + err = tg3_restart_hw(tp, reset_phy); + + if (!err) + tg3_netif_start(tp); + + tg3_full_unlock(tp); + + if (!err) + tg3_phy_start(tp); + + return err; +} + +static const struct net_device_ops tg3_netdev_ops = { + .ndo_open = tg3_open, + .ndo_stop = tg3_close, + .ndo_start_xmit = tg3_start_xmit, + .ndo_get_stats64 = tg3_get_stats64, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_rx_mode = tg3_set_rx_mode, + .ndo_set_mac_address = tg3_set_mac_addr, + .ndo_do_ioctl = tg3_ioctl, + .ndo_tx_timeout = tg3_tx_timeout, + .ndo_change_mtu = tg3_change_mtu, + .ndo_fix_features = tg3_fix_features, + .ndo_set_features = tg3_set_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tg3_poll_controller, +#endif +}; + static void __devinit tg3_get_eeprom_size(struct tg3 *tp) { u32 cursize, val, magic; @@ -12731,254 +13037,6 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) } } -static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp, - u32 offset, u32 len, u8 *buf) -{ - int i, j, rc = 0; - u32 val; - - for (i = 0; i < len; i += 4) { - u32 addr; - __be32 data; - - addr = offset + i; - - memcpy(&data, buf + i, 4); - - /* - * The SEEPROM interface expects the data to always be opposite - * the native endian format. We accomplish this by reversing - * all the operations that would have been performed on the - * data from a call to tg3_nvram_read_be32(). - */ - tw32(GRC_EEPROM_DATA, swab32(be32_to_cpu(data))); - - val = tr32(GRC_EEPROM_ADDR); - tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE); - - val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK | - EEPROM_ADDR_READ); - tw32(GRC_EEPROM_ADDR, val | - (0 << EEPROM_ADDR_DEVID_SHIFT) | - (addr & EEPROM_ADDR_ADDR_MASK) | - EEPROM_ADDR_START | - EEPROM_ADDR_WRITE); - - for (j = 0; j < 1000; j++) { - val = tr32(GRC_EEPROM_ADDR); - - if (val & EEPROM_ADDR_COMPLETE) - break; - msleep(1); - } - if (!(val & EEPROM_ADDR_COMPLETE)) { - rc = -EBUSY; - break; - } - } - - return rc; -} - -/* offset and length are dword aligned */ -static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len, - u8 *buf) -{ - int ret = 0; - u32 pagesize = tp->nvram_pagesize; - u32 pagemask = pagesize - 1; - u32 nvram_cmd; - u8 *tmp; - - tmp = kmalloc(pagesize, GFP_KERNEL); - if (tmp == NULL) - return -ENOMEM; - - while (len) { - int j; - u32 phy_addr, page_off, size; - - phy_addr = offset & ~pagemask; - - for (j = 0; j < pagesize; j += 4) { - ret = tg3_nvram_read_be32(tp, phy_addr + j, - (__be32 *) (tmp + j)); - if (ret) - break; - } - if (ret) - break; - - page_off = offset & pagemask; - size = pagesize; - if (len < size) - size = len; - - len -= size; - - memcpy(tmp + page_off, buf, size); - - offset = offset + (pagesize - page_off); - - tg3_enable_nvram_access(tp); - - /* - * Before we can erase the flash page, we need - * to issue a special "write enable" command. - */ - nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE; - - if (tg3_nvram_exec_cmd(tp, nvram_cmd)) - break; - - /* Erase the target page */ - tw32(NVRAM_ADDR, phy_addr); - - nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR | - NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE; - - if (tg3_nvram_exec_cmd(tp, nvram_cmd)) - break; - - /* Issue another write enable to start the write. */ - nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE; - - if (tg3_nvram_exec_cmd(tp, nvram_cmd)) - break; - - for (j = 0; j < pagesize; j += 4) { - __be32 data; - - data = *((__be32 *) (tmp + j)); - - tw32(NVRAM_WRDATA, be32_to_cpu(data)); - - tw32(NVRAM_ADDR, phy_addr + j); - - nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | - NVRAM_CMD_WR; - - if (j == 0) - nvram_cmd |= NVRAM_CMD_FIRST; - else if (j == (pagesize - 4)) - nvram_cmd |= NVRAM_CMD_LAST; - - if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd))) - break; - } - if (ret) - break; - } - - nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE; - tg3_nvram_exec_cmd(tp, nvram_cmd); - - kfree(tmp); - - return ret; -} - -/* offset and length are dword aligned */ -static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, - u8 *buf) -{ - int i, ret = 0; - - for (i = 0; i < len; i += 4, offset += 4) { - u32 page_off, phy_addr, nvram_cmd; - __be32 data; - - memcpy(&data, buf + i, 4); - tw32(NVRAM_WRDATA, be32_to_cpu(data)); - - page_off = offset % tp->nvram_pagesize; - - phy_addr = tg3_nvram_phys_addr(tp, offset); - - tw32(NVRAM_ADDR, phy_addr); - - nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR; - - if (page_off == 0 || i == 0) - nvram_cmd |= NVRAM_CMD_FIRST; - if (page_off == (tp->nvram_pagesize - 4)) - nvram_cmd |= NVRAM_CMD_LAST; - - if (i == (len - 4)) - nvram_cmd |= NVRAM_CMD_LAST; - - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && - !tg3_flag(tp, 5755_PLUS) && - (tp->nvram_jedecnum == JEDEC_ST) && - (nvram_cmd & NVRAM_CMD_FIRST)) { - - if ((ret = tg3_nvram_exec_cmd(tp, - NVRAM_CMD_WREN | NVRAM_CMD_GO | - NVRAM_CMD_DONE))) - - break; - } - if (!tg3_flag(tp, FLASH)) { - /* We always do complete word writes to eeprom. */ - nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST); - } - - if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd))) - break; - } - return ret; -} - -/* offset and length are dword aligned */ -static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) -{ - int ret; - - if (tg3_flag(tp, EEPROM_WRITE_PROT)) { - tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl & - ~GRC_LCLCTRL_GPIO_OUTPUT1); - udelay(40); - } - - if (!tg3_flag(tp, NVRAM)) { - ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf); - } else { - u32 grc_mode; - - ret = tg3_nvram_lock(tp); - if (ret) - return ret; - - tg3_enable_nvram_access(tp); - if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) - tw32(NVRAM_WRITE1, 0x406); - - grc_mode = tr32(GRC_MODE); - tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE); - - if (tg3_flag(tp, NVRAM_BUFFERED) || !tg3_flag(tp, FLASH)) { - ret = tg3_nvram_write_block_buffered(tp, offset, len, - buf); - } else { - ret = tg3_nvram_write_block_unbuffered(tp, offset, len, - buf); - } - - grc_mode = tr32(GRC_MODE); - tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE); - - tg3_disable_nvram_access(tp); - tg3_nvram_unlock(tp); - } - - if (tg3_flag(tp, EEPROM_WRITE_PROT)) { - tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); - udelay(40); - } - - return ret; -} - struct subsys_tbl_ent { u16 subsys_vendor, subsys_devid; u32 phy_id; @@ -13329,14 +13387,13 @@ static void __devinit tg3_phy_init_link_config(struct tg3 *tp) adv |= ADVERTISED_FIBRE; tp->link_config.advertising = adv; - tp->link_config.speed = SPEED_INVALID; - tp->link_config.duplex = DUPLEX_INVALID; + tp->link_config.speed = SPEED_UNKNOWN; + tp->link_config.duplex = DUPLEX_UNKNOWN; tp->link_config.autoneg = AUTONEG_ENABLE; - tp->link_config.active_speed = SPEED_INVALID; - tp->link_config.active_duplex = DUPLEX_INVALID; - tp->link_config.orig_speed = SPEED_INVALID; - tp->link_config.orig_duplex = DUPLEX_INVALID; - tp->link_config.orig_autoneg = AUTONEG_INVALID; + tp->link_config.active_speed = SPEED_UNKNOWN; + tp->link_config.active_duplex = DUPLEX_UNKNOWN; + + tp->old_link = -1; } static int __devinit tg3_phy_probe(struct tg3 *tp) @@ -13833,8 +13890,6 @@ done: tp->fw_ver[TG3_VER_SIZE - 1] = 0; } -static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); - static inline u32 tg3_rx_ret_ring_size(struct tg3 *tp) { if (tg3_flag(tp, LRG_PROD_RING_CAP)) @@ -13852,49 +13907,50 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_write_reorder_chipsets) = { { }, }; -static int __devinit tg3_get_invariants(struct tg3 *tp) +static struct pci_dev * __devinit tg3_find_peer(struct tg3 *tp) { - u32 misc_ctrl_reg; - u32 pci_state_reg, grc_misc_cfg; - u32 val; - u16 pci_cmd; - int err; + struct pci_dev *peer; + unsigned int func, devnr = tp->pdev->devfn & ~7; - /* 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 - * to match the cacheline size. The Broadcom driver have this - * workaround but turns MWI off all the times so never uses - * it. This seems to suggest that the workaround is insufficient. + for (func = 0; func < 8; func++) { + peer = pci_get_slot(tp->pdev->bus, devnr | func); + if (peer && peer != tp->pdev) + break; + pci_dev_put(peer); + } + /* 5704 can be configured in single-port mode, set peer to + * tp->pdev in that case. */ - pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd); - pci_cmd &= ~PCI_COMMAND_INVALIDATE; - pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); + if (!peer) { + peer = tp->pdev; + return peer; + } - /* Important! -- Make sure register accesses are byteswapped - * correctly. Also, for those chips that require it, make - * sure that indirect register accesses are enabled before - * the first operation. + /* + * We don't need to keep the refcount elevated; there's no way + * to remove one half of this device without removing the other */ - pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, - &misc_ctrl_reg); - tp->misc_host_ctrl |= (misc_ctrl_reg & - MISC_HOST_CTRL_CHIPREV); - pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, - tp->misc_host_ctrl); + pci_dev_put(peer); + + return peer; +} - tp->pci_chip_rev_id = (misc_ctrl_reg >> - MISC_HOST_CTRL_CHIPREV_SHIFT); +static void __devinit tg3_detect_asic_rev(struct tg3 *tp, u32 misc_ctrl_reg) +{ + tp->pci_chip_rev_id = misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) { - u32 prod_id_asic_rev; + u32 reg; + + /* All devices that use the alternate + * ASIC REV location have a CPMU. + */ + tg3_flag_set(tp, CPMU_PRESENT); if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720) - pci_read_config_dword(tp->pdev, - TG3PCI_GEN2_PRODID_ASICREV, - &prod_id_asic_rev); + reg = TG3PCI_GEN2_PRODID_ASICREV; else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 || @@ -13905,14 +13961,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev->device == TG3PCI_DEVICE_TIGON3_57766 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_57782 || tp->pdev->device == TG3PCI_DEVICE_TIGON3_57786) - pci_read_config_dword(tp->pdev, - TG3PCI_GEN15_PRODID_ASICREV, - &prod_id_asic_rev); + reg = TG3PCI_GEN15_PRODID_ASICREV; else - pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, - &prod_id_asic_rev); + reg = TG3PCI_PRODID_ASICREV; - tp->pci_chip_rev_id = prod_id_asic_rev; + pci_read_config_dword(tp->pdev, reg, &tp->pci_chip_rev_id); } /* Wrong chip ID in 5752 A0. This code can be removed later @@ -13921,6 +13974,77 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW) tp->pci_chip_rev_id = CHIPREV_ID_5752_A0; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) + tg3_flag_set(tp, 5717_PLUS); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766) + tg3_flag_set(tp, 57765_CLASS); + + if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS)) + tg3_flag_set(tp, 57765_PLUS); + + /* Intentionally exclude ASIC_REV_5906 */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + tg3_flag(tp, 57765_PLUS)) + tg3_flag_set(tp, 5755_PLUS); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) + tg3_flag_set(tp, 5780_CLASS); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || + tg3_flag(tp, 5755_PLUS) || + tg3_flag(tp, 5780_CLASS)) + tg3_flag_set(tp, 5750_PLUS); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || + tg3_flag(tp, 5750_PLUS)) + tg3_flag_set(tp, 5705_PLUS); +} + +static int __devinit tg3_get_invariants(struct tg3 *tp) +{ + u32 misc_ctrl_reg; + u32 pci_state_reg, grc_misc_cfg; + u32 val; + u16 pci_cmd; + int err; + + /* 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 + * to match the cacheline size. The Broadcom driver have this + * workaround but turns MWI off all the times so never uses + * it. This seems to suggest that the workaround is insufficient. + */ + pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd); + pci_cmd &= ~PCI_COMMAND_INVALIDATE; + pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); + + /* Important! -- Make sure register accesses are byteswapped + * correctly. Also, for those chips that require it, make + * sure that indirect register accesses are enabled before + * the first operation. + */ + pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + &misc_ctrl_reg); + tp->misc_host_ctrl |= (misc_ctrl_reg & + MISC_HOST_CTRL_CHIPREV); + pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); + + tg3_detect_asic_rev(tp, misc_ctrl_reg); + /* If we have 5702/03 A1 or A2 on certain ICH chipsets, * we need to disable memory and use config. cycles * only to access all registers. The 5702/03 chips @@ -14017,9 +14141,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) * Any tg3 device found behind the bridge will also need the 40-bit * DMA workaround. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { - tg3_flag_set(tp, 5780_CLASS); + if (tg3_flag(tp, 5780_CLASS)) { tg3_flag_set(tp, 40BIT_DMA_BUG); tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); } else { @@ -14045,39 +14167,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) tp->pdev_peer = tg3_find_peer(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) - tg3_flag_set(tp, 5717_PLUS); - - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766) - tg3_flag_set(tp, 57765_CLASS); - - if (tg3_flag(tp, 57765_CLASS) || tg3_flag(tp, 5717_PLUS)) - tg3_flag_set(tp, 57765_PLUS); - - /* Intentionally exclude ASIC_REV_5906 */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - tg3_flag(tp, 57765_PLUS)) - tg3_flag_set(tp, 5755_PLUS); - - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || - tg3_flag(tp, 5755_PLUS) || - tg3_flag(tp, 5780_CLASS)) - tg3_flag_set(tp, 5750_PLUS); - - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 || - tg3_flag(tp, 5750_PLUS)) - tg3_flag_set(tp, 5705_PLUS); - /* Determine TSO capabilities */ if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) ; /* Do nothing. HW bug. */ @@ -14149,8 +14238,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) tp->dma_limit = TG3_TX_BD_DMA_MAX_4K; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766) - tp->dma_limit = TG3_TX_BD_DMA_MAX_2K; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || @@ -14174,12 +14261,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_flag_set(tp, PCI_EXPRESS); - if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0) { - int readrq = pcie_get_readrq(tp->pdev); - if (readrq > 2048) - pcie_set_readrq(tp->pdev, 2048); - } - pci_read_config_word(tp->pdev, pci_pcie_cap(tp->pdev) + PCI_EXP_LNKCTL, &lnkctl); @@ -14409,13 +14490,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tg3_ape_lock_init(tp); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - tg3_flag(tp, 57765_PLUS)) - tg3_flag_set(tp, CPMU_PRESENT); - /* Set up tp->grc_local_ctrl before calling * tg3_pwrsrc_switch_to_vmain(). GPIO1 driven high * will bring 5700's external PHY out of reset. @@ -15350,34 +15424,6 @@ static char * __devinit tg3_bus_string(struct tg3 *tp, char *str) return str; } -static struct pci_dev * __devinit tg3_find_peer(struct tg3 *tp) -{ - struct pci_dev *peer; - unsigned int func, devnr = tp->pdev->devfn & ~7; - - for (func = 0; func < 8; func++) { - peer = pci_get_slot(tp->pdev->bus, devnr | func); - if (peer && peer != tp->pdev) - break; - pci_dev_put(peer); - } - /* 5704 can be configured in single-port mode, set peer to - * tp->pdev in that case. - */ - if (!peer) { - peer = tp->pdev; - return peer; - } - - /* - * We don't need to keep the refcount elevated; there's no way - * to remove one half of this device without removing the other - */ - pci_dev_put(peer); - - return peer; -} - static void __devinit tg3_init_coal(struct tg3 *tp) { struct ethtool_coalesce *ec = &tp->coal; @@ -15409,24 +15455,6 @@ static void __devinit tg3_init_coal(struct tg3 *tp) } } -static const struct net_device_ops tg3_netdev_ops = { - .ndo_open = tg3_open, - .ndo_stop = tg3_close, - .ndo_start_xmit = tg3_start_xmit, - .ndo_get_stats64 = tg3_get_stats64, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = tg3_set_rx_mode, - .ndo_set_mac_address = tg3_set_mac_addr, - .ndo_do_ioctl = tg3_ioctl, - .ndo_tx_timeout = tg3_tx_timeout, - .ndo_change_mtu = tg3_change_mtu, - .ndo_fix_features = tg3_fix_features, - .ndo_set_features = tg3_set_features, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = tg3_poll_controller, -#endif -}; - static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -15471,7 +15499,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS); if (!dev) { - dev_err(&pdev->dev, "Etherdev alloc failed, aborting\n"); err = -ENOMEM; goto err_out_power_down; } @@ -15728,6 +15755,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_frob_aux_power(tp, false); } + tg3_timer_init(tp); + err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Cannot register net device, aborting\n"); @@ -15853,7 +15882,7 @@ static int tg3_suspend(struct device *device) tg3_phy_stop(tp); tg3_netif_stop(tp); - del_timer_sync(&tp->timer); + tg3_timer_stop(tp); tg3_full_lock(tp, 1); tg3_disable_ints(tp); @@ -15877,8 +15906,7 @@ static int tg3_suspend(struct device *device) if (err2) goto out; - tp->timer.expires = jiffies + tp->timer_offset; - add_timer(&tp->timer); + tg3_timer_start(tp); netif_device_attach(dev); tg3_netif_start(tp); @@ -15912,8 +15940,7 @@ static int tg3_resume(struct device *device) if (err) goto out; - tp->timer.expires = jiffies + tp->timer_offset; - add_timer(&tp->timer); + tg3_timer_start(tp); tg3_netif_start(tp); @@ -15961,11 +15988,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, tg3_netif_stop(tp); - del_timer_sync(&tp->timer); + tg3_timer_stop(tp); /* Want to make sure that the reset task doesn't run */ tg3_reset_task_cancel(tp); - tg3_flag_clear(tp, TX_RECOVERY_PENDING); netif_device_detach(netdev); @@ -16058,8 +16084,7 @@ static void tg3_io_resume(struct pci_dev *pdev) netif_device_attach(netdev); - tp->timer.expires = jiffies + tp->timer_offset; - add_timer(&tp->timer); + tg3_timer_start(tp); tg3_netif_start(tp); |