diff options
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/ich8lan.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/netdev.c | 49 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc.h | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_defines.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_ethtool.c | 294 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igc/igc_main.c | 246 |
7 files changed, 362 insertions, 266 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 735bf25952fc..f999cca37a8a 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -300,7 +300,11 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) * so forcibly disable it. */ hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown; - e1000_disable_ulp_lpt_lp(hw, true); + ret_val = e1000_disable_ulp_lpt_lp(hw, true); + if (ret_val) { + e_warn("Failed to disable ULP\n"); + goto out; + } ret_val = hw->phy.ops.acquire(hw); if (ret_val) { diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e0b074820b47..32f23a15ff64 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -107,6 +107,45 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = { {0, NULL} }; +struct e1000e_me_supported { + u16 device_id; /* supported device ID */ +}; + +static const struct e1000e_me_supported me_supported[] = { + {E1000_DEV_ID_PCH_LPT_I217_LM}, + {E1000_DEV_ID_PCH_LPTLP_I218_LM}, + {E1000_DEV_ID_PCH_I218_LM2}, + {E1000_DEV_ID_PCH_I218_LM3}, + {E1000_DEV_ID_PCH_SPT_I219_LM}, + {E1000_DEV_ID_PCH_SPT_I219_LM2}, + {E1000_DEV_ID_PCH_LBG_I219_LM3}, + {E1000_DEV_ID_PCH_SPT_I219_LM4}, + {E1000_DEV_ID_PCH_SPT_I219_LM5}, + {E1000_DEV_ID_PCH_CNP_I219_LM6}, + {E1000_DEV_ID_PCH_CNP_I219_LM7}, + {E1000_DEV_ID_PCH_ICP_I219_LM8}, + {E1000_DEV_ID_PCH_ICP_I219_LM9}, + {E1000_DEV_ID_PCH_CMP_I219_LM10}, + {E1000_DEV_ID_PCH_CMP_I219_LM11}, + {E1000_DEV_ID_PCH_CMP_I219_LM12}, + {E1000_DEV_ID_PCH_TGP_I219_LM13}, + {E1000_DEV_ID_PCH_TGP_I219_LM14}, + {E1000_DEV_ID_PCH_TGP_I219_LM15}, + {0} +}; + +static bool e1000e_check_me(u16 device_id) +{ + struct e1000e_me_supported *id; + + for (id = (struct e1000e_me_supported *)me_supported; + id->device_id; id++) + if (device_id == id->device_id) + return true; + + return false; +} + /** * __ew32_prepare - prepare to write to MAC CSR register on certain parts * @hw: pointer to the HW structure @@ -5294,6 +5333,10 @@ static void e1000_watchdog_task(struct work_struct *work) /* oops */ break; } + if (hw->mac.type == e1000_pch_spt) { + netdev->features &= ~NETIF_F_TSO; + netdev->features &= ~NETIF_F_TSO6; + } } /* enable transmits in the hardware, need to do this @@ -6912,7 +6955,8 @@ static int e1000e_pm_suspend(struct device *dev) e1000e_pm_thaw(dev); /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp) + if (hw->mac.type >= e1000_pch_cnp && + !e1000e_check_me(hw->adapter->pdev->device)) e1000e_s0ix_entry_flow(adapter); return rc; @@ -6927,7 +6971,8 @@ static int e1000e_pm_resume(struct device *dev) int rc; /* Introduce S0ix implementation */ - if (hw->mac.type >= e1000_pch_cnp) + if (hw->mac.type >= e1000_pch_cnp && + !e1000e_check_me(hw->adapter->pdev->device)) e1000e_s0ix_exit_flow(adapter); rc = __e1000_resume(pdev); diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 39d3b76a6f5d..2cd003c5ad43 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -143,7 +143,8 @@ static int igb_get_link_ksettings(struct net_device *netdev, u32 speed; u32 supported, advertising; - status = rd32(E1000_STATUS); + status = pm_runtime_suspended(&adapter->pdev->dev) ? + 0 : rd32(E1000_STATUS); if (hw->phy.media_type == e1000_media_type_copper) { supported = (SUPPORTED_10baseT_Half | diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index fcc6261d7f67..14f9edaaaf83 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -190,8 +190,8 @@ struct igc_adapter { /* Any access to elements in nfc_rule_list is protected by the * nfc_rule_lock. */ - spinlock_t nfc_rule_lock; - struct hlist_head nfc_rule_list; + struct mutex nfc_rule_lock; + struct list_head nfc_rule_list; unsigned int nfc_rule_count; u8 rss_indir_tbl[IGC_RETA_SIZE]; @@ -232,16 +232,6 @@ void igc_write_rss_indir_tbl(struct igc_adapter *adapter); bool igc_has_link(struct igc_adapter *adapter); void igc_reset(struct igc_adapter *adapter); int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx); -int igc_add_mac_filter(struct igc_adapter *adapter, - enum igc_mac_filter_type type, const u8 *addr, - int queue); -int igc_del_mac_filter(struct igc_adapter *adapter, - enum igc_mac_filter_type type, const u8 *addr); -int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio, - int queue); -void igc_del_vlan_prio_filter(struct igc_adapter *adapter, int prio); -int igc_add_etype_filter(struct igc_adapter *adapter, u16 etype, int queue); -int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype); void igc_update_stats(struct igc_adapter *adapter); /* igc_dump declarations */ @@ -461,9 +451,9 @@ struct igc_nfc_filter { }; struct igc_nfc_rule { - struct hlist_node nfc_node; + struct list_head list; struct igc_nfc_filter filter; - u16 sw_idx; + u32 location; u16 action; }; @@ -544,10 +534,10 @@ static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data) } void igc_reinit_locked(struct igc_adapter *); -int igc_enable_nfc_rule(struct igc_adapter *adapter, - const struct igc_nfc_rule *rule); -int igc_disable_nfc_rule(struct igc_adapter *adapter, - const struct igc_nfc_rule *rule); +struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter, + u32 location); +int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule); +void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule); void igc_ptp_init(struct igc_adapter *adapter); void igc_ptp_reset(struct igc_adapter *adapter); diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 45b567587ca9..3d8d40d6fa3f 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -265,13 +265,9 @@ #define IGC_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ #define IGC_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ #define IGC_TXD_CMD_EOP 0x01000000 /* End of Packet */ -#define IGC_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ #define IGC_TXD_CMD_IC 0x04000000 /* Insert Checksum */ -#define IGC_TXD_CMD_RS 0x08000000 /* Report Status */ -#define IGC_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ #define IGC_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */ #define IGC_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ -#define IGC_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ #define IGC_TXD_STAT_DD 0x00000001 /* Descriptor Done */ #define IGC_TXD_STAT_EC 0x00000002 /* Excess Collisions */ #define IGC_TXD_STAT_LC 0x00000004 /* Late Collisions */ diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 66e0760a8f9e..946e775e34ae 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -939,16 +939,11 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, cmd->data = IGC_MAX_RXNFC_RULES; - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { - if (fsp->location <= rule->sw_idx) - break; - } - - if (!rule || fsp->location != rule->sw_idx) - return -EINVAL; + mutex_lock(&adapter->nfc_rule_lock); - if (!rule->filter.match_flags) - return -EINVAL; + rule = igc_get_nfc_rule(adapter, fsp->location); + if (!rule) + goto out; fsp->flow_type = ETHER_FLOW; fsp->ring_cookie = rule->action; @@ -976,7 +971,12 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, eth_broadcast_addr(fsp->m_u.ether_spec.h_source); } + mutex_unlock(&adapter->nfc_rule_lock); return 0; + +out: + mutex_unlock(&adapter->nfc_rule_lock); + return -EINVAL; } static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, @@ -988,13 +988,19 @@ static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, cmd->data = IGC_MAX_RXNFC_RULES; - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { - if (cnt == cmd->rule_cnt) + mutex_lock(&adapter->nfc_rule_lock); + + list_for_each_entry(rule, &adapter->nfc_rule_list, list) { + if (cnt == cmd->rule_cnt) { + mutex_unlock(&adapter->nfc_rule_lock); return -EMSGSIZE; - rule_locs[cnt] = rule->sw_idx; + } + rule_locs[cnt] = rule->location; cnt++; } + mutex_unlock(&adapter->nfc_rule_lock); + cmd->rule_cnt = cnt; return 0; @@ -1177,111 +1183,81 @@ static int igc_ethtool_set_rss_hash_opt(struct igc_adapter *adapter, return 0; } -int igc_enable_nfc_rule(struct igc_adapter *adapter, - const struct igc_nfc_rule *rule) +static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, + const struct ethtool_rx_flow_spec *fsp) { - int err = -EINVAL; + INIT_LIST_HEAD(&rule->list); - if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { - err = igc_add_etype_filter(adapter, rule->filter.etype, - rule->action); - if (err) - return err; - } + rule->action = fsp->ring_cookie; + rule->location = fsp->location; - if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { - err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC, - rule->filter.src_addr, rule->action); - if (err) - return err; + if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { + rule->filter.vlan_tci = ntohs(fsp->h_ext.vlan_tci); + rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI; } - if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { - err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, - rule->filter.dst_addr, rule->action); - if (err) - return err; + if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) { + rule->filter.etype = ntohs(fsp->h_u.ether_spec.h_proto); + rule->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE; } - if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { - int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >> - VLAN_PRIO_SHIFT; - - err = igc_add_vlan_prio_filter(adapter, prio, rule->action); - if (err) - return err; + /* Both source and destination address filters only support the full + * mask. + */ + if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) { + rule->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR; + ether_addr_copy(rule->filter.src_addr, + fsp->h_u.ether_spec.h_source); } - return 0; -} - -int igc_disable_nfc_rule(struct igc_adapter *adapter, - const struct igc_nfc_rule *rule) -{ - if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) - igc_del_etype_filter(adapter, rule->filter.etype); - - if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { - int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >> - VLAN_PRIO_SHIFT; - igc_del_vlan_prio_filter(adapter, prio); + if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) { + rule->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR; + ether_addr_copy(rule->filter.dst_addr, + fsp->h_u.ether_spec.h_dest); } - - if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) - igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC, - rule->filter.src_addr); - - if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) - igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, - rule->filter.dst_addr); - - return 0; } -static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, - struct igc_nfc_rule *input, - u16 sw_idx) +/** + * igc_ethtool_check_nfc_rule() - Check if NFC rule is valid + * @adapter: Pointer to adapter + * @rule: Rule under evaluation + * + * Rules with both destination and source MAC addresses are considered invalid + * since the driver doesn't support them. + * + * Also, if there is already another rule with the same filter in a different + * location, @rule is considered invalid. + * + * Context: Expects adapter->nfc_rule_lock to be held by caller. + * + * Return: 0 in case of success, negative errno code otherwise. + */ +static int igc_ethtool_check_nfc_rule(struct igc_adapter *adapter, + struct igc_nfc_rule *rule) { - struct igc_nfc_rule *rule, *parent; - int err = -EINVAL; - - parent = NULL; - rule = NULL; + struct net_device *dev = adapter->netdev; + u8 flags = rule->filter.match_flags; + struct igc_nfc_rule *tmp; - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { - /* hash found, or no matching entry */ - if (rule->sw_idx >= sw_idx) - break; - parent = rule; + if (!flags) { + netdev_dbg(dev, "Rule with no match\n"); + return -EINVAL; } - /* if there is an old rule occupying our place remove it */ - if (rule && rule->sw_idx == sw_idx) { - if (!input) - err = igc_disable_nfc_rule(adapter, rule); - - hlist_del(&rule->nfc_node); - kfree(rule); - adapter->nfc_rule_count--; + if (flags & IGC_FILTER_FLAG_DST_MAC_ADDR && + flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { + netdev_dbg(dev, "Filters with both dst and src are not supported\n"); + return -EOPNOTSUPP; } - /* If no input this was a delete, err should be 0 if a rule was - * successfully found and removed from the list else -EINVAL - */ - if (!input) - return err; - - /* initialize node */ - INIT_HLIST_NODE(&input->nfc_node); - - /* add filter to the list */ - if (parent) - hlist_add_behind(&input->nfc_node, &parent->nfc_node); - else - hlist_add_head(&input->nfc_node, &adapter->nfc_rule_list); - - /* update counts */ - adapter->nfc_rule_count++; + list_for_each_entry(tmp, &adapter->nfc_rule_list, list) { + if (!memcmp(&rule->filter, &tmp->filter, + sizeof(rule->filter)) && + tmp->location != rule->location) { + netdev_dbg(dev, "Rule already exists\n"); + return -EEXIST; + } + } return 0; } @@ -1292,99 +1268,60 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, struct net_device *netdev = adapter->netdev; struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; - struct igc_nfc_rule *rule, *tmp; - int err = 0; + struct igc_nfc_rule *rule, *old_rule; + int err; - if (!(netdev->hw_features & NETIF_F_NTUPLE)) + if (!(netdev->hw_features & NETIF_F_NTUPLE)) { + netdev_dbg(netdev, "N-tuple filters disabled\n"); return -EOPNOTSUPP; + } - /* Don't allow programming if the action is a queue greater than - * the number of online Rx queues. - */ - if (fsp->ring_cookie == RX_CLS_FLOW_DISC || - fsp->ring_cookie >= adapter->num_rx_queues) { - netdev_err(netdev, - "ethtool -N: The specified action is invalid\n"); - return -EINVAL; + if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) { + netdev_dbg(netdev, "Only ethernet flow type is supported\n"); + return -EOPNOTSUPP; } - /* Don't allow indexes to exist outside of available space */ - if (fsp->location >= IGC_MAX_RXNFC_RULES) { - netdev_err(netdev, "Location out of range\n"); + if ((fsp->flow_type & FLOW_EXT) && + fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) { + netdev_dbg(netdev, "VLAN mask not supported\n"); + return -EOPNOTSUPP; + } + + if (fsp->ring_cookie >= adapter->num_rx_queues) { + netdev_dbg(netdev, "Invalid action\n"); return -EINVAL; } - if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) + if (fsp->location >= IGC_MAX_RXNFC_RULES) { + netdev_dbg(netdev, "Invalid location\n"); return -EINVAL; + } rule = kzalloc(sizeof(*rule), GFP_KERNEL); if (!rule) return -ENOMEM; - if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) { - rule->filter.etype = ntohs(fsp->h_u.ether_spec.h_proto); - rule->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE; - } + igc_ethtool_init_nfc_rule(rule, fsp); - /* Both source and destination address filters only support the full - * mask. - */ - if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) { - rule->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR; - ether_addr_copy(rule->filter.src_addr, - fsp->h_u.ether_spec.h_source); - } + mutex_lock(&adapter->nfc_rule_lock); - if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) { - rule->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR; - ether_addr_copy(rule->filter.dst_addr, - fsp->h_u.ether_spec.h_dest); - } - - if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR && - rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { - netdev_dbg(netdev, "Filters with both dst and src are not supported\n"); - err = -EOPNOTSUPP; - goto err_out; - } - - if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { - if (fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) { - netdev_dbg(netdev, "VLAN mask not supported\n"); - err = -EOPNOTSUPP; - goto err_out; - } - rule->filter.vlan_tci = ntohs(fsp->h_ext.vlan_tci); - rule->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI; - } - - rule->action = fsp->ring_cookie; - rule->sw_idx = fsp->location; - - spin_lock(&adapter->nfc_rule_lock); + err = igc_ethtool_check_nfc_rule(adapter, rule); + if (err) + goto err; - hlist_for_each_entry(tmp, &adapter->nfc_rule_list, nfc_node) { - if (!memcmp(&rule->filter, &tmp->filter, - sizeof(rule->filter))) { - err = -EEXIST; - netdev_err(netdev, - "ethtool: this filter is already set\n"); - goto err_out_w_lock; - } - } + old_rule = igc_get_nfc_rule(adapter, fsp->location); + if (old_rule) + igc_del_nfc_rule(adapter, old_rule); - err = igc_enable_nfc_rule(adapter, rule); + err = igc_add_nfc_rule(adapter, rule); if (err) - goto err_out_w_lock; + goto err; - igc_ethtool_update_nfc_rule(adapter, rule, rule->sw_idx); - - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); return 0; -err_out_w_lock: - spin_unlock(&adapter->nfc_rule_lock); -err_out: +err: + mutex_unlock(&adapter->nfc_rule_lock); kfree(rule); return err; } @@ -1394,13 +1331,20 @@ static int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter, { struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; - int err; + struct igc_nfc_rule *rule; - spin_lock(&adapter->nfc_rule_lock); - err = igc_ethtool_update_nfc_rule(adapter, NULL, fsp->location); - spin_unlock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); - return err; + rule = igc_get_nfc_rule(adapter, fsp->location); + if (!rule) { + mutex_unlock(&adapter->nfc_rule_lock); + return -EINVAL; + } + + igc_del_nfc_rule(adapter, rule); + + mutex_unlock(&adapter->nfc_rule_lock); + return 0; } static int igc_ethtool_set_rxnfc(struct net_device *dev, diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index f48d6127a220..97d26991c87e 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2174,18 +2174,6 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget) return !!budget; } -static void igc_restore_nfc_rules(struct igc_adapter *adapter) -{ - struct igc_nfc_rule *rule; - - spin_lock(&adapter->nfc_rule_lock); - - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) - igc_enable_nfc_rule(adapter, rule); - - spin_unlock(&adapter->nfc_rule_lock); -} - static int igc_find_mac_filter(struct igc_adapter *adapter, enum igc_mac_filter_type type, const u8 *addr) { @@ -2242,16 +2230,13 @@ static int igc_get_avail_mac_filter_slot(struct igc_adapter *adapter) * * Return: 0 in case of success, negative errno code otherwise. */ -int igc_add_mac_filter(struct igc_adapter *adapter, - enum igc_mac_filter_type type, const u8 *addr, - int queue) +static int igc_add_mac_filter(struct igc_adapter *adapter, + enum igc_mac_filter_type type, const u8 *addr, + int queue) { struct net_device *dev = adapter->netdev; int index; - if (!is_valid_ether_addr(addr)) - return -EINVAL; - index = igc_find_mac_filter(adapter, type, addr); if (index >= 0) goto update_filter; @@ -2274,21 +2259,16 @@ update_filter: * @adapter: Pointer to adapter where the filter should be deleted from * @type: MAC address filter type (source or destination) * @addr: MAC address - * - * Return: 0 in case of success, negative errno code otherwise. */ -int igc_del_mac_filter(struct igc_adapter *adapter, - enum igc_mac_filter_type type, const u8 *addr) +static void igc_del_mac_filter(struct igc_adapter *adapter, + enum igc_mac_filter_type type, const u8 *addr) { struct net_device *dev = adapter->netdev; int index; - if (!is_valid_ether_addr(addr)) - return -EINVAL; - index = igc_find_mac_filter(adapter, type, addr); if (index < 0) - return -ENOENT; + return; if (index == 0) { /* If this is the default filter, we don't actually delete it. @@ -2306,8 +2286,6 @@ int igc_del_mac_filter(struct igc_adapter *adapter, igc_clear_mac_filter_hw(adapter, index); } - - return 0; } /** @@ -2318,7 +2296,8 @@ int igc_del_mac_filter(struct igc_adapter *adapter, * * Return: 0 in case of success, negative errno code otherwise. */ -int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio, int queue) +static int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio, + int queue) { struct net_device *dev = adapter->netdev; struct igc_hw *hw = &adapter->hw; @@ -2346,7 +2325,7 @@ int igc_add_vlan_prio_filter(struct igc_adapter *adapter, int prio, int queue) * @adapter: Pointer to adapter where the filter should be deleted from * @prio: VLAN priority value */ -void igc_del_vlan_prio_filter(struct igc_adapter *adapter, int prio) +static void igc_del_vlan_prio_filter(struct igc_adapter *adapter, int prio) { struct igc_hw *hw = &adapter->hw; u32 vlanpqf; @@ -2387,7 +2366,8 @@ static int igc_get_avail_etype_filter_slot(struct igc_adapter *adapter) * * Return: 0 in case of success, negative errno code otherwise. */ -int igc_add_etype_filter(struct igc_adapter *adapter, u16 etype, int queue) +static int igc_add_etype_filter(struct igc_adapter *adapter, u16 etype, + int queue) { struct igc_hw *hw = &adapter->hw; int index; @@ -2436,25 +2416,181 @@ static int igc_find_etype_filter(struct igc_adapter *adapter, u16 etype) * igc_del_etype_filter() - Delete ethertype filter * @adapter: Pointer to adapter where the filter should be deleted from * @etype: Ethertype value - * - * Return: 0 in case of success, negative errno code otherwise. */ -int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype) +static void igc_del_etype_filter(struct igc_adapter *adapter, u16 etype) { struct igc_hw *hw = &adapter->hw; int index; index = igc_find_etype_filter(adapter, etype); if (index < 0) - return -ENOENT; + return; wr32(IGC_ETQF(index), 0); netdev_dbg(adapter->netdev, "Delete ethertype filter: etype %04x\n", etype); +} + +static int igc_enable_nfc_rule(struct igc_adapter *adapter, + const struct igc_nfc_rule *rule) +{ + int err; + + if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) { + err = igc_add_etype_filter(adapter, rule->filter.etype, + rule->action); + if (err) + return err; + } + + if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) { + err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC, + rule->filter.src_addr, rule->action); + if (err) + return err; + } + + if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) { + err = igc_add_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, + rule->filter.dst_addr, rule->action); + if (err) + return err; + } + + if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { + int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; + + err = igc_add_vlan_prio_filter(adapter, prio, rule->action); + if (err) + return err; + } + return 0; } +static void igc_disable_nfc_rule(struct igc_adapter *adapter, + const struct igc_nfc_rule *rule) +{ + if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) + igc_del_etype_filter(adapter, rule->filter.etype); + + if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) { + int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; + + igc_del_vlan_prio_filter(adapter, prio); + } + + if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) + igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_SRC, + rule->filter.src_addr); + + if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) + igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, + rule->filter.dst_addr); +} + +/** + * igc_get_nfc_rule() - Get NFC rule + * @adapter: Pointer to adapter + * @location: Rule location + * + * Context: Expects adapter->nfc_rule_lock to be held by caller. + * + * Return: Pointer to NFC rule at @location. If not found, NULL. + */ +struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter, + u32 location) +{ + struct igc_nfc_rule *rule; + + list_for_each_entry(rule, &adapter->nfc_rule_list, list) { + if (rule->location == location) + return rule; + if (rule->location > location) + break; + } + + return NULL; +} + +/** + * igc_del_nfc_rule() - Delete NFC rule + * @adapter: Pointer to adapter + * @rule: Pointer to rule to be deleted + * + * Disable NFC rule in hardware and delete it from adapter. + * + * Context: Expects adapter->nfc_rule_lock to be held by caller. + */ +void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule) +{ + igc_disable_nfc_rule(adapter, rule); + + list_del(&rule->list); + adapter->nfc_rule_count--; + + kfree(rule); +} + +static void igc_flush_nfc_rules(struct igc_adapter *adapter) +{ + struct igc_nfc_rule *rule, *tmp; + + mutex_lock(&adapter->nfc_rule_lock); + + list_for_each_entry_safe(rule, tmp, &adapter->nfc_rule_list, list) + igc_del_nfc_rule(adapter, rule); + + mutex_unlock(&adapter->nfc_rule_lock); +} + +/** + * igc_add_nfc_rule() - Add NFC rule + * @adapter: Pointer to adapter + * @rule: Pointer to rule to be added + * + * Enable NFC rule in hardware and add it to adapter. + * + * Context: Expects adapter->nfc_rule_lock to be held by caller. + * + * Return: 0 on success, negative errno on failure. + */ +int igc_add_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule) +{ + struct igc_nfc_rule *pred, *cur; + int err; + + err = igc_enable_nfc_rule(adapter, rule); + if (err) + return err; + + pred = NULL; + list_for_each_entry(cur, &adapter->nfc_rule_list, list) { + if (cur->location >= rule->location) + break; + pred = cur; + } + + list_add(&rule->list, pred ? &pred->list : &adapter->nfc_rule_list); + adapter->nfc_rule_count++; + return 0; +} + +static void igc_restore_nfc_rules(struct igc_adapter *adapter) +{ + struct igc_nfc_rule *rule; + + mutex_lock(&adapter->nfc_rule_lock); + + list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list) + igc_enable_nfc_rule(adapter, rule); + + mutex_unlock(&adapter->nfc_rule_lock); +} + static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) { struct igc_adapter *adapter = netdev_priv(netdev); @@ -2466,7 +2602,8 @@ static int igc_uc_unsync(struct net_device *netdev, const unsigned char *addr) { struct igc_adapter *adapter = netdev_priv(netdev); - return igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, addr); + igc_del_mac_filter(adapter, IGC_MAC_FILTER_TYPE_DST, addr); + return 0; } /** @@ -3424,7 +3561,10 @@ static int igc_sw_init(struct igc_adapter *adapter) VLAN_HLEN; adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; - spin_lock_init(&adapter->nfc_rule_lock); + mutex_init(&adapter->nfc_rule_lock); + INIT_LIST_HEAD(&adapter->nfc_rule_list); + adapter->nfc_rule_count = 0; + spin_lock_init(&adapter->stats64_lock); /* Assume MSI-X interrupts, will be checked during IRQ allocation */ adapter->flags |= IGC_FLAG_HAS_MSIX; @@ -3651,18 +3791,6 @@ void igc_update_stats(struct igc_adapter *adapter) adapter->stats.mgpdc += rd32(IGC_MGTPDC); } -static void igc_nfc_rule_exit(struct igc_adapter *adapter) -{ - struct igc_nfc_rule *rule; - - spin_lock(&adapter->nfc_rule_lock); - - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) - igc_disable_nfc_rule(adapter, rule); - - spin_unlock(&adapter->nfc_rule_lock); -} - /** * igc_down - Close the interface * @adapter: board private structure @@ -3681,8 +3809,6 @@ void igc_down(struct igc_adapter *adapter) wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN); /* flush and sleep below */ - igc_nfc_rule_exit(adapter); - /* set trans_start so we don't get spurious watchdogs during reset */ netif_trans_update(netdev); @@ -3831,20 +3957,8 @@ static int igc_set_features(struct net_device *netdev, if (!(changed & (NETIF_F_RXALL | NETIF_F_NTUPLE))) return 0; - if (!(features & NETIF_F_NTUPLE)) { - struct hlist_node *node2; - struct igc_nfc_rule *rule; - - spin_lock(&adapter->nfc_rule_lock); - hlist_for_each_entry_safe(rule, node2, - &adapter->nfc_rule_list, nfc_node) { - igc_disable_nfc_rule(adapter, rule); - hlist_del(&rule->nfc_node); - kfree(rule); - } - spin_unlock(&adapter->nfc_rule_lock); - adapter->nfc_rule_count = 0; - } + if (!(features & NETIF_F_NTUPLE)) + igc_flush_nfc_rules(adapter); netdev->features = features; @@ -5111,6 +5225,8 @@ static void igc_remove(struct pci_dev *pdev) pm_runtime_get_noresume(&pdev->dev); + igc_flush_nfc_rules(adapter); + igc_ptp_stop(adapter); set_bit(__IGC_DOWN, &adapter->state); |