diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom')
-rw-r--r-- | drivers/net/ethernet/broadcom/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2.c | 312 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 64 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 299 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/cnic.c | 91 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/cnic.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/cnic_defs.h | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/cnic_if.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 105 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.h | 12 |
16 files changed, 654 insertions, 298 deletions
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 52c96036dcc4..2fa5b86f139d 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -130,7 +130,7 @@ config BNX2X_SRIOV config BGMAC tristate "BCMA bus GBit core support" - depends on BCMA_HOST_SOC && HAS_DMA + depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX select PHYLIB ---help--- This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus. diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 6a2de1d79ff6..4148058cef81 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -1,6 +1,6 @@ /* bnx2.c: Broadcom NX2 network driver. * - * Copyright (c) 2004-2011 Broadcom Corporation + * Copyright (c) 2004-2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,8 +58,8 @@ #include "bnx2_fw.h" #define DRV_MODULE_NAME "bnx2" -#define DRV_MODULE_VERSION "2.2.3" -#define DRV_MODULE_RELDATE "June 27, 2012" +#define DRV_MODULE_VERSION "2.2.4" +#define DRV_MODULE_RELDATE "Aug 05, 2013" #define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.3.fw" #define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw" #define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1b.fw" @@ -3908,136 +3908,121 @@ init_cpu_err: return rc; } -static int -bnx2_set_power_state(struct bnx2 *bp, pci_power_t state) +static void +bnx2_setup_wol(struct bnx2 *bp) { - u16 pmcsr; + int i; + u32 val, wol_msg; - pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr); + if (bp->wol) { + u32 advertising; + u8 autoneg; - switch (state) { - case PCI_D0: { - u32 val; + autoneg = bp->autoneg; + advertising = bp->advertising; - pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, - (pmcsr & ~PCI_PM_CTRL_STATE_MASK) | - PCI_PM_CTRL_PME_STATUS); + if (bp->phy_port == PORT_TP) { + bp->autoneg = AUTONEG_SPEED; + bp->advertising = ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_Autoneg; + } - if (pmcsr & PCI_PM_CTRL_STATE_MASK) - /* delay required during transition out of D3hot */ - msleep(20); + spin_lock_bh(&bp->phy_lock); + bnx2_setup_phy(bp, bp->phy_port); + spin_unlock_bh(&bp->phy_lock); - val = BNX2_RD(bp, BNX2_EMAC_MODE); - val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD; - val &= ~BNX2_EMAC_MODE_MPKT; - BNX2_WR(bp, BNX2_EMAC_MODE, val); + bp->autoneg = autoneg; + bp->advertising = advertising; - val = BNX2_RD(bp, BNX2_RPM_CONFIG); - val &= ~BNX2_RPM_CONFIG_ACPI_ENA; - BNX2_WR(bp, BNX2_RPM_CONFIG, val); - break; - } - case PCI_D3hot: { - int i; - u32 val, wol_msg; - - if (bp->wol) { - u32 advertising; - u8 autoneg; - - autoneg = bp->autoneg; - advertising = bp->advertising; - - if (bp->phy_port == PORT_TP) { - bp->autoneg = AUTONEG_SPEED; - bp->advertising = ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | - ADVERTISED_Autoneg; - } + bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); - spin_lock_bh(&bp->phy_lock); - bnx2_setup_phy(bp, bp->phy_port); - spin_unlock_bh(&bp->phy_lock); + val = BNX2_RD(bp, BNX2_EMAC_MODE); - bp->autoneg = autoneg; - bp->advertising = advertising; + /* Enable port mode. */ + val &= ~BNX2_EMAC_MODE_PORT; + val |= BNX2_EMAC_MODE_MPKT_RCVD | + BNX2_EMAC_MODE_ACPI_RCVD | + BNX2_EMAC_MODE_MPKT; + if (bp->phy_port == PORT_TP) { + val |= BNX2_EMAC_MODE_PORT_MII; + } else { + val |= BNX2_EMAC_MODE_PORT_GMII; + if (bp->line_speed == SPEED_2500) + val |= BNX2_EMAC_MODE_25G_MODE; + } - bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); + BNX2_WR(bp, BNX2_EMAC_MODE, val); - val = BNX2_RD(bp, BNX2_EMAC_MODE); + /* receive all multicast */ + for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) { + BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4), + 0xffffffff); + } + BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE); - /* Enable port mode. */ - val &= ~BNX2_EMAC_MODE_PORT; - val |= BNX2_EMAC_MODE_MPKT_RCVD | - BNX2_EMAC_MODE_ACPI_RCVD | - BNX2_EMAC_MODE_MPKT; - if (bp->phy_port == PORT_TP) - val |= BNX2_EMAC_MODE_PORT_MII; - else { - val |= BNX2_EMAC_MODE_PORT_GMII; - if (bp->line_speed == SPEED_2500) - val |= BNX2_EMAC_MODE_25G_MODE; - } + val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN; + BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0); + BNX2_WR(bp, BNX2_RPM_SORT_USER0, val); + BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA); - BNX2_WR(bp, BNX2_EMAC_MODE, val); + /* Need to enable EMAC and RPM for WOL. */ + BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, + BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE | + BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE | + BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE); - /* receive all multicast */ - for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) { - BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4), - 0xffffffff); - } - BNX2_WR(bp, BNX2_EMAC_RX_MODE, - BNX2_EMAC_RX_MODE_SORT_MODE); + val = BNX2_RD(bp, BNX2_RPM_CONFIG); + val &= ~BNX2_RPM_CONFIG_ACPI_ENA; + BNX2_WR(bp, BNX2_RPM_CONFIG, val); - val = 1 | BNX2_RPM_SORT_USER0_BC_EN | - BNX2_RPM_SORT_USER0_MC_EN; - BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0); - BNX2_WR(bp, BNX2_RPM_SORT_USER0, val); - BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | - BNX2_RPM_SORT_USER0_ENA); + wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL; + } else { + wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; + } - /* Need to enable EMAC and RPM for WOL. */ - BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, - BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE | - BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE | - BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE); + if (!(bp->flags & BNX2_FLAG_NO_WOL)) + bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0); - val = BNX2_RD(bp, BNX2_RPM_CONFIG); - val &= ~BNX2_RPM_CONFIG_ACPI_ENA; - BNX2_WR(bp, BNX2_RPM_CONFIG, val); +} - wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL; - } - else { - wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; - } +static int +bnx2_set_power_state(struct bnx2 *bp, pci_power_t state) +{ + switch (state) { + case PCI_D0: { + u32 val; + + pci_enable_wake(bp->pdev, PCI_D0, false); + pci_set_power_state(bp->pdev, PCI_D0); - if (!(bp->flags & BNX2_FLAG_NO_WOL)) - bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, - 1, 0); + val = BNX2_RD(bp, BNX2_EMAC_MODE); + val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD; + val &= ~BNX2_EMAC_MODE_MPKT; + BNX2_WR(bp, BNX2_EMAC_MODE, val); - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + val = BNX2_RD(bp, BNX2_RPM_CONFIG); + val &= ~BNX2_RPM_CONFIG_ACPI_ENA; + BNX2_WR(bp, BNX2_RPM_CONFIG, val); + break; + } + case PCI_D3hot: { + bnx2_setup_wol(bp); + pci_wake_from_d3(bp->pdev, bp->wol); if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) || (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) { if (bp->wol) - pmcsr |= 3; - } - else { - pmcsr |= 3; - } - if (bp->wol) { - pmcsr |= PCI_PM_CTRL_PME_ENABLE; + pci_set_power_state(bp->pdev, PCI_D3hot); + } else { + pci_set_power_state(bp->pdev, PCI_D3hot); } - pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, - pmcsr); /* No more memory access after this point until * device is brought back to D0. */ - udelay(50); break; } default: @@ -6317,7 +6302,6 @@ bnx2_open(struct net_device *dev) netif_carrier_off(dev); - bnx2_set_power_state(bp, PCI_D0); bnx2_disable_int(bp); rc = bnx2_setup_int_mode(bp, disable_msi); @@ -6724,7 +6708,6 @@ bnx2_close(struct net_device *dev) bnx2_del_napi(bp); bp->link_up = 0; netif_carrier_off(bp->dev); - bnx2_set_power_state(bp, PCI_D3hot); return 0; } @@ -7081,6 +7064,9 @@ bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) else { bp->wol = 0; } + + device_set_wakeup_enable(&bp->pdev->dev, bp->wol); + return 0; } @@ -7156,9 +7142,6 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct bnx2 *bp = netdev_priv(dev); int rc; - if (!netif_running(dev)) - return -EAGAIN; - /* parameters already validated in ethtool_get_eeprom */ rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); @@ -7173,9 +7156,6 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct bnx2 *bp = netdev_priv(dev); int rc; - if (!netif_running(dev)) - return -EAGAIN; - /* parameters already validated in ethtool_set_eeprom */ rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); @@ -7535,8 +7515,6 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) { struct bnx2 *bp = netdev_priv(dev); - bnx2_set_power_state(bp, PCI_D0); - memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS); if (etest->flags & ETH_TEST_FL_OFFLINE) { int i; @@ -7585,8 +7563,6 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) etest->flags |= ETH_TEST_FL_FAILED; } - if (!netif_running(bp->dev)) - bnx2_set_power_state(bp, PCI_D3hot); } static void @@ -7658,8 +7634,6 @@ bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) switch (state) { case ETHTOOL_ID_ACTIVE: - bnx2_set_power_state(bp, PCI_D0); - bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG); BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); return 1; /* cycle on/off once per second */ @@ -7680,9 +7654,6 @@ bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) case ETHTOOL_ID_INACTIVE: BNX2_WR(bp, BNX2_EMAC_LED, 0); BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save); - - if (!netif_running(dev)) - bnx2_set_power_state(bp, PCI_D3hot); break; } @@ -8130,8 +8101,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) goto err_out_release; } - bnx2_set_power_state(bp, PCI_D0); - /* Configure byte swap and enable write to the reg_window registers. * Rely on CPU to do target byte swapping on big endian systems * The chip's target access swapping will not swap all accesses @@ -8170,13 +8139,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (BNX2_CHIP(bp) == BNX2_CHIP_5709 && BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) { - if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) + if (pdev->msix_cap) bp->flags |= BNX2_FLAG_MSIX_CAP; } if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 && BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) { - if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) + if (pdev->msi_cap) bp->flags |= BNX2_FLAG_MSI_CAP; } @@ -8369,6 +8338,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->wol = 0; } + if (bp->flags & BNX2_FLAG_NO_WOL) + device_set_wakeup_capable(&bp->pdev->dev, false); + else + device_set_wakeup_enable(&bp->pdev->dev, bp->wol); + if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) { bp->tx_quick_cons_trip_int = bp->tx_quick_cons_trip; @@ -8609,46 +8583,52 @@ bnx2_remove_one(struct pci_dev *pdev) } static int -bnx2_suspend(struct pci_dev *pdev, pm_message_t state) +bnx2_suspend(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct net_device *dev = pci_get_drvdata(pdev); struct bnx2 *bp = netdev_priv(dev); - /* PCI register 4 needs to be saved whether netif_running() or not. - * MSI address and data need to be saved if using MSI and - * netif_running(). - */ - pci_save_state(pdev); - if (!netif_running(dev)) - return 0; - - cancel_work_sync(&bp->reset_task); - bnx2_netif_stop(bp, true); - netif_device_detach(dev); - del_timer_sync(&bp->timer); - bnx2_shutdown_chip(bp); - bnx2_free_skbs(bp); - bnx2_set_power_state(bp, pci_choose_state(pdev, state)); + if (netif_running(dev)) { + cancel_work_sync(&bp->reset_task); + bnx2_netif_stop(bp, true); + netif_device_detach(dev); + del_timer_sync(&bp->timer); + bnx2_shutdown_chip(bp); + __bnx2_free_irq(bp); + bnx2_free_skbs(bp); + } + bnx2_setup_wol(bp); return 0; } static int -bnx2_resume(struct pci_dev *pdev) +bnx2_resume(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct net_device *dev = pci_get_drvdata(pdev); struct bnx2 *bp = netdev_priv(dev); - pci_restore_state(pdev); if (!netif_running(dev)) return 0; bnx2_set_power_state(bp, PCI_D0); netif_device_attach(dev); + bnx2_request_irq(bp); bnx2_init_nic(bp, 1); bnx2_netif_start(bp, true); return 0; } +#ifdef CONFIG_PM_SLEEP +static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume); +#define BNX2_PM_OPS (&bnx2_pm_ops) + +#else + +#define BNX2_PM_OPS NULL + +#endif /* CONFIG_PM_SLEEP */ /** * bnx2_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device @@ -8694,24 +8674,28 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct bnx2 *bp = netdev_priv(dev); - pci_ers_result_t result; - int err; + pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT; + int err = 0; rtnl_lock(); if (pci_enable_device(pdev)) { dev_err(&pdev->dev, "Cannot re-enable PCI device after reset\n"); - result = PCI_ERS_RESULT_DISCONNECT; } else { pci_set_master(pdev); pci_restore_state(pdev); pci_save_state(pdev); - if (netif_running(dev)) { - bnx2_set_power_state(bp, PCI_D0); - bnx2_init_nic(bp, 1); - } - result = PCI_ERS_RESULT_RECOVERED; + if (netif_running(dev)) + err = bnx2_init_nic(bp, 1); + + if (!err) + result = PCI_ERS_RESULT_RECOVERED; + } + + if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) { + bnx2_napi_enable(bp); + dev_close(dev); } rtnl_unlock(); @@ -8748,6 +8732,28 @@ static void bnx2_io_resume(struct pci_dev *pdev) rtnl_unlock(); } +static void bnx2_shutdown(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2 *bp; + + if (!dev) + return; + + bp = netdev_priv(dev); + if (!bp) + return; + + rtnl_lock(); + if (netif_running(dev)) + dev_close(bp->dev); + + if (system_state == SYSTEM_POWER_OFF) + bnx2_set_power_state(bp, PCI_D3hot); + + rtnl_unlock(); +} + static const struct pci_error_handlers bnx2_err_handler = { .error_detected = bnx2_io_error_detected, .slot_reset = bnx2_io_slot_reset, @@ -8759,9 +8765,9 @@ static struct pci_driver bnx2_pci_driver = { .id_table = bnx2_pci_tbl, .probe = bnx2_init_one, .remove = bnx2_remove_one, - .suspend = bnx2_suspend, - .resume = bnx2_resume, + .driver.pm = BNX2_PM_OPS, .err_handler = &bnx2_err_handler, + .shutdown = bnx2_shutdown, }; module_pci_driver(bnx2_pci_driver); diff --git a/drivers/net/ethernet/broadcom/bnx2.h b/drivers/net/ethernet/broadcom/bnx2.h index 172efbecfea2..18cb2d23e56b 100644 --- a/drivers/net/ethernet/broadcom/bnx2.h +++ b/drivers/net/ethernet/broadcom/bnx2.h @@ -1,6 +1,6 @@ /* bnx2.h: Broadcom NX2 network driver. * - * Copyright (c) 2004-2011 Broadcom Corporation + * Copyright (c) 2004-2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index ce9b387b5a19..126dec4342e6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1331,7 +1331,7 @@ enum { BNX2X_SP_RTNL_ENABLE_SRIOV, BNX2X_SP_RTNL_VFPF_MCAST, BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN, - BNX2X_SP_RTNL_VFPF_STORM_RX_MODE, + BNX2X_SP_RTNL_RX_MODE, BNX2X_SP_RTNL_HYPERVISOR_VLAN, }; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index f2d1ff10054b..2e90868a9276 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2060,7 +2060,11 @@ void bnx2x_squeeze_objects(struct bnx2x *bp) rparam.mcast_obj = &bp->mcast_obj; __set_bit(RAMROD_DRV_CLR_ONLY, &rparam.ramrod_flags); - /* Add a DEL command... */ + /* Add a DEL command... - Since we're doing a driver cleanup only, + * we take a lock surrounding both the initial send and the CONTs, + * as we don't want a true completion to disrupt us in the middle. + */ + netif_addr_lock_bh(bp->dev); rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); if (rc < 0) BNX2X_ERR("Failed to add a new DEL command to a multi-cast object: %d\n", @@ -2072,11 +2076,13 @@ void bnx2x_squeeze_objects(struct bnx2x *bp) if (rc < 0) { BNX2X_ERR("Failed to clean multi-cast object: %d\n", rc); + netif_addr_unlock_bh(bp->dev); return; } rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); } + netif_addr_unlock_bh(bp->dev); } #ifndef BNX2X_STOP_ON_ERROR @@ -2432,9 +2438,7 @@ int bnx2x_load_cnic(struct bnx2x *bp) } /* Initialize Rx filter. */ - netif_addr_lock_bh(bp->dev); - bnx2x_set_rx_mode(bp->dev); - netif_addr_unlock_bh(bp->dev); + bnx2x_set_rx_mode_inner(bp); /* re-read iscsi info */ bnx2x_get_iscsi_info(bp); @@ -2704,9 +2708,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Start fast path */ /* Initialize Rx filter. */ - netif_addr_lock_bh(bp->dev); - bnx2x_set_rx_mode(bp->dev); - netif_addr_unlock_bh(bp->dev); + bnx2x_set_rx_mode_inner(bp); /* Start the Tx */ switch (load_mode) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index c07a6d054cfe..38be494ffa6e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -418,6 +418,7 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set); * netif_addr_lock_bh() */ void bnx2x_set_rx_mode(struct net_device *dev); +void bnx2x_set_rx_mode_inner(struct bnx2x *bp); /** * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW. diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 955d6cfd9cb7..7f4ec80f0cb3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9634,11 +9634,9 @@ sp_rtnl_not_reset: } } - if (test_and_clear_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE, - &bp->sp_rtnl_state)) { - DP(BNX2X_MSG_SP, - "sending set storm rx mode vf pf channel message from rtnl sp-task\n"); - bnx2x_vfpf_storm_rx_mode(bp); + if (test_and_clear_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state)) { + DP(BNX2X_MSG_SP, "Handling Rx Mode setting\n"); + bnx2x_set_rx_mode_inner(bp); } if (test_and_clear_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN, @@ -11860,34 +11858,48 @@ static int bnx2x_set_mc_list(struct bnx2x *bp) void bnx2x_set_rx_mode(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); - u32 rx_mode = BNX2X_RX_MODE_NORMAL; if (bp->state != BNX2X_STATE_OPEN) { DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); return; + } else { + /* Schedule an SP task to handle rest of change */ + DP(NETIF_MSG_IFUP, "Scheduling an Rx mode change\n"); + smp_mb__before_clear_bit(); + set_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state); + smp_mb__after_clear_bit(); + schedule_delayed_work(&bp->sp_rtnl_task, 0); } +} + +void bnx2x_set_rx_mode_inner(struct bnx2x *bp) +{ + u32 rx_mode = BNX2X_RX_MODE_NORMAL; DP(NETIF_MSG_IFUP, "dev->flags = %x\n", bp->dev->flags); - if (dev->flags & IFF_PROMISC) + netif_addr_lock_bh(bp->dev); + + if (bp->dev->flags & IFF_PROMISC) { rx_mode = BNX2X_RX_MODE_PROMISC; - else if ((dev->flags & IFF_ALLMULTI) || - ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) && - CHIP_IS_E1(bp))) + } else if ((bp->dev->flags & IFF_ALLMULTI) || + ((netdev_mc_count(bp->dev) > BNX2X_MAX_MULTICAST) && + CHIP_IS_E1(bp))) { rx_mode = BNX2X_RX_MODE_ALLMULTI; - else { + } else { if (IS_PF(bp)) { /* some multicasts */ if (bnx2x_set_mc_list(bp) < 0) rx_mode = BNX2X_RX_MODE_ALLMULTI; + /* release bh lock, as bnx2x_set_uc_list might sleep */ + netif_addr_unlock_bh(bp->dev); if (bnx2x_set_uc_list(bp) < 0) rx_mode = BNX2X_RX_MODE_PROMISC; + netif_addr_lock_bh(bp->dev); } else { /* configuring mcast to a vf involves sleeping (when we - * wait for the pf's response). Since this function is - * called from non sleepable context we must schedule - * a work item for this purpose + * wait for the pf's response). */ smp_mb__before_clear_bit(); set_bit(BNX2X_SP_RTNL_VFPF_MCAST, @@ -11905,22 +11917,20 @@ void bnx2x_set_rx_mode(struct net_device *dev) /* Schedule the rx_mode command */ if (test_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state)) { set_bit(BNX2X_FILTER_RX_MODE_SCHED, &bp->sp_state); + netif_addr_unlock_bh(bp->dev); return; } if (IS_PF(bp)) { bnx2x_set_storm_rx_mode(bp); + netif_addr_unlock_bh(bp->dev); } else { - /* configuring rx mode to storms in a vf involves sleeping (when - * we wait for the pf's response). Since this function is - * called from non sleepable context we must schedule - * a work item for this purpose + /* VF will need to request the PF to make this change, and so + * the VF needs to release the bottom-half lock prior to the + * request (as it will likely require sleep on the VF side) */ - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_VFPF_STORM_RX_MODE, - &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - schedule_delayed_work(&bp->sp_rtnl_task, 0); + netif_addr_unlock_bh(bp->dev); + bnx2x_vfpf_storm_rx_mode(bp); } } @@ -12545,16 +12555,14 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp) static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev, int cnic_cnt, bool is_vf) { - int pos, index; + int index; u16 control = 0; - pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); - /* * If MSI-X is not supported - return number of SBs needed to support * one fast path queue: one FP queue + SB for CNIC */ - if (!pos) { + if (!pdev->msix_cap) { dev_info(&pdev->dev, "no msix capability found\n"); return 1 + cnic_cnt; } @@ -12567,7 +12575,7 @@ static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev, * without the default SB. * For VFs there is no default SB, then we return (index+1). */ - pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control); + pci_read_config_word(pdev, pdev->msix_cap + PCI_MSI_FLAGS, &control); index = control & PCI_MSIX_FLAGS_QSIZE; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 8f03c984550f..1d46b68fb766 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -159,16 +159,6 @@ static inline void __bnx2x_exe_queue_reset_pending( } } -static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp, - struct bnx2x_exe_queue_obj *o) -{ - spin_lock_bh(&o->lock); - - __bnx2x_exe_queue_reset_pending(bp, o); - - spin_unlock_bh(&o->lock); -} - /** * bnx2x_exe_queue_step - execute one execution chunk atomically * @@ -176,7 +166,7 @@ static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp, * @o: queue * @ramrod_flags: flags * - * (Atomicity is ensured using the exe_queue->lock). + * (Should be called while holding the exe_queue->lock). */ static inline int bnx2x_exe_queue_step(struct bnx2x *bp, struct bnx2x_exe_queue_obj *o, @@ -187,8 +177,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp, memset(&spacer, 0, sizeof(spacer)); - spin_lock_bh(&o->lock); - /* Next step should not be performed until the current is finished, * unless a DRV_CLEAR_ONLY bit is set. In this case we just want to * properly clear object internals without sending any command to the FW @@ -200,7 +188,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp, DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: resetting a pending_comp list\n"); __bnx2x_exe_queue_reset_pending(bp, o); } else { - spin_unlock_bh(&o->lock); return 1; } } @@ -228,10 +215,8 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp, } /* Sanity check */ - if (!cur_len) { - spin_unlock_bh(&o->lock); + if (!cur_len) return 0; - } rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags); if (rc < 0) @@ -245,7 +230,6 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp, */ __bnx2x_exe_queue_reset_pending(bp, o); - spin_unlock_bh(&o->lock); return rc; } @@ -432,12 +416,219 @@ static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) return true; } +/** + * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock + * + * @bp: device handle + * @o: vlan_mac object + * + * @details: Non-blocking implementation; should be called under execution + * queue lock. + */ +static int __bnx2x_vlan_mac_h_write_trylock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + if (o->head_reader) { + DP(BNX2X_MSG_SP, "vlan_mac_lock writer - There are readers; Busy\n"); + return -EBUSY; + } + + DP(BNX2X_MSG_SP, "vlan_mac_lock writer - Taken\n"); + return 0; +} + +/** + * __bnx2x_vlan_mac_h_exec_pending - execute step instead of a previous step + * + * @bp: device handle + * @o: vlan_mac object + * + * @details Should be called under execution queue lock; notice it might release + * and reclaim it during its run. + */ +static void __bnx2x_vlan_mac_h_exec_pending(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + int rc; + unsigned long ramrod_flags = o->saved_ramrod_flags; + + DP(BNX2X_MSG_SP, "vlan_mac_lock execute pending command with ramrod flags %lu\n", + ramrod_flags); + o->head_exe_request = false; + o->saved_ramrod_flags = 0; + rc = bnx2x_exe_queue_step(bp, &o->exe_queue, &ramrod_flags); + if (rc != 0) { + BNX2X_ERR("execution of pending commands failed with rc %d\n", + rc); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); +#endif + } +} + +/** + * __bnx2x_vlan_mac_h_pend - Pend an execution step which couldn't run + * + * @bp: device handle + * @o: vlan_mac object + * @ramrod_flags: ramrod flags of missed execution + * + * @details Should be called under execution queue lock. + */ +static void __bnx2x_vlan_mac_h_pend(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + unsigned long ramrod_flags) +{ + o->head_exe_request = true; + o->saved_ramrod_flags = ramrod_flags; + DP(BNX2X_MSG_SP, "Placing pending execution with ramrod flags %lu\n", + ramrod_flags); +} + +/** + * __bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock + * + * @bp: device handle + * @o: vlan_mac object + * + * @details Should be called under execution queue lock. Notice if a pending + * execution exists, it would perform it - possibly releasing and + * reclaiming the execution queue lock. + */ +static void __bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + /* It's possible a new pending execution was added since this writer + * executed. If so, execute again. [Ad infinitum] + */ + while (o->head_exe_request) { + DP(BNX2X_MSG_SP, "vlan_mac_lock - writer release encountered a pending request\n"); + __bnx2x_vlan_mac_h_exec_pending(bp, o); + } +} + +/** + * bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock + * + * @bp: device handle + * @o: vlan_mac object + * + * @details Notice if a pending execution exists, it would perform it - + * possibly releasing and reclaiming the execution queue lock. + */ +void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + spin_lock_bh(&o->exe_queue.lock); + __bnx2x_vlan_mac_h_write_unlock(bp, o); + spin_unlock_bh(&o->exe_queue.lock); +} + +/** + * __bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock + * + * @bp: device handle + * @o: vlan_mac object + * + * @details Should be called under the execution queue lock. May sleep. May + * release and reclaim execution queue lock during its run. + */ +static int __bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + /* If we got here, we're holding lock --> no WRITER exists */ + o->head_reader++; + DP(BNX2X_MSG_SP, "vlan_mac_lock - locked reader - number %d\n", + o->head_reader); + + return 0; +} + +/** + * bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock + * + * @bp: device handle + * @o: vlan_mac object + * + * @details May sleep. Claims and releases execution queue lock during its run. + */ +int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + int rc; + + spin_lock_bh(&o->exe_queue.lock); + rc = __bnx2x_vlan_mac_h_read_lock(bp, o); + spin_unlock_bh(&o->exe_queue.lock); + + return rc; +} + +/** + * __bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock + * + * @bp: device handle + * @o: vlan_mac object + * + * @details Should be called under execution queue lock. Notice if a pending + * execution exists, it would be performed if this was the last + * reader. possibly releasing and reclaiming the execution queue lock. + */ +static void __bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + if (!o->head_reader) { + BNX2X_ERR("Need to release vlan mac reader lock, but lock isn't taken\n"); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); +#endif + } else { + o->head_reader--; + DP(BNX2X_MSG_SP, "vlan_mac_lock - decreased readers to %d\n", + o->head_reader); + } + + /* It's possible a new pending execution was added, and that this reader + * was last - if so we need to execute the command. + */ + if (!o->head_reader && o->head_exe_request) { + DP(BNX2X_MSG_SP, "vlan_mac_lock - reader release encountered a pending request\n"); + + /* Writer release will do the trick */ + __bnx2x_vlan_mac_h_write_unlock(bp, o); + } +} + +/** + * bnx2x_vlan_mac_h_read_unlock - unlock the vlan mac head list reader lock + * + * @bp: device handle + * @o: vlan_mac object + * + * @details Notice if a pending execution exists, it would be performed if this + * was the last reader. Claims and releases the execution queue lock + * during its run. + */ +void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + spin_lock_bh(&o->exe_queue.lock); + __bnx2x_vlan_mac_h_read_unlock(bp, o); + spin_unlock_bh(&o->exe_queue.lock); +} + static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o, int n, u8 *base, u8 stride, u8 size) { struct bnx2x_vlan_mac_registry_elem *pos; u8 *next = base; int counter = 0; + int read_lock; + + DP(BNX2X_MSG_SP, "get_n_elements - taking vlan_mac_lock (reader)\n"); + read_lock = bnx2x_vlan_mac_h_read_lock(bp, o); + if (read_lock != 0) + BNX2X_ERR("get_n_elements failed to get vlan mac reader lock; Access without lock\n"); /* traverse list */ list_for_each_entry(pos, &o->head, link) { @@ -449,6 +640,12 @@ static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o, next += stride + size; } } + + if (read_lock == 0) { + DP(BNX2X_MSG_SP, "get_n_elements - releasing vlan_mac_lock (reader)\n"); + bnx2x_vlan_mac_h_read_unlock(bp, o); + } + return counter * ETH_ALEN; } @@ -1397,6 +1594,32 @@ static int bnx2x_wait_vlan_mac(struct bnx2x *bp, return -EBUSY; } +static int __bnx2x_vlan_mac_execute_step(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + unsigned long *ramrod_flags) +{ + int rc = 0; + + spin_lock_bh(&o->exe_queue.lock); + + DP(BNX2X_MSG_SP, "vlan_mac_execute_step - trying to take writer lock\n"); + rc = __bnx2x_vlan_mac_h_write_trylock(bp, o); + + if (rc != 0) { + __bnx2x_vlan_mac_h_pend(bp, o, *ramrod_flags); + + /* Calling function should not diffrentiate between this case + * and the case in which there is already a pending ramrod + */ + rc = 1; + } else { + rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags); + } + spin_unlock_bh(&o->exe_queue.lock); + + return rc; +} + /** * bnx2x_complete_vlan_mac - complete one VLAN-MAC ramrod * @@ -1414,19 +1637,27 @@ static int bnx2x_complete_vlan_mac(struct bnx2x *bp, struct bnx2x_raw_obj *r = &o->raw; int rc; + /* Clearing the pending list & raw state should be made + * atomically (as execution flow assumes they represent the same). + */ + spin_lock_bh(&o->exe_queue.lock); + /* Reset pending list */ - bnx2x_exe_queue_reset_pending(bp, &o->exe_queue); + __bnx2x_exe_queue_reset_pending(bp, &o->exe_queue); /* Clear pending */ r->clear_pending(r); + spin_unlock_bh(&o->exe_queue.lock); + /* If ramrod failed this is most likely a SW bug */ if (cqe->message.error) return -EINVAL; /* Run the next bulk of pending commands if requested */ if (test_bit(RAMROD_CONT, ramrod_flags)) { - rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags); + rc = __bnx2x_vlan_mac_execute_step(bp, o, ramrod_flags); + if (rc < 0) return rc; } @@ -1719,9 +1950,8 @@ static inline int bnx2x_vlan_mac_push_new_cmd( * @p: * */ -int bnx2x_config_vlan_mac( - struct bnx2x *bp, - struct bnx2x_vlan_mac_ramrod_params *p) +int bnx2x_config_vlan_mac(struct bnx2x *bp, + struct bnx2x_vlan_mac_ramrod_params *p) { int rc = 0; struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj; @@ -1752,7 +1982,8 @@ int bnx2x_config_vlan_mac( /* Execute commands if required */ if (cont || test_bit(RAMROD_EXEC, ramrod_flags) || test_bit(RAMROD_COMP_WAIT, ramrod_flags)) { - rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags); + rc = __bnx2x_vlan_mac_execute_step(bp, p->vlan_mac_obj, + &p->ramrod_flags); if (rc < 0) return rc; } @@ -1775,8 +2006,9 @@ int bnx2x_config_vlan_mac( return rc; /* Make a next step */ - rc = bnx2x_exe_queue_step(bp, &o->exe_queue, - ramrod_flags); + rc = __bnx2x_vlan_mac_execute_step(bp, + p->vlan_mac_obj, + &p->ramrod_flags); if (rc < 0) return rc; } @@ -1806,10 +2038,11 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, unsigned long *ramrod_flags) { struct bnx2x_vlan_mac_registry_elem *pos = NULL; - int rc = 0; struct bnx2x_vlan_mac_ramrod_params p; struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n; + int read_lock; + int rc = 0; /* Clear pending commands first */ @@ -1844,6 +2077,11 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, __clear_bit(RAMROD_EXEC, &p.ramrod_flags); __clear_bit(RAMROD_CONT, &p.ramrod_flags); + DP(BNX2X_MSG_SP, "vlan_mac_del_all -- taking vlan_mac_lock (reader)\n"); + read_lock = bnx2x_vlan_mac_h_read_lock(bp, o); + if (read_lock != 0) + return read_lock; + list_for_each_entry(pos, &o->head, link) { if (pos->vlan_mac_flags == *vlan_mac_flags) { p.user_req.vlan_mac_flags = pos->vlan_mac_flags; @@ -1851,11 +2089,15 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, rc = bnx2x_config_vlan_mac(bp, &p); if (rc < 0) { BNX2X_ERR("Failed to add a new DEL command\n"); + bnx2x_vlan_mac_h_read_unlock(bp, o); return rc; } } } + DP(BNX2X_MSG_SP, "vlan_mac_del_all -- releasing vlan_mac_lock (reader)\n"); + bnx2x_vlan_mac_h_read_unlock(bp, o); + p.ramrod_flags = *ramrod_flags; __set_bit(RAMROD_CONT, &p.ramrod_flags); @@ -1887,6 +2129,9 @@ static inline void bnx2x_init_vlan_mac_common(struct bnx2x_vlan_mac_obj *o, struct bnx2x_credit_pool_obj *vlans_pool) { INIT_LIST_HEAD(&o->head); + o->head_reader = 0; + o->head_exe_request = false; + o->saved_ramrod_flags = 0; o->macs_pool = macs_pool; o->vlans_pool = vlans_pool; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 798dfe996733..533a3abd8c82 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -285,6 +285,12 @@ struct bnx2x_vlan_mac_obj { * entries. */ struct list_head head; + /* Implement a simple reader/writer lock on the head list. + * all these fields should only be accessed under the exe_queue lock + */ + u8 head_reader; /* Num. of readers accessing head list */ + bool head_exe_request; /* Pending execution request. */ + unsigned long saved_ramrod_flags; /* Ramrods of pending execution */ /* TODO: Add it's initialization in the init functions */ struct bnx2x_exe_queue_obj exe_queue; @@ -1302,8 +1308,16 @@ void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, struct bnx2x_credit_pool_obj *macs_pool, struct bnx2x_credit_pool_obj *vlans_pool); +int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o); +void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o); +int bnx2x_vlan_mac_h_write_lock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o); +void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o); int bnx2x_config_vlan_mac(struct bnx2x *bp, - struct bnx2x_vlan_mac_ramrod_params *p); + struct bnx2x_vlan_mac_ramrod_params *p); int bnx2x_vlan_mac_move(struct bnx2x *bp, struct bnx2x_vlan_mac_ramrod_params *p, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 44104fb27947..1d925fd9cdc6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -491,12 +491,20 @@ static inline void bnx2x_vfop_credit(struct bnx2x *bp, * and a valid credit counter */ if (!vfop->rc && args->credit) { - int cnt = 0; struct list_head *pos; + int read_lock; + int cnt = 0; + + read_lock = bnx2x_vlan_mac_h_read_lock(bp, obj); + if (read_lock) + DP(BNX2X_MSG_SP, "Failed to take vlan mac read head; continuing anyway\n"); list_for_each(pos, &obj->head) cnt++; + if (!read_lock) + bnx2x_vlan_mac_h_read_unlock(bp, obj); + atomic_set(args->credit, cnt); } } diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index d78d4cf140ed..4f8a5357cedc 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -1,6 +1,6 @@ /* cnic.c: Broadcom CNIC core network driver. * - * Copyright (c) 2006-2012 Broadcom Corporation + * Copyright (c) 2006-2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1427,6 +1427,28 @@ static void cnic_reply_bnx2x_kcqes(struct cnic_dev *dev, int ulp_type, rcu_read_unlock(); } +static void cnic_bnx2x_set_tcp_options(struct cnic_dev *dev, int time_stamps, + int en_tcp_dack) +{ + struct cnic_local *cp = dev->cnic_priv; + struct bnx2x *bp = netdev_priv(dev->netdev); + u8 xstorm_flags = XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN; + u16 tstorm_flags = 0; + + if (time_stamps) { + xstorm_flags |= XSTORM_L5CM_TCP_FLAGS_TS_ENABLED; + tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_TS_ENABLED; + } + if (en_tcp_dack) + tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_DELAYED_ACK_EN; + + CNIC_WR8(dev, BAR_XSTRORM_INTMEM + + XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), xstorm_flags); + + CNIC_WR16(dev, BAR_TSTRORM_INTMEM + + TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), tstorm_flags); +} + static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe) { struct cnic_local *cp = dev->cnic_priv; @@ -1506,6 +1528,10 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe) CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(pfid), hq_bds); + cnic_bnx2x_set_tcp_options(dev, + req1->flags & ISCSI_KWQE_INIT1_TIME_STAMPS_ENABLE, + req1->flags & ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE); + return 0; } @@ -2035,9 +2061,6 @@ static void cnic_init_storm_conn_bufs(struct cnic_dev *dev, xstorm_buf->pseudo_header_checksum = swab16(~csum_ipv6_magic(&src_ip, &dst_ip, 0, IPPROTO_TCP, 0)); - if (!(kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK)) - tstorm_buf->params |= - L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE; if (kwqe3->ka_timeout) { tstorm_buf->ka_enable = 1; tstorm_buf->ka_timeout = kwqe3->ka_timeout; @@ -2084,25 +2107,6 @@ static void cnic_init_bnx2x_mac(struct cnic_dev *dev) mac[0]); } -static void cnic_bnx2x_set_tcp_timestamp(struct cnic_dev *dev, int tcp_ts) -{ - struct cnic_local *cp = dev->cnic_priv; - struct bnx2x *bp = netdev_priv(dev->netdev); - u8 xstorm_flags = XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN; - u16 tstorm_flags = 0; - - if (tcp_ts) { - xstorm_flags |= XSTORM_L5CM_TCP_FLAGS_TS_ENABLED; - tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_TS_ENABLED; - } - - CNIC_WR8(dev, BAR_XSTRORM_INTMEM + - XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), xstorm_flags); - - CNIC_WR16(dev, BAR_TSTRORM_INTMEM + - TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->pfid), tstorm_flags); -} - static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[], u32 num, int *work) { @@ -2178,9 +2182,6 @@ static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[], CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_LOCAL_VLAN_OFFSET(cp->pfid), csk->vlan_id); - cnic_bnx2x_set_tcp_timestamp(dev, - kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_TIME_STAMP); - ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_TCP_CONNECT, kwqe1->cid, ISCSI_CONNECTION_TYPE, &l5_data); if (!ret) @@ -3603,6 +3604,7 @@ static int cnic_cm_create(struct cnic_dev *dev, int ulp_type, u32 cid, csk1->rcv_buf = DEF_RCV_BUF; csk1->snd_buf = DEF_SND_BUF; csk1->seed = DEF_SEED; + csk1->tcp_flags = 0; *csk = csk1; return 0; @@ -4020,15 +4022,18 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe) cnic_cm_upcall(cp, csk, opcode); break; - case L5CM_RAMROD_CMD_ID_CLOSE: - if (l4kcqe->status != 0) { - netdev_warn(dev->netdev, "RAMROD CLOSE compl with " - "status 0x%x\n", l4kcqe->status); + case L5CM_RAMROD_CMD_ID_CLOSE: { + struct iscsi_kcqe *l5kcqe = (struct iscsi_kcqe *) kcqe; + + if (l4kcqe->status != 0 || l5kcqe->completion_status != 0) { + netdev_warn(dev->netdev, "RAMROD CLOSE compl with status 0x%x completion status 0x%x\n", + l4kcqe->status, l5kcqe->completion_status); opcode = L4_KCQE_OPCODE_VALUE_CLOSE_COMP; /* Fall through */ } else { break; } + } case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED: case L4_KCQE_OPCODE_VALUE_CLOSE_COMP: case L4_KCQE_OPCODE_VALUE_RESET_COMP: @@ -4219,7 +4224,7 @@ static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev) u32 port = CNIC_PORT(cp); cnic_init_bnx2x_mac(dev); - cnic_bnx2x_set_tcp_timestamp(dev, 1); + cnic_bnx2x_set_tcp_options(dev, 0, 1); CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfid), 0); @@ -5271,6 +5276,13 @@ static int cnic_register_netdev(struct cnic_dev *dev) if (err) netdev_err(dev->netdev, "register_cnic failed\n"); + /* Read iSCSI config again. On some bnx2x device, iSCSI config + * can change after firmware is downloaded. + */ + dev->max_iscsi_conn = ethdev->max_iscsi_conn; + if (ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI) + dev->max_iscsi_conn = 0; + return err; } @@ -5628,7 +5640,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event, dev = cnic_from_netdev(netdev); - if (!dev && (event == NETDEV_REGISTER || netif_running(netdev))) { + if (!dev && event == NETDEV_REGISTER) { /* Check for the hot-plug device */ dev = is_cnic_dev(netdev); if (dev) { @@ -5644,7 +5656,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event, else if (event == NETDEV_UNREGISTER) cnic_ulp_exit(dev); - if (event == NETDEV_UP || (new_dev && netif_running(netdev))) { + if (event == NETDEV_UP) { if (cnic_register_netdev(dev) != 0) { cnic_put(dev); goto done; @@ -5693,21 +5705,8 @@ static struct notifier_block cnic_netdev_notifier = { static void cnic_release(void) { - struct cnic_dev *dev; struct cnic_uio_dev *udev; - while (!list_empty(&cnic_dev_list)) { - dev = list_entry(cnic_dev_list.next, struct cnic_dev, list); - if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) { - cnic_ulp_stop(dev); - cnic_stop_hw(dev); - } - - cnic_ulp_exit(dev); - cnic_unregister_netdev(dev); - list_del_init(&dev->list); - cnic_free_dev(dev); - } while (!list_empty(&cnic_udev_list)) { udev = list_entry(cnic_udev_list.next, struct cnic_uio_dev, list); diff --git a/drivers/net/ethernet/broadcom/cnic.h b/drivers/net/ethernet/broadcom/cnic.h index 62c670619ae6..e7a247473596 100644 --- a/drivers/net/ethernet/broadcom/cnic.h +++ b/drivers/net/ethernet/broadcom/cnic.h @@ -1,6 +1,6 @@ /* cnic.h: Broadcom CNIC core network driver. * - * Copyright (c) 2006-2011 Broadcom Corporation + * Copyright (c) 2006-2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/ethernet/broadcom/cnic_defs.h b/drivers/net/ethernet/broadcom/cnic_defs.h index ede3db35d757..95a8e4b11c9f 100644 --- a/drivers/net/ethernet/broadcom/cnic_defs.h +++ b/drivers/net/ethernet/broadcom/cnic_defs.h @@ -1,7 +1,7 @@ /* cnic.c: Broadcom CNIC core network driver. * - * Copyright (c) 2006-2012 Broadcom Corporation + * Copyright (c) 2006-2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -5400,8 +5400,8 @@ struct tstorm_l5cm_tcp_flags { u16 flags; #define TSTORM_L5CM_TCP_FLAGS_VLAN_ID (0xFFF<<0) #define TSTORM_L5CM_TCP_FLAGS_VLAN_ID_SHIFT 0 -#define TSTORM_L5CM_TCP_FLAGS_RSRV0 (0x1<<12) -#define TSTORM_L5CM_TCP_FLAGS_RSRV0_SHIFT 12 +#define TSTORM_L5CM_TCP_FLAGS_DELAYED_ACK_EN (0x1<<12) +#define TSTORM_L5CM_TCP_FLAGS_DELAYED_ACK_SHIFT 12 #define TSTORM_L5CM_TCP_FLAGS_TS_ENABLED (0x1<<13) #define TSTORM_L5CM_TCP_FLAGS_TS_ENABLED_SHIFT 13 #define TSTORM_L5CM_TCP_FLAGS_RSRV1 (0x3<<14) diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h index ec9bb9ad4bb3..95aff7642b85 100644 --- a/drivers/net/ethernet/broadcom/cnic_if.h +++ b/drivers/net/ethernet/broadcom/cnic_if.h @@ -1,6 +1,6 @@ /* cnic_if.h: Broadcom CNIC core network driver. * - * Copyright (c) 2006-2012 Broadcom Corporation + * Copyright (c) 2006-2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,8 +14,8 @@ #include "bnx2x/bnx2x_mfw_req.h" -#define CNIC_MODULE_VERSION "2.5.16" -#define CNIC_MODULE_RELDATE "Dec 05, 2012" +#define CNIC_MODULE_VERSION "2.5.17" +#define CNIC_MODULE_RELDATE "July 28, 2013" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 @@ -238,8 +238,8 @@ struct cnic_sock { u16 src_port; u16 dst_port; u16 vlan_id; - unsigned char old_ha[6]; - unsigned char ha[6]; + unsigned char old_ha[ETH_ALEN]; + unsigned char ha[ETH_ALEN]; u32 mtu; u32 cid; u32 l5_cid; @@ -308,7 +308,7 @@ struct cnic_dev { #define CNIC_F_BNX2_CLASS 3 #define CNIC_F_BNX2X_CLASS 4 atomic_t ref_count; - u8 mac_addr[6]; + u8 mac_addr[ETH_ALEN]; int max_iscsi_conn; int max_fcoe_conn; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 0da2214ef1b9..95b8995187d7 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -94,10 +94,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 132 +#define TG3_MIN_NUM 133 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "May 21, 2013" +#define DRV_MODULE_RELDATE "Jul 29, 2013" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1 @@ -4226,8 +4226,6 @@ static int tg3_power_down_prepare(struct tg3 *tp) static void tg3_power_down(struct tg3 *tp) { - tg3_power_down_prepare(tp); - pci_wake_from_d3(tp->pdev, tg3_flag(tp, WOL_ENABLE)); pci_set_power_state(tp->pdev, PCI_D3hot); } @@ -6095,10 +6093,12 @@ static u64 tg3_refclk_read(struct tg3 *tp) /* tp->lock must be held */ static void tg3_refclk_write(struct tg3 *tp, u64 newval) { - tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP); + u32 clock_ctl = tr32(TG3_EAV_REF_CLCK_CTL); + + tw32(TG3_EAV_REF_CLCK_CTL, clock_ctl | TG3_EAV_REF_CLCK_CTL_STOP); tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff); tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32); - tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME); + tw32_f(TG3_EAV_REF_CLCK_CTL, clock_ctl | TG3_EAV_REF_CLCK_CTL_RESUME); } static inline void tg3_full_lock(struct tg3 *tp, int irq_sync); @@ -6214,6 +6214,59 @@ static int tg3_ptp_settime(struct ptp_clock_info *ptp, static int tg3_ptp_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { + struct tg3 *tp = container_of(ptp, struct tg3, ptp_info); + u32 clock_ctl; + int rval = 0; + + switch (rq->type) { + case PTP_CLK_REQ_PEROUT: + if (rq->perout.index != 0) + return -EINVAL; + + tg3_full_lock(tp, 0); + clock_ctl = tr32(TG3_EAV_REF_CLCK_CTL); + clock_ctl &= ~TG3_EAV_CTL_TSYNC_GPIO_MASK; + + if (on) { + u64 nsec; + + nsec = rq->perout.start.sec * 1000000000ULL + + rq->perout.start.nsec; + + if (rq->perout.period.sec || rq->perout.period.nsec) { + netdev_warn(tp->dev, + "Device supports only a one-shot timesync output, period must be 0\n"); + rval = -EINVAL; + goto err_out; + } + + if (nsec & (1ULL << 63)) { + netdev_warn(tp->dev, + "Start value (nsec) is over limit. Maximum size of start is only 63 bits\n"); + rval = -EINVAL; + goto err_out; + } + + tw32(TG3_EAV_WATCHDOG0_LSB, (nsec & 0xffffffff)); + tw32(TG3_EAV_WATCHDOG0_MSB, + TG3_EAV_WATCHDOG0_EN | + ((nsec >> 32) & TG3_EAV_WATCHDOG_MSB_MASK)); + + tw32(TG3_EAV_REF_CLCK_CTL, + clock_ctl | TG3_EAV_CTL_TSYNC_WDOG0); + } else { + tw32(TG3_EAV_WATCHDOG0_MSB, 0); + tw32(TG3_EAV_REF_CLCK_CTL, clock_ctl); + } + +err_out: + tg3_full_unlock(tp); + return rval; + + default: + break; + } + return -EOPNOTSUPP; } @@ -6223,7 +6276,7 @@ static const struct ptp_clock_info tg3_ptp_caps = { .max_adj = 250000000, .n_alarm = 0, .n_ext_ts = 0, - .n_per_out = 0, + .n_per_out = 1, .pps = 0, .adjfreq = tg3_ptp_adjfreq, .adjtime = tg3_ptp_adjtime, @@ -10367,6 +10420,9 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) if (tg3_flag(tp, 5755_PLUS)) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; + if (tg3_asic_rev(tp) == ASIC_REV_5762) + tp->rx_mode |= RX_MODE_IPV4_FRAG_FIX; + if (tg3_flag(tp, ENABLE_RSS)) tp->rx_mode |= RX_MODE_RSS_ENABLE | RX_MODE_RSS_ITBL_HASH_BITS_7 | @@ -11502,7 +11558,7 @@ static int tg3_close(struct net_device *dev) memset(&tp->net_stats_prev, 0, sizeof(tp->net_stats_prev)); memset(&tp->estats_prev, 0, sizeof(tp->estats_prev)); - tg3_power_down(tp); + tg3_power_down_prepare(tp); tg3_carrier_off(tp); @@ -11724,9 +11780,6 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (tg3_flag(tp, NO_NVRAM)) return -EINVAL; - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) - return -EAGAIN; - offset = eeprom->offset; len = eeprom->len; eeprom->len = 0; @@ -11784,9 +11837,6 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *buf; __be32 start, end; - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) - return -EAGAIN; - if (tg3_flag(tp, NO_NVRAM) || eeprom->magic != TG3_EEPROM_MAGIC) return -EINVAL; @@ -13515,7 +13565,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_phy_start(tp); } if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) - tg3_power_down(tp); + tg3_power_down_prepare(tp); } @@ -15917,7 +15967,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) */ 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); + tp->msi_cap = tp->pdev->msi_cap; } else { struct pci_dev *bridge = NULL; @@ -17547,11 +17597,6 @@ static int tg3_init_one(struct pci_dev *pdev, tg3_asic_rev(tp) == ASIC_REV_5762) tg3_flag_set(tp, PTP_CAPABLE); - if (tg3_flag(tp, 5717_PLUS)) { - /* Resume a low-power mode */ - tg3_frob_aux_power(tp, false); - } - tg3_timer_init(tp); tg3_carrier_off(tp); @@ -17755,6 +17800,23 @@ out: static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume); +static void tg3_shutdown(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct tg3 *tp = netdev_priv(dev); + + rtnl_lock(); + netif_device_detach(dev); + + if (netif_running(dev)) + dev_close(dev); + + if (system_state == SYSTEM_POWER_OFF) + tg3_power_down(tp); + + rtnl_unlock(); +} + /** * tg3_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device @@ -17914,6 +17976,7 @@ static struct pci_driver tg3_driver = { .remove = tg3_remove_one, .err_handler = &tg3_err_handler, .driver.pm = &tg3_pm_ops, + .shutdown = tg3_shutdown, }; module_pci_driver(tg3_driver); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index cd63d1189aae..ddb8be1298ea 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -532,6 +532,7 @@ #define RX_MODE_RSS_ITBL_HASH_BITS_7 0x00700000 #define RX_MODE_RSS_ENABLE 0x00800000 #define RX_MODE_IPV6_CSUM_ENABLE 0x01000000 +#define RX_MODE_IPV4_FRAG_FIX 0x02000000 #define MAC_RX_STATUS 0x0000046c #define RX_STATUS_REMOTE_TX_XOFFED 0x00000001 #define RX_STATUS_XOFF_RCVD 0x00000002 @@ -1818,12 +1819,21 @@ #define TG3_EAV_REF_CLCK_CTL 0x00006908 #define TG3_EAV_REF_CLCK_CTL_STOP 0x00000002 #define TG3_EAV_REF_CLCK_CTL_RESUME 0x00000004 +#define TG3_EAV_CTL_TSYNC_GPIO_MASK (0x3 << 16) +#define TG3_EAV_CTL_TSYNC_WDOG0 (1 << 17) + +#define TG3_EAV_WATCHDOG0_LSB 0x00006918 +#define TG3_EAV_WATCHDOG0_MSB 0x0000691c +#define TG3_EAV_WATCHDOG0_EN (1 << 31) +#define TG3_EAV_WATCHDOG_MSB_MASK 0x7fffffff + #define TG3_EAV_REF_CLK_CORRECT_CTL 0x00006928 #define TG3_EAV_REF_CLK_CORRECT_EN (1 << 31) #define TG3_EAV_REF_CLK_CORRECT_NEG (1 << 30) #define TG3_EAV_REF_CLK_CORRECT_MASK 0xffffff -/* 0x690c --> 0x7000 unused */ + +/* 0x692c --> 0x7000 unused */ /* NVRAM Control registers */ #define NVRAM_CMD 0x00007000 |