Skip to contentSkip to conversation

sfc: VF representors for EF100 - RX side

PATCH Superseded [email protected] 3 participants 19 messages Jul 22, 2022 – Jul 26, 2022

Subsystems (3)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover sfc: VF representors for EF100 - RX side

From: Edward Cree <[email protected]>

This series adds the receive path for EF100 VF representors, plus other
minor features such as statistics and MAC address setting.

Edward Cree (14):
sfc: plumb ef100 representor stats
sfc: ef100 representor RX NAPI poll
sfc: ef100 representor RX top half
sfc: determine wire m-port at EF100 PF probe time
sfc: check ef100 RX packets are from the wire
sfc: receive packets from EF100 VFs into representors
sfc: insert default MAE rules to connect VFs to representors
sfc: move table locking into filter_table_{probe,remove} methods
sfc: use a dynamic m-port for representor RX and set it promisc
sfc: look up VF's client ID when creating representor
sfc: fetch existing assigned MAC address from FW when creating VF rep
sfc: set EF100 VF MAC address through representor
sfc: get provisioned MAC address on EF100 VF probe
sfc: implement ethtool get/set RX ring size for EF100 reps

 drivers/net/ethernet/sfc/Makefile         |   3 +-
 drivers/net/ethernet/sfc/ef10.c           |  26 +-
 drivers/net/ethernet/sfc/ef100.c          |   1 +
 drivers/net/ethernet/sfc/ef100_netdev.c   |  12 +
 drivers/net/ethernet/sfc/ef100_nic.c      | 142 ++++++++--
 drivers/net/ethernet/sfc/ef100_nic.h      |   5 +
 drivers/net/ethernet/sfc/ef100_rep.c      | 250 +++++++++++++++++-
 drivers/net/ethernet/sfc/ef100_rep.h      |  22 ++
 drivers/net/ethernet/sfc/ef100_rx.c       |  45 +++-
 drivers/net/ethernet/sfc/ef10_sriov.c     |  16 +-
 drivers/net/ethernet/sfc/ethtool_common.c |   1 +
 drivers/net/ethernet/sfc/filter.h         |  18 ++
 drivers/net/ethernet/sfc/mae.c            | 304 +++++++++++++++++++++-
 drivers/net/ethernet/sfc/mae.h            |  20 ++
 drivers/net/ethernet/sfc/mcdi.h           |   4 +
 drivers/net/ethernet/sfc/mcdi_filters.c   |   6 +-
 drivers/net/ethernet/sfc/mcdi_filters.h   |   1 +
 drivers/net/ethernet/sfc/mcdi_pcol_mae.h  |  24 ++
 drivers/net/ethernet/sfc/net_driver.h     |   5 +
 drivers/net/ethernet/sfc/rx_common.c      |   4 -
 drivers/net/ethernet/sfc/tc.c             | 252 ++++++++++++++++++
 drivers/net/ethernet/sfc/tc.h             |  85 ++++++
 22 files changed, 1180 insertions(+), 66 deletions(-)
 create mode 100644 drivers/net/ethernet/sfc/mcdi_pcol_mae.h
 create mode 100644 drivers/net/ethernet/sfc/tc.c
 create mode 100644 drivers/net/ethernet/sfc/tc.h
#1 lore raw

PATCH 1/14 sfc: plumb ef100 representor stats

From: Edward Cree <[email protected]>

Implement .ndo_get_stats64() method to read values out of struct
efx_rep_sw_stats.

---
 drivers/net/ethernet/sfc/ef100_rep.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
drivers/net/ethernet/sfc/ef100_rep.c +14 -0
index d07539f091b8..102071ed051b 100644
@@ -79,10 +79,24 @@ static int efx_ef100_rep_get_phys_port_name(struct net_device *dev,
 	return 0;
 }
 
+static void efx_ef100_rep_get_stats64(struct net_device *dev,
+				      struct rtnl_link_stats64 *stats)
+{
+	struct efx_rep *efv = netdev_priv(dev);
+
+	stats->rx_packets = atomic64_read(&efv->stats.rx_packets);
+	stats->tx_packets = atomic64_read(&efv->stats.tx_packets);
+	stats->rx_bytes = atomic64_read(&efv->stats.rx_bytes);
+	stats->tx_bytes = atomic64_read(&efv->stats.tx_bytes);
+	stats->rx_dropped = atomic64_read(&efv->stats.rx_dropped);
+	stats->tx_errors = atomic64_read(&efv->stats.tx_errors);
+}
+
 static const struct net_device_ops efx_ef100_rep_netdev_ops = {
 	.ndo_start_xmit		= efx_ef100_rep_xmit,
 	.ndo_get_port_parent_id	= efx_ef100_rep_get_port_parent_id,
 	.ndo_get_phys_port_name	= efx_ef100_rep_get_phys_port_name,
+	.ndo_get_stats64	= efx_ef100_rep_get_stats64,
 };
 
 static void efx_ef100_rep_get_drvinfo(struct net_device *dev,
#3 lore raw

PATCH 3/14 sfc: ef100 representor RX top half

In reply to [email protected]

From: Edward Cree <[email protected]>

Representor RX uses a NAPI context driven by a 'fake interrupt': when
the parent PF receives a packet destined for the representor, it adds it to an SKB list (efv->rx_list), and schedules NAPI if the 'fake interrupt' is primed. The NAPI poll then pulls packets off this list and feeds them to the stack with netif_receive_skb_list().
This scheme allows us to decouple representor RX from the parent PF's
RX fast-path.
This patch implements the 'top half', which builds an SKB, copies data
into it from the RX buffer (which can then be released), adds it to the queue and fires the 'fake interrupt' if necessary.

---
 drivers/net/ethernet/sfc/ef100_rep.c | 55 ++++++++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_rep.h |  1 +
 2 files changed, 56 insertions(+)
drivers/net/ethernet/sfc/ef100_rep.c +55 -0
index fe45ae963391..e6c6e9e764b2 100644
@@ -13,9 +13,12 @@
 #include "ef100_netdev.h"
 #include "ef100_nic.h"
 #include "mae.h"
+#include "rx_common.h"
 
 #define EFX_EF100_REP_DRIVER	"efx_ef100_rep"
 
+#define EFX_REP_DEFAULT_PSEUDO_RING_SIZE	64
+
 static int efx_ef100_rep_poll(struct napi_struct *napi, int weight);
 
 static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv,
@@ -198,6 +201,7 @@ static int efx_ef100_configure_rep(struct efx_rep *efv)
 	u32 selector;
 	int rc;
 
+	efv->rx_pring_size = EFX_REP_DEFAULT_PSEUDO_RING_SIZE;
 	/* Construct mport selector for corresponding VF */
 	efx_mae_mport_vf(efx, efv->idx, &selector);
 	/* Look up actual mport ID */
@@ -320,3 +324,54 @@ static int efx_ef100_rep_poll(struct napi_struct *napi, int weight)
 		}
 	return spent;
 }
+
+void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf)
+{
+	u8 *eh = efx_rx_buf_va(rx_buf);
+	struct sk_buff *skb;
+	bool primed;
+
+	/* Don't allow too many queued SKBs to build up, as they consume
+	 * GFP_ATOMIC memory.  If we overrun, just start dropping.
+	 */
+	if (efv->write_index - READ_ONCE(efv->read_index) > efv->rx_pring_size) {
+		atomic64_inc(&efv->stats.rx_dropped);
+		if (net_ratelimit())
+			netif_dbg(efv->parent, rx_err, efv->net_dev,
+				  "nodesc-dropped packet of length %u\n",
+				  rx_buf->len);
+		return;
+	}
+
+	skb = netdev_alloc_skb(efv->net_dev, rx_buf->len);
+	if (!skb) {
+		atomic64_inc(&efv->stats.rx_dropped);
+		if (net_ratelimit())
+			netif_dbg(efv->parent, rx_err, efv->net_dev,
+				  "noskb-dropped packet of length %u\n",
+				  rx_buf->len);
+		return;
+	}
+	memcpy(skb->data, eh, rx_buf->len);
+	__skb_put(skb, rx_buf->len);
+
+	skb_record_rx_queue(skb, 0); /* rep is single-queue */
+
+	/* Move past the ethernet header */
+	skb->protocol = eth_type_trans(skb, efv->net_dev);
+
+	skb_checksum_none_assert(skb);
+
+	atomic64_inc(&efv->stats.rx_packets);
+	atomic64_add(rx_buf->len, &efv->stats.rx_bytes);
+
+	/* Add it to the rx list */
+	spin_lock_bh(&efv->rx_lock);
+	primed = efv->read_index == efv->write_index;
+	list_add_tail(&skb->list, &efv->rx_list);
+	efv->write_index++;
+	spin_unlock_bh(&efv->rx_lock);
+	/* Trigger rx work */
+	if (primed)
+		napi_schedule(&efv->napi);
+}
drivers/net/ethernet/sfc/ef100_rep.h +1 -0
index 77037ab22052..7d2f15cee8d1 100644
@@ -57,4 +57,5 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i);
 void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv);
 void efx_ef100_fini_vfreps(struct efx_nic *efx);
 
+void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf);
 #endif /* EF100_REP_H */
#2 lore raw

PATCH 2/14 sfc: ef100 representor RX NAPI poll

In reply to [email protected]

From: Edward Cree <[email protected]>

This patch adds the 'bottom half' napi->poll routine for representor RX. See the next patch (with the top half) for an explanation of the 'fake
interrupt' scheme used to drive this NAPI context.

---
 drivers/net/ethernet/sfc/ef100_rep.c | 64 ++++++++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_rep.h | 11 +++++
 2 files changed, 75 insertions(+)
drivers/net/ethernet/sfc/ef100_rep.c +64 -0
index 102071ed051b..fe45ae963391 100644
@@ -16,12 +16,16 @@
 
 #define EFX_EF100_REP_DRIVER	"efx_ef100_rep"
 
+static int efx_ef100_rep_poll(struct napi_struct *napi, int weight);
+
 static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv,
 				     unsigned int i)
 {
 	efv->parent = efx;
 	efv->idx = i;
 	INIT_LIST_HEAD(&efv->list);
+	INIT_LIST_HEAD(&efv->rx_list);
+	spin_lock_init(&efv->rx_lock);
 	efv->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
 			  NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
 			  NETIF_MSG_IFUP | NETIF_MSG_RX_ERR |
@@ -29,6 +33,25 @@ static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv,
 	return 0;
 }
 
+static int efx_ef100_rep_open(struct net_device *net_dev)
+{
+	struct efx_rep *efv = netdev_priv(net_dev);
+
+	netif_napi_add(net_dev, &efv->napi, efx_ef100_rep_poll,
+		       NAPI_POLL_WEIGHT);
+	napi_enable(&efv->napi);
+	return 0;
+}
+
+static int efx_ef100_rep_close(struct net_device *net_dev)
+{
+	struct efx_rep *efv = netdev_priv(net_dev);
+
+	napi_disable(&efv->napi);
+	netif_napi_del(&efv->napi);
+	return 0;
+}
+
 static netdev_tx_t efx_ef100_rep_xmit(struct sk_buff *skb,
 				      struct net_device *dev)
 {
@@ -93,6 +116,8 @@ static void efx_ef100_rep_get_stats64(struct net_device *dev,
 }
 
 static const struct net_device_ops efx_ef100_rep_netdev_ops = {
+	.ndo_open		= efx_ef100_rep_open,
+	.ndo_stop		= efx_ef100_rep_close,
 	.ndo_start_xmit		= efx_ef100_rep_xmit,
 	.ndo_get_port_parent_id	= efx_ef100_rep_get_port_parent_id,
 	.ndo_get_phys_port_name	= efx_ef100_rep_get_phys_port_name,
@@ -256,3 +281,42 @@ void efx_ef100_fini_vfreps(struct efx_nic *efx)
 	list_for_each_entry_safe(efv, next, &efx->vf_reps, list)
 		efx_ef100_vfrep_destroy(efx, efv);
 }
+
+static int efx_ef100_rep_poll(struct napi_struct *napi, int weight)
+{
+	struct efx_rep *efv = container_of(napi, struct efx_rep, napi);
+	unsigned int read_index;
+	struct list_head head;
+	struct sk_buff *skb;
+	bool need_resched;
+	int spent = 0;
+
+	INIT_LIST_HEAD(&head);
+	/* Grab up to 'weight' pending SKBs */
+	spin_lock_bh(&efv->rx_lock);
+	read_index = efv->write_index;
+	while (spent < weight && !list_empty(&efv->rx_list)) {
+		skb = list_first_entry(&efv->rx_list, struct sk_buff, list);
+		list_del(&skb->list);
+		list_add_tail(&skb->list, &head);
+		spent++;
+	}
+	spin_unlock_bh(&efv->rx_lock);
+	/* Receive them */
+	netif_receive_skb_list(&head);
+	if (spent < weight)
+		if (napi_complete_done(napi, spent)) {
+			spin_lock_bh(&efv->rx_lock);
+			efv->read_index = read_index;
+			/* If write_index advanced while we were doing the
+			 * RX, then storing our read_index won't re-prime the
+			 * fake-interrupt.  In that case, we need to schedule
+			 * NAPI again to consume the additional packet(s).
+			 */
+			need_resched = efv->write_index != read_index;
+			spin_unlock_bh(&efv->rx_lock);
+			if (need_resched)
+				napi_schedule(&efv->napi);
+		}
+	return spent;
+}
drivers/net/ethernet/sfc/ef100_rep.h +11 -0
index d47fd8ff6220..77037ab22052 100644
@@ -29,7 +29,13 @@ struct efx_rep_sw_stats {
  * @msg_enable: log message enable flags
  * @mport: m-port ID of corresponding VF
  * @idx: VF index
+ * @write_index: number of packets enqueued to @rx_list
+ * @read_index: number of packets consumed from @rx_list
+ * @rx_pring_size: max length of RX list
  * @list: entry on efx->vf_reps
+ * @rx_list: list of SKBs queued for receive in NAPI poll
+ * @rx_lock: protects @rx_list
+ * @napi: NAPI control structure
  * @stats: software traffic counters for netdev stats
  */
 struct efx_rep {
@@ -38,7 +44,12 @@ struct efx_rep {
 	u32 msg_enable;
 	u32 mport;
 	unsigned int idx;
+	unsigned int write_index, read_index;
+	unsigned int rx_pring_size;
 	struct list_head list;
+	struct list_head rx_list;
+	spinlock_t rx_lock;
+	struct napi_struct napi;
 	struct efx_rep_sw_stats stats;
 };
 
#4 lore raw

PATCH 4/14 sfc: determine wire m-port at EF100 PF probe time

In reply to [email protected]

From: Edward Cree <[email protected]>

Traffic delivered to the (MAE admin) PF could be from either the wire
or a VF. The INGRESS_MPORT field of the RX prefix distinguishes these; base_mport is the value this field will have for traffic from the wire (which should be delivered to the PF's netdevice, not a representor).

---
 drivers/net/ethernet/sfc/ef100_nic.c | 34 ++++++++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_nic.h |  2 ++
 drivers/net/ethernet/sfc/mae.c       | 10 ++++++++
 drivers/net/ethernet/sfc/mae.h       |  1 +
 4 files changed, 47 insertions(+)
drivers/net/ethernet/sfc/ef100_nic.c +34 -0
index 4625d35269e6..10fc79d4720c 100644
@@ -24,6 +24,7 @@
 #include "ef100_tx.h"
 #include "ef100_sriov.h"
 #include "ef100_netdev.h"
+#include "mae.h"
 #include "rx_common.h"
 
 #define EF100_MAX_VIS 4096
@@ -704,6 +705,29 @@ static unsigned int efx_ef100_recycle_ring_size(const struct efx_nic *efx)
 	return 10 * EFX_RECYCLE_RING_SIZE_10G;
 }
 
+static int efx_ef100_get_base_mport(struct efx_nic *efx)
+{
+	struct ef100_nic_data *nic_data = efx->nic_data;
+	u32 selector, id;
+	int rc;
+
+	/* Construct mport selector for "physical network port" */
+	efx_mae_mport_wire(efx, &selector);
+	/* Look up actual mport ID */
+	rc = efx_mae_lookup_mport(efx, selector, &id);
+	if (rc)
+		return rc;
+	/* The ID should always fit in 16 bits, because that's how wide the
+	 * corresponding fields in the RX prefix & TX override descriptor are
+	 */
+	if (id >> 16)
+		netif_warn(efx, probe, efx->net_dev, "Bad base m-port id %#x\n",
+			   id);
+	nic_data->base_mport = id;
+	nic_data->have_mport = true;
+	return 0;
+}
+
 static int compare_versions(const char *a, const char *b)
 {
 	int a_major, a_minor, a_point, a_patch;
@@ -1064,6 +1088,16 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 	eth_hw_addr_set(net_dev, net_dev->perm_addr);
 	memcpy(nic_data->port_id, net_dev->perm_addr, ETH_ALEN);
 
+	if (!nic_data->grp_mae)
+		return 0;
+
+	rc = efx_ef100_get_base_mport(efx);
+	if (rc) {
+		netif_warn(efx, probe, net_dev,
+			   "Failed to probe base mport rc %d; representors will not function\n",
+			   rc);
+	}
+
 	return 0;
 
 fail:
drivers/net/ethernet/sfc/ef100_nic.h +2 -0
index 40f84a275057..0295933145fa 100644
@@ -72,6 +72,8 @@ struct ef100_nic_data {
 	u8 port_id[ETH_ALEN];
 	DECLARE_BITMAP(evq_phases, EFX_MAX_CHANNELS);
 	u64 stats[EF100_STAT_COUNT];
+	u32 base_mport;
+	bool have_mport; /* base_mport was populated successfully */
 	bool grp_mae; /* MAE Privilege */
 	u16 tso_max_hdr_len;
 	u16 tso_max_payload_num_segs;
drivers/net/ethernet/sfc/mae.c +10 -0
index 011ebd46ada5..0cbcadde6677 100644
@@ -13,6 +13,16 @@
 #include "mcdi.h"
 #include "mcdi_pcol.h"
 
+void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
+{
+	efx_dword_t mport;
+
+	EFX_POPULATE_DWORD_2(mport,
+			     MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
+			     MAE_MPORT_SELECTOR_PPORT_ID, efx->port_num);
+	*out = EFX_DWORD_VAL(mport);
+}
+
 void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out)
 {
 	efx_dword_t mport;
drivers/net/ethernet/sfc/mae.h +1 -0
index 27e69e8a54b6..25c2fd94e158 100644
@@ -15,6 +15,7 @@
 
 #include "net_driver.h"
 
+void efx_mae_mport_wire(struct efx_nic *efx, u32 *out);
 void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out);
 
 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
#8 lore raw

PATCH 5/14 sfc: check ef100 RX packets are from the wire

In reply to [email protected]

From: Edward Cree <[email protected]>

If not, for now drop them and warn. A subsequent patch will look up
the source m-port to try and find a representor to deliver them to.

---
 drivers/net/ethernet/sfc/ef100_rx.c       | 28 ++++++++++++++++++-----
 drivers/net/ethernet/sfc/ethtool_common.c |  1 +
 drivers/net/ethernet/sfc/net_driver.h     |  3 +++
 3 files changed, 26 insertions(+), 6 deletions(-)
drivers/net/ethernet/sfc/ef100_rx.c +22 -6
index 85207acf7dee..b8da9e3b7bf2 100644
@@ -55,10 +55,14 @@ static bool ef100_has_fcs_error(struct efx_channel *channel, u32 *prefix)
 
 void __ef100_rx_packet(struct efx_channel *channel)
 {
-	struct efx_rx_buffer *rx_buf = efx_rx_buffer(&channel->rx_queue, channel->rx_pkt_index);
+	struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
+	struct efx_rx_buffer *rx_buf = efx_rx_buffer(rx_queue,
+						     channel->rx_pkt_index);
 	struct efx_nic *efx = channel->efx;
+	struct ef100_nic_data *nic_data;
 	u8 *eh = efx_rx_buf_va(rx_buf);
 	__wsum csum = 0;
+	u16 ing_port;
 	u32 *prefix;
 
 	prefix = (u32 *)(eh - ESE_GZ_RX_PKT_PREFIX_LEN);
@@ -76,6 +80,19 @@ void __ef100_rx_packet(struct efx_channel *channel)
 		goto out;
 	}
 
+	ing_port = le16_to_cpu((__force __le16) PREFIX_FIELD(prefix, INGRESS_MPORT));
+
+	nic_data = efx->nic_data;
+
+	if (nic_data->have_mport && ing_port != nic_data->base_mport) {
+		if (net_ratelimit())
+			netif_warn(efx, drv, efx->net_dev,
+				   "Unrecognised ing_port %04x (base %04x), dropping\n",
+				   ing_port, nic_data->base_mport);
+		channel->n_rx_mport_bad++;
+		goto free_rx_buffer;
+	}
+
 	if (likely(efx->net_dev->features & NETIF_F_RXCSUM)) {
 		if (PREFIX_FIELD(prefix, NT_OR_INNER_L3_CLASS) == 1) {
 			++channel->n_rx_ip_hdr_chksum_err;
@@ -87,17 +104,16 @@ void __ef100_rx_packet(struct efx_channel *channel)
 	}
 
 	if (channel->type->receive_skb) {
-		struct efx_rx_queue *rx_queue =
-			efx_channel_get_rx_queue(channel);
-
 		/* no support for special channels yet, so just discard */
 		WARN_ON_ONCE(1);
-		efx_free_rx_buffers(rx_queue, rx_buf, 1);
-		goto out;
+		goto free_rx_buffer;
 	}
 
 	efx_rx_packet_gro(channel, rx_buf, channel->rx_pkt_n_frags, eh, csum);
+	goto out;
 
+free_rx_buffer:
+	efx_free_rx_buffers(rx_queue, rx_buf, 1);
 out:
 	channel->rx_pkt_n_frags = 0;
 }
drivers/net/ethernet/sfc/ethtool_common.c +1 -0
index 58ad9d665805..bc840ede3053 100644
@@ -91,6 +91,7 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = {
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_bad_drops),
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_tx),
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_redirect),
+	EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mport_bad),
 #ifdef CONFIG_RFS_ACCEL
 	EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(rfs_filter_count),
 	EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_succeeded),
drivers/net/ethernet/sfc/net_driver.h +3 -0
index 4cde54cf77b9..6b64ba3a7d36 100644
@@ -478,6 +478,8 @@ enum efx_sync_events_state {
  * @n_rx_xdp_bad_drops: Count of RX packets dropped due to XDP errors
  * @n_rx_xdp_tx: Count of RX packets retransmitted due to XDP
  * @n_rx_xdp_redirect: Count of RX packets redirected to a different NIC by XDP
+ * @n_rx_mport_bad: Count of RX packets dropped because their ingress mport was
+ *	not recognised
  * @rx_pkt_n_frags: Number of fragments in next packet to be delivered by
  *	__efx_rx_packet(), or zero if there is none
  * @rx_pkt_index: Ring index of first buffer for next packet to be delivered
@@ -540,6 +542,7 @@ struct efx_channel {
 	unsigned int n_rx_xdp_bad_drops;
 	unsigned int n_rx_xdp_tx;
 	unsigned int n_rx_xdp_redirect;
+	unsigned int n_rx_mport_bad;
 
 	unsigned int rx_pkt_n_frags;
 	unsigned int rx_pkt_index;
#9 lore raw

PATCH 6/14 sfc: receive packets from EF100 VFs into representors

In reply to [email protected]

From: Edward Cree <[email protected]>

If the source m-port of a packet in __ef100_rx_packet() is a VF,
hand off the packet to the corresponding representor with efx_ef100_rep_rx_packet().

---
 drivers/net/ethernet/sfc/ef100_rep.c | 19 +++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_rep.h |  5 +++++
 drivers/net/ethernet/sfc/ef100_rx.c  | 17 +++++++++++++++++
 3 files changed, 41 insertions(+)
drivers/net/ethernet/sfc/ef100_rep.c +19 -0
index e6c6e9e764b2..c0bc12b9e348 100644
@@ -224,6 +224,7 @@ static void efx_ef100_rep_destroy_netdev(struct efx_rep *efv)
 	list_del(&efv->list);
 	spin_unlock_bh(&efx->vf_reps_lock);
 	rtnl_unlock();
+	synchronize_rcu();
 	free_netdev(efv->net_dev);
 }
 
@@ -375,3 +376,21 @@ void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf)
 	if (primed)
 		napi_schedule(&efv->napi);
 }
+
+struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport)
+{
+	struct efx_rep *efv, *out = NULL;
+
+	/* spinlock guards against list mutation while we're walking it;
+	 * but caller must also hold rcu_read_lock() to ensure the netdev
+	 * isn't freed after we drop the spinlock.
+	 */
+	spin_lock_bh(&efx->vf_reps_lock);
+	list_for_each_entry(efv, &efx->vf_reps, list)
+		if (efv->mport == mport) {
+			out = efv;
+			break;
+		}
+	spin_unlock_bh(&efx->vf_reps_lock);
+	return out;
+}
drivers/net/ethernet/sfc/ef100_rep.h +5 -0
index 7d2f15cee8d1..f3787133f793 100644
@@ -58,4 +58,9 @@ void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv);
 void efx_ef100_fini_vfreps(struct efx_nic *efx);
 
 void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf);
+/* Returns the representor corresponding to a VF m-port, or NULL
+ * @mport is an m-port label, *not* an m-port ID!
+ * Caller must hold rcu_read_lock().
+ */
+struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
 #endif /* EF100_REP_H */
drivers/net/ethernet/sfc/ef100_rx.c +17 -0
index b8da9e3b7bf2..2b5568170340 100644
@@ -85,6 +85,23 @@ void __ef100_rx_packet(struct efx_channel *channel)
 	nic_data = efx->nic_data;
 
 	if (nic_data->have_mport && ing_port != nic_data->base_mport) {
+		struct efx_rep *efv;
+
+		rcu_read_lock();
+		efv = efx_ef100_find_rep_by_mport(efx, ing_port);
+		if (efv) {
+			if (efv->net_dev->flags & IFF_UP)
+				efx_ef100_rep_rx_packet(efv, rx_buf);
+			rcu_read_unlock();
+			/* Representor Rx doesn't care about PF Rx buffer
+			 * ownership, it just makes a copy. So, we are done
+			 * with the Rx buffer from PF point of view and should
+			 * free it.
+			 */
+			goto free_rx_buffer;
+		}
+		rcu_read_unlock();
+
 		if (net_ratelimit())
 			netif_warn(efx, drv, efx->net_dev,
 				   "Unrecognised ing_port %04x (base %04x), dropping\n",
#14 lore raw

PATCH 10/14 sfc: look up VF's client ID when creating representor

In reply to [email protected]

From: Edward Cree <[email protected]>

Firmware gives us a handle which we will later use to administrate the
VF's virtual MAC configuration.

---
 drivers/net/ethernet/sfc/ef100_nic.c | 23 +++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_nic.h |  1 +
 drivers/net/ethernet/sfc/ef100_rep.c | 17 +++++++++++++++++
 drivers/net/ethernet/sfc/ef100_rep.h |  2 ++
 4 files changed, 43 insertions(+)
drivers/net/ethernet/sfc/ef100_nic.c +23 -0
index 0ae27de314b5..7ca4e9769455 100644
@@ -1092,6 +1092,29 @@ static int ef100_probe_main(struct efx_nic *efx)
 	return rc;
 }
 
+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
+	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
+	size_t outlen;
+	int rc;
+
+	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
+		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
+	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
+		       pciefn_flat);
+
+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf,
+			  sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		return rc;
+	if (outlen < sizeof(outbuf))
+		return -EIO;
+	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
+	return 0;
+}
+
 int ef100_probe_netdev_pf(struct efx_nic *efx)
 {
 	struct ef100_nic_data *nic_data = efx->nic_data;
drivers/net/ethernet/sfc/ef100_nic.h +1 -0
index 0295933145fa..cf78a5a2b7d6 100644
@@ -17,6 +17,7 @@
 extern const struct efx_nic_type ef100_pf_nic_type;
 extern const struct efx_nic_type ef100_vf_nic_type;
 
+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
 int ef100_probe_netdev_pf(struct efx_nic *efx);
 int ef100_probe_vf(struct efx_nic *efx);
 void ef100_remove(struct efx_nic *efx);
drivers/net/ethernet/sfc/ef100_rep.c +17 -0
index eac932710c63..3c5f22a6c3b5 100644
@@ -200,6 +200,7 @@ static struct efx_rep *efx_ef100_rep_create_netdev(struct efx_nic *efx,
 static int efx_ef100_configure_rep(struct efx_rep *efv)
 {
 	struct efx_nic *efx = efv->parent;
+	efx_qword_t pciefn;
 	u32 selector;
 	int rc;
 
@@ -214,6 +215,22 @@ static int efx_ef100_configure_rep(struct efx_rep *efv)
 	/* mport label should fit in 16 bits */
 	WARN_ON(efv->mport >> 16);
 
+	/* Construct PCIE_FUNCTION structure for the representee */
+	EFX_POPULATE_QWORD_3(pciefn,
+			     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
+			     PCIE_FUNCTION_VF, efv->idx,
+			     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
+	/* look up representee's client ID */
+	rc = efx_ef100_lookup_client_id(efx, pciefn, &efv->clid);
+	if (rc) {
+		efv->clid = CLIENT_HANDLE_NULL;
+		pci_dbg(efx->pci_dev, "Failed to get VF %u client ID, rc %d\n",
+			efv->idx, rc);
+	} else {
+		pci_dbg(efx->pci_dev, "VF %u client ID %#x\n",
+			efv->idx, efv->clid);
+	}
+
 	return efx_tc_configure_default_rule_rep(efv);
 }
 
drivers/net/ethernet/sfc/ef100_rep.h +2 -0
index 070f700893c1..0fa6ad6b2c92 100644
@@ -29,6 +29,7 @@ struct efx_rep_sw_stats {
  * @net_dev: representor netdevice
  * @msg_enable: log message enable flags
  * @mport: m-port ID of corresponding VF
+ * @clid: client ID of corresponding VF
  * @idx: VF index
  * @write_index: number of packets enqueued to @rx_list
  * @read_index: number of packets consumed from @rx_list
@@ -45,6 +46,7 @@ struct efx_rep {
 	struct net_device *net_dev;
 	u32 msg_enable;
 	u32 mport;
+	u32 clid;
 	unsigned int idx;
 	unsigned int write_index, read_index;
 	unsigned int rx_pring_size;
#12 lore raw

PATCH 8/14 sfc: move table locking into filter_table_{probe,remove} methods

In reply to [email protected]

From: Edward Cree <[email protected]>

We need to be able to drop the efx->filter_sem in ef100_filter_table_up()
so that we can call functions that insert filters (and thus take that rwsem for read), which means the efx->type->filter_table_probe method needs to be responsible for taking the lock in the first place.

---
 drivers/net/ethernet/sfc/ef10.c         | 26 ++++++++++++++-----------
 drivers/net/ethernet/sfc/ef100_nic.c    | 22 +++++++++++++--------
 drivers/net/ethernet/sfc/ef10_sriov.c   | 16 +++------------
 drivers/net/ethernet/sfc/mcdi_filters.h |  1 +
 drivers/net/ethernet/sfc/rx_common.c    |  4 ----
 5 files changed, 33 insertions(+), 36 deletions(-)
drivers/net/ethernet/sfc/ef10.c +15 -11
index ab979fd11133..ee734b69150f 100644
@@ -2538,23 +2538,33 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx)
 
 	if (rc)
 		return rc;
+	down_write(&efx->filter_sem);
 	rc = efx_mcdi_filter_table_probe(efx, nic_data->workaround_26807);
 
 	if (rc)
-		return rc;
+		goto out_unlock;
 
 	list_for_each_entry(vlan, &nic_data->vlan_list, list) {
 		rc = efx_mcdi_filter_add_vlan(efx, vlan->vid);
 		if (rc)
 			goto fail_add_vlan;
 	}
-	return 0;
+	goto out_unlock;
 
 fail_add_vlan:
 	efx_mcdi_filter_table_remove(efx);
+out_unlock:
+	up_write(&efx->filter_sem);
 	return rc;
 }
 
+static void efx_ef10_filter_table_remove(struct efx_nic *efx)
+{
+	down_write(&efx->filter_sem);
+	efx_mcdi_filter_table_remove(efx);
+	up_write(&efx->filter_sem);
+}
+
 /* This creates an entry in the RX descriptor queue */
 static inline void
 efx_ef10_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index)
@@ -3211,9 +3221,7 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
 
 	efx_device_detach_sync(efx);
 	efx_net_stop(efx->net_dev);
-	down_write(&efx->filter_sem);
-	efx_mcdi_filter_table_remove(efx);
-	up_write(&efx->filter_sem);
+	efx_ef10_filter_table_remove(efx);
 
 	rc = efx_ef10_vadaptor_free(efx, efx->vport_id);
 	if (rc)
@@ -3243,9 +3251,7 @@ static int efx_ef10_vport_set_mac_address(struct efx_nic *efx)
 	if (rc2)
 		goto reset_nic;
 restore_filters:
-	down_write(&efx->filter_sem);
 	rc2 = efx_ef10_filter_table_probe(efx);
-	up_write(&efx->filter_sem);
 	if (rc2)
 		goto reset_nic;
 
@@ -3275,8 +3281,7 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
 	efx_net_stop(efx->net_dev);
 
 	mutex_lock(&efx->mac_lock);
-	down_write(&efx->filter_sem);
-	efx_mcdi_filter_table_remove(efx);
+	efx_ef10_filter_table_remove(efx);
 
 	ether_addr_copy(MCDI_PTR(inbuf, VADAPTOR_SET_MAC_IN_MACADDR),
 			efx->net_dev->dev_addr);
@@ -3286,7 +3291,6 @@ static int efx_ef10_set_mac_address(struct efx_nic *efx)
 				sizeof(inbuf), NULL, 0, NULL);
 
 	efx_ef10_filter_table_probe(efx);
-	up_write(&efx->filter_sem);
 	mutex_unlock(&efx->mac_lock);
 
 	if (was_enabled)
@@ -4092,7 +4096,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
 	.ev_test_generate = efx_ef10_ev_test_generate,
 	.filter_table_probe = efx_ef10_filter_table_probe,
 	.filter_table_restore = efx_mcdi_filter_table_restore,
-	.filter_table_remove = efx_mcdi_filter_table_remove,
+	.filter_table_remove = efx_ef10_filter_table_remove,
 	.filter_update_rx_scatter = efx_mcdi_update_rx_scatter,
 	.filter_insert = efx_mcdi_filter_insert,
 	.filter_remove_safe = efx_mcdi_filter_remove_safe,
drivers/net/ethernet/sfc/ef100_nic.c +14 -8
index 900d209766ae..fa459b95f367 100644
@@ -375,26 +375,32 @@ static int ef100_filter_table_up(struct efx_nic *efx)
 {
 	int rc;
 
+	down_write(&efx->filter_sem);
 	rc = efx_mcdi_filter_add_vlan(efx, EFX_FILTER_VID_UNSPEC);
-	if (rc) {
-		efx_mcdi_filter_table_down(efx);
-		return rc;
-	}
+	if (rc)
+		goto fail_unspec;
 
 	rc = efx_mcdi_filter_add_vlan(efx, 0);
-	if (rc) {
-		efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
-		efx_mcdi_filter_table_down(efx);
-	}
+	if (rc)
+		goto fail_vlan0;
+	up_write(&efx->filter_sem);
+	return 0;
 
+fail_vlan0:
+	efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
+fail_unspec:
+	efx_mcdi_filter_table_down(efx);
+	up_write(&efx->filter_sem);
 	return rc;
 }
 
 static void ef100_filter_table_down(struct efx_nic *efx)
 {
+	down_write(&efx->filter_sem);
 	efx_mcdi_filter_del_vlan(efx, 0);
 	efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
 	efx_mcdi_filter_table_down(efx);
+	up_write(&efx->filter_sem);
 }
 
 /*	Other
drivers/net/ethernet/sfc/ef10_sriov.c +3 -13
index 92550c7e85ce..9aae0d8b713f 100644
@@ -501,14 +501,11 @@ int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, const u8 *mac)
 		efx_device_detach_sync(vf->efx);
 		efx_net_stop(vf->efx->net_dev);
 
-		down_write(&vf->efx->filter_sem);
 		vf->efx->type->filter_table_remove(vf->efx);
 
 		rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
-		if (rc) {
-			up_write(&vf->efx->filter_sem);
+		if (rc)
 			return rc;
-		}
 	}
 
 	rc = efx_ef10_evb_port_assign(efx, EVB_PORT_ID_NULL, vf_i);
@@ -539,12 +536,9 @@ int efx_ef10_sriov_set_vf_mac(struct efx_nic *efx, int vf_i, const u8 *mac)
 	if (vf->efx) {
 		/* VF cannot use the vport_id that the PF created */
 		rc = efx_ef10_vadaptor_alloc(vf->efx, EVB_PORT_ID_ASSIGNED);
-		if (rc) {
-			up_write(&vf->efx->filter_sem);
+		if (rc)
 			return rc;
-		}
 		vf->efx->type->filter_table_probe(vf->efx);
-		up_write(&vf->efx->filter_sem);
 		efx_net_open(vf->efx->net_dev);
 		efx_device_attach_if_not_resetting(vf->efx);
 	}
@@ -580,7 +574,6 @@ int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
 		efx_net_stop(vf->efx->net_dev);
 
 		mutex_lock(&vf->efx->mac_lock);
-		down_write(&vf->efx->filter_sem);
 		vf->efx->type->filter_table_remove(vf->efx);
 
 		rc = efx_ef10_vadaptor_free(vf->efx, EVB_PORT_ID_ASSIGNED);
@@ -654,7 +647,6 @@ int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
 		if (rc2)
 			goto reset_nic_up_write;
 
-		up_write(&vf->efx->filter_sem);
 		mutex_unlock(&vf->efx->mac_lock);
 
 		rc2 = efx_net_open(vf->efx->net_dev);
@@ -666,10 +658,8 @@ int efx_ef10_sriov_set_vf_vlan(struct efx_nic *efx, int vf_i, u16 vlan,
 	return rc;
 
 reset_nic_up_write:
-	if (vf->efx) {
-		up_write(&vf->efx->filter_sem);
+	if (vf->efx)
 		mutex_unlock(&vf->efx->mac_lock);
-	}
 reset_nic:
 	if (vf->efx) {
 		netif_err(efx, drv, efx->net_dev,
drivers/net/ethernet/sfc/mcdi_filters.h +1 -0
index 06426aa9f2f3..c0d6558b9fd2 100644
@@ -89,6 +89,7 @@ struct efx_mcdi_filter_table {
 	 */
 	bool mc_chaining;
 	bool vlan_filter;
+	/* Entries on the vlan_list are added/removed under filter_sem */
 	struct list_head vlan_list;
 };
 
drivers/net/ethernet/sfc/rx_common.c +0 -4
index bd21d6ac778a..4826e6a7e4ce 100644
@@ -793,7 +793,6 @@ int efx_probe_filters(struct efx_nic *efx)
 	int rc;
 
 	mutex_lock(&efx->mac_lock);
-	down_write(&efx->filter_sem);
 	rc = efx->type->filter_table_probe(efx);
 	if (rc)
 		goto out_unlock;
@@ -830,7 +829,6 @@ int efx_probe_filters(struct efx_nic *efx)
 	}
 #endif
 out_unlock:
-	up_write(&efx->filter_sem);
 	mutex_unlock(&efx->mac_lock);
 	return rc;
 }
@@ -846,9 +844,7 @@ void efx_remove_filters(struct efx_nic *efx)
 		channel->rps_flow_id = NULL;
 	}
 #endif
-	down_write(&efx->filter_sem);
 	efx->type->filter_table_remove(efx);
-	up_write(&efx->filter_sem);
 }
 
 #ifdef CONFIG_RFS_ACCEL
#11 lore raw

PATCH 7/14 sfc: insert default MAE rules to connect VFs to representors

In reply to [email protected]

From: Edward Cree <[email protected]>

Default rules are low-priority switching rules which the hardware uses
in the absence of higher-priority rules. Each representor requires a corresponding rule matching traffic from its representee VF and delivering to the PF (where a check on INGRESS_MPORT in __ef100_rx_packet() will direct it to the representor). No rule is required in the reverse direction, because representor TX uses a TX override descriptor to bypass the MAE and deliver directly to the VF.
Since inserting any rule into the MAE disables the firmware's own
default rules, also insert a pair of rules to connect the PF to the physical network port and vice-versa.

---
 drivers/net/ethernet/sfc/Makefile        |   3 +-
 drivers/net/ethernet/sfc/ef100.c         |   1 +
 drivers/net/ethernet/sfc/ef100_netdev.c  |   2 +
 drivers/net/ethernet/sfc/ef100_nic.c     |  17 ++
 drivers/net/ethernet/sfc/ef100_rep.c     |  20 +-
 drivers/net/ethernet/sfc/ef100_rep.h     |   3 +
 drivers/net/ethernet/sfc/mae.c           | 257 ++++++++++++++++++++++-
 drivers/net/ethernet/sfc/mae.h           |  16 ++
 drivers/net/ethernet/sfc/mcdi.h          |   4 +
 drivers/net/ethernet/sfc/mcdi_pcol_mae.h |  24 +++
 drivers/net/ethernet/sfc/net_driver.h    |   2 +
 drivers/net/ethernet/sfc/tc.c            | 183 ++++++++++++++++
 drivers/net/ethernet/sfc/tc.h            |  76 +++++++
 13 files changed, 602 insertions(+), 6 deletions(-)
 create mode 100644 drivers/net/ethernet/sfc/mcdi_pcol_mae.h
 create mode 100644 drivers/net/ethernet/sfc/tc.c
 create mode 100644 drivers/net/ethernet/sfc/tc.h
drivers/net/ethernet/sfc/Makefile +2 -1
index 4c759488fc77..bb06fa228367 100644
@@ -8,7 +8,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
 			   ef100.o ef100_nic.o ef100_netdev.o \
 			   ef100_ethtool.o ef100_rx.o ef100_tx.o
 sfc-$(CONFIG_SFC_MTD)	+= mtd.o
-sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o mae.o
+sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
+                           mae.o tc.o
 
 obj-$(CONFIG_SFC)	+= sfc.o
 
drivers/net/ethernet/sfc/ef100.c +1 -0
index 425017fbcb25..dbb6fb2e3b14 100644
@@ -431,6 +431,7 @@ static void ef100_pci_remove(struct pci_dev *pci_dev)
 
 	probe_data = container_of(efx, struct efx_probe_data, efx);
 	ef100_remove_netdev(probe_data);
+	efx_fini_struct_tc(efx);
 
 	ef100_remove(efx);
 	efx_fini_io(efx);
drivers/net/ethernet/sfc/ef100_netdev.c +2 -0
index 9e65de1ab889..03aba7bd59ed 100644
@@ -329,6 +329,8 @@ void ef100_remove_netdev(struct efx_probe_data *probe_data)
 
 	ef100_unregister_netdev(efx);
 
+	efx_fini_tc(efx);
+
 	down_write(&efx->filter_sem);
 	efx_mcdi_filter_table_remove(efx);
 	up_write(&efx->filter_sem);
drivers/net/ethernet/sfc/ef100_nic.c +17 -0
index 10fc79d4720c..900d209766ae 100644
@@ -1091,6 +1091,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 	if (!nic_data->grp_mae)
 		return 0;
 
+	rc = efx_init_struct_tc(efx);
+	if (rc)
+		return rc;
+
 	rc = efx_ef100_get_base_mport(efx);
 	if (rc) {
 		netif_warn(efx, probe, net_dev,
@@ -1098,6 +1102,19 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 			   rc);
 	}
 
+	rc = efx_init_tc(efx);
+	if (rc) {
+		/* Either we don't have an MAE at all (i.e. legacy v-switching),
+		 * or we do but we failed to probe it.  In the latter case, we
+		 * may not have set up default rules, in which case we won't be
+		 * able to pass any traffic.  However, we don't fail the probe,
+		 * because the user might need to use the netdevice to apply
+		 * configuration changes to fix whatever's wrong with the MAE.
+		 */
+		netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n",
+			   rc);
+	}
+
 	return 0;
 
 fail:
drivers/net/ethernet/sfc/ef100_rep.c +16 -4
index c0bc12b9e348..eac932710c63 100644
@@ -27,6 +27,8 @@ static int efx_ef100_rep_init_struct(struct efx_nic *efx, struct efx_rep *efv,
 	efv->parent = efx;
 	efv->idx = i;
 	INIT_LIST_HEAD(&efv->list);
+	efv->dflt.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
+	INIT_LIST_HEAD(&efv->dflt.acts.list);
 	INIT_LIST_HEAD(&efv->rx_list);
 	spin_lock_init(&efv->rx_lock);
 	efv->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
@@ -212,7 +214,14 @@ static int efx_ef100_configure_rep(struct efx_rep *efv)
 	/* mport label should fit in 16 bits */
 	WARN_ON(efv->mport >> 16);
 
-	return 0;
+	return efx_tc_configure_default_rule_rep(efv);
+}
+
+static void efx_ef100_deconfigure_rep(struct efx_rep *efv)
+{
+	struct efx_nic *efx = efv->parent;
+
+	efx_tc_deconfigure_default_rule(efx, &efv->dflt);
 }
 
 static void efx_ef100_rep_destroy_netdev(struct efx_rep *efv)
@@ -246,19 +255,21 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
 		pci_err(efx->pci_dev,
 			"Failed to configure representor for VF %d, rc %d\n",
 			i, rc);
-		goto fail;
+		goto fail1;
 	}
 	rc = register_netdev(efv->net_dev);
 	if (rc) {
 		pci_err(efx->pci_dev,
 			"Failed to register representor for VF %d, rc %d\n",
 			i, rc);
-		goto fail;
+		goto fail2;
 	}
 	pci_dbg(efx->pci_dev, "Representor for VF %d is %s\n", i,
 		efv->net_dev->name);
 	return 0;
-fail:
+fail2:
+	efx_ef100_deconfigure_rep(efv);
+fail1:
 	efx_ef100_rep_destroy_netdev(efv);
 	return rc;
 }
@@ -272,6 +283,7 @@ void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv)
 		return;
 	netif_dbg(efx, drv, rep_dev, "Removing VF representor\n");
 	unregister_netdev(rep_dev);
+	efx_ef100_deconfigure_rep(efv);
 	efx_ef100_rep_destroy_netdev(efv);
 }
 
drivers/net/ethernet/sfc/ef100_rep.h +3 -0
index f3787133f793..070f700893c1 100644
@@ -14,6 +14,7 @@
 #define EF100_REP_H
 
 #include "net_driver.h"
+#include "tc.h"
 
 struct efx_rep_sw_stats {
 	atomic64_t rx_packets, tx_packets;
@@ -32,6 +33,7 @@ struct efx_rep_sw_stats {
  * @write_index: number of packets enqueued to @rx_list
  * @read_index: number of packets consumed from @rx_list
  * @rx_pring_size: max length of RX list
+ * @dflt: default-rule for MAE switching
  * @list: entry on efx->vf_reps
  * @rx_list: list of SKBs queued for receive in NAPI poll
  * @rx_lock: protects @rx_list
@@ -46,6 +48,7 @@ struct efx_rep {
 	unsigned int idx;
 	unsigned int write_index, read_index;
 	unsigned int rx_pring_size;
+	struct efx_tc_flow_rule dflt;
 	struct list_head list;
 	struct list_head rx_list;
 	spinlock_t rx_lock;
drivers/net/ethernet/sfc/mae.c +256 -1

278 lines not on this page · raw message

drivers/net/ethernet/sfc/mae.h +16 -0
index 25c2fd94e158..e9651f611750 100644
@@ -14,10 +14,26 @@
 /* MCDI interface for the ef100 Match-Action Engine */
 
 #include "net_driver.h"
+#include "tc.h"
+#include "mcdi_pcol.h" /* needed for various MC_CMD_MAE_*_NULL defines */
 
 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out);
+void efx_mae_mport_uplink(struct efx_nic *efx, u32 *out);
 void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out);
+void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
 
 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
 
+int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act);
+int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id);
+
+int efx_mae_alloc_action_set_list(struct efx_nic *efx,
+				  struct efx_tc_action_set_list *acts);
+int efx_mae_free_action_set_list(struct efx_nic *efx,
+				 struct efx_tc_action_set_list *acts);
+
+int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
+			u32 prio, u32 acts_id, u32 *id);
+int efx_mae_delete_rule(struct efx_nic *efx, u32 id);
+
 #endif /* EF100_MAE_H */
drivers/net/ethernet/sfc/mcdi.h +4 -0
index f74f6ce8b27d..26bc69f76801 100644
@@ -205,6 +205,8 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
 	((_ofst) + BUILD_BUG_ON_ZERO((_ofst) & (_align - 1)))
 #define _MCDI_DWORD(_buf, _field)					\
 	((_buf) + (_MCDI_CHECK_ALIGN(MC_CMD_ ## _field ## _OFST, 4) >> 2))
+#define _MCDI_STRUCT_DWORD(_buf, _field)				\
+	((_buf) + (_MCDI_CHECK_ALIGN(_field ## _OFST, 4) >> 2))
 
 #define MCDI_BYTE(_buf, _field)						\
 	((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1),	\
@@ -214,6 +216,8 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
 	 le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
 #define MCDI_SET_DWORD(_buf, _field, _value)				\
 	EFX_POPULATE_DWORD_1(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0, _value)
+#define MCDI_STRUCT_SET_DWORD(_buf, _field, _value)			\
+	EFX_POPULATE_DWORD_1(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0, _value)
 #define MCDI_DWORD(_buf, _field)					\
 	EFX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0)
 #define MCDI_POPULATE_DWORD_1(_buf, _field, _name1, _value1)		\
drivers/net/ethernet/sfc/mcdi_pcol_mae.h new file +24 -0
new file mode 100644
index 000000000000..ff6d80c8e486
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2019 Solarflare Communications Inc.
+ * Copyright 2019-2022 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef MCDI_PCOL_MAE_H
+#define MCDI_PCOL_MAE_H
+/* MCDI definitions for Match-Action Engine functionality, that are
+ * missing from the main mcdi_pcol.h
+ */
+
+/* MC_CMD_MAE_COUNTER_LIST_ALLOC is not (yet) a released API, but the
+ * following value is needed as an argument to MC_CMD_MAE_ACTION_SET_ALLOC.
+ */
+/* enum: A counter ID that is guaranteed never to represent a real counter */
+#define          MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL 0xffffffff
+
+#endif /* MCDI_PCOL_MAE_H */
drivers/net/ethernet/sfc/net_driver.h +2 -0
index 6b64ba3a7d36..7ef823d7a89a 100644
@@ -978,6 +978,7 @@ enum efx_xdp_tx_queues_mode {
  * @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their
  *      xdp_rxq_info structures?
  * @netdev_notifier: Netdevice notifier.
+ * @tc: state for TC offload (EF100).
  * @mem_bar: The BAR that is mapped into membase.
  * @reg_base: Offset from the start of the bar to the function control window.
  * @monitor_work: Hardware monitor workitem
@@ -1161,6 +1162,7 @@ struct efx_nic {
 	bool xdp_rxq_info_failed;
 
 	struct notifier_block netdev_notifier;
+	struct efx_tc_state *tc;
 
 	unsigned int mem_bar;
 	u32 reg_base;
drivers/net/ethernet/sfc/tc.c new file +183 -0

183 lines not on this page · raw message

drivers/net/ethernet/sfc/tc.h new file +76 -0

76 lines not on this page · raw message

#16 lore raw

PATCH 12/14 sfc: set EF100 VF MAC address through representor

In reply to [email protected]

From: Edward Cree <[email protected]>

When setting the VF rep's MAC address, set the provisioned MAC address
for the VF through MC_CMD_SET_CLIENT_MAC_ADDRESSES.

---
 drivers/net/ethernet/sfc/ef100_rep.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
drivers/net/ethernet/sfc/ef100_rep.c +28 -0
index ebab4579e63b..58365a4c7c6a 100644
@@ -107,6 +107,33 @@ static int efx_ef100_rep_get_phys_port_name(struct net_device *dev,
 	return 0;
 }
 
+static int efx_ef100_rep_set_mac_address(struct net_device *net_dev, void *data)
+{
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1));
+	struct efx_rep *efv = netdev_priv(net_dev);
+	struct efx_nic *efx = efv->parent;
+	struct sockaddr *addr = data;
+	const u8 *new_addr = addr->sa_data;
+	int rc;
+
+	if (efv->clid == CLIENT_HANDLE_NULL) {
+		netif_info(efx, drv, net_dev, "Unable to set representee MAC address (client ID is null)\n");
+	} else {
+		BUILD_BUG_ON(MC_CMD_SET_CLIENT_MAC_ADDRESSES_OUT_LEN);
+		MCDI_SET_DWORD(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
+			       efv->clid);
+		ether_addr_copy(MCDI_PTR(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_MAC_ADDRS),
+				new_addr);
+		rc = efx_mcdi_rpc(efx, MC_CMD_SET_CLIENT_MAC_ADDRESSES, inbuf,
+				  sizeof(inbuf), NULL, 0, NULL);
+		if (rc)
+			return rc;
+	}
+
+	eth_hw_addr_set(net_dev, new_addr);
+	return 0;
+}
+
 static void efx_ef100_rep_get_stats64(struct net_device *dev,
 				      struct rtnl_link_stats64 *stats)
 {
@@ -126,6 +153,7 @@ static const struct net_device_ops efx_ef100_rep_netdev_ops = {
 	.ndo_start_xmit		= efx_ef100_rep_xmit,
 	.ndo_get_port_parent_id	= efx_ef100_rep_get_port_parent_id,
 	.ndo_get_phys_port_name	= efx_ef100_rep_get_phys_port_name,
+	.ndo_set_mac_address    = efx_ef100_rep_set_mac_address,
 	.ndo_get_stats64	= efx_ef100_rep_get_stats64,
 };
 
#13 lore raw

PATCH 9/14 sfc: use a dynamic m-port for representor RX and set it promisc

In reply to [email protected]

From: Edward Cree <[email protected]>

Representors do not want to be subject to the PF's Ethernet address
filters, since traffic from VFs will typically have a destination either elsewhere on the link segment or on an overlay network.
So, create a dynamic m-port with promiscuous and all-multicast
filters, and set it as the egress port of representor default rules. Since the m-port is an alias of the calling PF's own m-port, traffic will still be delivered to the PF's RXQs, but it will be subject to the VNRX filter rules installed on the dynamic m-port (specified by the v-port ID field of the filter spec).

---
 drivers/net/ethernet/sfc/ef100_nic.c    | 11 ++++
 drivers/net/ethernet/sfc/filter.h       | 18 ++++++
 drivers/net/ethernet/sfc/mae.c          | 37 +++++++++++++
 drivers/net/ethernet/sfc/mae.h          |  3 +
 drivers/net/ethernet/sfc/mcdi_filters.c |  6 +-
 drivers/net/ethernet/sfc/tc.c           | 73 ++++++++++++++++++++++++-
 drivers/net/ethernet/sfc/tc.h           |  9 +++
 7 files changed, 154 insertions(+), 3 deletions(-)
drivers/net/ethernet/sfc/ef100_nic.c +11 -0
index fa459b95f367..0ae27de314b5 100644
@@ -24,6 +24,7 @@
 #include "ef100_tx.h"
 #include "ef100_sriov.h"
 #include "ef100_netdev.h"
+#include "tc.h"
 #include "mae.h"
 #include "rx_common.h"
 
@@ -383,7 +384,16 @@ static int ef100_filter_table_up(struct efx_nic *efx)
 	rc = efx_mcdi_filter_add_vlan(efx, 0);
 	if (rc)
 		goto fail_vlan0;
+	/* Drop the lock: we've finished altering table existence, and
+	 * filter insertion will need to take the lock for read.
+	 */
 	up_write(&efx->filter_sem);
+	rc = efx_tc_insert_rep_filters(efx);
+	/* Rep filter failure is nonfatal */
+	if (rc)
+		netif_warn(efx, drv, efx->net_dev,
+			   "Failed to insert representor filters, rc %d\n",
+			   rc);
 	return 0;
 
 fail_vlan0:
@@ -396,6 +406,7 @@ static int ef100_filter_table_up(struct efx_nic *efx)
 
 static void ef100_filter_table_down(struct efx_nic *efx)
 {
+	efx_tc_remove_rep_filters(efx);
 	down_write(&efx->filter_sem);
 	efx_mcdi_filter_del_vlan(efx, 0);
 	efx_mcdi_filter_del_vlan(efx, EFX_FILTER_VID_UNSPEC);
drivers/net/ethernet/sfc/filter.h +18 -0
index 40b2af8bfb81..4d928839d292 100644
@@ -88,6 +88,7 @@ enum efx_filter_priority {
  *	the automatic filter in its place.
  * @EFX_FILTER_FLAG_RX: Filter is for RX
  * @EFX_FILTER_FLAG_TX: Filter is for TX
+ * @EFX_FILTER_FLAG_VPORT_ID: Virtual port ID for adapter switching.
  */
 enum efx_filter_flags {
 	EFX_FILTER_FLAG_RX_RSS = 0x01,
@@ -95,6 +96,7 @@ enum efx_filter_flags {
 	EFX_FILTER_FLAG_RX_OVER_AUTO = 0x04,
 	EFX_FILTER_FLAG_RX = 0x08,
 	EFX_FILTER_FLAG_TX = 0x10,
+	EFX_FILTER_FLAG_VPORT_ID = 0x20,
 };
 
 /** enum efx_encap_type - types of encapsulation
@@ -127,6 +129,9 @@ enum efx_encap_type {
  *	MCFW context_id.
  * @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for
  *	an RX drop filter
+ * @vport_id: Virtual port ID associated with RX queue, for adapter switching,
+ *	if %EFX_FILTER_FLAG_VPORT_ID is set.  This is an MCFW vport_id, or on
+ *	EF100 an mport selector.
  * @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set
  * @inner_vid: Inner VLAN ID to match, if %EFX_FILTER_MATCH_INNER_VID is set
  * @loc_mac: Local MAC address to match, if %EFX_FILTER_MATCH_LOC_MAC or
@@ -156,6 +161,7 @@ struct efx_filter_spec {
 	u32	priority:2;
 	u32	flags:6;
 	u32	dmaq_id:12;
+	u32	vport_id;
 	u32	rss_context;
 	__be16	outer_vid __aligned(4); /* allow jhash2() of match values */
 	__be16	inner_vid;
@@ -292,6 +298,18 @@ static inline int efx_filter_set_mc_def(struct efx_filter_spec *spec)
 	return 0;
 }
 
+/**
+ * efx_filter_set_vport_id - override virtual port id relating to filter
+ * @spec: Specification to initialise
+ * @vport_id: firmware ID of the virtual port
+ */
+static inline void efx_filter_set_vport_id(struct efx_filter_spec *spec,
+					   u32 vport_id)
+{
+	spec->flags |= EFX_FILTER_FLAG_VPORT_ID;
+	spec->vport_id = vport_id;
+}
+
 static inline void efx_filter_set_encap_type(struct efx_filter_spec *spec,
 					     enum efx_encap_type encap_type)
 {
drivers/net/ethernet/sfc/mae.c +37 -0
index ea87ec83e618..97627f5e3674 100644
@@ -13,6 +13,43 @@
 #include "mcdi.h"
 #include "mcdi_pcol_mae.h"
 
+int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN);
+	size_t outlen;
+	int rc;
+
+	if (WARN_ON_ONCE(!id))
+		return -EINVAL;
+	if (WARN_ON_ONCE(!label))
+		return -EINVAL;
+
+	MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_TYPE,
+		       MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_MPORT_TYPE_ALIAS);
+	MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
+		       MAE_MPORT_SELECTOR_ASSIGNED);
+	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_ALLOC, inbuf, sizeof(inbuf),
+			  outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		return rc;
+	if (outlen < sizeof(outbuf))
+		return -EIO;
+	*id = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID);
+	*label = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
+	return 0;
+}
+
+int efx_mae_free_mport(struct efx_nic *efx, u32 id)
+{
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_FREE_IN_LEN);
+
+	BUILD_BUG_ON(MC_CMD_MAE_MPORT_FREE_OUT_LEN);
+	MCDI_SET_DWORD(inbuf, MAE_MPORT_FREE_IN_MPORT_ID, id);
+	return efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_FREE, inbuf, sizeof(inbuf),
+			    NULL, 0, NULL);
+}
+
 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
 {
 	efx_dword_t mport;
drivers/net/ethernet/sfc/mae.h +3 -0
index e9651f611750..0369be4d8983 100644
@@ -17,6 +17,9 @@
 #include "tc.h"
 #include "mcdi_pcol.h" /* needed for various MC_CMD_MAE_*_NULL defines */
 
+int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label);
+int efx_mae_free_mport(struct efx_nic *efx, u32 id);
+
 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out);
 void efx_mae_mport_uplink(struct efx_nic *efx, u32 *out);
 void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out);
drivers/net/ethernet/sfc/mcdi_filters.c +5 -1
index 1523be77b9db..4ff6586116ee 100644
@@ -221,7 +221,10 @@ static void efx_mcdi_filter_push_prep(struct efx_nic *efx,
 		efx_mcdi_filter_push_prep_set_match_fields(efx, spec, inbuf);
 	}
 
-	MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, efx->vport_id);
+	if (flags & EFX_FILTER_FLAG_VPORT_ID)
+		MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, spec->vport_id);
+	else
+		MCDI_SET_DWORD(inbuf, FILTER_OP_IN_PORT_ID, efx->vport_id);
 	MCDI_SET_DWORD(inbuf, FILTER_OP_IN_RX_DEST,
 		       spec->dmaq_id == EFX_FILTER_RX_DMAQ_ID_DROP ?
 		       MC_CMD_FILTER_OP_IN_RX_DEST_DROP :
@@ -488,6 +491,7 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
 			saved_spec->flags |= spec->flags;
 			saved_spec->rss_context = spec->rss_context;
 			saved_spec->dmaq_id = spec->dmaq_id;
+			saved_spec->vport_id = spec->vport_id;
 		}
 	} else if (!replacing) {
 		kfree(saved_spec);
drivers/net/ethernet/sfc/tc.c +71 -2

109 lines not on this page · raw message

drivers/net/ethernet/sfc/tc.h +9 -0
index 46c5101eaa8d..309123c6b386 100644
@@ -49,12 +49,18 @@ enum efx_tc_rule_prios {
 /**
  * struct efx_tc_state - control plane data for TC offload
  *
+ * @reps_mport_id: MAE port allocated for representor RX
+ * @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
+ * @reps_filter_mc: VNIC filter for representor multicast RX (allmulti)
+ * @reps_mport_vport_id: vport_id for representor RX filters
  * @dflt: Match-action rules for default switching; at priority
  *	%EFX_TC_PRIO_DFLT.  Named by *ingress* port
  * @dflt.pf: rule for traffic ingressing from PF (egresses to wire)
  * @dflt.wire: rule for traffic ingressing from wire (egresses to PF)
  */
 struct efx_tc_state {
+	u32 reps_mport_id, reps_mport_vport_id;
+	s32 reps_filter_uc, reps_filter_mc;
 	struct {
 		struct efx_tc_flow_rule pf;
 		struct efx_tc_flow_rule wire;
@@ -67,6 +73,9 @@ int efx_tc_configure_default_rule_rep(struct efx_rep *efv);
 void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
 				     struct efx_tc_flow_rule *rule);
 
+int efx_tc_insert_rep_filters(struct efx_nic *efx);
+void efx_tc_remove_rep_filters(struct efx_nic *efx);
+
 int efx_init_tc(struct efx_nic *efx);
 void efx_fini_tc(struct efx_nic *efx);
 
#17 lore raw

PATCH 13/14 sfc: get provisioned MAC address on EF100 VF probe

In reply to [email protected]

From: Edward Cree <[email protected]>

Move the implementation from the PF-specific probe path to that part
which is common to both PFs and VFs.

---
 drivers/net/ethernet/sfc/ef100_netdev.c | 10 ++++++++++
 drivers/net/ethernet/sfc/ef100_nic.c    | 11 -----------
 2 files changed, 10 insertions(+), 11 deletions(-)
drivers/net/ethernet/sfc/ef100_netdev.c +10 -0
index 03aba7bd59ed..0f7447858837 100644
@@ -347,6 +347,7 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
 {
 	struct efx_nic *efx = &probe_data->efx;
 	struct efx_probe_data **probe_ptr;
+	struct ef100_nic_data *nic_data;
 	struct net_device *net_dev;
 	int rc;
 
@@ -398,6 +399,15 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
 	/* Don't fail init if RSS setup doesn't work. */
 	efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels);
 
+	rc = ef100_get_mac_address(efx, net_dev->perm_addr, CLIENT_HANDLE_SELF,
+				   efx->type->is_vf);
+	if (rc)
+		goto fail;
+	/* Assign MAC address */
+	eth_hw_addr_set(net_dev, net_dev->perm_addr);
+	nic_data = efx->nic_data;
+	memcpy(nic_data->port_id, net_dev->perm_addr, ETH_ALEN);
+
 	rc = ef100_register_netdev(efx);
 	if (rc)
 		goto fail;
drivers/net/ethernet/sfc/ef100_nic.c +0 -11
index 92908640a0a6..b74b0d60528e 100644
@@ -1132,14 +1132,6 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 	struct net_device *net_dev = efx->net_dev;
 	int rc;
 
-	rc = ef100_get_mac_address(efx, net_dev->perm_addr, CLIENT_HANDLE_SELF,
-				   false);
-	if (rc)
-		goto fail;
-	/* Assign MAC address */
-	eth_hw_addr_set(net_dev, net_dev->perm_addr);
-	memcpy(nic_data->port_id, net_dev->perm_addr, ETH_ALEN);
-
 	if (!nic_data->grp_mae)
 		return 0;
 
@@ -1168,9 +1160,6 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 	}
 
 	return 0;
-
-fail:
-	return rc;
 }
 
 int ef100_probe_vf(struct efx_nic *efx)
#18 lore raw

PATCH 14/14 sfc: implement ethtool get/set RX ring size for EF100 reps

In reply to [email protected]

From: Edward Cree <[email protected]>

It's not truly a ring, but the maximum length of the list of queued RX
SKBs is analogous to an RX ring size, so use that API to configure it.

---
 drivers/net/ethernet/sfc/ef100_rep.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
drivers/net/ethernet/sfc/ef100_rep.c +27 -0
index 58365a4c7c6a..efbe7d482d7b 100644
@@ -178,10 +178,37 @@ static void efx_ef100_rep_ethtool_set_msglevel(struct net_device *net_dev,
 	efv->msg_enable = msg_enable;
 }
 
+static void efx_ef100_rep_ethtool_get_ringparam(struct net_device *net_dev,
+						struct ethtool_ringparam *ring,
+						struct kernel_ethtool_ringparam *kring,
+						struct netlink_ext_ack *ext_ack)
+{
+	struct efx_rep *efv = netdev_priv(net_dev);
+
+	ring->rx_max_pending = U32_MAX;
+	ring->rx_pending = efv->rx_pring_size;
+}
+
+static int efx_ef100_rep_ethtool_set_ringparam(struct net_device *net_dev,
+					       struct ethtool_ringparam *ring,
+					       struct kernel_ethtool_ringparam *kring,
+					       struct netlink_ext_ack *ext_ack)
+{
+	struct efx_rep *efv = netdev_priv(net_dev);
+
+	if (ring->rx_mini_pending || ring->rx_jumbo_pending || ring->tx_pending)
+		return -EINVAL;
+
+	efv->rx_pring_size = ring->rx_pending;
+	return 0;
+}
+
 static const struct ethtool_ops efx_ef100_rep_ethtool_ops = {
 	.get_drvinfo		= efx_ef100_rep_get_drvinfo,
 	.get_msglevel		= efx_ef100_rep_ethtool_get_msglevel,
 	.set_msglevel		= efx_ef100_rep_ethtool_set_msglevel,
+	.get_ringparam		= efx_ef100_rep_ethtool_get_ringparam,
+	.set_ringparam		= efx_ef100_rep_ethtool_set_ringparam,
 };
 
 static struct efx_rep *efx_ef100_rep_create_netdev(struct efx_nic *efx,
#15 lore raw

PATCH 11/14 sfc: fetch existing assigned MAC address from FW when creating VF rep

In reply to [email protected]

From: Edward Cree <[email protected]>

For the sake of code commonality, this changes the PF probe path to also
use MC_CMD_GET_CLIENT_MAC_ADDRESSES instead of the old MC_CMD_GET_MAC_ADDRESSES.

---
 drivers/net/ethernet/sfc/ef100_nic.c | 32 +++++++++++++++++++---------
 drivers/net/ethernet/sfc/ef100_nic.h |  2 ++
 drivers/net/ethernet/sfc/ef100_rep.c |  6 ++++++
 3 files changed, 30 insertions(+), 10 deletions(-)
drivers/net/ethernet/sfc/ef100_nic.c +22 -10
index 7ca4e9769455..92908640a0a6 100644
@@ -130,23 +130,34 @@ static void ef100_mcdi_reboot_detected(struct efx_nic *efx)
 
 /*	MCDI calls
  */
-static int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address)
+int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
+			  int client_handle, bool empty_ok)
 {
-	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_MAC_ADDRESSES_OUT_LEN);
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_MAC_ADDRESSES_OUT_LEN(1));
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_MAC_ADDRESSES_IN_LEN);
 	size_t outlen;
 	int rc;
 
-	BUILD_BUG_ON(MC_CMD_GET_MAC_ADDRESSES_IN_LEN != 0);
+	MCDI_SET_DWORD(inbuf, GET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
+		       client_handle);
 
-	rc = efx_mcdi_rpc(efx, MC_CMD_GET_MAC_ADDRESSES, NULL, 0,
-			  outbuf, sizeof(outbuf), &outlen);
+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_MAC_ADDRESSES, inbuf,
+			  sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
 	if (rc)
 		return rc;
-	if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)
-		return -EIO;
 
-	ether_addr_copy(mac_address,
-			MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE));
+	if (outlen >= MC_CMD_GET_CLIENT_MAC_ADDRESSES_OUT_LEN(1)) {
+		ether_addr_copy(mac_address,
+				MCDI_PTR(outbuf,
+					 GET_CLIENT_MAC_ADDRESSES_OUT_MAC_ADDRS));
+	} else if (empty_ok) {
+		pci_warn(efx->pci_dev,
+			 "No MAC address provisioned for client ID %#x.\n",
+			 client_handle);
+		eth_zero_addr(mac_address);
+	} else {
+		return -ENOENT;
+	}
 	return 0;
 }
 
@@ -1121,7 +1132,8 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 	struct net_device *net_dev = efx->net_dev;
 	int rc;
 
-	rc = ef100_get_mac_address(efx, net_dev->perm_addr);
+	rc = ef100_get_mac_address(efx, net_dev->perm_addr, CLIENT_HANDLE_SELF,
+				   false);
 	if (rc)
 		goto fail;
 	/* Assign MAC address */
drivers/net/ethernet/sfc/ef100_nic.h +2 -0
index cf78a5a2b7d6..5241fc1d928e 100644
@@ -17,6 +17,8 @@
 extern const struct efx_nic_type ef100_pf_nic_type;
 extern const struct efx_nic_type ef100_vf_nic_type;
 
+int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
+			  int client_handle, bool empty_ok);
 int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
 int ef100_probe_netdev_pf(struct efx_nic *efx);
 int ef100_probe_vf(struct efx_nic *efx);
drivers/net/ethernet/sfc/ef100_rep.c +6 -0
index 3c5f22a6c3b5..ebab4579e63b 100644
@@ -199,6 +199,7 @@ static struct efx_rep *efx_ef100_rep_create_netdev(struct efx_nic *efx,
 
 static int efx_ef100_configure_rep(struct efx_rep *efv)
 {
+	struct net_device *net_dev = efv->net_dev;
 	struct efx_nic *efx = efv->parent;
 	efx_qword_t pciefn;
 	u32 selector;
@@ -229,6 +230,11 @@ static int efx_ef100_configure_rep(struct efx_rep *efv)
 	} else {
 		pci_dbg(efx->pci_dev, "VF %u client ID %#x\n",
 			efv->idx, efv->clid);
+
+		/* Get the assigned MAC address */
+		(void)ef100_get_mac_address(efx, net_dev->perm_addr, efv->clid,
+					    true);
+		eth_hw_addr_set(net_dev, net_dev->perm_addr);
 	}
 
 	return efx_tc_configure_default_rule_rep(efv);
#5 lore raw

Re: [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time

In reply to [email protected]
I love your patch! Yet something to improve:

Hi,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/ecree-xilinx-com/sfc-VF-representors-for-EF100-RX-side/20220723-001059
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 949d6b405e6160ae44baea39192d67b39cb7eeac
config: mips-randconfig-s041-20220721 (https://download.01.org/0day-ci/archive/20220723/[email protected]/config)
compiler: mips-linux-gcc (GCC) 12.1.0

reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-39-gce1a6720-dirty
# https://github.com/intel-lab-lkp/linux/commit/f00d0e9f57792091c90518b98e8b722a4018f062
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review ecree-xilinx-com/sfc-VF-representors-for-EF100-RX-side/20220723-001059
git checkout f00d0e9f57792091c90518b98e8b722a4018f062
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=mips SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable

All errors (new ones prefixed by >>):

mips-linux-ld: drivers/net/ethernet/sfc/ef100_nic.o: in function `ef100_probe_netdev_pf':
ef100_nic.c:(.text+0x2904): undefined reference to `efx_mae_mport_wire'

>> mips-linux-ld: ef100_nic.c:(.text+0x2914): undefined reference to `efx_mae_lookup_mport'
Signature · 2 lines
0-DAY CI Kernel Test Service
https://01.org/lkp
#6 lore raw

Re: [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time

In reply to [email protected]
I love your patch! Yet something to improve:

Hi,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/ecree-xilinx-com/sfc-VF-representors-for-EF100-RX-side/20220723-001059
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 949d6b405e6160ae44baea39192d67b39cb7eeac
config: s390-randconfig-r003-20220721 (https://download.01.org/0day-ci/archive/20220723/[email protected]/config)
compiler: s390-linux-gcc (GCC) 12.1.0

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/f00d0e9f57792091c90518b98e8b722a4018f062
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review ecree-xilinx-com/sfc-VF-representors-for-EF100-RX-side/20220723-001059 git checkout f00d0e9f57792091c90518b98e8b722a4018f062
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=s390 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable

All errors (new ones prefixed by >>):

s390-linux-ld: s390-linux-ld: DWARF error: could not find abbrev number 5931 drivers/net/ethernet/sfc/ef100_nic.o: in function `ef100_probe_netdev_pf':
ef100_nic.c:(.text+0x2520): undefined reference to `efx_mae_mport_wire'

>> s390-linux-ld: ef100_nic.c:(.text+0x2534): undefined reference to `efx_mae_lookup_mport'
Signature · 2 lines
0-DAY CI Kernel Test Service
https://01.org/lkp
#10 lore raw

Re: [PATCH net-next 06/14] sfc: receive packets from EF100 VFs into representors

In reply to [email protected]
I love your patch! Yet something to improve:

Hi,

I love your patch! Yet something to improve:

[auto build test ERROR on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/ecree-xilinx-com/sfc-VF-representors-for-EF100-RX-side/20220723-001059
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 949d6b405e6160ae44baea39192d67b39cb7eeac
config: s390-randconfig-r003-20220721 (https://download.01.org/0day-ci/archive/20220723/[email protected]/config)
compiler: s390-linux-gcc (GCC) 12.1.0

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/9c27ea557e7daaf1ef637c760e2ea4b29e5141b0
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review ecree-xilinx-com/sfc-VF-representors-for-EF100-RX-side/20220723-001059 git checkout 9c27ea557e7daaf1ef637c760e2ea4b29e5141b0
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=s390 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable

All errors (new ones prefixed by >>):

s390-linux-ld: s390-linux-ld: DWARF error: could not find abbrev number 119 drivers/net/ethernet/sfc/ef100_nic.o: in function `ef100_probe_netdev_pf':
ef100_nic.c:(.text+0x2520): undefined reference to `efx_mae_mport_wire'
s390-linux-ld: ef100_nic.c:(.text+0x2534): undefined reference to `efx_mae_lookup_mport'
s390-linux-ld: s390-linux-ld: DWARF error: could not find abbrev number 13089 drivers/net/ethernet/sfc/ef100_rx.o: in function `__ef100_rx_packet':
ef100_rx.c:(.text+0x1f8): undefined reference to `efx_ef100_find_rep_by_mport'

>> s390-linux-ld: ef100_rx.c:(.text+0x240): undefined reference to `efx_ef100_rep_rx_packet'
Signature · 2 lines
0-DAY CI Kernel Test Service
https://01.org/lkp
#7 lore raw

Re: [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time

In reply to kernel test robot
Quoted 6 lines · kernel test robot

All errors (new ones prefixed by >>):

   s390-linux-ld: s390-linux-ld: DWARF error: could not find abbrev number 5931
   drivers/net/ethernet/sfc/ef100_nic.o: in function `ef100_probe_netdev_pf':
   ef100_nic.c:(.text+0x2520): undefined reference to `efx_mae_mport_wire'
Quoted 1 line
Quoted 1 line

s390-linux-ld: ef100_nic.c:(.text+0x2534): undefined reference to `efx_mae_lookup_mport'

Oh, I see what's wrong here.
mae.o is under CONFIG_SFC_SRIOV in the Makefile, but these calls into it
are made unconditionally. And I hadn't thought to test with CONFIG_SFC_SRIOV=n. (D'oh!)
I'm able to reproduce on x86_64 with that config change, will fix in v2.

-ed