From 16fdc16c6bff6764fc8c9a5f10640dfdb7ce201a Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:12 -0700 Subject: igc: Refactor igc_ethtool_add_nfc_rule() Current implementation of igc_ethtool_add_nfc_rule() is quite long and a bit convoluted so this patch does a code refactoring to improve the code. Code related to NFC rule object initialization is refactored out to the local helper function igc_ethtool_init_nfc_rule(). Likewise, code related to NFC rule validation is refactored out to another local helper, igc_ethtool_is_nfc_rule_valid(). RX_CLS_FLOW_DISC check is removed since it is redundant. The macro is defined as the max value fsp->ring_cookie can have, so checking if fsp->ring_cookie >= adapter->num_rx_queues is already sufficient. Finally, some log messages are improved or added, and obvious comments are removed. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_ethtool.c | 150 ++++++++++++++++----------- 1 file changed, 92 insertions(+), 58 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 66e0760a8f9e..1145c88a8e44 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1271,9 +1271,6 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, 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); @@ -1286,41 +1283,19 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, return 0; } -static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, - struct ethtool_rxnfc *cmd) +static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, + const struct ethtool_rx_flow_spec *fsp) { - 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; - - if (!(netdev->hw_features & NETIF_F_NTUPLE)) - return -EOPNOTSUPP; + INIT_HLIST_NODE(&rule->nfc_node); - /* 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; - } + rule->action = fsp->ring_cookie; + rule->sw_idx = fsp->location; - /* 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"); - return -EINVAL; + 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 ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) - 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; @@ -1340,51 +1315,110 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, 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; - } +/** + * 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, @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 net_device *dev = adapter->netdev; + u8 flags = rule->filter.match_flags; + struct igc_nfc_rule *tmp; - 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; + if (!flags) { + netdev_dbg(dev, "Rule with no match\n"); + return -EINVAL; } - rule->action = fsp->ring_cookie; - rule->sw_idx = fsp->location; - - spin_lock(&adapter->nfc_rule_lock); + 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; + } 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; + netdev_dbg(dev, "Rule already exists\n"); + return -EEXIST; } } + return 0; +} + +static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, + struct ethtool_rxnfc *cmd) +{ + struct net_device *netdev = adapter->netdev; + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; + struct igc_nfc_rule *rule; + int err; + + if (!(netdev->hw_features & NETIF_F_NTUPLE)) { + netdev_dbg(netdev, "N-tuple filters disabled\n"); + return -EOPNOTSUPP; + } + + if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW) { + netdev_dbg(netdev, "Only ethernet flow type is supported\n"); + return -EOPNOTSUPP; + } + + 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->location >= IGC_MAX_RXNFC_RULES) { + netdev_dbg(netdev, "Invalid location\n"); + return -EINVAL; + } + + rule = kzalloc(sizeof(*rule), GFP_KERNEL); + if (!rule) + return -ENOMEM; + + igc_ethtool_init_nfc_rule(rule, fsp); + + spin_lock(&adapter->nfc_rule_lock); + + err = igc_ethtool_check_nfc_rule(adapter, rule); + if (err) + goto err; + err = igc_enable_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); return 0; -err_out_w_lock: +err: spin_unlock(&adapter->nfc_rule_lock); -err_out: kfree(rule); return err; } -- cgit v1.2.3 From d3ba9e6f6157e6fa047d853936dabb981e315080 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:13 -0700 Subject: igc: Fix 'sw_idx' type in struct igc_nfc_rule The 'sw_idx' field from 'struct igc_nfc_rule' is u16 type but it is assigned an u32 value in igc_ethtool_init_nfc_rule(). This patch changes 'sw_idx' type to u32 so they match. Also, it makes more sense to call this field 'location' since it holds the NFC rule location. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 2 +- drivers/net/ethernet/intel/igc/igc_ethtool.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index fcc6261d7f67..ae7d48070ee2 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -463,7 +463,7 @@ struct igc_nfc_filter { struct igc_nfc_rule { struct hlist_node nfc_node; struct igc_nfc_filter filter; - u16 sw_idx; + u32 location; u16 action; }; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 1145c88a8e44..24aa321f64b5 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -940,11 +940,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) + if (fsp->location <= rule->location) break; } - if (!rule || fsp->location != rule->sw_idx) + if (!rule || fsp->location != rule->location) return -EINVAL; if (!rule->filter.match_flags) @@ -991,7 +991,7 @@ static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { if (cnt == cmd->rule_cnt) return -EMSGSIZE; - rule_locs[cnt] = rule->sw_idx; + rule_locs[cnt] = rule->location; cnt++; } @@ -1240,7 +1240,7 @@ int igc_disable_nfc_rule(struct igc_adapter *adapter, static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *input, - u16 sw_idx) + u32 location) { struct igc_nfc_rule *rule, *parent; int err = -EINVAL; @@ -1250,13 +1250,13 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { /* hash found, or no matching entry */ - if (rule->sw_idx >= sw_idx) + if (rule->location >= location) break; parent = rule; } /* if there is an old rule occupying our place remove it */ - if (rule && rule->sw_idx == sw_idx) { + if (rule && rule->location == location) { if (!input) err = igc_disable_nfc_rule(adapter, rule); @@ -1289,7 +1289,7 @@ static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, INIT_HLIST_NODE(&rule->nfc_node); rule->action = fsp->ring_cookie; - rule->sw_idx = fsp->location; + rule->location = fsp->location; if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) { rule->filter.vlan_tci = ntohs(fsp->h_ext.vlan_tci); @@ -1412,7 +1412,7 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, if (err) goto err; - igc_ethtool_update_nfc_rule(adapter, rule, rule->sw_idx); + igc_ethtool_update_nfc_rule(adapter, rule, rule->location); spin_unlock(&adapter->nfc_rule_lock); return 0; -- cgit v1.2.3 From b500350a36ae6e83a03931723b787b771f411817 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:14 -0700 Subject: igc: Fix locking issue when retrieving NFC rules Access to NFC rules stored in adapter->nfc_rule_list is protect by adapter->nfc_rule_lock. The functions igc_ethtool_get_nfc_rule() and igc_ethtool_get_nfc_rules() are missing to hold the lock while accessing rule objects. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_ethtool.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 24aa321f64b5..decd29fbfbe2 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -939,16 +939,18 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, cmd->data = IGC_MAX_RXNFC_RULES; + spin_lock(&adapter->nfc_rule_lock); + hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { if (fsp->location <= rule->location) break; } if (!rule || fsp->location != rule->location) - return -EINVAL; + goto out; if (!rule->filter.match_flags) - return -EINVAL; + goto out; fsp->flow_type = ETHER_FLOW; fsp->ring_cookie = rule->action; @@ -976,7 +978,12 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, eth_broadcast_addr(fsp->m_u.ether_spec.h_source); } + spin_unlock(&adapter->nfc_rule_lock); return 0; + +out: + spin_unlock(&adapter->nfc_rule_lock); + return -EINVAL; } static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, @@ -988,13 +995,19 @@ static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, cmd->data = IGC_MAX_RXNFC_RULES; + spin_lock(&adapter->nfc_rule_lock); + hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { - if (cnt == cmd->rule_cnt) + if (cnt == cmd->rule_cnt) { + spin_unlock(&adapter->nfc_rule_lock); return -EMSGSIZE; + } rule_locs[cnt] = rule->location; cnt++; } + spin_unlock(&adapter->nfc_rule_lock); + cmd->rule_cnt = cnt; return 0; -- cgit v1.2.3 From 4bdf89e85ed3881e8c40510ebad918dded9e5831 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:15 -0700 Subject: igc: Fix NFC rule overwrite cases When the 'loc' argument is passed in ethtool, the input rule overwrites any rule present in that location. In this situation we must disable the old rule otherwise it is left enabled in hardware. This patch fixes the issue by always calling igc_disable_nfc_rule() when deleting the old rule, no matter the value of 'input' argument. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_ethtool.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index decd29fbfbe2..f01a7ec0c1c2 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1270,8 +1270,7 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, /* if there is an old rule occupying our place remove it */ if (rule && rule->location == location) { - if (!input) - err = igc_disable_nfc_rule(adapter, rule); + err = igc_disable_nfc_rule(adapter, rule); hlist_del(&rule->nfc_node); kfree(rule); -- cgit v1.2.3 From 39707c16e6b34fb70b3f170d5733245256d768e5 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:16 -0700 Subject: igc: Fix NFC rules with multicast addresses Multicast MAC addresses are valid address for NFC rules but igc_add_mac_filter() is currently rejecting them. In fact, the I225 controller doesn't impose any constraint on the address value so this patch gets rid of the address validation check in MAC filter APIs. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_main.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index f48d6127a220..acb8dfdf275f 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2249,9 +2249,6 @@ int igc_add_mac_filter(struct igc_adapter *adapter, 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; @@ -2283,9 +2280,6 @@ int igc_del_mac_filter(struct igc_adapter *adapter, 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; -- cgit v1.2.3 From d957c6010a907d86d41d1bee024a9827e385c4fa Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:17 -0700 Subject: igc: Fix NFC rules restoration When network interface is brought up, the driver re-enables the NFC rules previously configured. However, this is done in reverse order the rules were added and hardware filters are configured differently. For example, consider the following rules: $ ethtool -N eth0 flow-type ether dst 00:00:00:00:00:AA queue 0 $ ethtool -N eth0 flow-type ether dst 00:00:00:00:00:BB queue 1 $ ethtool -N eth0 flow-type ether dst 00:00:00:00:00:CC queue 2 $ ethtool -N eth0 flow-type ether dst 00:00:00:00:00:DD queue 3 RAL/RAH registers are configure so filter index 1 has address ending with AA, filter index 2 has address ending in BB, and so on. If we bring the interface down and up again, RAL/RAH registers are configured so filter index 1 has address ending in DD, filter index 2 has CC, and so on. IOW, in reverse order we had before bringing the interface down. This issue can be fixed by traversing adapter->nfc_rule_list in backwards when restoring the rules. Since hlist doesn't support backwards traversal, this patch replaces it by list_head and fixes igc_restore_nfc_rules() accordingly. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 4 ++-- drivers/net/ethernet/intel/igc/igc_ethtool.c | 19 ++++++++----------- drivers/net/ethernet/intel/igc/igc_main.c | 16 +++++++++------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index ae7d48070ee2..76bc3a51ad70 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -191,7 +191,7 @@ struct igc_adapter { * nfc_rule_lock. */ spinlock_t nfc_rule_lock; - struct hlist_head nfc_rule_list; + struct list_head nfc_rule_list; unsigned int nfc_rule_count; u8 rss_indir_tbl[IGC_RETA_SIZE]; @@ -461,7 +461,7 @@ struct igc_nfc_filter { }; struct igc_nfc_rule { - struct hlist_node nfc_node; + struct list_head list; struct igc_nfc_filter filter; u32 location; u16 action; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index f01a7ec0c1c2..a90493fee0d2 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -941,7 +941,7 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, spin_lock(&adapter->nfc_rule_lock); - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { + list_for_each_entry(rule, &adapter->nfc_rule_list, list) { if (fsp->location <= rule->location) break; } @@ -997,7 +997,7 @@ static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, spin_lock(&adapter->nfc_rule_lock); - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { + list_for_each_entry(rule, &adapter->nfc_rule_list, list) { if (cnt == cmd->rule_cnt) { spin_unlock(&adapter->nfc_rule_lock); return -EMSGSIZE; @@ -1261,7 +1261,7 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, parent = NULL; rule = NULL; - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) { + list_for_each_entry(rule, &adapter->nfc_rule_list, list) { /* hash found, or no matching entry */ if (rule->location >= location) break; @@ -1272,7 +1272,7 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, if (rule && rule->location == location) { err = igc_disable_nfc_rule(adapter, rule); - hlist_del(&rule->nfc_node); + list_del(&rule->list); kfree(rule); adapter->nfc_rule_count--; } @@ -1283,11 +1283,8 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, if (!input) return err; - /* 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); + list_add(&input->list, parent ? &parent->list : + &adapter->nfc_rule_list); /* update counts */ adapter->nfc_rule_count++; @@ -1298,7 +1295,7 @@ static int igc_ethtool_update_nfc_rule(struct igc_adapter *adapter, static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, const struct ethtool_rx_flow_spec *fsp) { - INIT_HLIST_NODE(&rule->nfc_node); + INIT_LIST_HEAD(&rule->list); rule->action = fsp->ring_cookie; rule->location = fsp->location; @@ -1362,7 +1359,7 @@ static int igc_ethtool_check_nfc_rule(struct igc_adapter *adapter, return -EOPNOTSUPP; } - hlist_for_each_entry(tmp, &adapter->nfc_rule_list, nfc_node) { + list_for_each_entry(tmp, &adapter->nfc_rule_list, list) { if (!memcmp(&rule->filter, &tmp->filter, sizeof(rule->filter))) { netdev_dbg(dev, "Rule already exists\n"); diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index acb8dfdf275f..cf76e2c1f9b1 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2180,7 +2180,7 @@ static void igc_restore_nfc_rules(struct igc_adapter *adapter) spin_lock(&adapter->nfc_rule_lock); - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) + list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list) igc_enable_nfc_rule(adapter, rule); spin_unlock(&adapter->nfc_rule_lock); @@ -3419,6 +3419,9 @@ static int igc_sw_init(struct igc_adapter *adapter) adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; spin_lock_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,7 +3654,7 @@ static void igc_nfc_rule_exit(struct igc_adapter *adapter) spin_lock(&adapter->nfc_rule_lock); - hlist_for_each_entry(rule, &adapter->nfc_rule_list, nfc_node) + list_for_each_entry(rule, &adapter->nfc_rule_list, list) igc_disable_nfc_rule(adapter, rule); spin_unlock(&adapter->nfc_rule_lock); @@ -3826,14 +3829,13 @@ static int igc_set_features(struct net_device *netdev, return 0; if (!(features & NETIF_F_NTUPLE)) { - struct hlist_node *node2; - struct igc_nfc_rule *rule; + struct igc_nfc_rule *rule, *tmp; spin_lock(&adapter->nfc_rule_lock); - hlist_for_each_entry_safe(rule, node2, - &adapter->nfc_rule_list, nfc_node) { + list_for_each_entry_safe(rule, tmp, + &adapter->nfc_rule_list, list) { igc_disable_nfc_rule(adapter, rule); - hlist_del(&rule->nfc_node); + list_del(&rule->list); kfree(rule); } spin_unlock(&adapter->nfc_rule_lock); -- cgit v1.2.3 From 36fa21520f33317fe51bf80bc154873e922c2a26 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:18 -0700 Subject: igc: Refactor igc_ethtool_update_nfc_rule() Current implementation of igc_ethtool_update_nfc_rule() is a bit convoluted since it handles too many things: rule lookup, deletion and addition. This patch breaks it into three functions so we simplify the code and improve code reuse. Code related to rule lookup is refactored out to a new function called igc_get_nfc_rule(). Code related to rule addition is refactored out to a new function called igc_add_nfc_rule(). This function enables the rule in hardware and adds it to the adapter's list. Code related to rule deletion is refactored out to a new function called igc_del_nfc_rule(). This function disables the rule in hardware, removes it from adapter's list, and deletes it. As a byproduct of this refactoring, igc_enable_nfc_rule() and igc_disable_nfc_rule() are moved to igc_main.c since they are not used in igc_ethtool.c anymore, and igc_restore_nfc_rules() and igc_nfc_rule_ exit() are moved around to avoid forward declaration. Also, since this patch already touches igc_ethtool_get_nfc_rule(), it takes the opportunity to remove the 'match_flags' check. Empty flags are not allowed to be added so no need to check that. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 18 +-- drivers/net/ethernet/intel/igc/igc_ethtool.c | 138 +++--------------- drivers/net/ethernet/intel/igc/igc_main.c | 205 ++++++++++++++++++++++----- 3 files changed, 195 insertions(+), 166 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 76bc3a51ad70..a484b328268b 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -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 */ @@ -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_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index a90493fee0d2..43dff09a8f86 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -941,15 +941,8 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, spin_lock(&adapter->nfc_rule_lock); - list_for_each_entry(rule, &adapter->nfc_rule_list, list) { - if (fsp->location <= rule->location) - break; - } - - if (!rule || fsp->location != rule->location) - goto out; - - if (!rule->filter.match_flags) + rule = igc_get_nfc_rule(adapter, fsp->location); + if (!rule) goto out; fsp->flow_type = ETHER_FLOW; @@ -1190,108 +1183,6 @@ 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) -{ - int err = -EINVAL; - - 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; -} - -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 (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, - u32 location) -{ - struct igc_nfc_rule *rule, *parent; - int err = -EINVAL; - - parent = NULL; - rule = NULL; - - list_for_each_entry(rule, &adapter->nfc_rule_list, list) { - /* hash found, or no matching entry */ - if (rule->location >= location) - break; - parent = rule; - } - - /* if there is an old rule occupying our place remove it */ - if (rule && rule->location == location) { - err = igc_disable_nfc_rule(adapter, rule); - - list_del(&rule->list); - kfree(rule); - adapter->nfc_rule_count--; - } - - /* 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; - - list_add(&input->list, parent ? &parent->list : - &adapter->nfc_rule_list); - - /* update counts */ - adapter->nfc_rule_count++; - - return 0; -} - static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, const struct ethtool_rx_flow_spec *fsp) { @@ -1376,7 +1267,7 @@ 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; + struct igc_nfc_rule *rule, *old_rule; int err; if (!(netdev->hw_features & NETIF_F_NTUPLE)) { @@ -1417,12 +1308,14 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, if (err) goto err; - err = igc_enable_nfc_rule(adapter, rule); + old_rule = igc_get_nfc_rule(adapter, fsp->location); + if (old_rule) + igc_del_nfc_rule(adapter, old_rule); + + err = igc_add_nfc_rule(adapter, rule); if (err) goto err; - igc_ethtool_update_nfc_rule(adapter, rule, rule->location); - spin_unlock(&adapter->nfc_rule_lock); return 0; @@ -1437,13 +1330,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); - return err; + rule = igc_get_nfc_rule(adapter, fsp->location); + if (!rule) { + spin_unlock(&adapter->nfc_rule_lock); + return -EINVAL; + } + + igc_del_nfc_rule(adapter, rule); + + spin_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 cf76e2c1f9b1..ad9217335a64 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); - - list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list) - 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,9 +2230,9 @@ 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; @@ -2274,8 +2262,8 @@ update_filter: * * 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 int 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; @@ -2312,7 +2300,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; @@ -2340,7 +2329,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; @@ -2381,7 +2370,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; @@ -2433,7 +2423,7 @@ static int igc_find_etype_filter(struct igc_adapter *adapter, u16 etype) * * Return: 0 in case of success, negative errno code otherwise. */ -int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype) +static int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype) { struct igc_hw *hw = &adapter->hw; int index; @@ -2449,6 +2439,167 @@ int igc_del_etype_filter(struct igc_adapter *adapter, u16 etype) return 0; } +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 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 (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; +} + +/** + * 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); +} + +/** + * 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; + + spin_lock(&adapter->nfc_rule_lock); + + list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list) + igc_enable_nfc_rule(adapter, rule); + + spin_unlock(&adapter->nfc_rule_lock); +} + +static void igc_nfc_rule_exit(struct igc_adapter *adapter) +{ + struct igc_nfc_rule *rule; + + spin_lock(&adapter->nfc_rule_lock); + + list_for_each_entry(rule, &adapter->nfc_rule_list, list) + igc_disable_nfc_rule(adapter, rule); + + spin_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); @@ -3648,18 +3799,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); - - list_for_each_entry(rule, &adapter->nfc_rule_list, list) - igc_disable_nfc_rule(adapter, rule); - - spin_unlock(&adapter->nfc_rule_lock); -} - /** * igc_down - Close the interface * @adapter: board private structure -- cgit v1.2.3 From e256ec83fabd5803a576c46e03289e519d087fda Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:19 -0700 Subject: igc: Fix NFC rules leak when driver is unloaded If we have RFC rules in adapter->nfc_rule_list when the IGC driver is unloaded, all rules are leaked. This patch fixes the issue by introducing the helper igc_flush_nfc_rules() and calling it in igc_remove(). It also updates igc_set_features() so is reuses the new helper instead of re-implementing it. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_main.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index ad9217335a64..0a6f880e3538 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2544,6 +2544,18 @@ void igc_del_nfc_rule(struct igc_adapter *adapter, struct igc_nfc_rule *rule) kfree(rule); } +static void igc_flush_nfc_rules(struct igc_adapter *adapter) +{ + struct igc_nfc_rule *rule, *tmp; + + spin_lock(&adapter->nfc_rule_lock); + + list_for_each_entry_safe(rule, tmp, &adapter->nfc_rule_list, list) + igc_del_nfc_rule(adapter, rule); + + spin_unlock(&adapter->nfc_rule_lock); +} + /** * igc_add_nfc_rule() - Add NFC rule * @adapter: Pointer to adapter @@ -3967,19 +3979,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 igc_nfc_rule *rule, *tmp; - - spin_lock(&adapter->nfc_rule_lock); - list_for_each_entry_safe(rule, tmp, - &adapter->nfc_rule_list, list) { - igc_disable_nfc_rule(adapter, rule); - list_del(&rule->list); - 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; @@ -5246,6 +5247,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); -- cgit v1.2.3 From 1894df0ccb6ac7ba8b2c799e7d74b5db1180c518 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:20 -0700 Subject: igc: Fix NFC rule validation If we try to overwrite an existing rule with the same filter but different action, we get EEXIST error as shown below. $ ethtool -N eth0 flow-type ether dst action 1 loc 10 $ ethtool -N eth0 flow-type ether dst action 2 loc 10 rmgr: Cannot insert RX class rule: File exists The second command is expected to overwrite the previous rule in location 10 and succeed. This patch fixes igc_ethtool_check_nfc_rule() so it also checks the rules location. In case they match, the rule under evaluation should not be considered invalid. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_ethtool.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 43dff09a8f86..d14c46dce053 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1225,8 +1225,8 @@ static void igc_ethtool_init_nfc_rule(struct igc_nfc_rule *rule, * 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, @rule is - * considered invalid. + * 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. * @@ -1252,7 +1252,8 @@ static int igc_ethtool_check_nfc_rule(struct igc_adapter *adapter, list_for_each_entry(tmp, &adapter->nfc_rule_list, list) { if (!memcmp(&rule->filter, &tmp->filter, - sizeof(rule->filter))) { + sizeof(rule->filter)) && + tmp->location != rule->location) { netdev_dbg(dev, "Rule already exists\n"); return -EEXIST; } -- cgit v1.2.3 From acda576f72b8a2eed44aa3840561daa0ce837744 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:21 -0700 Subject: igc: Change return type from igc_disable_nfc_rule() None of igc_disable_nfc_rule() callers actually check its returning value. A closer look at why this function would fail shows that the only situation is when we try to delete an Ethertype or MAC filter that doesn't exist. That situation is very unlikely so we can change igc_del_etype_filter() and igc_del_mac_filter() logic to "if the filter doesn't exist, we are done", and keep the logic in igc_disable_nfc_rule() callers simple. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_main.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 0a6f880e3538..9338209cedf2 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2259,18 +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. */ -static 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; 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. @@ -2288,8 +2286,6 @@ static int igc_del_mac_filter(struct igc_adapter *adapter, igc_clear_mac_filter_hw(adapter, index); } - - return 0; } /** @@ -2420,23 +2416,20 @@ 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. */ -static 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); - return 0; } static int igc_enable_nfc_rule(struct igc_adapter *adapter, @@ -2477,8 +2470,8 @@ static int igc_enable_nfc_rule(struct igc_adapter *adapter, return 0; } -static int igc_disable_nfc_rule(struct igc_adapter *adapter, - const struct igc_nfc_rule *rule) +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); @@ -2497,8 +2490,6 @@ static int igc_disable_nfc_rule(struct igc_adapter *adapter, 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; } /** @@ -2623,7 +2614,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; } /** -- cgit v1.2.3 From 42fc5dc042796a825d9e2db8ee4cd977b12f73d1 Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:22 -0700 Subject: igc: Change adapter->nfc_rule_lock to mutex This patch changes adapter->nfc_rule_lock type from spin_lock to mutex so we avoid unnecessary busy waiting on lock contention. A closer look at the execution context of NFC rule API users shows that all of them run in process context. The API users are: ethtool ops, igc_configure(), called when interface is brought up by user or reset workequeue thread, igc_down(), called when interface is brought down, and igc_remove(), called when driver is unloaded. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 2 +- drivers/net/ethernet/intel/igc/igc_ethtool.c | 24 ++++++++++++------------ drivers/net/ethernet/intel/igc/igc_main.c | 14 +++++++------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index a484b328268b..14f9edaaaf83 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -190,7 +190,7 @@ struct igc_adapter { /* Any access to elements in nfc_rule_list is protected by the * nfc_rule_lock. */ - spinlock_t nfc_rule_lock; + struct mutex nfc_rule_lock; struct list_head nfc_rule_list; unsigned int nfc_rule_count; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index d14c46dce053..946e775e34ae 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -939,7 +939,7 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, cmd->data = IGC_MAX_RXNFC_RULES; - spin_lock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); rule = igc_get_nfc_rule(adapter, fsp->location); if (!rule) @@ -971,11 +971,11 @@ static int igc_ethtool_get_nfc_rule(struct igc_adapter *adapter, eth_broadcast_addr(fsp->m_u.ether_spec.h_source); } - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); return 0; out: - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); return -EINVAL; } @@ -988,18 +988,18 @@ static int igc_ethtool_get_nfc_rules(struct igc_adapter *adapter, cmd->data = IGC_MAX_RXNFC_RULES; - spin_lock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); list_for_each_entry(rule, &adapter->nfc_rule_list, list) { if (cnt == cmd->rule_cnt) { - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); return -EMSGSIZE; } rule_locs[cnt] = rule->location; cnt++; } - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); cmd->rule_cnt = cnt; @@ -1303,7 +1303,7 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, igc_ethtool_init_nfc_rule(rule, fsp); - spin_lock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); err = igc_ethtool_check_nfc_rule(adapter, rule); if (err) @@ -1317,11 +1317,11 @@ static int igc_ethtool_add_nfc_rule(struct igc_adapter *adapter, if (err) goto err; - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); return 0; err: - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); kfree(rule); return err; } @@ -1333,17 +1333,17 @@ static int igc_ethtool_del_nfc_rule(struct igc_adapter *adapter, (struct ethtool_rx_flow_spec *)&cmd->fs; struct igc_nfc_rule *rule; - spin_lock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); rule = igc_get_nfc_rule(adapter, fsp->location); if (!rule) { - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); return -EINVAL; } igc_del_nfc_rule(adapter, rule); - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); return 0; } diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 9338209cedf2..165263ae8add 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2539,12 +2539,12 @@ static void igc_flush_nfc_rules(struct igc_adapter *adapter) { struct igc_nfc_rule *rule, *tmp; - spin_lock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); list_for_each_entry_safe(rule, tmp, &adapter->nfc_rule_list, list) igc_del_nfc_rule(adapter, rule); - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); } /** @@ -2583,24 +2583,24 @@ static void igc_restore_nfc_rules(struct igc_adapter *adapter) { struct igc_nfc_rule *rule; - spin_lock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); list_for_each_entry_reverse(rule, &adapter->nfc_rule_list, list) igc_enable_nfc_rule(adapter, rule); - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); } static void igc_nfc_rule_exit(struct igc_adapter *adapter) { struct igc_nfc_rule *rule; - spin_lock(&adapter->nfc_rule_lock); + mutex_lock(&adapter->nfc_rule_lock); list_for_each_entry(rule, &adapter->nfc_rule_list, list) igc_disable_nfc_rule(adapter, rule); - spin_unlock(&adapter->nfc_rule_lock); + mutex_unlock(&adapter->nfc_rule_lock); } static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) @@ -3573,7 +3573,7 @@ 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; -- cgit v1.2.3 From 5c739e77ca338a37765370290e02cb270651380b Mon Sep 17 00:00:00 2001 From: Andre Guedes Date: Fri, 24 Apr 2020 13:16:23 -0700 Subject: igc: Remove igc_nfc_rule_exit() During igc_down(), we call igc_nfc_rule_exit() which traverse the NFC rule list disabling filters one by one. Later on in igc_down() flow we issue an hardware reset which also clear all filters. Since we already reset the hardware, we don't actually need to disable each filter manually. In order to simplify the code, this patch removes igc_nfc_rule() altogether. Signed-off-by: Andre Guedes Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_main.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 165263ae8add..97d26991c87e 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2591,18 +2591,6 @@ static void igc_restore_nfc_rules(struct igc_adapter *adapter) mutex_unlock(&adapter->nfc_rule_lock); } -static void igc_nfc_rule_exit(struct igc_adapter *adapter) -{ - struct igc_nfc_rule *rule; - - mutex_lock(&adapter->nfc_rule_lock); - - list_for_each_entry(rule, &adapter->nfc_rule_list, list) - igc_disable_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); @@ -3821,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); -- cgit v1.2.3 From 14ec06b02e260b2e78785741d0e734f4b04db1fe Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Mon, 4 May 2020 09:29:25 +0300 Subject: igc: Remove unused descriptor's flags Enable Tidv register, Report Packet Sent, Report Status and Ethernet CRC flags not in use. This patch comes to clean up these flags. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_defines.h | 4 ---- 1 file changed, 4 deletions(-) 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 */ -- cgit v1.2.3 From 165ae7a8feb53dc47fb041357e4b253bfc927cf9 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 5 May 2020 12:01:54 +0800 Subject: igb: Report speed and duplex as unknown when device is runtime suspended igb device gets runtime suspended when there's no link partner. We can't get correct speed under that state: $ cat /sys/class/net/enp3s0/speed 1000 In addition to that, an error can also be spotted in dmesg: [ 385.991957] igb 0000:03:00.0 enp3s0: PCIe link lost Since device can only be runtime suspended when there's no link partner, we can skip reading register and let the following logic set speed and duplex with correct status. The more generic approach will be wrap get_link_ksettings() with begin() and complete() callbacks. However, for this particular issue, begin() calls igb_runtime_resume() , which tries to rtnl_lock() while the lock is already hold by upper ethtool layer. So let's take this approach until the igb_runtime_resume() no longer needs to hold rtnl_lock. CC: stable Suggested-by: Alexander Duyck Signed-off-by: Kai-Heng Feng Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ethtool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 | -- cgit v1.2.3 From 0c80cdbf33207c7aea1aec9027ad8011bd6178ad Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Thu, 7 May 2020 14:25:45 +0800 Subject: e1000e: Warn if disabling ULP failed The hardware may stop working if driver failed to disable ULP mode. Take the return value of e1000_disable_ulp_lpt_lp() into account, and pass up the error if it fails. Signed-off-by: Kai-Heng Feng Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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) { -- cgit v1.2.3 From f29801030ac67bf98b7a65d3aea67b30769d4f7c Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Thu, 7 May 2020 22:21:07 +0800 Subject: e1000e: Disable TSO for buffer overrun workaround Commit b10effb92e27 ("e1000e: fix buffer overrun while the I219 is processing DMA transactions") imposes roughly 30% performance penalty. The commit log states that "Disabling TSO eliminates performance loss for TCP traffic without a noticeable impact on CPU performance", so let's disable TSO by default to regain the loss. CC: stable Fixes: b10effb92e27 ("e1000e: fix buffer overrun while the I219 is processing DMA transactions") BugLink: https://bugs.launchpad.net/bugs/1802691 Signed-off-by: Kai-Heng Feng Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index e0b074820b47..66609cf689de 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5294,6 +5294,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 -- cgit v1.2.3 From e086ba2fccda4c196b84a167493f67f089d0ebdc Mon Sep 17 00:00:00 2001 From: Vitaly Lifshits Date: Thu, 7 May 2020 20:14:06 +0300 Subject: e1000e: disable s0ix entry and exit flows for ME systems Since ME systems do not support SLP_S0 in S0ix state, and S0ix entry and exit flows may cause errors on them it is best to avoid using e1000e_s0ix_entry_flow and e1000e_s0ix_exit_flow functions. This was done by creating a struct of all devices that comes with ME and by checking if the current device has ME. Signed-off-by: Vitaly Lifshits Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 45 ++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 66609cf689de..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 @@ -6916,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; @@ -6931,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); -- cgit v1.2.3