572 lines
17 KiB
Diff
572 lines
17 KiB
Diff
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
|
|||
|
|
index 9b8217523fd2..15d77ccb749d 100644
|
||
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
|
||
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
|
||
|
|
@@ -771,6 +771,13 @@ struct ixgbe_adapter {
|
||
|
|
u32 atr_sample_rate;
|
||
|
|
spinlock_t fdir_perfect_lock;
|
||
|
|
|
||
|
|
+ struct ixgbe_etqf_entry {
|
||
|
|
+ bool used;
|
||
|
|
+ u32 loc;
|
||
|
|
+ u16 etype;
|
||
|
|
+ u8 ring;
|
||
|
|
+ } etqf_filters[IXGBE_MAX_ETQF_FILTERS];
|
||
|
|
+
|
||
|
|
bool fw_emp_reset_disabled;
|
||
|
|
|
||
|
|
#ifdef IXGBE_FCOE
|
||
|
|
@@ -1010,6 +1017,8 @@ void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
|
||
|
|
int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
|
||
|
|
struct ixgbe_fdir_filter *input,
|
||
|
|
u16 sw_idx);
|
||
|
|
+void ixgbe_etqf_filter_restore(struct ixgbe_adapter *adapter);
|
||
|
|
+void ixgbe_etqf_filter_exit(struct ixgbe_adapter *adapter);
|
||
|
|
void ixgbe_set_rx_mode(struct net_device *netdev);
|
||
|
|
#ifdef CONFIG_IXGBE_DCB
|
||
|
|
void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter);
|
||
|
|
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
|
||
|
|
index 5b1cf49df3d3..75689ca7eb2d 100644
|
||
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
|
||
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
|
||
|
|
@@ -5,6 +5,7 @@
|
||
|
|
#include <linux/module.h>
|
||
|
|
|
||
|
|
#include "ixgbe.h"
|
||
|
|
+#include "ixgbe_phy.h"
|
||
|
|
|
||
|
|
static struct dentry *ixgbe_dbg_root;
|
||
|
|
|
||
|
|
@@ -185,6 +186,123 @@ static const struct file_operations ixgbe_dbg_netdev_ops_fops = {
|
||
|
|
.write = ixgbe_dbg_netdev_ops_write,
|
||
|
|
};
|
||
|
|
|
||
|
|
+#define IXGBE_SFF_I2C_MAX 32
|
||
|
|
+
|
||
|
|
+struct ixgbe_sff_i2c_ctx {
|
||
|
|
+ struct ixgbe_adapter *adapter;
|
||
|
|
+ int resp_len;
|
||
|
|
+ char resp[IXGBE_SFF_I2C_MAX * 3 + 16];
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static int ixgbe_dbg_sff_i2c_open(struct inode *inode, struct file *filp)
|
||
|
|
+{
|
||
|
|
+ struct ixgbe_sff_i2c_ctx *ctx;
|
||
|
|
+
|
||
|
|
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||
|
|
+ if (!ctx)
|
||
|
|
+ return -ENOMEM;
|
||
|
|
+ ctx->adapter = inode->i_private;
|
||
|
|
+ filp->private_data = ctx;
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int ixgbe_dbg_sff_i2c_release(struct inode *inode, struct file *filp)
|
||
|
|
+{
|
||
|
|
+ kfree(filp->private_data);
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static ssize_t ixgbe_dbg_sff_i2c_write(struct file *filp,
|
||
|
|
+ const char __user *ubuf,
|
||
|
|
+ size_t count, loff_t *ppos)
|
||
|
|
+{
|
||
|
|
+ struct ixgbe_sff_i2c_ctx *ctx = filp->private_data;
|
||
|
|
+ struct ixgbe_hw *hw = &ctx->adapter->hw;
|
||
|
|
+ u8 data[IXGBE_SFF_I2C_MAX];
|
||
|
|
+ u8 wdata[IXGBE_SFF_I2C_MAX];
|
||
|
|
+ char cmd[160];
|
||
|
|
+ unsigned int addr, raddr, delay, n, wn, v;
|
||
|
|
+ int status, off, consumed, i;
|
||
|
|
+ char op;
|
||
|
|
+
|
||
|
|
+ if (*ppos != 0 || count >= sizeof(cmd))
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ if (copy_from_user(cmd, ubuf, count))
|
||
|
|
+ return -EFAULT;
|
||
|
|
+ cmd[count] = '\0';
|
||
|
|
+
|
||
|
|
+ if (sscanf(cmd, " %c %x %n", &op, &addr, &off) < 2)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+
|
||
|
|
+ if (op == 'r') {
|
||
|
|
+ if (sscanf(cmd + off, "%x", &n) != 1 || n < 1 ||
|
||
|
|
+ n > IXGBE_SFF_I2C_MAX)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ status = ixgbe_i2c_raw_read(hw, addr, data, n);
|
||
|
|
+ } else if (op == 'w') {
|
||
|
|
+ n = 0;
|
||
|
|
+ while (n < IXGBE_SFF_I2C_MAX &&
|
||
|
|
+ sscanf(cmd + off, "%x%n", &v, &consumed) == 1) {
|
||
|
|
+ data[n++] = v;
|
||
|
|
+ off += consumed;
|
||
|
|
+ }
|
||
|
|
+ status = ixgbe_i2c_raw_write(hw, addr, data, n);
|
||
|
|
+ } else if (op == 'x') {
|
||
|
|
+ if (sscanf(cmd + off, "%x %u %x %n", &raddr, &delay, &n,
|
||
|
|
+ &consumed) < 3)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ off += consumed;
|
||
|
|
+ if (n > IXGBE_SFF_I2C_MAX || delay > 50000)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ wn = 0;
|
||
|
|
+ while (wn < IXGBE_SFF_I2C_MAX &&
|
||
|
|
+ sscanf(cmd + off, "%x%n", &v, &consumed) == 1) {
|
||
|
|
+ wdata[wn++] = v;
|
||
|
|
+ off += consumed;
|
||
|
|
+ }
|
||
|
|
+ status = ixgbe_i2c_raw_xfer(hw, addr, wdata, wn, delay,
|
||
|
|
+ raddr, data, n);
|
||
|
|
+ } else {
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (status) {
|
||
|
|
+ ctx->resp_len = scnprintf(ctx->resp, sizeof(ctx->resp),
|
||
|
|
+ "err %d\n", status);
|
||
|
|
+ } else if (op == 'r' || (op == 'x' && n)) {
|
||
|
|
+ off = scnprintf(ctx->resp, sizeof(ctx->resp), "ok");
|
||
|
|
+ for (i = 0; i < n; i++)
|
||
|
|
+ off += scnprintf(ctx->resp + off,
|
||
|
|
+ sizeof(ctx->resp) - off,
|
||
|
|
+ " %02x", data[i]);
|
||
|
|
+ off += scnprintf(ctx->resp + off, sizeof(ctx->resp) - off,
|
||
|
|
+ "\n");
|
||
|
|
+ ctx->resp_len = off;
|
||
|
|
+ } else {
|
||
|
|
+ ctx->resp_len = scnprintf(ctx->resp, sizeof(ctx->resp), "ok\n");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *ppos = 0;
|
||
|
|
+ return count;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static ssize_t ixgbe_dbg_sff_i2c_read(struct file *filp, char __user *ubuf,
|
||
|
|
+ size_t count, loff_t *ppos)
|
||
|
|
+{
|
||
|
|
+ struct ixgbe_sff_i2c_ctx *ctx = filp->private_data;
|
||
|
|
+
|
||
|
|
+ return simple_read_from_buffer(ubuf, count, ppos, ctx->resp,
|
||
|
|
+ ctx->resp_len);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static const struct file_operations ixgbe_dbg_sff_i2c_fops = {
|
||
|
|
+ .owner = THIS_MODULE,
|
||
|
|
+ .open = ixgbe_dbg_sff_i2c_open,
|
||
|
|
+ .release = ixgbe_dbg_sff_i2c_release,
|
||
|
|
+ .read = ixgbe_dbg_sff_i2c_read,
|
||
|
|
+ .write = ixgbe_dbg_sff_i2c_write,
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
/**
|
||
|
|
* ixgbe_dbg_adapter_init - setup the debugfs directory for the adapter
|
||
|
|
* @adapter: the adapter that is starting up
|
||
|
|
@@ -198,6 +316,8 @@ void ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter)
|
||
|
|
adapter, &ixgbe_dbg_reg_ops_fops);
|
||
|
|
debugfs_create_file("netdev_ops", 0600, adapter->ixgbe_dbg_adapter,
|
||
|
|
adapter, &ixgbe_dbg_netdev_ops_fops);
|
||
|
|
+ debugfs_create_file("sff_i2c", 0600, adapter->ixgbe_dbg_adapter,
|
||
|
|
+ adapter, &ixgbe_dbg_sff_i2c_fops);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
|
||
|
|
index 36e43b5e88d1..8bcb0ec0e65d 100644
|
||
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
|
||
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
|
||
|
|
@@ -2664,6 +2664,142 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static u32 ixgbe_etqf_filter_count(struct ixgbe_adapter *adapter)
|
||
|
|
+{
|
||
|
|
+ u32 n = 0;
|
||
|
|
+ int i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++)
|
||
|
|
+ if (adapter->etqf_filters[i].used)
|
||
|
|
+ n++;
|
||
|
|
+ return n;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int ixgbe_add_etqf_entry(struct ixgbe_adapter *adapter,
|
||
|
|
+ struct ethtool_rxnfc *cmd)
|
||
|
|
+{
|
||
|
|
+ struct ethtool_rx_flow_spec *fsp =
|
||
|
|
+ (struct ethtool_rx_flow_spec *)&cmd->fs;
|
||
|
|
+ static const u8 zero_mac[ETH_ALEN];
|
||
|
|
+ struct ixgbe_etqf_entry *slot = NULL;
|
||
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
||
|
|
+ u16 etype = ntohs(fsp->h_u.ether_spec.h_proto);
|
||
|
|
+ u32 ring;
|
||
|
|
+ int i;
|
||
|
|
+
|
||
|
|
+ if (fsp->flow_type != ETHER_FLOW)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ if (fsp->m_u.ether_spec.h_proto != htons(0xFFFF) ||
|
||
|
|
+ !ether_addr_equal(fsp->m_u.ether_spec.h_dest, zero_mac) ||
|
||
|
|
+ !ether_addr_equal(fsp->m_u.ether_spec.h_source, zero_mac))
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ if (etype == ETH_P_1588)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
|
||
|
|
+ if (ethtool_get_flow_spec_ring_vf(fsp->ring_cookie) ||
|
||
|
|
+ ring >= adapter->num_rx_queues)
|
||
|
|
+ return -EINVAL;
|
||
|
|
+ if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2))
|
||
|
|
+ return -EINVAL;
|
||
|
|
+
|
||
|
|
+ spin_lock(&adapter->fdir_perfect_lock);
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++) {
|
||
|
|
+ struct ixgbe_etqf_entry *e = &adapter->etqf_filters[i];
|
||
|
|
+
|
||
|
|
+ if (!e->used)
|
||
|
|
+ continue;
|
||
|
|
+ if (e->etype == etype && e->loc != fsp->location) {
|
||
|
|
+ spin_unlock(&adapter->fdir_perfect_lock);
|
||
|
|
+ return -EEXIST;
|
||
|
|
+ }
|
||
|
|
+ if (e->loc == fsp->location)
|
||
|
|
+ slot = e;
|
||
|
|
+ }
|
||
|
|
+ if (!slot) {
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++) {
|
||
|
|
+ if (i == IXGBE_ETQF_FILTER_1588 ||
|
||
|
|
+ adapter->etqf_filters[i].used ||
|
||
|
|
+ (IXGBE_READ_REG(hw, IXGBE_ETQF(i)) &
|
||
|
|
+ IXGBE_ETQF_FILTER_EN))
|
||
|
|
+ continue;
|
||
|
|
+ slot = &adapter->etqf_filters[i];
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ if (!slot) {
|
||
|
|
+ spin_unlock(&adapter->fdir_perfect_lock);
|
||
|
|
+ return -ENOSPC;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ i = slot - adapter->etqf_filters;
|
||
|
|
+ slot->used = true;
|
||
|
|
+ slot->loc = fsp->location;
|
||
|
|
+ slot->etype = etype;
|
||
|
|
+ slot->ring = ring;
|
||
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ETQS(i), IXGBE_ETQS_QUEUE_EN |
|
||
|
|
+ ((u32)adapter->rx_ring[ring]->reg_idx <<
|
||
|
|
+ IXGBE_ETQS_RX_QUEUE_SHIFT));
|
||
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ETQF(i), IXGBE_ETQF_FILTER_EN | etype);
|
||
|
|
+ spin_unlock(&adapter->fdir_perfect_lock);
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* Caller holds fdir_perfect_lock. */
|
||
|
|
+static int ixgbe_del_etqf_entry(struct ixgbe_adapter *adapter, u32 loc)
|
||
|
|
+{
|
||
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
||
|
|
+ int i;
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++) {
|
||
|
|
+ struct ixgbe_etqf_entry *e = &adapter->etqf_filters[i];
|
||
|
|
+
|
||
|
|
+ if (!e->used || e->loc != loc)
|
||
|
|
+ continue;
|
||
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ETQF(i), 0);
|
||
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ETQS(i), 0);
|
||
|
|
+ e->used = false;
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+ return -ENOENT;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void ixgbe_etqf_filter_restore(struct ixgbe_adapter *adapter)
|
||
|
|
+{
|
||
|
|
+ struct ixgbe_hw *hw = &adapter->hw;
|
||
|
|
+ int i;
|
||
|
|
+
|
||
|
|
+ spin_lock(&adapter->fdir_perfect_lock);
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++) {
|
||
|
|
+ struct ixgbe_etqf_entry *e = &adapter->etqf_filters[i];
|
||
|
|
+
|
||
|
|
+ if (!e->used)
|
||
|
|
+ continue;
|
||
|
|
+ if (e->ring >= adapter->num_rx_queues) {
|
||
|
|
+ e->used = false;
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ETQS(i), IXGBE_ETQS_QUEUE_EN |
|
||
|
|
+ ((u32)adapter->rx_ring[e->ring]->reg_idx <<
|
||
|
|
+ IXGBE_ETQS_RX_QUEUE_SHIFT));
|
||
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_ETQF(i),
|
||
|
|
+ IXGBE_ETQF_FILTER_EN | e->etype);
|
||
|
|
+ }
|
||
|
|
+ spin_unlock(&adapter->fdir_perfect_lock);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void ixgbe_etqf_filter_exit(struct ixgbe_adapter *adapter)
|
||
|
|
+{
|
||
|
|
+ int i;
|
||
|
|
+
|
||
|
|
+ spin_lock(&adapter->fdir_perfect_lock);
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++)
|
||
|
|
+ adapter->etqf_filters[i].used = false;
|
||
|
|
+ spin_unlock(&adapter->fdir_perfect_lock);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
static int ixgbe_get_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
|
||
|
|
struct ethtool_rxnfc *cmd)
|
||
|
|
{
|
||
|
|
@@ -2672,10 +2808,23 @@ static int ixgbe_get_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
|
||
|
|
(struct ethtool_rx_flow_spec *)&cmd->fs;
|
||
|
|
struct hlist_node *node2;
|
||
|
|
struct ixgbe_fdir_filter *rule = NULL;
|
||
|
|
+ int i;
|
||
|
|
|
||
|
|
/* report total rule count */
|
||
|
|
cmd->data = (1024 << adapter->fdir_pballoc) - 2;
|
||
|
|
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++) {
|
||
|
|
+ struct ixgbe_etqf_entry *e = &adapter->etqf_filters[i];
|
||
|
|
+
|
||
|
|
+ if (!e->used || e->loc != fsp->location)
|
||
|
|
+ continue;
|
||
|
|
+ fsp->flow_type = ETHER_FLOW;
|
||
|
|
+ fsp->h_u.ether_spec.h_proto = htons(e->etype);
|
||
|
|
+ fsp->m_u.ether_spec.h_proto = htons(0xFFFF);
|
||
|
|
+ fsp->ring_cookie = e->ring;
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
hlist_for_each_entry_safe(rule, node2,
|
||
|
|
&adapter->fdir_filter_list, fdir_node) {
|
||
|
|
if (fsp->location <= rule->sw_idx)
|
||
|
|
@@ -2740,6 +2889,7 @@ static int ixgbe_get_ethtool_fdir_all(struct ixgbe_adapter *adapter,
|
||
|
|
struct hlist_node *node2;
|
||
|
|
struct ixgbe_fdir_filter *rule;
|
||
|
|
int cnt = 0;
|
||
|
|
+ int i;
|
||
|
|
|
||
|
|
/* report total rule count */
|
||
|
|
cmd->data = (1024 << adapter->fdir_pballoc) - 2;
|
||
|
|
@@ -2752,6 +2902,17 @@ static int ixgbe_get_ethtool_fdir_all(struct ixgbe_adapter *adapter,
|
||
|
|
cnt++;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ for (i = 0; i < IXGBE_MAX_ETQF_FILTERS; i++) {
|
||
|
|
+ struct ixgbe_etqf_entry *e = &adapter->etqf_filters[i];
|
||
|
|
+
|
||
|
|
+ if (!e->used)
|
||
|
|
+ continue;
|
||
|
|
+ if (cnt == cmd->rule_cnt)
|
||
|
|
+ return -EMSGSIZE;
|
||
|
|
+ rule_locs[cnt] = e->loc;
|
||
|
|
+ cnt++;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
cmd->rule_cnt = cnt;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
@@ -2825,7 +2986,9 @@ static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
||
|
|
|
||
|
|
switch (cmd->cmd) {
|
||
|
|
case ETHTOOL_GRXCLSRLCNT:
|
||
|
|
- cmd->rule_cnt = adapter->fdir_filter_count;
|
||
|
|
+ cmd->rule_cnt = adapter->fdir_filter_count +
|
||
|
|
+ ixgbe_etqf_filter_count(adapter);
|
||
|
|
+ cmd->data = (1024 << adapter->fdir_pballoc) - 2;
|
||
|
|
ret = 0;
|
||
|
|
break;
|
||
|
|
case ETHTOOL_GRXCLSRULE:
|
||
|
|
@@ -3077,7 +3240,10 @@ static int ixgbe_del_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
|
||
|
|
int err;
|
||
|
|
|
||
|
|
spin_lock(&adapter->fdir_perfect_lock);
|
||
|
|
- err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, fsp->location);
|
||
|
|
+ err = ixgbe_del_etqf_entry(adapter, fsp->location);
|
||
|
|
+ if (err)
|
||
|
|
+ err = ixgbe_update_ethtool_fdir_entry(adapter, NULL,
|
||
|
|
+ fsp->location);
|
||
|
|
spin_unlock(&adapter->fdir_perfect_lock);
|
||
|
|
|
||
|
|
return err;
|
||
|
|
@@ -3207,7 +3373,10 @@ static int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
||
|
|
|
||
|
|
switch (cmd->cmd) {
|
||
|
|
case ETHTOOL_SRXCLSRLINS:
|
||
|
|
- ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd);
|
||
|
|
+ if ((cmd->fs.flow_type & ~FLOW_EXT) == ETHER_FLOW)
|
||
|
|
+ ret = ixgbe_add_etqf_entry(adapter, cmd);
|
||
|
|
+ else
|
||
|
|
+ ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd);
|
||
|
|
break;
|
||
|
|
case ETHTOOL_SRXCLSRLDEL:
|
||
|
|
ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd);
|
||
|
|
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
|
||
|
|
index 011fda9c6193..1b5cb4f7bb68 100644
|
||
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
|
||
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
|
||
|
|
@@ -647,6 +647,10 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
|
||
|
|
if (!(adapter->netdev->features & NETIF_F_FCOE_CRC))
|
||
|
|
return;
|
||
|
|
|
||
|
|
+ /* leave registers un-configured if FCoE is disabled */
|
||
|
|
+ if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
/* Enable L2 EtherType filter for FCoE, needed for FCoE CRC and DDP */
|
||
|
|
etqf = ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN;
|
||
|
|
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
|
||
|
|
@@ -656,10 +660,6 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
|
||
|
|
IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), etqf);
|
||
|
|
IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0);
|
||
|
|
|
||
|
|
- /* leave registers un-configured if FCoE is disabled */
|
||
|
|
- if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
|
||
|
|
- return;
|
||
|
|
-
|
||
|
|
/* Use one or more Rx queues for FCoE by redirection table */
|
||
|
|
fcreta_size = IXGBE_FCRETA_SIZE;
|
||
|
|
if (adapter->hw.mac.type == ixgbe_mac_X550)
|
||
|
|
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
||
|
|
index 8873a8cc4a18..85fdf1ab4177 100644
|
||
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
||
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
|
||
|
|
@@ -5911,6 +5911,8 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
|
||
|
|
ixgbe_fdir_filter_restore(adapter);
|
||
|
|
}
|
||
|
|
|
||
|
|
+ ixgbe_etqf_filter_restore(adapter);
|
||
|
|
+
|
||
|
|
switch (hw->mac.type) {
|
||
|
|
case ixgbe_mac_82599EB:
|
||
|
|
case ixgbe_mac_X540:
|
||
|
|
@@ -7533,6 +7535,7 @@ int ixgbe_close(struct net_device *netdev)
|
||
|
|
ixgbe_close_suspend(adapter);
|
||
|
|
|
||
|
|
ixgbe_fdir_filter_exit(adapter);
|
||
|
|
+ ixgbe_etqf_filter_exit(adapter);
|
||
|
|
|
||
|
|
ixgbe_release_hw_control(adapter);
|
||
|
|
|
||
|
|
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
|
||
|
|
index ab733e73927d..fb876b9e9395 100644
|
||
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
|
||
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
|
||
|
|
@@ -60,6 +60,102 @@ static int ixgbe_in_i2c_byte_ack(struct ixgbe_hw *hw, u8 *byte)
|
||
|
|
return ixgbe_clock_out_i2c_bit(hw, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int ixgbe_i2c_raw_write_unlocked(struct ixgbe_hw *hw, u8 addr,
|
||
|
|
+ const u8 *buf, u8 len)
|
||
|
|
+{
|
||
|
|
+ int status;
|
||
|
|
+ u8 i;
|
||
|
|
+
|
||
|
|
+ ixgbe_i2c_start(hw);
|
||
|
|
+ status = ixgbe_out_i2c_byte_ack(hw, addr);
|
||
|
|
+ for (i = 0; !status && i < len; i++)
|
||
|
|
+ status = ixgbe_out_i2c_byte_ack(hw, buf[i]);
|
||
|
|
+
|
||
|
|
+ if (status)
|
||
|
|
+ ixgbe_i2c_bus_clear(hw);
|
||
|
|
+ else
|
||
|
|
+ ixgbe_i2c_stop(hw);
|
||
|
|
+
|
||
|
|
+ return status;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int ixgbe_i2c_raw_read_unlocked(struct ixgbe_hw *hw, u8 addr,
|
||
|
|
+ u8 *buf, u8 len)
|
||
|
|
+{
|
||
|
|
+ u32 i2cctl;
|
||
|
|
+ int status;
|
||
|
|
+ u8 i;
|
||
|
|
+
|
||
|
|
+ ixgbe_i2c_start(hw);
|
||
|
|
+ status = ixgbe_out_i2c_byte_ack(hw, addr);
|
||
|
|
+ for (i = 0; !status && i < len; i++) {
|
||
|
|
+ status = ixgbe_clock_in_i2c_byte(hw, &buf[i]);
|
||
|
|
+ if (!status)
|
||
|
|
+ status = ixgbe_clock_out_i2c_bit(hw, i == len - 1);
|
||
|
|
+ if (!status && i != len - 1) {
|
||
|
|
+ /* our ACK left SDA driven low; release it so the
|
||
|
|
+ * slave can drive the next byte
|
||
|
|
+ */
|
||
|
|
+ i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
|
||
|
|
+ i2cctl |= IXGBE_I2C_DATA_OUT(hw);
|
||
|
|
+ i2cctl |= IXGBE_I2C_DATA_OE_N_EN(hw);
|
||
|
|
+ IXGBE_WRITE_REG(hw, IXGBE_I2CCTL(hw), i2cctl);
|
||
|
|
+ IXGBE_WRITE_FLUSH(hw);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (status)
|
||
|
|
+ ixgbe_i2c_bus_clear(hw);
|
||
|
|
+ else
|
||
|
|
+ ixgbe_i2c_stop(hw);
|
||
|
|
+
|
||
|
|
+ return status;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int ixgbe_i2c_raw_write(struct ixgbe_hw *hw, u8 addr, const u8 *buf, u8 len)
|
||
|
|
+{
|
||
|
|
+ u32 swfw_mask = hw->phy.phy_semaphore_mask;
|
||
|
|
+ int status;
|
||
|
|
+
|
||
|
|
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
|
||
|
|
+ return -EBUSY;
|
||
|
|
+ status = ixgbe_i2c_raw_write_unlocked(hw, addr, buf, len);
|
||
|
|
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
|
||
|
|
+ return status;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int ixgbe_i2c_raw_read(struct ixgbe_hw *hw, u8 addr, u8 *buf, u8 len)
|
||
|
|
+{
|
||
|
|
+ u32 swfw_mask = hw->phy.phy_semaphore_mask;
|
||
|
|
+ int status;
|
||
|
|
+
|
||
|
|
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
|
||
|
|
+ return -EBUSY;
|
||
|
|
+ status = ixgbe_i2c_raw_read_unlocked(hw, addr, buf, len);
|
||
|
|
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
|
||
|
|
+ return status;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int ixgbe_i2c_raw_xfer(struct ixgbe_hw *hw, u8 waddr, const u8 *wbuf, u8 wlen,
|
||
|
|
+ u32 delay_us, u8 raddr, u8 *rbuf, u8 rlen)
|
||
|
|
+{
|
||
|
|
+ u32 swfw_mask = hw->phy.phy_semaphore_mask;
|
||
|
|
+ int status = 0;
|
||
|
|
+
|
||
|
|
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
|
||
|
|
+ return -EBUSY;
|
||
|
|
+
|
||
|
|
+ if (wlen)
|
||
|
|
+ status = ixgbe_i2c_raw_write_unlocked(hw, waddr, wbuf, wlen);
|
||
|
|
+ if (!status && delay_us)
|
||
|
|
+ usleep_range(delay_us, delay_us + delay_us / 10 + 10);
|
||
|
|
+ if (!status && rlen)
|
||
|
|
+ status = ixgbe_i2c_raw_read_unlocked(hw, raddr, rbuf, rlen);
|
||
|
|
+
|
||
|
|
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
|
||
|
|
+ return status;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/**
|
||
|
|
* ixgbe_ones_comp_byte_add - Perform one's complement addition
|
||
|
|
* @add1: addend 1
|
||
|
|
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
|
||
|
|
index 039ba4b6c120..b93bdd972d7a 100644
|
||
|
|
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
|
||
|
|
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
|
||
|
|
@@ -178,4 +178,8 @@ int ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg,
|
||
|
|
u16 *val, bool lock);
|
||
|
|
int ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *, u8 addr, u16 reg,
|
||
|
|
u16 val, bool lock);
|
||
|
|
+int ixgbe_i2c_raw_write(struct ixgbe_hw *hw, u8 addr, const u8 *buf, u8 len);
|
||
|
|
+int ixgbe_i2c_raw_read(struct ixgbe_hw *hw, u8 addr, u8 *buf, u8 len);
|
||
|
|
+int ixgbe_i2c_raw_xfer(struct ixgbe_hw *hw, u8 waddr, const u8 *wbuf, u8 wlen,
|
||
|
|
+ u32 delay_us, u8 raddr, u8 *rbuf, u8 rlen);
|
||
|
|
#endif /* _IXGBE_PHY_H_ */
|