diff options
Diffstat (limited to 'drivers/net/igb')
-rw-r--r-- | drivers/net/igb/e1000_82575.c | 18 | ||||
-rw-r--r-- | drivers/net/igb/e1000_defines.h | 31 | ||||
-rw-r--r-- | drivers/net/igb/e1000_hw.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/e1000_phy.c | 206 | ||||
-rw-r--r-- | drivers/net/igb/e1000_phy.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/igb.h | 11 | ||||
-rw-r--r-- | drivers/net/igb/igb_ethtool.c | 52 | ||||
-rw-r--r-- | drivers/net/igb/igb_main.c | 164 |
8 files changed, 408 insertions, 78 deletions
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 187622f1c816..bc183f5487cb 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -132,6 +132,8 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_82580_SERDES: case E1000_DEV_ID_82580_SGMII: case E1000_DEV_ID_82580_COPPER_DUAL: + case E1000_DEV_ID_DH89XXCC_SGMII: + case E1000_DEV_ID_DH89XXCC_SERDES: mac->type = e1000_82580; break; case E1000_DEV_ID_I350_COPPER: @@ -282,10 +284,18 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) /* Verify phy id and set remaining function pointers */ switch (phy->id) { + case I347AT4_E_PHY_ID: + case M88E1112_E_PHY_ID: case M88E1111_I_PHY_ID: phy->type = e1000_phy_m88; phy->ops.get_phy_info = igb_get_phy_info_m88; - phy->ops.get_cable_length = igb_get_cable_length_m88; + + if (phy->id == I347AT4_E_PHY_ID || + phy->id == M88E1112_E_PHY_ID) + phy->ops.get_cable_length = igb_get_cable_length_m88_gen2; + else + phy->ops.get_cable_length = igb_get_cable_length_m88; + phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; break; case IGP03E1000_E_PHY_ID: @@ -1058,7 +1068,11 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) } switch (hw->phy.type) { case e1000_phy_m88: - ret_val = igb_copper_link_setup_m88(hw); + if (hw->phy.id == I347AT4_E_PHY_ID || + hw->phy.id == M88E1112_E_PHY_ID) + ret_val = igb_copper_link_setup_m88_gen2(hw); + else + ret_val = igb_copper_link_setup_m88(hw); break; case e1000_phy_igp_3: ret_val = igb_copper_link_setup_igp(hw); diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index bbd2ec308eb0..62222796a8b3 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -634,6 +634,8 @@ * E = External */ #define M88E1111_I_PHY_ID 0x01410CC0 +#define M88E1112_E_PHY_ID 0x01410C90 +#define I347AT4_E_PHY_ID 0x01410DC0 #define IGP03E1000_E_PHY_ID 0x02A80390 #define I82580_I_PHY_ID 0x015403A0 #define I350_I_PHY_ID 0x015403B0 @@ -702,6 +704,35 @@ #define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 #define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ +/* Intel i347-AT4 Registers */ + +#define I347AT4_PCDL 0x10 /* PHY Cable Diagnostics Length */ +#define I347AT4_PCDC 0x15 /* PHY Cable Diagnostics Control */ +#define I347AT4_PAGE_SELECT 0x16 + +/* i347-AT4 Extended PHY Specific Control Register */ + +/* + * Number of times we will attempt to autonegotiate before downshifting if we + * are the master + */ +#define I347AT4_PSCR_DOWNSHIFT_ENABLE 0x0800 +#define I347AT4_PSCR_DOWNSHIFT_MASK 0x7000 +#define I347AT4_PSCR_DOWNSHIFT_1X 0x0000 +#define I347AT4_PSCR_DOWNSHIFT_2X 0x1000 +#define I347AT4_PSCR_DOWNSHIFT_3X 0x2000 +#define I347AT4_PSCR_DOWNSHIFT_4X 0x3000 +#define I347AT4_PSCR_DOWNSHIFT_5X 0x4000 +#define I347AT4_PSCR_DOWNSHIFT_6X 0x5000 +#define I347AT4_PSCR_DOWNSHIFT_7X 0x6000 +#define I347AT4_PSCR_DOWNSHIFT_8X 0x7000 + +/* i347-AT4 PHY Cable Diagnostics Control */ +#define I347AT4_PCDC_CABLE_LENGTH_UNIT 0x0400 /* 0=cm 1=meters */ + +/* Marvell 1112 only registers */ +#define M88E1112_VCT_DSP_DISTANCE 0x001A + /* M88EC018 Rev 2 specific DownShift settings */ #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index cb8db78b1a05..c0b017f8d782 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -54,6 +54,8 @@ struct e1000_hw; #define E1000_DEV_ID_82580_SERDES 0x1510 #define E1000_DEV_ID_82580_SGMII 0x1511 #define E1000_DEV_ID_82580_COPPER_DUAL 0x1516 +#define E1000_DEV_ID_DH89XXCC_SGMII 0x0436 +#define E1000_DEV_ID_DH89XXCC_SERDES 0x0438 #define E1000_DEV_ID_I350_COPPER 0x1521 #define E1000_DEV_ID_I350_FIBER 0x1522 #define E1000_DEV_ID_I350_SERDES 0x1523 diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index cf1f32300923..ddd036a78999 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c @@ -570,6 +570,89 @@ out: } /** + * igb_copper_link_setup_m88_gen2 - Setup m88 PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up MDI/MDI-X and polarity for i347-AT4, m88e1322 and m88e1112 PHY's. + * Also enables and sets the downshift parameters. + **/ +s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + if (phy->reset_disable) { + ret_val = 0; + goto out; + } + + /* Enable CRS on Tx. This must be set for half-duplex operation. */ + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); + if (ret_val) + goto out; + + /* + * Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (phy->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + /* M88E1112 does not support this mode) */ + if (phy->id != M88E1112_E_PHY_ID) { + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + } + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* + * Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if (phy->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + + /* Enable downshift and setting it to X6 */ + phy_data &= ~I347AT4_PSCR_DOWNSHIFT_MASK; + phy_data |= I347AT4_PSCR_DOWNSHIFT_6X; + phy_data |= I347AT4_PSCR_DOWNSHIFT_ENABLE; + + ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); + if (ret_val) + goto out; + + /* Commit the changes. */ + ret_val = igb_phy_sw_reset(hw); + if (ret_val) { + hw_dbg("Error committing the PHY changes\n"); + goto out; + } + +out: + return ret_val; +} + +/** * igb_copper_link_setup_igp - Setup igp PHY's for copper link * @hw: pointer to the HW structure * @@ -1124,18 +1207,25 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) goto out; if (!link) { - /* - * We didn't get link. - * Reset the DSP and cross our fingers. - */ - ret_val = phy->ops.write_reg(hw, - M88E1000_PHY_PAGE_SELECT, - 0x001d); - if (ret_val) - goto out; - ret_val = igb_phy_reset_dsp(hw); - if (ret_val) - goto out; + if (hw->phy.type != e1000_phy_m88 || + hw->phy.id == I347AT4_E_PHY_ID || + hw->phy.id == M88E1112_E_PHY_ID) { + hw_dbg("Link taking longer than expected.\n"); + } else { + + /* + * We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = phy->ops.write_reg(hw, + M88E1000_PHY_PAGE_SELECT, + 0x001d); + if (ret_val) + goto out; + ret_val = igb_phy_reset_dsp(hw); + if (ret_val) + goto out; + } } /* Try once more */ @@ -1145,6 +1235,11 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) goto out; } + if (hw->phy.type != e1000_phy_m88 || + hw->phy.id == I347AT4_E_PHY_ID || + hw->phy.id == M88E1112_E_PHY_ID) + goto out; + ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); if (ret_val) goto out; @@ -1557,6 +1652,93 @@ out: return ret_val; } +s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, phy_data2, index, default_page, is_cm; + + switch (hw->phy.id) { + case I347AT4_E_PHY_ID: + /* Remember the original page select and set it to 7 */ + ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT, + &default_page); + if (ret_val) + goto out; + + ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x07); + if (ret_val) + goto out; + + /* Get cable length from PHY Cable Diagnostics Control Reg */ + ret_val = phy->ops.read_reg(hw, (I347AT4_PCDL + phy->addr), + &phy_data); + if (ret_val) + goto out; + + /* Check if the unit of cable length is meters or cm */ + ret_val = phy->ops.read_reg(hw, I347AT4_PCDC, &phy_data2); + if (ret_val) + goto out; + + is_cm = !(phy_data & I347AT4_PCDC_CABLE_LENGTH_UNIT); + + /* Populate the phy structure with cable length in meters */ + phy->min_cable_length = phy_data / (is_cm ? 100 : 1); + phy->max_cable_length = phy_data / (is_cm ? 100 : 1); + phy->cable_length = phy_data / (is_cm ? 100 : 1); + + /* Reset the page selec to its original value */ + ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, + default_page); + if (ret_val) + goto out; + break; + case M88E1112_E_PHY_ID: + /* Remember the original page select and set it to 5 */ + ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT, + &default_page); + if (ret_val) + goto out; + + ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, 0x05); + if (ret_val) + goto out; + + ret_val = phy->ops.read_reg(hw, M88E1112_VCT_DSP_DISTANCE, + &phy_data); + if (ret_val) + goto out; + + index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT; + if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { + ret_val = -E1000_ERR_PHY; + goto out; + } + + phy->min_cable_length = e1000_m88_cable_length_table[index]; + phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; + + phy->cable_length = (phy->min_cable_length + + phy->max_cable_length) / 2; + + /* Reset the page select to its original value */ + ret_val = phy->ops.write_reg(hw, I347AT4_PAGE_SELECT, + default_page); + if (ret_val) + goto out; + + break; + default: + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + /** * igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY * @hw: pointer to the HW structure diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h index 565a6dbb3714..2cc117705a31 100644 --- a/drivers/net/igb/e1000_phy.h +++ b/drivers/net/igb/e1000_phy.h @@ -45,9 +45,11 @@ s32 igb_check_downshift(struct e1000_hw *hw); s32 igb_check_reset_block(struct e1000_hw *hw); s32 igb_copper_link_setup_igp(struct e1000_hw *hw); s32 igb_copper_link_setup_m88(struct e1000_hw *hw); +s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw); s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw); s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw); s32 igb_get_cable_length_m88(struct e1000_hw *hw); +s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw); s32 igb_get_cable_length_igp_2(struct e1000_hw *hw); s32 igb_get_phy_id(struct e1000_hw *hw); s32 igb_get_phy_info_igp(struct e1000_hw *hw); diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 6e63d9a7fc75..edab9c442399 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -143,7 +143,7 @@ struct igb_buffer { u16 next_to_watch; unsigned int bytecount; u16 gso_segs; - union skb_shared_tx shtx; + u8 tx_flags; u8 mapped_as_page; }; /* RX */ @@ -159,6 +159,7 @@ struct igb_tx_queue_stats { u64 packets; u64 bytes; u64 restart_queue; + u64 restart_queue2; }; struct igb_rx_queue_stats { @@ -210,11 +211,14 @@ struct igb_ring { /* TX */ struct { struct igb_tx_queue_stats tx_stats; + struct u64_stats_sync tx_syncp; + struct u64_stats_sync tx_syncp2; bool detect_tx_hung; }; /* RX */ struct { struct igb_rx_queue_stats rx_stats; + struct u64_stats_sync rx_syncp; u32 rx_buffer_len; }; }; @@ -288,6 +292,9 @@ struct igb_adapter { struct timecompare compare; struct hwtstamp_config hwtstamp_config; + spinlock_t stats64_lock; + struct rtnl_link_stats64 stats64; + /* structs defined in e1000_hw.h */ struct e1000_hw hw; struct e1000_hw_stats stats; @@ -357,7 +364,7 @@ extern netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *, struct igb_ring *); extern void igb_unmap_and_free_tx_resource(struct igb_ring *, struct igb_buffer *); extern void igb_alloc_rx_buffers_adv(struct igb_ring *, int); -extern void igb_update_stats(struct igb_adapter *); +extern void igb_update_stats(struct igb_adapter *, struct rtnl_link_stats64 *); extern bool igb_has_link(struct igb_adapter *adapter); extern void igb_set_ethtool_ops(struct net_device *); extern void igb_power_up_link(struct igb_adapter *); diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 26bf6a13d1c1..a70e16bcfa7e 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -90,8 +90,8 @@ static const struct igb_stats igb_gstrings_stats[] = { #define IGB_NETDEV_STAT(_net_stat) { \ .stat_string = __stringify(_net_stat), \ - .sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \ - .stat_offset = offsetof(struct net_device_stats, _net_stat) \ + .sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \ + .stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \ } static const struct igb_stats igb_gstrings_net_stats[] = { IGB_NETDEV_STAT(rx_errors), @@ -111,8 +111,9 @@ static const struct igb_stats igb_gstrings_net_stats[] = { (sizeof(igb_gstrings_net_stats) / sizeof(struct igb_stats)) #define IGB_RX_QUEUE_STATS_LEN \ (sizeof(struct igb_rx_queue_stats) / sizeof(u64)) -#define IGB_TX_QUEUE_STATS_LEN \ - (sizeof(struct igb_tx_queue_stats) / sizeof(u64)) + +#define IGB_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */ + #define IGB_QUEUE_STATS_LEN \ ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues * \ IGB_RX_QUEUE_STATS_LEN) + \ @@ -2070,12 +2071,14 @@ static void igb_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct igb_adapter *adapter = netdev_priv(netdev); - struct net_device_stats *net_stats = &netdev->stats; - u64 *queue_stat; - int i, j, k; + struct rtnl_link_stats64 *net_stats = &adapter->stats64; + unsigned int start; + struct igb_ring *ring; + int i, j; char *p; - igb_update_stats(adapter); + spin_lock(&adapter->stats64_lock); + igb_update_stats(adapter, net_stats); for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { p = (char *)adapter + igb_gstrings_stats[i].stat_offset; @@ -2088,15 +2091,36 @@ static void igb_get_ethtool_stats(struct net_device *netdev, sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } for (j = 0; j < adapter->num_tx_queues; j++) { - queue_stat = (u64 *)&adapter->tx_ring[j]->tx_stats; - for (k = 0; k < IGB_TX_QUEUE_STATS_LEN; k++, i++) - data[i] = queue_stat[k]; + u64 restart2; + + ring = adapter->tx_ring[j]; + do { + start = u64_stats_fetch_begin_bh(&ring->tx_syncp); + data[i] = ring->tx_stats.packets; + data[i+1] = ring->tx_stats.bytes; + data[i+2] = ring->tx_stats.restart_queue; + } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start)); + do { + start = u64_stats_fetch_begin_bh(&ring->tx_syncp2); + restart2 = ring->tx_stats.restart_queue2; + } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start)); + data[i+2] += restart2; + + i += IGB_TX_QUEUE_STATS_LEN; } for (j = 0; j < adapter->num_rx_queues; j++) { - queue_stat = (u64 *)&adapter->rx_ring[j]->rx_stats; - for (k = 0; k < IGB_RX_QUEUE_STATS_LEN; k++, i++) - data[i] = queue_stat[k]; + ring = adapter->rx_ring[j]; + do { + start = u64_stats_fetch_begin_bh(&ring->rx_syncp); + data[i] = ring->rx_stats.packets; + data[i+1] = ring->rx_stats.bytes; + data[i+2] = ring->rx_stats.drops; + data[i+3] = ring->rx_stats.csum_err; + data[i+4] = ring->rx_stats.alloc_failed; + } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start)); + i += IGB_RX_QUEUE_STATS_LEN; } + spin_unlock(&adapter->stats64_lock); } static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index aaf506c56ccb..14db09e2fa8b 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -71,6 +71,8 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 }, @@ -94,7 +96,6 @@ static int igb_setup_all_rx_resources(struct igb_adapter *); static void igb_free_all_tx_resources(struct igb_adapter *); static void igb_free_all_rx_resources(struct igb_adapter *); static void igb_setup_mrqc(struct igb_adapter *); -void igb_update_stats(struct igb_adapter *); static int igb_probe(struct pci_dev *, const struct pci_device_id *); static void __devexit igb_remove(struct pci_dev *pdev); static int igb_sw_init(struct igb_adapter *); @@ -111,7 +112,8 @@ static void igb_update_phy_info(unsigned long); static void igb_watchdog(unsigned long); static void igb_watchdog_task(struct work_struct *); static netdev_tx_t igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *); -static struct net_device_stats *igb_get_stats(struct net_device *); +static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats); static int igb_change_mtu(struct net_device *, int); static int igb_set_mac(struct net_device *, void *); static void igb_set_uta(struct igb_adapter *adapter); @@ -986,7 +988,7 @@ static void igb_clear_interrupt_scheme(struct igb_adapter *adapter) * Attempt to configure interrupts using the best available * capabilities of the hardware and kernel. **/ -static void igb_set_interrupt_capability(struct igb_adapter *adapter) +static int igb_set_interrupt_capability(struct igb_adapter *adapter) { int err; int numvecs, i; @@ -1052,8 +1054,10 @@ msi_only: if (!pci_enable_msi(adapter->pdev)) adapter->flags |= IGB_FLAG_HAS_MSI; out: - /* Notify the stack of the (possibly) reduced Tx Queue count. */ - adapter->netdev->real_num_tx_queues = adapter->num_tx_queues; + /* Notify the stack of the (possibly) reduced queue counts. */ + netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues); + return netif_set_real_num_rx_queues(adapter->netdev, + adapter->num_rx_queues); } /** @@ -1152,7 +1156,9 @@ static int igb_init_interrupt_scheme(struct igb_adapter *adapter) struct pci_dev *pdev = adapter->pdev; int err; - igb_set_interrupt_capability(adapter); + err = igb_set_interrupt_capability(adapter); + if (err) + return err; err = igb_alloc_q_vectors(adapter); if (err) { @@ -1530,7 +1536,9 @@ void igb_down(struct igb_adapter *adapter) netif_carrier_off(netdev); /* record the stats before reset*/ - igb_update_stats(adapter); + spin_lock(&adapter->stats64_lock); + igb_update_stats(adapter, &adapter->stats64); + spin_unlock(&adapter->stats64_lock); adapter->link_speed = 0; adapter->link_duplex = 0; @@ -1683,7 +1691,7 @@ static const struct net_device_ops igb_netdev_ops = { .ndo_open = igb_open, .ndo_stop = igb_close, .ndo_start_xmit = igb_xmit_frame_adv, - .ndo_get_stats = igb_get_stats, + .ndo_get_stats64 = igb_get_stats64, .ndo_set_rx_mode = igb_set_rx_mode, .ndo_set_multicast_list = igb_set_rx_mode, .ndo_set_mac_address = igb_set_mac, @@ -1856,8 +1864,10 @@ static int __devinit igb_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_IPV6_CSUM; netdev->vlan_features |= NETIF_F_SG; - if (pci_using_dac) + if (pci_using_dac) { netdev->features |= NETIF_F_HIGHDMA; + netdev->vlan_features |= NETIF_F_HIGHDMA; + } if (hw->mac.type >= e1000_82576) netdev->features |= NETIF_F_SCTP_CSUM; @@ -1888,9 +1898,9 @@ static int __devinit igb_probe(struct pci_dev *pdev, goto err_eeprom; } - setup_timer(&adapter->watchdog_timer, &igb_watchdog, + setup_timer(&adapter->watchdog_timer, igb_watchdog, (unsigned long) adapter); - setup_timer(&adapter->phy_info_timer, &igb_update_phy_info, + setup_timer(&adapter->phy_info_timer, igb_update_phy_info, (unsigned long) adapter); INIT_WORK(&adapter->reset_task, igb_reset_task); @@ -2268,6 +2278,7 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + spin_lock_init(&adapter->stats64_lock); #ifdef CONFIG_PCI_IOV if (hw->mac.type == e1000_82576) adapter->vfs_allocated_count = (max_vfs > 7) ? 7 : max_vfs; @@ -3475,7 +3486,9 @@ static void igb_watchdog_task(struct work_struct *work) } } - igb_update_stats(adapter); + spin_lock(&adapter->stats64_lock); + igb_update_stats(adapter, &adapter->stats64); + spin_unlock(&adapter->stats64_lock); for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *tx_ring = adapter->tx_ring[i]; @@ -3542,6 +3555,8 @@ static void igb_update_ring_itr(struct igb_q_vector *q_vector) int new_val = q_vector->itr_val; int avg_wire_size = 0; struct igb_adapter *adapter = q_vector->adapter; + struct igb_ring *ring; + unsigned int packets; /* For non-gigabit speeds, just fix the interrupt rate at 4000 * ints/sec - ITR timer value of 120 ticks. @@ -3551,16 +3566,21 @@ static void igb_update_ring_itr(struct igb_q_vector *q_vector) goto set_itr_val; } - if (q_vector->rx_ring && q_vector->rx_ring->total_packets) { - struct igb_ring *ring = q_vector->rx_ring; - avg_wire_size = ring->total_bytes / ring->total_packets; + ring = q_vector->rx_ring; + if (ring) { + packets = ACCESS_ONCE(ring->total_packets); + + if (packets) + avg_wire_size = ring->total_bytes / packets; } - if (q_vector->tx_ring && q_vector->tx_ring->total_packets) { - struct igb_ring *ring = q_vector->tx_ring; - avg_wire_size = max_t(u32, avg_wire_size, - (ring->total_bytes / - ring->total_packets)); + ring = q_vector->tx_ring; + if (ring) { + packets = ACCESS_ONCE(ring->total_packets); + + if (packets) + avg_wire_size = max_t(u32, avg_wire_size, + ring->total_bytes / packets); } /* if avg_wire_size isn't set no work was done */ @@ -3954,7 +3974,7 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb, } tx_ring->buffer_info[i].skb = skb; - tx_ring->buffer_info[i].shtx = skb_shinfo(skb)->tx_flags; + tx_ring->buffer_info[i].tx_flags = skb_shinfo(skb)->tx_flags; /* multiply data chunks by size of headers */ tx_ring->buffer_info[i].bytecount = ((gso_segs - 1) * hlen) + skb->len; tx_ring->buffer_info[i].gso_segs = gso_segs; @@ -4069,7 +4089,11 @@ static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, int size) /* A reprieve! */ netif_wake_subqueue(netdev, tx_ring->queue_index); - tx_ring->tx_stats.restart_queue++; + + u64_stats_update_begin(&tx_ring->tx_syncp2); + tx_ring->tx_stats.restart_queue2++; + u64_stats_update_end(&tx_ring->tx_syncp2); + return 0; } @@ -4088,7 +4112,6 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, u32 tx_flags = 0; u16 first; u8 hdr_len = 0; - union skb_shared_tx *shtx = skb_tx(skb); /* need: 1 descriptor per page, * + 2 desc gap to keep tail from touching head, @@ -4100,12 +4123,12 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, return NETDEV_TX_BUSY; } - if (unlikely(shtx->hardware)) { - shtx->in_progress = 1; + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_flags |= IGB_TX_FLAGS_TSTAMP; } - if (vlan_tx_tag_present(skb) && adapter->vlgrp) { + if (vlan_tx_tag_present(skb)) { tx_flags |= IGB_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); } @@ -4207,16 +4230,22 @@ static void igb_reset_task(struct work_struct *work) } /** - * igb_get_stats - Get System Network Statistics + * igb_get_stats64 - Get System Network Statistics * @netdev: network interface device structure + * @stats: rtnl_link_stats64 pointer * - * Returns the address of the device statistics structure. - * The statistics are actually updated from the timer callback. **/ -static struct net_device_stats *igb_get_stats(struct net_device *netdev) +static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) { - /* only return the current stats */ - return &netdev->stats; + struct igb_adapter *adapter = netdev_priv(netdev); + + spin_lock(&adapter->stats64_lock); + igb_update_stats(adapter, &adapter->stats64); + memcpy(stats, &adapter->stats64, sizeof(*stats)); + spin_unlock(&adapter->stats64_lock); + + return stats; } /** @@ -4298,15 +4327,17 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) * @adapter: board private structure **/ -void igb_update_stats(struct igb_adapter *adapter) +void igb_update_stats(struct igb_adapter *adapter, + struct rtnl_link_stats64 *net_stats) { - struct net_device_stats *net_stats = igb_get_stats(adapter->netdev); struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; u32 reg, mpc; u16 phy_tmp; int i; u64 bytes, packets; + unsigned int start; + u64 _bytes, _packets; #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF @@ -4324,10 +4355,17 @@ void igb_update_stats(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { u32 rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0x0FFF; struct igb_ring *ring = adapter->rx_ring[i]; + ring->rx_stats.drops += rqdpc_tmp; net_stats->rx_fifo_errors += rqdpc_tmp; - bytes += ring->rx_stats.bytes; - packets += ring->rx_stats.packets; + + do { + start = u64_stats_fetch_begin_bh(&ring->rx_syncp); + _bytes = ring->rx_stats.bytes; + _packets = ring->rx_stats.packets; + } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start)); + bytes += _bytes; + packets += _packets; } net_stats->rx_bytes = bytes; @@ -4337,8 +4375,13 @@ void igb_update_stats(struct igb_adapter *adapter) packets = 0; for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = adapter->tx_ring[i]; - bytes += ring->tx_stats.bytes; - packets += ring->tx_stats.packets; + do { + start = u64_stats_fetch_begin_bh(&ring->tx_syncp); + _bytes = ring->tx_stats.bytes; + _packets = ring->tx_stats.packets; + } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start)); + bytes += _bytes; + packets += _packets; } net_stats->tx_bytes = bytes; net_stats->tx_packets = packets; @@ -4660,12 +4703,13 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf) u32 vmolr = rd32(E1000_VMOLR(vf)); struct vf_data_storage *vf_data = &adapter->vf_data[vf]; - vf_data->flags |= ~(IGB_VF_FLAG_UNI_PROMISC | + vf_data->flags &= ~(IGB_VF_FLAG_UNI_PROMISC | IGB_VF_FLAG_MULTI_PROMISC); vmolr &= ~(E1000_VMOLR_ROPE | E1000_VMOLR_ROMPE | E1000_VMOLR_MPME); if (*msgbuf & E1000_VF_SET_PROMISC_MULTICAST) { vmolr |= E1000_VMOLR_MPME; + vf_data->flags |= IGB_VF_FLAG_MULTI_PROMISC; *msgbuf &= ~E1000_VF_SET_PROMISC_MULTICAST; } else { /* @@ -5319,7 +5363,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct igb_buffer *bu u64 regval; /* if skb does not support hw timestamp or TX stamp not valid exit */ - if (likely(!buffer_info->shtx.hardware) || + if (likely(!(buffer_info->tx_flags & SKBTX_HW_TSTAMP)) || !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID)) return; @@ -5389,7 +5433,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && !(test_bit(__IGB_DOWN, &adapter->state))) { netif_wake_subqueue(netdev, tx_ring->queue_index); + + u64_stats_update_begin(&tx_ring->tx_syncp); tx_ring->tx_stats.restart_queue++; + u64_stats_update_end(&tx_ring->tx_syncp); } } @@ -5429,9 +5476,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) } tx_ring->total_bytes += total_bytes; tx_ring->total_packets += total_packets; + u64_stats_update_begin(&tx_ring->tx_syncp); tx_ring->tx_stats.bytes += total_bytes; tx_ring->tx_stats.packets += total_packets; - return (count < tx_ring->count); + u64_stats_update_end(&tx_ring->tx_syncp); + return count < tx_ring->count; } /** @@ -5456,7 +5505,7 @@ static void igb_receive_skb(struct igb_q_vector *q_vector, static inline void igb_rx_checksum_adv(struct igb_ring *ring, u32 status_err, struct sk_buff *skb) { - skb->ip_summed = CHECKSUM_NONE; + skb_checksum_none_assert(skb); /* Ignore Checksum bit is set or checksum is disabled through ethtool */ if (!(ring->flags & IGB_RING_FLAG_RX_CSUM) || @@ -5472,9 +5521,11 @@ static inline void igb_rx_checksum_adv(struct igb_ring *ring, * packets, (aka let the stack check the crc32c) */ if ((skb->len == 60) && - (ring->flags & IGB_RING_FLAG_RX_SCTP_CSUM)) + (ring->flags & IGB_RING_FLAG_RX_SCTP_CSUM)) { + u64_stats_update_begin(&ring->rx_syncp); ring->rx_stats.csum_err++; - + u64_stats_update_end(&ring->rx_syncp); + } /* let the stack verify checksum errors */ return; } @@ -5500,7 +5551,7 @@ static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr, * values must belong to this one here and therefore we don't need to * compare any of the additional attributes stored for it. * - * If nothing went wrong, then it should have a skb_shared_tx that we + * If nothing went wrong, then it should have a shared tx_flags that we * can turn into a skb_shared_hwtstamps. */ if (staterr & E1000_RXDADV_STAT_TSIP) { @@ -5661,8 +5712,10 @@ next_desc: rx_ring->total_packets += total_packets; rx_ring->total_bytes += total_bytes; + u64_stats_update_begin(&rx_ring->rx_syncp); rx_ring->rx_stats.packets += total_packets; rx_ring->rx_stats.bytes += total_bytes; + u64_stats_update_end(&rx_ring->rx_syncp); return cleaned; } @@ -5690,8 +5743,10 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count) if ((bufsz < IGB_RXBUFFER_1024) && !buffer_info->page_dma) { if (!buffer_info->page) { buffer_info->page = netdev_alloc_page(netdev); - if (!buffer_info->page) { + if (unlikely(!buffer_info->page)) { + u64_stats_update_begin(&rx_ring->rx_syncp); rx_ring->rx_stats.alloc_failed++; + u64_stats_update_end(&rx_ring->rx_syncp); goto no_buffers; } buffer_info->page_offset = 0; @@ -5706,7 +5761,9 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count) if (dma_mapping_error(rx_ring->dev, buffer_info->page_dma)) { buffer_info->page_dma = 0; + u64_stats_update_begin(&rx_ring->rx_syncp); rx_ring->rx_stats.alloc_failed++; + u64_stats_update_end(&rx_ring->rx_syncp); goto no_buffers; } } @@ -5714,8 +5771,10 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count) skb = buffer_info->skb; if (!skb) { skb = netdev_alloc_skb_ip_align(netdev, bufsz); - if (!skb) { + if (unlikely(!skb)) { + u64_stats_update_begin(&rx_ring->rx_syncp); rx_ring->rx_stats.alloc_failed++; + u64_stats_update_end(&rx_ring->rx_syncp); goto no_buffers; } @@ -5729,7 +5788,9 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count) if (dma_mapping_error(rx_ring->dev, buffer_info->dma)) { buffer_info->dma = 0; + u64_stats_update_begin(&rx_ring->rx_syncp); rx_ring->rx_stats.alloc_failed++; + u64_stats_update_end(&rx_ring->rx_syncp); goto no_buffers; } } @@ -6092,7 +6153,7 @@ static void igb_restore_vlan(struct igb_adapter *adapter) if (adapter->vlgrp) { u16 vid; - for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + for (vid = 0; vid < VLAN_N_VID; vid++) { if (!vlan_group_get_device(adapter->vlgrp, vid)) continue; igb_vlan_rx_add_vid(adapter->netdev, vid); @@ -6107,6 +6168,13 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) mac->autoneg = 0; + /* Fiber NIC's only allow 1000 Gbps Full duplex */ + if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) && + spddplx != (SPEED_1000 + DUPLEX_FULL)) { + dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; + } + switch (spddplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; |