mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-18 10:46:12 +07:00
Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue
Jeff Kirsher says: ==================== 1GbE Intel Wired LAN Driver Updates 2019-03-19 This series contains updates to e100, e1000, e1000e, igb, igc and ixgbe. Serhey Popovych fixes the return value for several of our older drivers for netdev_update_features() to notify of changes applied. Kai-Heng Feng fixes the WoL setting for system suspend, which should not set to runtime suspend settings for igb. Then fixes a power management issue with e1000e for CNP+ devices. Colin Ian King fixes whitespace issue (indentation), which helps with readability. Sasha provides the remaining changes for igc, including the enabling of multi-queues to receive. Added support for displaying and configuring network flow classification (NFC) via ethtool. Added additional statistics and basic counters for igc. Fixed a typo, so it aligns with our other drivers. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
8d3a3048c3
@ -2797,7 +2797,7 @@ static int e100_set_features(struct net_device *netdev,
|
||||
|
||||
netdev->features = features;
|
||||
e100_exec_cb(nic, NULL, e100_configure);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct net_device_ops e100_netdev_ops = {
|
||||
|
@ -820,7 +820,7 @@ static int e1000_set_features(struct net_device *netdev,
|
||||
else
|
||||
e1000_reset(adapter);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct net_device_ops e1000_netdev_ops = {
|
||||
|
@ -7003,7 +7003,7 @@ static int e1000_set_features(struct net_device *netdev,
|
||||
else
|
||||
e1000e_reset(adapter);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct net_device_ops e1000e_netdev_ops = {
|
||||
@ -7350,7 +7350,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
|
||||
|
||||
if (pci_dev_run_wake(pdev))
|
||||
if (pci_dev_run_wake(pdev) && hw->mac.type < e1000_pch_cnp)
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
@ -3158,8 +3158,8 @@ static int igb_set_eee(struct net_device *netdev,
|
||||
} else if (!edata->eee_enabled) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Setting EEE options are not supported with EEE disabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
|
||||
if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
|
||||
|
@ -2480,7 +2480,7 @@ static int igb_set_features(struct net_device *netdev,
|
||||
else
|
||||
igb_reset(adapter);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
|
||||
@ -3452,6 +3452,9 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
|
||||
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
return 0;
|
||||
|
||||
|
@ -29,9 +29,15 @@ unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
|
||||
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
|
||||
const u32 max_rss_queues);
|
||||
int igc_reinit_queues(struct igc_adapter *adapter);
|
||||
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_steering_filter(struct igc_adapter *adapter,
|
||||
const u8 *addr, u8 queue, u8 flags);
|
||||
int igc_del_mac_steering_filter(struct igc_adapter *adapter,
|
||||
const u8 *addr, u8 queue, u8 flags);
|
||||
void igc_update_stats(struct igc_adapter *adapter);
|
||||
|
||||
extern char igc_driver_name[];
|
||||
extern char igc_driver_version[];
|
||||
@ -51,6 +57,13 @@ extern char igc_driver_version[];
|
||||
#define IGC_FLAG_VLAN_PROMISC BIT(15)
|
||||
#define IGC_FLAG_RX_LEGACY BIT(16)
|
||||
|
||||
#define IGC_FLAG_RSS_FIELD_IPV4_UDP BIT(6)
|
||||
#define IGC_FLAG_RSS_FIELD_IPV6_UDP BIT(7)
|
||||
|
||||
#define IGC_MRQC_ENABLE_RSS_MQ 0x00000002
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
|
||||
|
||||
#define IGC_START_ITR 648 /* ~6000 ints/sec */
|
||||
#define IGC_4K_ITR 980
|
||||
#define IGC_20K_ITR 196
|
||||
@ -284,15 +297,50 @@ struct igc_q_vector {
|
||||
struct igc_ring ring[0] ____cacheline_internodealigned_in_smp;
|
||||
};
|
||||
|
||||
#define MAX_ETYPE_FILTER (4 - 1)
|
||||
|
||||
enum igc_filter_match_flags {
|
||||
IGC_FILTER_FLAG_ETHER_TYPE = 0x1,
|
||||
IGC_FILTER_FLAG_VLAN_TCI = 0x2,
|
||||
IGC_FILTER_FLAG_SRC_MAC_ADDR = 0x4,
|
||||
IGC_FILTER_FLAG_DST_MAC_ADDR = 0x8,
|
||||
};
|
||||
|
||||
/* RX network flow classification data structure */
|
||||
struct igc_nfc_input {
|
||||
/* Byte layout in order, all values with MSB first:
|
||||
* match_flags - 1 byte
|
||||
* etype - 2 bytes
|
||||
* vlan_tci - 2 bytes
|
||||
*/
|
||||
u8 match_flags;
|
||||
__be16 etype;
|
||||
__be16 vlan_tci;
|
||||
u8 src_addr[ETH_ALEN];
|
||||
u8 dst_addr[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct igc_nfc_filter {
|
||||
struct hlist_node nfc_node;
|
||||
struct igc_nfc_input filter;
|
||||
unsigned long cookie;
|
||||
u16 etype_reg_index;
|
||||
u16 sw_idx;
|
||||
u16 action;
|
||||
};
|
||||
|
||||
struct igc_mac_addr {
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 queue;
|
||||
u8 state; /* bitmask */
|
||||
};
|
||||
|
||||
#define IGC_MAC_STATE_DEFAULT 0x1
|
||||
#define IGC_MAC_STATE_MODIFIED 0x2
|
||||
#define IGC_MAC_STATE_IN_USE 0x4
|
||||
#define IGC_MAC_STATE_DEFAULT 0x1
|
||||
#define IGC_MAC_STATE_IN_USE 0x2
|
||||
#define IGC_MAC_STATE_SRC_ADDR 0x4
|
||||
#define IGC_MAC_STATE_QUEUE_STEERING 0x8
|
||||
|
||||
#define IGC_MAX_RXNFC_FILTERS 16
|
||||
|
||||
/* Board specific private data structure */
|
||||
struct igc_adapter {
|
||||
@ -356,12 +404,22 @@ struct igc_adapter {
|
||||
u16 tx_ring_count;
|
||||
u16 rx_ring_count;
|
||||
|
||||
u32 tx_hwtstamp_timeouts;
|
||||
u32 tx_hwtstamp_skipped;
|
||||
u32 rx_hwtstamp_cleared;
|
||||
u32 *shadow_vfta;
|
||||
|
||||
u32 rss_queues;
|
||||
u32 rss_indir_tbl_init;
|
||||
|
||||
/* RX network flow classification support */
|
||||
struct hlist_head nfc_filter_list;
|
||||
struct hlist_head cls_flower_list;
|
||||
unsigned int nfc_filter_count;
|
||||
|
||||
/* lock for RX network flow classification filter */
|
||||
spinlock_t nfc_lock;
|
||||
bool etype_bitmap[MAX_ETYPE_FILTER];
|
||||
|
||||
struct igc_mac_addr *mac_table;
|
||||
|
||||
@ -447,6 +505,10 @@ static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data)
|
||||
|
||||
/* forward declaration */
|
||||
void igc_reinit_locked(struct igc_adapter *);
|
||||
int igc_add_filter(struct igc_adapter *adapter,
|
||||
struct igc_nfc_filter *input);
|
||||
int igc_erase_filter(struct igc_adapter *adapter,
|
||||
struct igc_nfc_filter *input);
|
||||
|
||||
#define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring))
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
#ifndef _IGC_BASE_H
|
||||
#define _IGC_BASE_H
|
||||
#ifndef _IGC_BASE_H_
|
||||
#define _IGC_BASE_H_
|
||||
|
||||
/* forward declaration */
|
||||
void igc_rx_fifo_flush_base(struct igc_hw *hw);
|
||||
|
@ -310,6 +310,12 @@
|
||||
IGC_RXDEXT_STATERR_CXE | \
|
||||
IGC_RXDEXT_STATERR_RXE)
|
||||
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV4 0x00020000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6 0x00100000
|
||||
#define IGC_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
|
||||
|
||||
/* Header split receive */
|
||||
#define IGC_RFCTL_IPV6_EX_DIS 0x00010000
|
||||
#define IGC_RFCTL_LEF 0x00040000
|
||||
@ -325,6 +331,10 @@
|
||||
#define I225_RXPBSIZE_DEFAULT 0x000000A2 /* RXPBSIZE default */
|
||||
#define I225_TXPBSIZE_DEFAULT 0x04000014 /* TXPBSIZE default */
|
||||
|
||||
/* Receive Checksum Control */
|
||||
#define IGC_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */
|
||||
#define IGC_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
|
||||
|
||||
/* GPY211 - I225 defines */
|
||||
#define GPY_MMD_MASK 0xFFFF0000
|
||||
#define GPY_MMD_SHIFT 16
|
||||
@ -390,4 +400,11 @@
|
||||
|
||||
#define IGC_N0_QUEUE -1
|
||||
|
||||
#define IGC_MAX_MAC_HDR_LEN 127
|
||||
#define IGC_MAX_NETWORK_HDR_LEN 511
|
||||
|
||||
#define IGC_VLAPQF_QUEUE_SEL(_n, q_idx) ((q_idx) << ((_n) * 4))
|
||||
#define IGC_VLAPQF_P_VALID(_n) (0x1 << (3 + (_n) * 4))
|
||||
#define IGC_VLAPQF_QUEUE_MASK 0x03
|
||||
|
||||
#endif /* _IGC_DEFINES_H_ */
|
||||
|
@ -2,10 +2,120 @@
|
||||
/* Copyright (c) 2018 Intel Corporation */
|
||||
|
||||
/* ethtool support for igc */
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "igc.h"
|
||||
|
||||
/* forward declaration */
|
||||
struct igc_stats {
|
||||
char stat_string[ETH_GSTRING_LEN];
|
||||
int sizeof_stat;
|
||||
int stat_offset;
|
||||
};
|
||||
|
||||
#define IGC_STAT(_name, _stat) { \
|
||||
.stat_string = _name, \
|
||||
.sizeof_stat = FIELD_SIZEOF(struct igc_adapter, _stat), \
|
||||
.stat_offset = offsetof(struct igc_adapter, _stat) \
|
||||
}
|
||||
|
||||
static const struct igc_stats igc_gstrings_stats[] = {
|
||||
IGC_STAT("rx_packets", stats.gprc),
|
||||
IGC_STAT("tx_packets", stats.gptc),
|
||||
IGC_STAT("rx_bytes", stats.gorc),
|
||||
IGC_STAT("tx_bytes", stats.gotc),
|
||||
IGC_STAT("rx_broadcast", stats.bprc),
|
||||
IGC_STAT("tx_broadcast", stats.bptc),
|
||||
IGC_STAT("rx_multicast", stats.mprc),
|
||||
IGC_STAT("tx_multicast", stats.mptc),
|
||||
IGC_STAT("multicast", stats.mprc),
|
||||
IGC_STAT("collisions", stats.colc),
|
||||
IGC_STAT("rx_crc_errors", stats.crcerrs),
|
||||
IGC_STAT("rx_no_buffer_count", stats.rnbc),
|
||||
IGC_STAT("rx_missed_errors", stats.mpc),
|
||||
IGC_STAT("tx_aborted_errors", stats.ecol),
|
||||
IGC_STAT("tx_carrier_errors", stats.tncrs),
|
||||
IGC_STAT("tx_window_errors", stats.latecol),
|
||||
IGC_STAT("tx_abort_late_coll", stats.latecol),
|
||||
IGC_STAT("tx_deferred_ok", stats.dc),
|
||||
IGC_STAT("tx_single_coll_ok", stats.scc),
|
||||
IGC_STAT("tx_multi_coll_ok", stats.mcc),
|
||||
IGC_STAT("tx_timeout_count", tx_timeout_count),
|
||||
IGC_STAT("rx_long_length_errors", stats.roc),
|
||||
IGC_STAT("rx_short_length_errors", stats.ruc),
|
||||
IGC_STAT("rx_align_errors", stats.algnerrc),
|
||||
IGC_STAT("tx_tcp_seg_good", stats.tsctc),
|
||||
IGC_STAT("tx_tcp_seg_failed", stats.tsctfc),
|
||||
IGC_STAT("rx_flow_control_xon", stats.xonrxc),
|
||||
IGC_STAT("rx_flow_control_xoff", stats.xoffrxc),
|
||||
IGC_STAT("tx_flow_control_xon", stats.xontxc),
|
||||
IGC_STAT("tx_flow_control_xoff", stats.xofftxc),
|
||||
IGC_STAT("rx_long_byte_count", stats.gorc),
|
||||
IGC_STAT("tx_dma_out_of_sync", stats.doosync),
|
||||
IGC_STAT("tx_smbus", stats.mgptc),
|
||||
IGC_STAT("rx_smbus", stats.mgprc),
|
||||
IGC_STAT("dropped_smbus", stats.mgpdc),
|
||||
IGC_STAT("os2bmc_rx_by_bmc", stats.o2bgptc),
|
||||
IGC_STAT("os2bmc_tx_by_bmc", stats.b2ospc),
|
||||
IGC_STAT("os2bmc_tx_by_host", stats.o2bspc),
|
||||
IGC_STAT("os2bmc_rx_by_host", stats.b2ogprc),
|
||||
IGC_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
|
||||
IGC_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
|
||||
IGC_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
|
||||
};
|
||||
|
||||
#define IGC_NETDEV_STAT(_net_stat) { \
|
||||
.stat_string = __stringify(_net_stat), \
|
||||
.sizeof_stat = FIELD_SIZEOF(struct rtnl_link_stats64, _net_stat), \
|
||||
.stat_offset = offsetof(struct rtnl_link_stats64, _net_stat) \
|
||||
}
|
||||
|
||||
static const struct igc_stats igc_gstrings_net_stats[] = {
|
||||
IGC_NETDEV_STAT(rx_errors),
|
||||
IGC_NETDEV_STAT(tx_errors),
|
||||
IGC_NETDEV_STAT(tx_dropped),
|
||||
IGC_NETDEV_STAT(rx_length_errors),
|
||||
IGC_NETDEV_STAT(rx_over_errors),
|
||||
IGC_NETDEV_STAT(rx_frame_errors),
|
||||
IGC_NETDEV_STAT(rx_fifo_errors),
|
||||
IGC_NETDEV_STAT(tx_fifo_errors),
|
||||
IGC_NETDEV_STAT(tx_heartbeat_errors)
|
||||
};
|
||||
|
||||
enum igc_diagnostics_results {
|
||||
TEST_REG = 0,
|
||||
TEST_EEP,
|
||||
TEST_IRQ,
|
||||
TEST_LOOP,
|
||||
TEST_LINK
|
||||
};
|
||||
|
||||
static const char igc_gstrings_test[][ETH_GSTRING_LEN] = {
|
||||
[TEST_REG] = "Register test (offline)",
|
||||
[TEST_EEP] = "Eeprom test (offline)",
|
||||
[TEST_IRQ] = "Interrupt test (offline)",
|
||||
[TEST_LOOP] = "Loopback test (offline)",
|
||||
[TEST_LINK] = "Link test (on/offline)"
|
||||
};
|
||||
|
||||
#define IGC_TEST_LEN (sizeof(igc_gstrings_test) / ETH_GSTRING_LEN)
|
||||
|
||||
#define IGC_GLOBAL_STATS_LEN \
|
||||
(sizeof(igc_gstrings_stats) / sizeof(struct igc_stats))
|
||||
#define IGC_NETDEV_STATS_LEN \
|
||||
(sizeof(igc_gstrings_net_stats) / sizeof(struct igc_stats))
|
||||
#define IGC_RX_QUEUE_STATS_LEN \
|
||||
(sizeof(struct igc_rx_queue_stats) / sizeof(u64))
|
||||
#define IGC_TX_QUEUE_STATS_LEN 3 /* packets, bytes, restart_queue */
|
||||
#define IGC_QUEUE_STATS_LEN \
|
||||
((((struct igc_adapter *)netdev_priv(netdev))->num_rx_queues * \
|
||||
IGC_RX_QUEUE_STATS_LEN) + \
|
||||
(((struct igc_adapter *)netdev_priv(netdev))->num_tx_queues * \
|
||||
IGC_TX_QUEUE_STATS_LEN))
|
||||
#define IGC_STATS_LEN \
|
||||
(IGC_GLOBAL_STATS_LEN + IGC_NETDEV_STATS_LEN + IGC_QUEUE_STATS_LEN)
|
||||
|
||||
static const char igc_priv_flags_strings[][ETH_GSTRING_LEN] = {
|
||||
#define IGC_PRIV_FLAGS_LEGACY_RX BIT(0)
|
||||
"legacy-rx",
|
||||
@ -545,6 +655,127 @@ static int igc_set_pauseparam(struct net_device *netdev,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void igc_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
|
||||
{
|
||||
struct igc_adapter *adapter = netdev_priv(netdev);
|
||||
u8 *p = data;
|
||||
int i;
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_TEST:
|
||||
memcpy(data, *igc_gstrings_test,
|
||||
IGC_TEST_LEN * ETH_GSTRING_LEN);
|
||||
break;
|
||||
case ETH_SS_STATS:
|
||||
for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) {
|
||||
memcpy(p, igc_gstrings_stats[i].stat_string,
|
||||
ETH_GSTRING_LEN);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
for (i = 0; i < IGC_NETDEV_STATS_LEN; i++) {
|
||||
memcpy(p, igc_gstrings_net_stats[i].stat_string,
|
||||
ETH_GSTRING_LEN);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
sprintf(p, "tx_queue_%u_packets", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
sprintf(p, "tx_queue_%u_bytes", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
sprintf(p, "tx_queue_%u_restart", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
for (i = 0; i < adapter->num_rx_queues; i++) {
|
||||
sprintf(p, "rx_queue_%u_packets", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
sprintf(p, "rx_queue_%u_bytes", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
sprintf(p, "rx_queue_%u_drops", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
sprintf(p, "rx_queue_%u_csum_err", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
sprintf(p, "rx_queue_%u_alloc_failed", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
/* BUG_ON(p - data != IGC_STATS_LEN * ETH_GSTRING_LEN); */
|
||||
break;
|
||||
case ETH_SS_PRIV_FLAGS:
|
||||
memcpy(data, igc_priv_flags_strings,
|
||||
IGC_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int igc_get_sset_count(struct net_device *netdev, int sset)
|
||||
{
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
return IGC_STATS_LEN;
|
||||
case ETH_SS_TEST:
|
||||
return IGC_TEST_LEN;
|
||||
case ETH_SS_PRIV_FLAGS:
|
||||
return IGC_PRIV_FLAGS_STR_LEN;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void igc_get_ethtool_stats(struct net_device *netdev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
struct igc_adapter *adapter = netdev_priv(netdev);
|
||||
struct rtnl_link_stats64 *net_stats = &adapter->stats64;
|
||||
unsigned int start;
|
||||
struct igc_ring *ring;
|
||||
int i, j;
|
||||
char *p;
|
||||
|
||||
spin_lock(&adapter->stats64_lock);
|
||||
igc_update_stats(adapter);
|
||||
|
||||
for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++) {
|
||||
p = (char *)adapter + igc_gstrings_stats[i].stat_offset;
|
||||
data[i] = (igc_gstrings_stats[i].sizeof_stat ==
|
||||
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
|
||||
}
|
||||
for (j = 0; j < IGC_NETDEV_STATS_LEN; j++, i++) {
|
||||
p = (char *)net_stats + igc_gstrings_net_stats[j].stat_offset;
|
||||
data[i] = (igc_gstrings_net_stats[j].sizeof_stat ==
|
||||
sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
|
||||
}
|
||||
for (j = 0; j < adapter->num_tx_queues; j++) {
|
||||
u64 restart2;
|
||||
|
||||
ring = adapter->tx_ring[j];
|
||||
do {
|
||||
start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
|
||||
data[i] = ring->tx_stats.packets;
|
||||
data[i + 1] = ring->tx_stats.bytes;
|
||||
data[i + 2] = ring->tx_stats.restart_queue;
|
||||
} while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
|
||||
do {
|
||||
start = u64_stats_fetch_begin_irq(&ring->tx_syncp2);
|
||||
restart2 = ring->tx_stats.restart_queue2;
|
||||
} while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start));
|
||||
data[i + 2] += restart2;
|
||||
|
||||
i += IGC_TX_QUEUE_STATS_LEN;
|
||||
}
|
||||
for (j = 0; j < adapter->num_rx_queues; j++) {
|
||||
ring = adapter->rx_ring[j];
|
||||
do {
|
||||
start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
|
||||
data[i] = ring->rx_stats.packets;
|
||||
data[i + 1] = ring->rx_stats.bytes;
|
||||
data[i + 2] = ring->rx_stats.drops;
|
||||
data[i + 3] = ring->rx_stats.csum_err;
|
||||
data[i + 4] = ring->rx_stats.alloc_failed;
|
||||
} while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
|
||||
i += IGC_RX_QUEUE_STATS_LEN;
|
||||
}
|
||||
spin_unlock(&adapter->stats64_lock);
|
||||
}
|
||||
|
||||
static int igc_get_coalesce(struct net_device *netdev,
|
||||
struct ethtool_coalesce *ec)
|
||||
{
|
||||
@ -643,6 +874,605 @@ static int igc_set_coalesce(struct net_device *netdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
|
||||
static int igc_get_ethtool_nfc_entry(struct igc_adapter *adapter,
|
||||
struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct ethtool_rx_flow_spec *fsp = &cmd->fs;
|
||||
struct igc_nfc_filter *rule = NULL;
|
||||
|
||||
/* report total rule count */
|
||||
cmd->data = IGC_MAX_RXNFC_FILTERS;
|
||||
|
||||
hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
|
||||
if (fsp->location <= rule->sw_idx)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rule || fsp->location != rule->sw_idx)
|
||||
return -EINVAL;
|
||||
|
||||
if (rule->filter.match_flags) {
|
||||
fsp->flow_type = ETHER_FLOW;
|
||||
fsp->ring_cookie = rule->action;
|
||||
if (rule->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
|
||||
fsp->h_u.ether_spec.h_proto = rule->filter.etype;
|
||||
fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK;
|
||||
}
|
||||
if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
|
||||
fsp->flow_type |= FLOW_EXT;
|
||||
fsp->h_ext.vlan_tci = rule->filter.vlan_tci;
|
||||
fsp->m_ext.vlan_tci = htons(VLAN_PRIO_MASK);
|
||||
}
|
||||
if (rule->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
|
||||
ether_addr_copy(fsp->h_u.ether_spec.h_dest,
|
||||
rule->filter.dst_addr);
|
||||
/* As we only support matching by the full
|
||||
* mask, return the mask to userspace
|
||||
*/
|
||||
eth_broadcast_addr(fsp->m_u.ether_spec.h_dest);
|
||||
}
|
||||
if (rule->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
|
||||
ether_addr_copy(fsp->h_u.ether_spec.h_source,
|
||||
rule->filter.src_addr);
|
||||
/* As we only support matching by the full
|
||||
* mask, return the mask to userspace
|
||||
*/
|
||||
eth_broadcast_addr(fsp->m_u.ether_spec.h_source);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int igc_get_ethtool_nfc_all(struct igc_adapter *adapter,
|
||||
struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs)
|
||||
{
|
||||
struct igc_nfc_filter *rule;
|
||||
int cnt = 0;
|
||||
|
||||
/* report total rule count */
|
||||
cmd->data = IGC_MAX_RXNFC_FILTERS;
|
||||
|
||||
hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
|
||||
if (cnt == cmd->rule_cnt)
|
||||
return -EMSGSIZE;
|
||||
rule_locs[cnt] = rule->sw_idx;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
cmd->rule_cnt = cnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_get_rss_hash_opts(struct igc_adapter *adapter,
|
||||
struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
cmd->data = 0;
|
||||
|
||||
/* Report default options for RSS on igc */
|
||||
switch (cmd->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
/* Fall through */
|
||||
case UDP_V4_FLOW:
|
||||
if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV4_UDP)
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
/* Fall through */
|
||||
case SCTP_V4_FLOW:
|
||||
/* Fall through */
|
||||
case AH_ESP_V4_FLOW:
|
||||
/* Fall through */
|
||||
case AH_V4_FLOW:
|
||||
/* Fall through */
|
||||
case ESP_V4_FLOW:
|
||||
/* Fall through */
|
||||
case IPV4_FLOW:
|
||||
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
break;
|
||||
case TCP_V6_FLOW:
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
/* Fall through */
|
||||
case UDP_V6_FLOW:
|
||||
if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV6_UDP)
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
/* Fall through */
|
||||
case SCTP_V6_FLOW:
|
||||
/* Fall through */
|
||||
case AH_ESP_V6_FLOW:
|
||||
/* Fall through */
|
||||
case AH_V6_FLOW:
|
||||
/* Fall through */
|
||||
case ESP_V6_FLOW:
|
||||
/* Fall through */
|
||||
case IPV6_FLOW:
|
||||
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs)
|
||||
{
|
||||
struct igc_adapter *adapter = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_GRXRINGS:
|
||||
cmd->data = adapter->num_rx_queues;
|
||||
ret = 0;
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRLCNT:
|
||||
cmd->rule_cnt = adapter->nfc_filter_count;
|
||||
ret = 0;
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRULE:
|
||||
ret = igc_get_ethtool_nfc_entry(adapter, cmd);
|
||||
break;
|
||||
case ETHTOOL_GRXCLSRLALL:
|
||||
ret = igc_get_ethtool_nfc_all(adapter, cmd, rule_locs);
|
||||
break;
|
||||
case ETHTOOL_GRXFH:
|
||||
ret = igc_get_rss_hash_opts(adapter, cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define UDP_RSS_FLAGS (IGC_FLAG_RSS_FIELD_IPV4_UDP | \
|
||||
IGC_FLAG_RSS_FIELD_IPV6_UDP)
|
||||
static int igc_set_rss_hash_opt(struct igc_adapter *adapter,
|
||||
struct ethtool_rxnfc *nfc)
|
||||
{
|
||||
u32 flags = adapter->flags;
|
||||
|
||||
/* RSS does not support anything other than hashing
|
||||
* to queues on src and dst IPs and ports
|
||||
*/
|
||||
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
|
||||
RXH_L4_B_0_1 | RXH_L4_B_2_3))
|
||||
return -EINVAL;
|
||||
|
||||
switch (nfc->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
case TCP_V6_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST) ||
|
||||
!(nfc->data & RXH_L4_B_0_1) ||
|
||||
!(nfc->data & RXH_L4_B_2_3))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case UDP_V4_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST))
|
||||
return -EINVAL;
|
||||
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
|
||||
case 0:
|
||||
flags &= ~IGC_FLAG_RSS_FIELD_IPV4_UDP;
|
||||
break;
|
||||
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
|
||||
flags |= IGC_FLAG_RSS_FIELD_IPV4_UDP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case UDP_V6_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST))
|
||||
return -EINVAL;
|
||||
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
|
||||
case 0:
|
||||
flags &= ~IGC_FLAG_RSS_FIELD_IPV6_UDP;
|
||||
break;
|
||||
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
|
||||
flags |= IGC_FLAG_RSS_FIELD_IPV6_UDP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case AH_ESP_V4_FLOW:
|
||||
case AH_V4_FLOW:
|
||||
case ESP_V4_FLOW:
|
||||
case SCTP_V4_FLOW:
|
||||
case AH_ESP_V6_FLOW:
|
||||
case AH_V6_FLOW:
|
||||
case ESP_V6_FLOW:
|
||||
case SCTP_V6_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST) ||
|
||||
(nfc->data & RXH_L4_B_0_1) ||
|
||||
(nfc->data & RXH_L4_B_2_3))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* if we changed something we need to update flags */
|
||||
if (flags != adapter->flags) {
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 mrqc = rd32(IGC_MRQC);
|
||||
|
||||
if ((flags & UDP_RSS_FLAGS) &&
|
||||
!(adapter->flags & UDP_RSS_FLAGS))
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");
|
||||
|
||||
adapter->flags = flags;
|
||||
|
||||
/* Perform hash on these packet types */
|
||||
mrqc |= IGC_MRQC_RSS_FIELD_IPV4 |
|
||||
IGC_MRQC_RSS_FIELD_IPV4_TCP |
|
||||
IGC_MRQC_RSS_FIELD_IPV6 |
|
||||
IGC_MRQC_RSS_FIELD_IPV6_TCP;
|
||||
|
||||
mrqc &= ~(IGC_MRQC_RSS_FIELD_IPV4_UDP |
|
||||
IGC_MRQC_RSS_FIELD_IPV6_UDP);
|
||||
|
||||
if (flags & IGC_FLAG_RSS_FIELD_IPV4_UDP)
|
||||
mrqc |= IGC_MRQC_RSS_FIELD_IPV4_UDP;
|
||||
|
||||
if (flags & IGC_FLAG_RSS_FIELD_IPV6_UDP)
|
||||
mrqc |= IGC_MRQC_RSS_FIELD_IPV6_UDP;
|
||||
|
||||
wr32(IGC_MRQC, mrqc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_rxnfc_write_etype_filter(struct igc_adapter *adapter,
|
||||
struct igc_nfc_filter *input)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u8 i;
|
||||
u32 etqf;
|
||||
u16 etype;
|
||||
|
||||
/* find an empty etype filter register */
|
||||
for (i = 0; i < MAX_ETYPE_FILTER; ++i) {
|
||||
if (!adapter->etype_bitmap[i])
|
||||
break;
|
||||
}
|
||||
if (i == MAX_ETYPE_FILTER) {
|
||||
dev_err(&adapter->pdev->dev, "ethtool -N: etype filters are all used.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
adapter->etype_bitmap[i] = true;
|
||||
|
||||
etqf = rd32(IGC_ETQF(i));
|
||||
etype = ntohs(input->filter.etype & ETHER_TYPE_FULL_MASK);
|
||||
|
||||
etqf |= IGC_ETQF_FILTER_ENABLE;
|
||||
etqf &= ~IGC_ETQF_ETYPE_MASK;
|
||||
etqf |= (etype & IGC_ETQF_ETYPE_MASK);
|
||||
|
||||
etqf &= ~IGC_ETQF_QUEUE_MASK;
|
||||
etqf |= ((input->action << IGC_ETQF_QUEUE_SHIFT)
|
||||
& IGC_ETQF_QUEUE_MASK);
|
||||
etqf |= IGC_ETQF_QUEUE_ENABLE;
|
||||
|
||||
wr32(IGC_ETQF(i), etqf);
|
||||
|
||||
input->etype_reg_index = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_rxnfc_write_vlan_prio_filter(struct igc_adapter *adapter,
|
||||
struct igc_nfc_filter *input)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u8 vlan_priority;
|
||||
u16 queue_index;
|
||||
u32 vlapqf;
|
||||
|
||||
vlapqf = rd32(IGC_VLAPQF);
|
||||
vlan_priority = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK)
|
||||
>> VLAN_PRIO_SHIFT;
|
||||
queue_index = (vlapqf >> (vlan_priority * 4)) & IGC_VLAPQF_QUEUE_MASK;
|
||||
|
||||
/* check whether this vlan prio is already set */
|
||||
if (vlapqf & IGC_VLAPQF_P_VALID(vlan_priority) &&
|
||||
queue_index != input->action) {
|
||||
dev_err(&adapter->pdev->dev, "ethtool rxnfc set vlan prio filter failed.\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
vlapqf |= IGC_VLAPQF_P_VALID(vlan_priority);
|
||||
vlapqf |= IGC_VLAPQF_QUEUE_SEL(vlan_priority, input->action);
|
||||
|
||||
wr32(IGC_VLAPQF, vlapqf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int igc_add_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (hw->mac.type == igc_i225 &&
|
||||
!(input->filter.match_flags & ~IGC_FILTER_FLAG_SRC_MAC_ADDR)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"i225 doesn't support flow classification rules specifying only source addresses.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE) {
|
||||
err = igc_rxnfc_write_etype_filter(adapter, input);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR) {
|
||||
err = igc_add_mac_steering_filter(adapter,
|
||||
input->filter.dst_addr,
|
||||
input->action, 0);
|
||||
err = min_t(int, err, 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR) {
|
||||
err = igc_add_mac_steering_filter(adapter,
|
||||
input->filter.src_addr,
|
||||
input->action,
|
||||
IGC_MAC_STATE_SRC_ADDR);
|
||||
err = min_t(int, err, 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI)
|
||||
err = igc_rxnfc_write_vlan_prio_filter(adapter, input);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void igc_clear_etype_filter_regs(struct igc_adapter *adapter,
|
||||
u16 reg_index)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 etqf = rd32(IGC_ETQF(reg_index));
|
||||
|
||||
etqf &= ~IGC_ETQF_QUEUE_ENABLE;
|
||||
etqf &= ~IGC_ETQF_QUEUE_MASK;
|
||||
etqf &= ~IGC_ETQF_FILTER_ENABLE;
|
||||
|
||||
wr32(IGC_ETQF(reg_index), etqf);
|
||||
|
||||
adapter->etype_bitmap[reg_index] = false;
|
||||
}
|
||||
|
||||
static void igc_clear_vlan_prio_filter(struct igc_adapter *adapter,
|
||||
u16 vlan_tci)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u8 vlan_priority;
|
||||
u32 vlapqf;
|
||||
|
||||
vlan_priority = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
|
||||
|
||||
vlapqf = rd32(IGC_VLAPQF);
|
||||
vlapqf &= ~IGC_VLAPQF_P_VALID(vlan_priority);
|
||||
vlapqf &= ~IGC_VLAPQF_QUEUE_SEL(vlan_priority,
|
||||
IGC_VLAPQF_QUEUE_MASK);
|
||||
|
||||
wr32(IGC_VLAPQF, vlapqf);
|
||||
}
|
||||
|
||||
int igc_erase_filter(struct igc_adapter *adapter, struct igc_nfc_filter *input)
|
||||
{
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_ETHER_TYPE)
|
||||
igc_clear_etype_filter_regs(adapter,
|
||||
input->etype_reg_index);
|
||||
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI)
|
||||
igc_clear_vlan_prio_filter(adapter,
|
||||
ntohs(input->filter.vlan_tci));
|
||||
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_SRC_MAC_ADDR)
|
||||
igc_del_mac_steering_filter(adapter, input->filter.src_addr,
|
||||
input->action,
|
||||
IGC_MAC_STATE_SRC_ADDR);
|
||||
|
||||
if (input->filter.match_flags & IGC_FILTER_FLAG_DST_MAC_ADDR)
|
||||
igc_del_mac_steering_filter(adapter, input->filter.dst_addr,
|
||||
input->action, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_update_ethtool_nfc_entry(struct igc_adapter *adapter,
|
||||
struct igc_nfc_filter *input,
|
||||
u16 sw_idx)
|
||||
{
|
||||
struct igc_nfc_filter *rule, *parent;
|
||||
int err = -EINVAL;
|
||||
|
||||
parent = NULL;
|
||||
rule = NULL;
|
||||
|
||||
hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
|
||||
/* hash found, or no matching entry */
|
||||
if (rule->sw_idx >= sw_idx)
|
||||
break;
|
||||
parent = rule;
|
||||
}
|
||||
|
||||
/* if there is an old rule occupying our place remove it */
|
||||
if (rule && rule->sw_idx == sw_idx) {
|
||||
if (!input)
|
||||
err = igc_erase_filter(adapter, rule);
|
||||
|
||||
hlist_del(&rule->nfc_node);
|
||||
kfree(rule);
|
||||
adapter->nfc_filter_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;
|
||||
|
||||
/* 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_filter_list);
|
||||
|
||||
/* update counts */
|
||||
adapter->nfc_filter_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int igc_add_ethtool_nfc_entry(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_filter *input, *rule;
|
||||
int err = 0;
|
||||
|
||||
if (!(netdev->hw_features & NETIF_F_NTUPLE))
|
||||
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) {
|
||||
dev_err(&adapter->pdev->dev, "ethtool -N: The specified action is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Don't allow indexes to exist outside of available space */
|
||||
if (fsp->location >= IGC_MAX_RXNFC_FILTERS) {
|
||||
dev_err(&adapter->pdev->dev, "Location out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((fsp->flow_type & ~FLOW_EXT) != ETHER_FLOW)
|
||||
return -EINVAL;
|
||||
|
||||
input = kzalloc(sizeof(*input), GFP_KERNEL);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
if (fsp->m_u.ether_spec.h_proto == ETHER_TYPE_FULL_MASK) {
|
||||
input->filter.etype = fsp->h_u.ether_spec.h_proto;
|
||||
input->filter.match_flags = IGC_FILTER_FLAG_ETHER_TYPE;
|
||||
}
|
||||
|
||||
/* Only support matching addresses by the full mask */
|
||||
if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_source)) {
|
||||
input->filter.match_flags |= IGC_FILTER_FLAG_SRC_MAC_ADDR;
|
||||
ether_addr_copy(input->filter.src_addr,
|
||||
fsp->h_u.ether_spec.h_source);
|
||||
}
|
||||
|
||||
/* Only support matching addresses by the full mask */
|
||||
if (is_broadcast_ether_addr(fsp->m_u.ether_spec.h_dest)) {
|
||||
input->filter.match_flags |= IGC_FILTER_FLAG_DST_MAC_ADDR;
|
||||
ether_addr_copy(input->filter.dst_addr,
|
||||
fsp->h_u.ether_spec.h_dest);
|
||||
}
|
||||
|
||||
if ((fsp->flow_type & FLOW_EXT) && fsp->m_ext.vlan_tci) {
|
||||
if (fsp->m_ext.vlan_tci != htons(VLAN_PRIO_MASK)) {
|
||||
err = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
input->filter.vlan_tci = fsp->h_ext.vlan_tci;
|
||||
input->filter.match_flags |= IGC_FILTER_FLAG_VLAN_TCI;
|
||||
}
|
||||
|
||||
input->action = fsp->ring_cookie;
|
||||
input->sw_idx = fsp->location;
|
||||
|
||||
spin_lock(&adapter->nfc_lock);
|
||||
|
||||
hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node) {
|
||||
if (!memcmp(&input->filter, &rule->filter,
|
||||
sizeof(input->filter))) {
|
||||
err = -EEXIST;
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"ethtool: this filter is already set\n");
|
||||
goto err_out_w_lock;
|
||||
}
|
||||
}
|
||||
|
||||
err = igc_add_filter(adapter, input);
|
||||
if (err)
|
||||
goto err_out_w_lock;
|
||||
|
||||
igc_update_ethtool_nfc_entry(adapter, input, input->sw_idx);
|
||||
|
||||
spin_unlock(&adapter->nfc_lock);
|
||||
return 0;
|
||||
|
||||
err_out_w_lock:
|
||||
spin_unlock(&adapter->nfc_lock);
|
||||
err_out:
|
||||
kfree(input);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int igc_del_ethtool_nfc_entry(struct igc_adapter *adapter,
|
||||
struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct ethtool_rx_flow_spec *fsp =
|
||||
(struct ethtool_rx_flow_spec *)&cmd->fs;
|
||||
int err;
|
||||
|
||||
spin_lock(&adapter->nfc_lock);
|
||||
err = igc_update_ethtool_nfc_entry(adapter, NULL, fsp->location);
|
||||
spin_unlock(&adapter->nfc_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int igc_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct igc_adapter *adapter = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_SRXFH:
|
||||
ret = igc_set_rss_hash_opt(adapter, cmd);
|
||||
break;
|
||||
case ETHTOOL_SRXCLSRLINS:
|
||||
ret = igc_add_ethtool_nfc_entry(adapter, cmd);
|
||||
break;
|
||||
case ETHTOOL_SRXCLSRLDEL:
|
||||
ret = igc_del_ethtool_nfc_entry(adapter, cmd);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
@ -885,17 +1715,13 @@ static int igc_get_link_ksettings(struct net_device *netdev,
|
||||
if (hw->mac.type == igc_i225 &&
|
||||
(status & IGC_STATUS_SPEED_2500)) {
|
||||
speed = SPEED_2500;
|
||||
hw_dbg("2500 Mbs, ");
|
||||
} else {
|
||||
speed = SPEED_1000;
|
||||
hw_dbg("1000 Mbs, ");
|
||||
}
|
||||
} else if (status & IGC_STATUS_SPEED_100) {
|
||||
speed = SPEED_100;
|
||||
hw_dbg("100 Mbs, ");
|
||||
} else {
|
||||
speed = SPEED_10;
|
||||
hw_dbg("10 Mbs, ");
|
||||
}
|
||||
if ((status & IGC_STATUS_FD) ||
|
||||
hw->phy.media_type != igc_media_type_copper)
|
||||
@ -1011,8 +1837,13 @@ static const struct ethtool_ops igc_ethtool_ops = {
|
||||
.set_ringparam = igc_set_ringparam,
|
||||
.get_pauseparam = igc_get_pauseparam,
|
||||
.set_pauseparam = igc_set_pauseparam,
|
||||
.get_strings = igc_get_strings,
|
||||
.get_sset_count = igc_get_sset_count,
|
||||
.get_ethtool_stats = igc_get_ethtool_stats,
|
||||
.get_coalesce = igc_get_coalesce,
|
||||
.set_coalesce = igc_set_coalesce,
|
||||
.get_rxnfc = igc_get_rxnfc,
|
||||
.set_rxnfc = igc_set_rxnfc,
|
||||
.get_rxfh_indir_size = igc_get_rxfh_indir_size,
|
||||
.get_rxfh = igc_get_rxfh,
|
||||
.set_rxfh = igc_set_rxfh,
|
||||
|
@ -620,6 +620,55 @@ static void igc_configure_tx(struct igc_adapter *adapter)
|
||||
*/
|
||||
static void igc_setup_mrqc(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u32 j, num_rx_queues;
|
||||
u32 mrqc, rxcsum;
|
||||
u32 rss_key[10];
|
||||
|
||||
netdev_rss_key_fill(rss_key, sizeof(rss_key));
|
||||
for (j = 0; j < 10; j++)
|
||||
wr32(IGC_RSSRK(j), rss_key[j]);
|
||||
|
||||
num_rx_queues = adapter->rss_queues;
|
||||
|
||||
if (adapter->rss_indir_tbl_init != num_rx_queues) {
|
||||
for (j = 0; j < IGC_RETA_SIZE; j++)
|
||||
adapter->rss_indir_tbl[j] =
|
||||
(j * num_rx_queues) / IGC_RETA_SIZE;
|
||||
adapter->rss_indir_tbl_init = num_rx_queues;
|
||||
}
|
||||
igc_write_rss_indir_tbl(adapter);
|
||||
|
||||
/* Disable raw packet checksumming so that RSS hash is placed in
|
||||
* descriptor on writeback. No need to enable TCP/UDP/IP checksum
|
||||
* offloads as they are enabled by default
|
||||
*/
|
||||
rxcsum = rd32(IGC_RXCSUM);
|
||||
rxcsum |= IGC_RXCSUM_PCSD;
|
||||
|
||||
/* Enable Receive Checksum Offload for SCTP */
|
||||
rxcsum |= IGC_RXCSUM_CRCOFL;
|
||||
|
||||
/* Don't need to set TUOFL or IPOFL, they default to 1 */
|
||||
wr32(IGC_RXCSUM, rxcsum);
|
||||
|
||||
/* Generate RSS hash based on packet types, TCP/UDP
|
||||
* port numbers and/or IPv4/v6 src and dst addresses
|
||||
*/
|
||||
mrqc = IGC_MRQC_RSS_FIELD_IPV4 |
|
||||
IGC_MRQC_RSS_FIELD_IPV4_TCP |
|
||||
IGC_MRQC_RSS_FIELD_IPV6 |
|
||||
IGC_MRQC_RSS_FIELD_IPV6_TCP |
|
||||
IGC_MRQC_RSS_FIELD_IPV6_TCP_EX;
|
||||
|
||||
if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV4_UDP)
|
||||
mrqc |= IGC_MRQC_RSS_FIELD_IPV4_UDP;
|
||||
if (adapter->flags & IGC_FLAG_RSS_FIELD_IPV6_UDP)
|
||||
mrqc |= IGC_MRQC_RSS_FIELD_IPV6_UDP;
|
||||
|
||||
mrqc |= IGC_MRQC_ENABLE_RSS_MQ;
|
||||
|
||||
wr32(IGC_MRQC, mrqc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1738,12 +1787,200 @@ void igc_up(struct igc_adapter *adapter)
|
||||
* igc_update_stats - Update the board statistics counters
|
||||
* @adapter: board private structure
|
||||
*/
|
||||
static void igc_update_stats(struct igc_adapter *adapter)
|
||||
void igc_update_stats(struct igc_adapter *adapter)
|
||||
{
|
||||
struct rtnl_link_stats64 *net_stats = &adapter->stats64;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
u64 _bytes, _packets;
|
||||
u64 bytes, packets;
|
||||
unsigned int start;
|
||||
u32 mpc;
|
||||
int i;
|
||||
|
||||
/* Prevent stats update while adapter is being reset, or if the pci
|
||||
* connection is down.
|
||||
*/
|
||||
if (adapter->link_speed == 0)
|
||||
return;
|
||||
if (pci_channel_offline(pdev))
|
||||
return;
|
||||
|
||||
packets = 0;
|
||||
bytes = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < adapter->num_rx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->rx_ring[i];
|
||||
u32 rqdpc = rd32(IGC_RQDPC(i));
|
||||
|
||||
if (hw->mac.type >= igc_i225)
|
||||
wr32(IGC_RQDPC(i), 0);
|
||||
|
||||
if (rqdpc) {
|
||||
ring->rx_stats.drops += rqdpc;
|
||||
net_stats->rx_fifo_errors += rqdpc;
|
||||
}
|
||||
|
||||
do {
|
||||
start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
|
||||
_bytes = ring->rx_stats.bytes;
|
||||
_packets = ring->rx_stats.packets;
|
||||
} while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
|
||||
bytes += _bytes;
|
||||
packets += _packets;
|
||||
}
|
||||
|
||||
net_stats->rx_bytes = bytes;
|
||||
net_stats->rx_packets = packets;
|
||||
|
||||
packets = 0;
|
||||
bytes = 0;
|
||||
for (i = 0; i < adapter->num_tx_queues; i++) {
|
||||
struct igc_ring *ring = adapter->tx_ring[i];
|
||||
|
||||
do {
|
||||
start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
|
||||
_bytes = ring->tx_stats.bytes;
|
||||
_packets = ring->tx_stats.packets;
|
||||
} while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
|
||||
bytes += _bytes;
|
||||
packets += _packets;
|
||||
}
|
||||
net_stats->tx_bytes = bytes;
|
||||
net_stats->tx_packets = packets;
|
||||
rcu_read_unlock();
|
||||
|
||||
/* read stats registers */
|
||||
adapter->stats.crcerrs += rd32(IGC_CRCERRS);
|
||||
adapter->stats.gprc += rd32(IGC_GPRC);
|
||||
adapter->stats.gorc += rd32(IGC_GORCL);
|
||||
rd32(IGC_GORCH); /* clear GORCL */
|
||||
adapter->stats.bprc += rd32(IGC_BPRC);
|
||||
adapter->stats.mprc += rd32(IGC_MPRC);
|
||||
adapter->stats.roc += rd32(IGC_ROC);
|
||||
|
||||
adapter->stats.prc64 += rd32(IGC_PRC64);
|
||||
adapter->stats.prc127 += rd32(IGC_PRC127);
|
||||
adapter->stats.prc255 += rd32(IGC_PRC255);
|
||||
adapter->stats.prc511 += rd32(IGC_PRC511);
|
||||
adapter->stats.prc1023 += rd32(IGC_PRC1023);
|
||||
adapter->stats.prc1522 += rd32(IGC_PRC1522);
|
||||
adapter->stats.symerrs += rd32(IGC_SYMERRS);
|
||||
adapter->stats.sec += rd32(IGC_SEC);
|
||||
|
||||
mpc = rd32(IGC_MPC);
|
||||
adapter->stats.mpc += mpc;
|
||||
net_stats->rx_fifo_errors += mpc;
|
||||
adapter->stats.scc += rd32(IGC_SCC);
|
||||
adapter->stats.ecol += rd32(IGC_ECOL);
|
||||
adapter->stats.mcc += rd32(IGC_MCC);
|
||||
adapter->stats.latecol += rd32(IGC_LATECOL);
|
||||
adapter->stats.dc += rd32(IGC_DC);
|
||||
adapter->stats.rlec += rd32(IGC_RLEC);
|
||||
adapter->stats.xonrxc += rd32(IGC_XONRXC);
|
||||
adapter->stats.xontxc += rd32(IGC_XONTXC);
|
||||
adapter->stats.xoffrxc += rd32(IGC_XOFFRXC);
|
||||
adapter->stats.xofftxc += rd32(IGC_XOFFTXC);
|
||||
adapter->stats.fcruc += rd32(IGC_FCRUC);
|
||||
adapter->stats.gptc += rd32(IGC_GPTC);
|
||||
adapter->stats.gotc += rd32(IGC_GOTCL);
|
||||
rd32(IGC_GOTCH); /* clear GOTCL */
|
||||
adapter->stats.rnbc += rd32(IGC_RNBC);
|
||||
adapter->stats.ruc += rd32(IGC_RUC);
|
||||
adapter->stats.rfc += rd32(IGC_RFC);
|
||||
adapter->stats.rjc += rd32(IGC_RJC);
|
||||
adapter->stats.tor += rd32(IGC_TORH);
|
||||
adapter->stats.tot += rd32(IGC_TOTH);
|
||||
adapter->stats.tpr += rd32(IGC_TPR);
|
||||
|
||||
adapter->stats.ptc64 += rd32(IGC_PTC64);
|
||||
adapter->stats.ptc127 += rd32(IGC_PTC127);
|
||||
adapter->stats.ptc255 += rd32(IGC_PTC255);
|
||||
adapter->stats.ptc511 += rd32(IGC_PTC511);
|
||||
adapter->stats.ptc1023 += rd32(IGC_PTC1023);
|
||||
adapter->stats.ptc1522 += rd32(IGC_PTC1522);
|
||||
|
||||
adapter->stats.mptc += rd32(IGC_MPTC);
|
||||
adapter->stats.bptc += rd32(IGC_BPTC);
|
||||
|
||||
adapter->stats.tpt += rd32(IGC_TPT);
|
||||
adapter->stats.colc += rd32(IGC_COLC);
|
||||
|
||||
adapter->stats.algnerrc += rd32(IGC_ALGNERRC);
|
||||
|
||||
adapter->stats.tsctc += rd32(IGC_TSCTC);
|
||||
adapter->stats.tsctfc += rd32(IGC_TSCTFC);
|
||||
|
||||
adapter->stats.iac += rd32(IGC_IAC);
|
||||
adapter->stats.icrxoc += rd32(IGC_ICRXOC);
|
||||
adapter->stats.icrxptc += rd32(IGC_ICRXPTC);
|
||||
adapter->stats.icrxatc += rd32(IGC_ICRXATC);
|
||||
adapter->stats.ictxptc += rd32(IGC_ICTXPTC);
|
||||
adapter->stats.ictxatc += rd32(IGC_ICTXATC);
|
||||
adapter->stats.ictxqec += rd32(IGC_ICTXQEC);
|
||||
adapter->stats.ictxqmtc += rd32(IGC_ICTXQMTC);
|
||||
adapter->stats.icrxdmtc += rd32(IGC_ICRXDMTC);
|
||||
|
||||
/* Fill out the OS statistics structure */
|
||||
net_stats->multicast = adapter->stats.mprc;
|
||||
net_stats->collisions = adapter->stats.colc;
|
||||
|
||||
/* Rx Errors */
|
||||
|
||||
/* RLEC on some newer hardware can be incorrect so build
|
||||
* our own version based on RUC and ROC
|
||||
*/
|
||||
net_stats->rx_errors = adapter->stats.rxerrc +
|
||||
adapter->stats.crcerrs + adapter->stats.algnerrc +
|
||||
adapter->stats.ruc + adapter->stats.roc +
|
||||
adapter->stats.cexterr;
|
||||
net_stats->rx_length_errors = adapter->stats.ruc +
|
||||
adapter->stats.roc;
|
||||
net_stats->rx_crc_errors = adapter->stats.crcerrs;
|
||||
net_stats->rx_frame_errors = adapter->stats.algnerrc;
|
||||
net_stats->rx_missed_errors = adapter->stats.mpc;
|
||||
|
||||
/* Tx Errors */
|
||||
net_stats->tx_errors = adapter->stats.ecol +
|
||||
adapter->stats.latecol;
|
||||
net_stats->tx_aborted_errors = adapter->stats.ecol;
|
||||
net_stats->tx_window_errors = adapter->stats.latecol;
|
||||
net_stats->tx_carrier_errors = adapter->stats.tncrs;
|
||||
|
||||
/* Tx Dropped needs to be maintained elsewhere */
|
||||
|
||||
/* Management Stats */
|
||||
adapter->stats.mgptc += rd32(IGC_MGTPTC);
|
||||
adapter->stats.mgprc += rd32(IGC_MGTPRC);
|
||||
adapter->stats.mgpdc += rd32(IGC_MGTPDC);
|
||||
}
|
||||
|
||||
static void igc_nfc_filter_exit(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_nfc_filter *rule;
|
||||
|
||||
spin_lock(&adapter->nfc_lock);
|
||||
|
||||
hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node)
|
||||
igc_erase_filter(adapter, rule);
|
||||
|
||||
hlist_for_each_entry(rule, &adapter->cls_flower_list, nfc_node)
|
||||
igc_erase_filter(adapter, rule);
|
||||
|
||||
spin_unlock(&adapter->nfc_lock);
|
||||
}
|
||||
|
||||
static void igc_nfc_filter_restore(struct igc_adapter *adapter)
|
||||
{
|
||||
struct igc_nfc_filter *rule;
|
||||
|
||||
spin_lock(&adapter->nfc_lock);
|
||||
|
||||
hlist_for_each_entry(rule, &adapter->nfc_filter_list, nfc_node)
|
||||
igc_add_filter(adapter, rule);
|
||||
|
||||
spin_unlock(&adapter->nfc_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1890,6 +2127,86 @@ static struct net_device_stats *igc_get_stats(struct net_device *netdev)
|
||||
return &netdev->stats;
|
||||
}
|
||||
|
||||
static netdev_features_t igc_fix_features(struct net_device *netdev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
/* Since there is no support for separate Rx/Tx vlan accel
|
||||
* enable/disable make sure Tx flag is always in same state as Rx.
|
||||
*/
|
||||
if (features & NETIF_F_HW_VLAN_CTAG_RX)
|
||||
features |= NETIF_F_HW_VLAN_CTAG_TX;
|
||||
else
|
||||
features &= ~NETIF_F_HW_VLAN_CTAG_TX;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
static int igc_set_features(struct net_device *netdev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
netdev_features_t changed = netdev->features ^ features;
|
||||
struct igc_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
/* Add VLAN support */
|
||||
if (!(changed & (NETIF_F_RXALL | NETIF_F_NTUPLE)))
|
||||
return 0;
|
||||
|
||||
if (!(features & NETIF_F_NTUPLE)) {
|
||||
struct hlist_node *node2;
|
||||
struct igc_nfc_filter *rule;
|
||||
|
||||
spin_lock(&adapter->nfc_lock);
|
||||
hlist_for_each_entry_safe(rule, node2,
|
||||
&adapter->nfc_filter_list, nfc_node) {
|
||||
igc_erase_filter(adapter, rule);
|
||||
hlist_del(&rule->nfc_node);
|
||||
kfree(rule);
|
||||
}
|
||||
spin_unlock(&adapter->nfc_lock);
|
||||
adapter->nfc_filter_count = 0;
|
||||
}
|
||||
|
||||
netdev->features = features;
|
||||
|
||||
if (netif_running(netdev))
|
||||
igc_reinit_locked(adapter);
|
||||
else
|
||||
igc_reset(adapter);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static netdev_features_t
|
||||
igc_features_check(struct sk_buff *skb, struct net_device *dev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
unsigned int network_hdr_len, mac_hdr_len;
|
||||
|
||||
/* Make certain the headers can be described by a context descriptor */
|
||||
mac_hdr_len = skb_network_header(skb) - skb->data;
|
||||
if (unlikely(mac_hdr_len > IGC_MAX_MAC_HDR_LEN))
|
||||
return features & ~(NETIF_F_HW_CSUM |
|
||||
NETIF_F_SCTP_CRC |
|
||||
NETIF_F_HW_VLAN_CTAG_TX |
|
||||
NETIF_F_TSO |
|
||||
NETIF_F_TSO6);
|
||||
|
||||
network_hdr_len = skb_checksum_start(skb) - skb_network_header(skb);
|
||||
if (unlikely(network_hdr_len > IGC_MAX_NETWORK_HDR_LEN))
|
||||
return features & ~(NETIF_F_HW_CSUM |
|
||||
NETIF_F_SCTP_CRC |
|
||||
NETIF_F_TSO |
|
||||
NETIF_F_TSO6);
|
||||
|
||||
/* We can only support IPv4 TSO in tunnels if we can mangle the
|
||||
* inner IP ID field, so strip TSO if MANGLEID is not supported.
|
||||
*/
|
||||
if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID))
|
||||
features &= ~NETIF_F_TSO;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_configure - configure the hardware for RX and TX
|
||||
* @adapter: private board structure
|
||||
@ -1906,6 +2223,7 @@ static void igc_configure(struct igc_adapter *adapter)
|
||||
igc_setup_mrqc(adapter);
|
||||
igc_setup_rctl(adapter);
|
||||
|
||||
igc_nfc_filter_restore(adapter);
|
||||
igc_configure_tx(adapter);
|
||||
igc_configure_rx(adapter);
|
||||
|
||||
@ -1967,6 +2285,127 @@ static void igc_set_default_mac_filter(struct igc_adapter *adapter)
|
||||
igc_rar_set_index(adapter, 0);
|
||||
}
|
||||
|
||||
/* If the filter to be added and an already existing filter express
|
||||
* the same address and address type, it should be possible to only
|
||||
* override the other configurations, for example the queue to steer
|
||||
* traffic.
|
||||
*/
|
||||
static bool igc_mac_entry_can_be_used(const struct igc_mac_addr *entry,
|
||||
const u8 *addr, const u8 flags)
|
||||
{
|
||||
if (!(entry->state & IGC_MAC_STATE_IN_USE))
|
||||
return true;
|
||||
|
||||
if ((entry->state & IGC_MAC_STATE_SRC_ADDR) !=
|
||||
(flags & IGC_MAC_STATE_SRC_ADDR))
|
||||
return false;
|
||||
|
||||
if (!ether_addr_equal(addr, entry->addr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Add a MAC filter for 'addr' directing matching traffic to 'queue',
|
||||
* 'flags' is used to indicate what kind of match is made, match is by
|
||||
* default for the destination address, if matching by source address
|
||||
* is desired the flag IGC_MAC_STATE_SRC_ADDR can be used.
|
||||
*/
|
||||
static int igc_add_mac_filter_flags(struct igc_adapter *adapter,
|
||||
const u8 *addr, const u8 queue,
|
||||
const u8 flags)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
int rar_entries = hw->mac.rar_entry_count;
|
||||
int i;
|
||||
|
||||
if (is_zero_ether_addr(addr))
|
||||
return -EINVAL;
|
||||
|
||||
/* Search for the first empty entry in the MAC table.
|
||||
* Do not touch entries at the end of the table reserved for the VF MAC
|
||||
* addresses.
|
||||
*/
|
||||
for (i = 0; i < rar_entries; i++) {
|
||||
if (!igc_mac_entry_can_be_used(&adapter->mac_table[i],
|
||||
addr, flags))
|
||||
continue;
|
||||
|
||||
ether_addr_copy(adapter->mac_table[i].addr, addr);
|
||||
adapter->mac_table[i].queue = queue;
|
||||
adapter->mac_table[i].state |= IGC_MAC_STATE_IN_USE | flags;
|
||||
|
||||
igc_rar_set_index(adapter, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
int igc_add_mac_steering_filter(struct igc_adapter *adapter,
|
||||
const u8 *addr, u8 queue, u8 flags)
|
||||
{
|
||||
return igc_add_mac_filter_flags(adapter, addr, queue,
|
||||
IGC_MAC_STATE_QUEUE_STEERING | flags);
|
||||
}
|
||||
|
||||
/* Remove a MAC filter for 'addr' directing matching traffic to
|
||||
* 'queue', 'flags' is used to indicate what kind of match need to be
|
||||
* removed, match is by default for the destination address, if
|
||||
* matching by source address is to be removed the flag
|
||||
* IGC_MAC_STATE_SRC_ADDR can be used.
|
||||
*/
|
||||
static int igc_del_mac_filter_flags(struct igc_adapter *adapter,
|
||||
const u8 *addr, const u8 queue,
|
||||
const u8 flags)
|
||||
{
|
||||
struct igc_hw *hw = &adapter->hw;
|
||||
int rar_entries = hw->mac.rar_entry_count;
|
||||
int i;
|
||||
|
||||
if (is_zero_ether_addr(addr))
|
||||
return -EINVAL;
|
||||
|
||||
/* Search for matching entry in the MAC table based on given address
|
||||
* and queue. Do not touch entries at the end of the table reserved
|
||||
* for the VF MAC addresses.
|
||||
*/
|
||||
for (i = 0; i < rar_entries; i++) {
|
||||
if (!(adapter->mac_table[i].state & IGC_MAC_STATE_IN_USE))
|
||||
continue;
|
||||
if ((adapter->mac_table[i].state & flags) != flags)
|
||||
continue;
|
||||
if (adapter->mac_table[i].queue != queue)
|
||||
continue;
|
||||
if (!ether_addr_equal(adapter->mac_table[i].addr, addr))
|
||||
continue;
|
||||
|
||||
/* When a filter for the default address is "deleted",
|
||||
* we return it to its initial configuration
|
||||
*/
|
||||
if (adapter->mac_table[i].state & IGC_MAC_STATE_DEFAULT) {
|
||||
adapter->mac_table[i].state =
|
||||
IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE;
|
||||
} else {
|
||||
adapter->mac_table[i].state = 0;
|
||||
adapter->mac_table[i].queue = 0;
|
||||
memset(adapter->mac_table[i].addr, 0, ETH_ALEN);
|
||||
}
|
||||
|
||||
igc_rar_set_index(adapter, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int igc_del_mac_steering_filter(struct igc_adapter *adapter,
|
||||
const u8 *addr, u8 queue, u8 flags)
|
||||
{
|
||||
return igc_del_mac_filter_flags(adapter, addr, queue,
|
||||
IGC_MAC_STATE_QUEUE_STEERING | flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
|
||||
* @netdev: network interface device structure
|
||||
@ -3434,6 +3873,9 @@ static const struct net_device_ops igc_netdev_ops = {
|
||||
.ndo_set_mac_address = igc_set_mac,
|
||||
.ndo_change_mtu = igc_change_mtu,
|
||||
.ndo_get_stats = igc_get_stats,
|
||||
.ndo_fix_features = igc_fix_features,
|
||||
.ndo_set_features = igc_set_features,
|
||||
.ndo_features_check = igc_features_check,
|
||||
};
|
||||
|
||||
/* PCIe configuration access */
|
||||
@ -3663,6 +4105,9 @@ static int igc_probe(struct pci_dev *pdev,
|
||||
if (err)
|
||||
goto err_sw_init;
|
||||
|
||||
/* copy netdev features into list of user selectable features */
|
||||
netdev->hw_features |= NETIF_F_NTUPLE;
|
||||
|
||||
/* MTU range: 68 - 9216 */
|
||||
netdev->min_mtu = ETH_MIN_MTU;
|
||||
netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE;
|
||||
|
@ -80,8 +80,23 @@
|
||||
/* MSI-X Table Register Descriptions */
|
||||
#define IGC_PBACL 0x05B68 /* MSIx PBA Clear - R/W 1 to clear */
|
||||
|
||||
/* RSS registers */
|
||||
#define IGC_MRQC 0x05818 /* Multiple Receive Control - RW */
|
||||
|
||||
/* Filtering Registers */
|
||||
#define IGC_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
|
||||
|
||||
/* ETQF register bit definitions */
|
||||
#define IGC_ETQF_FILTER_ENABLE BIT(26)
|
||||
#define IGC_ETQF_QUEUE_ENABLE BIT(31)
|
||||
#define IGC_ETQF_QUEUE_SHIFT 16
|
||||
#define IGC_ETQF_QUEUE_MASK 0x00070000
|
||||
#define IGC_ETQF_ETYPE_MASK 0x0000FFFF
|
||||
|
||||
/* Redirection Table - RW Array */
|
||||
#define IGC_RETA(_i) (0x05C00 + ((_i) * 4))
|
||||
/* RSS Random Key - RW Array */
|
||||
#define IGC_RSSRK(_i) (0x05C80 + ((_i) * 4))
|
||||
|
||||
/* Receive Register Descriptions */
|
||||
#define IGC_RCTL 0x00100 /* Rx Control - RW */
|
||||
@ -101,6 +116,7 @@
|
||||
#define IGC_UTA 0x0A000 /* Unicast Table Array - RW */
|
||||
#define IGC_RAL(_n) (0x05400 + ((_n) * 0x08))
|
||||
#define IGC_RAH(_n) (0x05404 + ((_n) * 0x08))
|
||||
#define IGC_VLAPQF 0x055B0 /* VLAN Priority Queue Filter VLAPQF */
|
||||
|
||||
/* Transmit Register Descriptions */
|
||||
#define IGC_TCTL 0x00400 /* Tx Control - RW */
|
||||
|
@ -9796,7 +9796,7 @@ static int ixgbe_set_features(struct net_device *netdev,
|
||||
NETIF_F_HW_VLAN_CTAG_FILTER))
|
||||
ixgbe_set_rx_mode(netdev);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user