summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c6
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c49
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c3
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h26
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h4
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ethtool.c294
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c246
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);