diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/tg3.c')
| -rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 225 |
1 files changed, 135 insertions, 90 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 01dfec115942..75f66587983d 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -54,7 +54,8 @@ #include <linux/ssb/ssb_driver_gige.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <linux/crc32poly.h> +#include <linux/crc32.h> +#include <linux/dmi.h> #include <net/checksum.h> #include <net/gso.h> @@ -5802,7 +5803,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, bool force_reset) u32 current_speed = SPEED_UNKNOWN; u8 current_duplex = DUPLEX_UNKNOWN; bool current_link_up = false; - u32 local_adv, remote_adv, sgsr; + u32 local_adv = 0, remote_adv = 0, sgsr; if ((tg3_asic_rev(tp) == ASIC_REV_5719 || tg3_asic_rev(tp) == ASIC_REV_5720) && @@ -5943,9 +5944,6 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, bool force_reset) else current_duplex = DUPLEX_HALF; - local_adv = 0; - remote_adv = 0; - if (bmcr & BMCR_ANENABLE) { u32 common; @@ -6685,7 +6683,7 @@ static void tg3_rx_data_free(struct tg3 *tp, struct ring_info *ri, u32 map_sz) * We only need to fill in the address because the other members * of the RX descriptor are invariant, see tg3_init_rings. * - * Note the purposeful assymetry of cpu vs. chip accesses. For + * Note the purposeful asymmetry of cpu vs. chip accesses. For * posting buffers we only dirty the first cache line of the RX * descriptor (containing the address). Whereas for the RX status * buffers the cpu only reads the last cacheline of the RX descriptor @@ -7424,7 +7422,7 @@ static void tg3_napi_enable(struct tg3 *tp) for (i = 0; i < tp->irq_cnt; i++) { tnapi = &tp->napi[i]; - napi_enable(&tnapi->napi); + napi_enable_locked(&tnapi->napi); if (tnapi->tx_buffers) { netif_queue_set_napi(tp->dev, txq_idx, NETDEV_QUEUE_TYPE_TX, @@ -7445,9 +7443,10 @@ static void tg3_napi_init(struct tg3 *tp) int i; for (i = 0; i < tp->irq_cnt; i++) { - netif_napi_add(tp->dev, &tp->napi[i].napi, - i ? tg3_poll_msix : tg3_poll); - netif_napi_set_irq(&tp->napi[i].napi, tp->napi[i].irq_vec); + netif_napi_add_locked(tp->dev, &tp->napi[i].napi, + i ? tg3_poll_msix : tg3_poll); + netif_napi_set_irq_locked(&tp->napi[i].napi, + tp->napi[i].irq_vec); } } @@ -9807,26 +9806,7 @@ static void tg3_setup_rxbd_thresholds(struct tg3 *tp) 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 ^= CRC32_POLY_LE; - } - } - - return ~reg; + return ~crc32(~0, buf, len); } static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all) @@ -10162,7 +10142,7 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) tp->grc_mode |= GRC_MODE_HOST_SENDBDS; /* Pseudo-header checksum is done by hardware logic and not - * the offload processers, so make the chip do the pseudo- + * the offload processors, so make the chip do the pseudo- * header checksums on receive. For transmit it is more * convenient to do the pseudo-header checksum in software * as Linux does that on transmit for us in all cases. @@ -11079,7 +11059,7 @@ static void tg3_chk_missed_msi(struct tg3 *tp) static void tg3_timer(struct timer_list *t) { - struct tg3 *tp = from_timer(tp, t, timer); + struct tg3 *tp = timer_container_of(tp, t, timer); spin_lock(&tp->lock); @@ -11250,7 +11230,7 @@ static void tg3_timer_start(struct tg3 *tp) static void tg3_timer_stop(struct tg3 *tp) { - del_timer_sync(&tp->timer); + timer_delete_sync(&tp->timer); } /* Restart hardware after configuration changes, self-test, etc. @@ -11259,6 +11239,8 @@ static void tg3_timer_stop(struct tg3 *tp) static int tg3_restart_hw(struct tg3 *tp, bool reset_phy) __releases(tp->lock) __acquires(tp->lock) + __releases(tp->dev->lock) + __acquires(tp->dev->lock) { int err; @@ -11271,7 +11253,9 @@ static int tg3_restart_hw(struct tg3 *tp, bool reset_phy) tg3_timer_stop(tp); tp->irq_sync = 0; tg3_napi_enable(tp); + netdev_unlock(tp->dev); dev_close(tp->dev); + netdev_lock(tp->dev); tg3_full_lock(tp, 0); } return err; @@ -11299,6 +11283,7 @@ static void tg3_reset_task(struct work_struct *work) tg3_netif_stop(tp); + netdev_lock(tp->dev); tg3_full_lock(tp, 1); if (tg3_flag(tp, TX_RECOVERY_PENDING)) { @@ -11318,12 +11303,14 @@ static void tg3_reset_task(struct work_struct *work) * call cancel_work_sync() and wait forever. */ tg3_flag_clear(tp, RESET_TASK_PENDING); + netdev_unlock(tp->dev); dev_close(tp->dev); goto out; } tg3_netif_start(tp); tg3_full_unlock(tp); + netdev_unlock(tp->dev); tg3_phy_start(tp); tg3_flag_clear(tp, RESET_TASK_PENDING); out: @@ -11683,9 +11670,11 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq, if (err) goto out_ints_fini; + netdev_lock(dev); tg3_napi_init(tp); tg3_napi_enable(tp); + netdev_unlock(dev); for (i = 0; i < tp->irq_cnt; i++) { err = tg3_request_irq(tp, i); @@ -12569,6 +12558,7 @@ static int tg3_set_ringparam(struct net_device *dev, irq_sync = 1; } + netdev_lock(dev); tg3_full_lock(tp, irq_sync); tp->rx_pending = ering->rx_pending; @@ -12597,6 +12587,7 @@ static int tg3_set_ringparam(struct net_device *dev, } tg3_full_unlock(tp); + netdev_unlock(dev); if (irq_sync && !err) tg3_phy_start(tp); @@ -12678,6 +12669,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam irq_sync = 1; } + netdev_lock(dev); tg3_full_lock(tp, irq_sync); if (epause->autoneg) @@ -12707,6 +12699,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam } tg3_full_unlock(tp); + netdev_unlock(dev); } tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED; @@ -12726,29 +12719,17 @@ static int tg3_get_sset_count(struct net_device *dev, int sset) } } -static int tg3_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, - u32 *rules __always_unused) +static u32 tg3_get_rx_ring_count(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); if (!tg3_flag(tp, SUPPORT_MSIX)) - return -EOPNOTSUPP; - - switch (info->cmd) { - case ETHTOOL_GRXRINGS: - if (netif_running(tp->dev)) - info->data = tp->rxq_cnt; - else { - info->data = num_online_cpus(); - if (info->data > TG3_RSS_MAX_NUM_QS) - info->data = TG3_RSS_MAX_NUM_QS; - } + return 1; - return 0; + if (netif_running(tp->dev)) + return tp->rxq_cnt; - default: - return -EOPNOTSUPP; - } + return min_t(u32, netif_get_num_default_rss_queues(), tp->rxq_max); } static u32 tg3_get_rxfh_indir_size(struct net_device *dev) @@ -13911,6 +13892,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, data[TG3_INTERRUPT_TEST] = 1; } + netdev_lock(dev); tg3_full_lock(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -13922,6 +13904,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, } tg3_full_unlock(tp); + netdev_unlock(dev); if (irq_sync && !err2) tg3_phy_start(tp); @@ -13931,22 +13914,20 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, } -static int tg3_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) +static int tg3_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf, + struct netlink_ext_ack *extack) { struct tg3 *tp = netdev_priv(dev); - struct hwtstamp_config stmpconf; if (!tg3_flag(tp, PTP_CAPABLE)) return -EOPNOTSUPP; - if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf))) - return -EFAULT; - - if (stmpconf.tx_type != HWTSTAMP_TX_ON && - stmpconf.tx_type != HWTSTAMP_TX_OFF) + if (stmpconf->tx_type != HWTSTAMP_TX_ON && + stmpconf->tx_type != HWTSTAMP_TX_OFF) return -ERANGE; - switch (stmpconf.rx_filter) { + switch (stmpconf->rx_filter) { case HWTSTAMP_FILTER_NONE: tp->rxptpctl = 0; break; @@ -14006,74 +13987,72 @@ static int tg3_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) tw32(TG3_RX_PTP_CTL, tp->rxptpctl | TG3_RX_PTP_CTL_HWTS_INTERLOCK); - if (stmpconf.tx_type == HWTSTAMP_TX_ON) + if (stmpconf->tx_type == HWTSTAMP_TX_ON) tg3_flag_set(tp, TX_TSTAMP_EN); else tg3_flag_clear(tp, TX_TSTAMP_EN); - return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ? - -EFAULT : 0; + return 0; } -static int tg3_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +static int tg3_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf) { struct tg3 *tp = netdev_priv(dev); - struct hwtstamp_config stmpconf; if (!tg3_flag(tp, PTP_CAPABLE)) return -EOPNOTSUPP; - stmpconf.flags = 0; - stmpconf.tx_type = (tg3_flag(tp, TX_TSTAMP_EN) ? - HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF); + stmpconf->flags = 0; + stmpconf->tx_type = tg3_flag(tp, TX_TSTAMP_EN) ? + HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; switch (tp->rxptpctl) { case 0: - stmpconf.rx_filter = HWTSTAMP_FILTER_NONE; + stmpconf->rx_filter = HWTSTAMP_FILTER_NONE; break; case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_ALL_V1_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; break; case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; break; default: WARN_ON_ONCE(1); return -ERANGE; } - return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ? - -EFAULT : 0; + return 0; } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -14128,12 +14107,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; - case SIOCSHWTSTAMP: - return tg3_hwtstamp_set(dev, ifr); - - case SIOCGHWTSTAMP: - return tg3_hwtstamp_get(dev, ifr); - default: /* do nothing */ break; @@ -14283,7 +14256,7 @@ static const struct ethtool_ops tg3_ethtool_ops = { .get_coalesce = tg3_get_coalesce, .set_coalesce = tg3_set_coalesce, .get_sset_count = tg3_get_sset_count, - .get_rxnfc = tg3_get_rxnfc, + .get_rx_ring_count = tg3_get_rx_ring_count, .get_rxfh_indir_size = tg3_get_rxfh_indir_size, .get_rxfh = tg3_get_rxfh, .set_rxfh = tg3_set_rxfh, @@ -14365,6 +14338,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_set_mtu(dev, tp, new_mtu); + netdev_lock(dev); tg3_full_lock(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -14384,6 +14358,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_netif_start(tp); tg3_full_unlock(tp); + netdev_unlock(dev); if (!err) tg3_phy_start(tp); @@ -14407,6 +14382,8 @@ static const struct net_device_ops tg3_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tg3_poll_controller, #endif + .ndo_hwtstamp_get = tg3_hwtstamp_get, + .ndo_hwtstamp_set = tg3_hwtstamp_set, }; static void tg3_get_eeprom_size(struct tg3 *tp) @@ -16610,7 +16587,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) tg3_flag_set(tp, PCIX_TARGET_HWBUG); - /* The chip can have it's power management PCI config + /* The chip can have its power management PCI config * space registers clobbered due to this bug. * So explicitly force the chip into D0 here. */ @@ -17839,6 +17816,9 @@ static int tg3_init_one(struct pci_dev *pdev, } else persist_dma_mask = dma_mask = DMA_BIT_MASK(64); + if (tg3_asic_rev(tp) == ASIC_REV_57766) + persist_dma_mask = DMA_BIT_MASK(31); + /* Configure DMA attributes. */ if (dma_mask > DMA_BIT_MASK(32)) { err = dma_set_mask(&pdev->dev, dma_mask); @@ -18161,6 +18141,7 @@ static int tg3_resume(struct device *device) netif_device_attach(dev); + netdev_lock(dev); tg3_full_lock(tp, 0); tg3_ape_driver_state_change(tp, RESET_KIND_INIT); @@ -18177,6 +18158,7 @@ static int tg3_resume(struct device *device) out: tg3_full_unlock(tp); + netdev_unlock(dev); if (!err) tg3_phy_start(tp); @@ -18189,6 +18171,50 @@ unlock: static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume); +/* Systems where ACPI _PTS (Prepare To Sleep) S5 will result in a fatal + * PCIe AER event on the tg3 device if the tg3 device is not, or cannot + * be, powered down. + */ +static const struct dmi_system_id tg3_restart_aer_quirk_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R440"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R540"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R640"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R650"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R740"), + }, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R750"), + }, + }, + {} +}; + static void tg3_shutdown(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); @@ -18205,6 +18231,19 @@ static void tg3_shutdown(struct pci_dev *pdev) if (system_state == SYSTEM_POWER_OFF) tg3_power_down(tp); + else if (system_state == SYSTEM_RESTART && + dmi_first_match(tg3_restart_aer_quirk_table) && + pdev->current_state != PCI_D3cold && + pdev->current_state != PCI_UNKNOWN) { + /* Disable PCIe AER on the tg3 to avoid a fatal + * error during this system restart. + */ + pcie_capability_clear_word(pdev, PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_CERE | + PCI_EXP_DEVCTL_NFERE | + PCI_EXP_DEVCTL_FERE | + PCI_EXP_DEVCTL_URRE); + } rtnl_unlock(); @@ -18257,7 +18296,9 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, done: if (state == pci_channel_io_perm_failure) { if (netdev) { + netdev_lock(netdev); tg3_napi_enable(tp); + netdev_unlock(netdev); dev_close(netdev); } err = PCI_ERS_RESULT_DISCONNECT; @@ -18296,7 +18337,6 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); pci_restore_state(pdev); - pci_save_state(pdev); if (!netdev || !netif_running(netdev)) { rc = PCI_ERS_RESULT_RECOVERED; @@ -18311,7 +18351,9 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) done: if (rc != PCI_ERS_RESULT_RECOVERED && netdev && netif_running(netdev)) { + netdev_lock(netdev); tg3_napi_enable(tp); + netdev_unlock(netdev); dev_close(netdev); } rtnl_unlock(); @@ -18337,12 +18379,14 @@ static void tg3_io_resume(struct pci_dev *pdev) if (!netdev || !netif_running(netdev)) goto done; + netdev_lock(netdev); tg3_full_lock(tp, 0); tg3_ape_driver_state_change(tp, RESET_KIND_INIT); tg3_flag_set(tp, INIT_COMPLETE); err = tg3_restart_hw(tp, true); if (err) { tg3_full_unlock(tp); + netdev_unlock(netdev); netdev_err(netdev, "Cannot restart hardware after reset.\n"); goto done; } @@ -18354,6 +18398,7 @@ static void tg3_io_resume(struct pci_dev *pdev) tg3_netif_start(tp); tg3_full_unlock(tp); + netdev_unlock(netdev); tg3_phy_start(tp); |
