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 #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_ */