All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side
@ 2022-07-22 16:04 ecree
  2022-07-22 16:04 ` [PATCH net-next 01/14] sfc: plumb ef100 representor stats ecree
                   ` (13 more replies)
  0 siblings, 14 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH net-next 01/14] sfc: plumb ef100 representor stats
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 02/14] sfc: ef100 representor RX NAPI poll ecree
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/ef100_rep.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index d07539f091b8..102071ed051b 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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,

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 02/14] sfc: ef100 representor RX NAPI poll
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
  2022-07-22 16:04 ` [PATCH net-next 01/14] sfc: plumb ef100 representor stats ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 03/14] sfc: ef100 representor RX top half ecree
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/ef100_rep.c | 64 ++++++++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_rep.h | 11 +++++
 2 files changed, 75 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index 102071ed051b..fe45ae963391 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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;
+}
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index d47fd8ff6220..77037ab22052 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -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;
 };
 

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 03/14] sfc: ef100 representor RX top half
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
  2022-07-22 16:04 ` [PATCH net-next 01/14] sfc: plumb ef100 representor stats ecree
  2022-07-22 16:04 ` [PATCH net-next 02/14] sfc: ef100 representor RX NAPI poll ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time ecree
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/ef100_rep.c | 55 ++++++++++++++++++++++++++++
 drivers/net/ethernet/sfc/ef100_rep.h |  1 +
 2 files changed, 56 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index fe45ae963391..e6c6e9e764b2 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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);
+}
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index 77037ab22052..7d2f15cee8d1 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -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 */

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (2 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 03/14] sfc: ef100 representor RX top half ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-23  3:04   ` kernel test robot
  2022-07-23  4:15   ` kernel test robot
  2022-07-22 16:04 ` [PATCH net-next 05/14] sfc: check ef100 RX packets are from the wire ecree
                   ` (9 subsequent siblings)
  13 siblings, 2 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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).

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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(+)

diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 4625d35269e6..10fc79d4720c 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -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:
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
index 40f84a275057..0295933145fa 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.h
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -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;
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index 011ebd46ada5..0cbcadde6677 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -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;
diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h
index 27e69e8a54b6..25c2fd94e158 100644
--- a/drivers/net/ethernet/sfc/mae.h
+++ b/drivers/net/ethernet/sfc/mae.h
@@ -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);

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 05/14] sfc: check ef100 RX packets are from the wire
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (3 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 06/14] sfc: receive packets from EF100 VFs into representors ecree
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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(-)

diff --git a/drivers/net/ethernet/sfc/ef100_rx.c b/drivers/net/ethernet/sfc/ef100_rx.c
index 85207acf7dee..b8da9e3b7bf2 100644
--- a/drivers/net/ethernet/sfc/ef100_rx.c
+++ b/drivers/net/ethernet/sfc/ef100_rx.c
@@ -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;
 }
diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c
index 58ad9d665805..bc840ede3053 100644
--- a/drivers/net/ethernet/sfc/ethtool_common.c
+++ b/drivers/net/ethernet/sfc/ethtool_common.c
@@ -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),
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 4cde54cf77b9..6b64ba3a7d36 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -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;

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 06/14] sfc: receive packets from EF100 VFs into representors
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (4 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 05/14] sfc: check ef100 RX packets are from the wire ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-23  7:18   ` kernel test robot
  2022-07-22 16:04 ` [PATCH net-next 07/14] sfc: insert default MAE rules to connect VFs to representors ecree
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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().

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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(+)

diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index e6c6e9e764b2..c0bc12b9e348 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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;
+}
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index 7d2f15cee8d1..f3787133f793 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -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 */
diff --git a/drivers/net/ethernet/sfc/ef100_rx.c b/drivers/net/ethernet/sfc/ef100_rx.c
index b8da9e3b7bf2..2b5568170340 100644
--- a/drivers/net/ethernet/sfc/ef100_rx.c
+++ b/drivers/net/ethernet/sfc/ef100_rx.c
@@ -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",

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 07/14] sfc: insert default MAE rules to connect VFs to representors
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (5 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 06/14] sfc: receive packets from EF100 VFs into representors ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 08/14] sfc: move table locking into filter_table_{probe,remove} methods ecree
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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

diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index 4c759488fc77..bb06fa228367 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -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
 
diff --git a/drivers/net/ethernet/sfc/ef100.c b/drivers/net/ethernet/sfc/ef100.c
index 425017fbcb25..dbb6fb2e3b14 100644
--- a/drivers/net/ethernet/sfc/ef100.c
+++ b/drivers/net/ethernet/sfc/ef100.c
@@ -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);
diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
index 9e65de1ab889..03aba7bd59ed 100644
--- a/drivers/net/ethernet/sfc/ef100_netdev.c
+++ b/drivers/net/ethernet/sfc/ef100_netdev.c
@@ -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);
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 10fc79d4720c..900d209766ae 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -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:
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index c0bc12b9e348..eac932710c63 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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);
 }
 
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index f3787133f793..070f700893c1 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -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;
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index 0cbcadde6677..ea87ec83e618 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -11,7 +11,7 @@
 
 #include "mae.h"
 #include "mcdi.h"
-#include "mcdi_pcol.h"
+#include "mcdi_pcol_mae.h"
 
 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
 {
@@ -23,6 +23,17 @@ void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
 	*out = EFX_DWORD_VAL(mport);
 }
 
+void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out)
+{
+	efx_dword_t mport;
+
+	EFX_POPULATE_DWORD_3(mport,
+			     MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
+			     MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
+			     MAE_MPORT_SELECTOR_FUNC_VF_ID, MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
+	*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;
@@ -34,6 +45,17 @@ void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out)
 	*out = EFX_DWORD_VAL(mport);
 }
 
+/* Constructs an mport selector from an mport ID, because they're not the same */
+void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out)
+{
+	efx_dword_t mport;
+
+	EFX_POPULATE_DWORD_2(mport,
+			     MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
+			     MAE_MPORT_SELECTOR_MPORT_ID, mport_id);
+	*out = EFX_DWORD_VAL(mport);
+}
+
 /* id is really only 24 bits wide */
 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
 {
@@ -52,3 +74,236 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
 	*id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
 	return 0;
 }
+
+static bool efx_mae_asl_id(u32 id)
+{
+	return !!(id & BIT(31));
+}
+
+int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN);
+	size_t outlen;
+	int rc;
+
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
+		       MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
+		       MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
+		       MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID,
+		       MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL);
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
+		       MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
+	if (act->deliver)
+		MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER,
+			       act->dest_mport);
+	BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL);
+	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf),
+			  outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		return rc;
+	if (outlen < sizeof(outbuf))
+		return -EIO;
+	act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
+	/* We rely on the high bit of AS IDs always being clear.
+	 * The firmware API guarantees this, but let's check it ourselves.
+	 */
+	if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) {
+		efx_mae_free_action_set(efx, act->fw_id);
+		return -EIO;
+	}
+	return 0;
+}
+
+int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1));
+	size_t outlen;
+	int rc;
+
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id);
+	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf),
+			  outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		return rc;
+	if (outlen < sizeof(outbuf))
+		return -EIO;
+	/* FW freed a different ID than we asked for, should never happen.
+	 * Warn because it means we've now got a different idea to the FW of
+	 * what action-sets exist, which could cause mayhem later.
+	 */
+	if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id))
+		return -EIO;
+	return 0;
+}
+
+int efx_mae_alloc_action_set_list(struct efx_nic *efx,
+				  struct efx_tc_action_set_list *acts)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN);
+	struct efx_tc_action_set *act;
+	size_t inlen, outlen, i = 0;
+	efx_dword_t *inbuf;
+	int rc;
+
+	list_for_each_entry(act, &acts->list, list)
+		i++;
+	if (i == 0)
+		return -EINVAL;
+	if (i == 1) {
+		/* Don't wrap an ASL around a single AS, just use the AS_ID
+		 * directly.  ASLs are a more limited resource.
+		 */
+		act = list_first_entry(&acts->list, struct efx_tc_action_set, list);
+		acts->fw_id = act->fw_id;
+		return 0;
+	}
+	if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2)
+		return -EOPNOTSUPP; /* Too many actions */
+	inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i);
+	inbuf = kzalloc(inlen, GFP_KERNEL);
+	if (!inbuf)
+		return -ENOMEM;
+	i = 0;
+	list_for_each_entry(act, &acts->list, list) {
+		MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS,
+				     i, act->fw_id);
+		i++;
+	}
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i);
+	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen,
+			  outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		goto out_free;
+	if (outlen < sizeof(outbuf)) {
+		rc = -EIO;
+		goto out_free;
+	}
+	acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID);
+	/* We rely on the high bit of ASL IDs always being set.
+	 * The firmware API guarantees this, but let's check it ourselves.
+	 */
+	if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) {
+		efx_mae_free_action_set_list(efx, acts);
+		rc = -EIO;
+	}
+out_free:
+	kfree(inbuf);
+	return rc;
+}
+
+int efx_mae_free_action_set_list(struct efx_nic *efx,
+				 struct efx_tc_action_set_list *acts)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1));
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1));
+	size_t outlen;
+	int rc;
+
+	/* If this is just an AS_ID with no ASL wrapper, then there is
+	 * nothing for us to free.  (The AS will be freed later.)
+	 */
+	if (efx_mae_asl_id(acts->fw_id)) {
+		MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID,
+			       acts->fw_id);
+		rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf,
+				  sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
+		if (rc)
+			return rc;
+		if (outlen < sizeof(outbuf))
+			return -EIO;
+		/* FW freed a different ID than we asked for, should never happen.
+		 * Warn because it means we've now got a different idea to the FW of
+		 * what action-set-lists exist, which could cause mayhem later.
+		 */
+		if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id))
+			return -EIO;
+	}
+	/* We're probably about to free @acts, but let's just make sure its
+	 * fw_id is blatted so that it won't look valid if it leaks out.
+	 */
+	acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL;
+	return 0;
+}
+
+static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
+					   const struct efx_tc_match *match)
+{
+	if (match->mask.ingress_port) {
+		if (~match->mask.ingress_port)
+			return -EOPNOTSUPP;
+		MCDI_STRUCT_SET_DWORD(match_crit,
+				      MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR,
+				      match->value.ingress_port);
+	}
+	MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK,
+			      match->mask.ingress_port);
+	return 0;
+}
+
+int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
+			u32 prio, u32 acts_id, u32 *id)
+{
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN));
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
+	MCDI_DECLARE_STRUCT_PTR(match_crit);
+	MCDI_DECLARE_STRUCT_PTR(response);
+	size_t outlen;
+	int rc;
+
+	if (!id)
+		return -EINVAL;
+
+	match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA);
+	response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE);
+	if (efx_mae_asl_id(acts_id)) {
+		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id);
+		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID,
+				      MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL);
+	} else {
+		/* We only had one AS, so we didn't wrap it in an ASL */
+		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID,
+				      MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
+		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id);
+	}
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio);
+	rc = efx_mae_populate_match_criteria(match_crit, match);
+	if (rc)
+		return rc;
+
+	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf),
+			  outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		return rc;
+	if (outlen < sizeof(outbuf))
+		return -EIO;
+	*id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
+	return 0;
+}
+
+int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1));
+	size_t outlen;
+	int rc;
+
+	MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id);
+	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf),
+			  outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		return rc;
+	if (outlen < sizeof(outbuf))
+		return -EIO;
+	/* FW freed a different ID than we asked for, should also never happen.
+	 * Warn because it means we've now got a different idea to the FW of
+	 * what rules exist, which could cause mayhem later.
+	 */
+	if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id))
+		return -EIO;
+	return 0;
+}
diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h
index 25c2fd94e158..e9651f611750 100644
--- a/drivers/net/ethernet/sfc/mae.h
+++ b/drivers/net/ethernet/sfc/mae.h
@@ -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 */
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index f74f6ce8b27d..26bc69f76801 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -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)		\
diff --git a/drivers/net/ethernet/sfc/mcdi_pcol_mae.h b/drivers/net/ethernet/sfc/mcdi_pcol_mae.h
new file mode 100644
index 000000000000..ff6d80c8e486
--- /dev/null
+++ b/drivers/net/ethernet/sfc/mcdi_pcol_mae.h
@@ -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 */
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 6b64ba3a7d36..7ef823d7a89a 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -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;
diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c
new file mode 100644
index 000000000000..0fb01f73c56e
--- /dev/null
+++ b/drivers/net/ethernet/sfc/tc.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2019 Solarflare Communications Inc.
+ * Copyright 2020-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.
+ */
+
+#include "tc.h"
+#include "mae.h"
+#include "ef100_rep.h"
+
+static void efx_tc_free_action_set(struct efx_nic *efx,
+				   struct efx_tc_action_set *act, bool in_hw)
+{
+	/* Failure paths calling this on the 'running action' set in_hw=false,
+	 * because if the alloc had succeeded we'd've put it in acts.list and
+	 * not still have it in act.
+	 */
+	if (in_hw) {
+		efx_mae_free_action_set(efx, act->fw_id);
+		/* in_hw is true iff we are on an acts.list; make sure to
+		 * remove ourselves from that list before we are freed.
+		 */
+		list_del(&act->list);
+	}
+	kfree(act);
+}
+
+static void efx_tc_free_action_set_list(struct efx_nic *efx,
+					struct efx_tc_action_set_list *acts,
+					bool in_hw)
+{
+	struct efx_tc_action_set *act, *next;
+
+	/* Failure paths set in_hw=false, because usually the acts didn't get
+	 * to efx_mae_alloc_action_set_list(); if they did, the failure tree
+	 * has a separate efx_mae_free_action_set_list() before calling us.
+	 */
+	if (in_hw)
+		efx_mae_free_action_set_list(efx, acts);
+	/* Any act that's on the list will be in_hw even if the list isn't */
+	list_for_each_entry_safe(act, next, &acts->list, list)
+		efx_tc_free_action_set(efx, act, true);
+	/* Don't kfree, as acts is embedded inside a struct efx_tc_flow_rule */
+}
+
+static void efx_tc_delete_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rule)
+{
+	efx_mae_delete_rule(efx, rule->fw_id);
+
+	/* Release entries in subsidiary tables */
+	efx_tc_free_action_set_list(efx, &rule->acts, true);
+	rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
+}
+
+static int efx_tc_configure_default_rule(struct efx_nic *efx, u32 ing_port,
+					 u32 eg_port, struct efx_tc_flow_rule *rule)
+{
+	struct efx_tc_action_set_list *acts = &rule->acts;
+	struct efx_tc_match *match = &rule->match;
+	struct efx_tc_action_set *act;
+	int rc;
+
+	match->value.ingress_port = ing_port;
+	match->mask.ingress_port = ~0;
+	act = kzalloc(sizeof(*act), GFP_KERNEL);
+	if (!act)
+		return -ENOMEM;
+	act->deliver = 1;
+	act->dest_mport = eg_port;
+	rc = efx_mae_alloc_action_set(efx, act);
+	if (rc)
+		goto fail1;
+	EFX_WARN_ON_PARANOID(!list_empty(&acts->list));
+	list_add_tail(&act->list, &acts->list);
+	rc = efx_mae_alloc_action_set_list(efx, acts);
+	if (rc)
+		goto fail2;
+	rc = efx_mae_insert_rule(efx, match, EFX_TC_PRIO_DFLT,
+				 acts->fw_id, &rule->fw_id);
+	if (rc)
+		goto fail3;
+	return 0;
+fail3:
+	efx_mae_free_action_set_list(efx, acts);
+fail2:
+	list_del(&act->list);
+	efx_mae_free_action_set(efx, act->fw_id);
+fail1:
+	kfree(act);
+	return rc;
+}
+
+static int efx_tc_configure_default_rule_pf(struct efx_nic *efx)
+{
+	struct efx_tc_flow_rule *rule = &efx->tc->dflt.pf;
+	u32 ing_port, eg_port;
+
+	efx_mae_mport_uplink(efx, &ing_port);
+	efx_mae_mport_wire(efx, &eg_port);
+	return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule);
+}
+
+static int efx_tc_configure_default_rule_wire(struct efx_nic *efx)
+{
+	struct efx_tc_flow_rule *rule = &efx->tc->dflt.wire;
+	u32 ing_port, eg_port;
+
+	efx_mae_mport_wire(efx, &ing_port);
+	efx_mae_mport_uplink(efx, &eg_port);
+	return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule);
+}
+
+int efx_tc_configure_default_rule_rep(struct efx_rep *efv)
+{
+	struct efx_tc_flow_rule *rule = &efv->dflt;
+	struct efx_nic *efx = efv->parent;
+	u32 ing_port, eg_port;
+
+	efx_mae_mport_mport(efx, efv->mport, &ing_port);
+	efx_mae_mport_uplink(efx, &eg_port);
+	return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule);
+}
+
+void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
+				     struct efx_tc_flow_rule *rule)
+{
+	if (rule->fw_id != MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL)
+		efx_tc_delete_rule(efx, rule);
+	rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
+}
+
+int efx_init_tc(struct efx_nic *efx)
+{
+	int rc;
+
+	rc = efx_tc_configure_default_rule_pf(efx);
+	if (rc)
+		return rc;
+	return efx_tc_configure_default_rule_wire(efx);
+}
+
+void efx_fini_tc(struct efx_nic *efx)
+{
+	/* We can get called even if efx_init_struct_tc() failed */
+	if (!efx->tc)
+		return;
+	efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf);
+	efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire);
+}
+
+int efx_init_struct_tc(struct efx_nic *efx)
+{
+	if (efx->type->is_vf)
+		return 0;
+
+	efx->tc = kzalloc(sizeof(*efx->tc), GFP_KERNEL);
+	if (!efx->tc)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list);
+	efx->tc->dflt.pf.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
+	INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list);
+	efx->tc->dflt.wire.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
+	return 0;
+}
+
+void efx_fini_struct_tc(struct efx_nic *efx)
+{
+	if (!efx->tc)
+		return;
+
+	EFX_WARN_ON_PARANOID(efx->tc->dflt.pf.fw_id !=
+			     MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
+	EFX_WARN_ON_PARANOID(efx->tc->dflt.wire.fw_id !=
+			     MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
+	kfree(efx->tc);
+	efx->tc = NULL;
+}
diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h
new file mode 100644
index 000000000000..46c5101eaa8d
--- /dev/null
+++ b/drivers/net/ethernet/sfc/tc.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for Solarflare network controllers and boards
+ * Copyright 2019 Solarflare Communications Inc.
+ * Copyright 2020-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 EFX_TC_H
+#define EFX_TC_H
+#include "net_driver.h"
+
+struct efx_tc_action_set {
+	u16 deliver:1;
+	u32 dest_mport;
+	u32 fw_id; /* index of this entry in firmware actions table */
+	struct list_head list;
+};
+
+struct efx_tc_match_fields {
+	/* L1 */
+	u32 ingress_port;
+};
+
+struct efx_tc_match {
+	struct efx_tc_match_fields value;
+	struct efx_tc_match_fields mask;
+};
+
+struct efx_tc_action_set_list {
+	struct list_head list;
+	u32 fw_id;
+};
+
+struct efx_tc_flow_rule {
+	struct efx_tc_match match;
+	struct efx_tc_action_set_list acts;
+	u32 fw_id;
+};
+
+enum efx_tc_rule_prios {
+	EFX_TC_PRIO_DFLT, /* Default switch rule; one of efx_tc_default_rules */
+	EFX_TC_PRIO__NUM
+};
+
+/**
+ * struct efx_tc_state - control plane data for TC offload
+ *
+ * @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 {
+	struct {
+		struct efx_tc_flow_rule pf;
+		struct efx_tc_flow_rule wire;
+	} dflt;
+};
+
+struct efx_rep;
+
+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_init_tc(struct efx_nic *efx);
+void efx_fini_tc(struct efx_nic *efx);
+
+int efx_init_struct_tc(struct efx_nic *efx);
+void efx_fini_struct_tc(struct efx_nic *efx);
+
+#endif /* EFX_TC_H */

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 08/14] sfc: move table locking into filter_table_{probe,remove} methods
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (6 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 07/14] sfc: insert default MAE rules to connect VFs to representors ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 09/14] sfc: use a dynamic m-port for representor RX and set it promisc ecree
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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(-)

diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index ab979fd11133..ee734b69150f 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -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,
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 900d209766ae..fa459b95f367 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -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
diff --git a/drivers/net/ethernet/sfc/ef10_sriov.c b/drivers/net/ethernet/sfc/ef10_sriov.c
index 92550c7e85ce..9aae0d8b713f 100644
--- a/drivers/net/ethernet/sfc/ef10_sriov.c
+++ b/drivers/net/ethernet/sfc/ef10_sriov.c
@@ -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,
diff --git a/drivers/net/ethernet/sfc/mcdi_filters.h b/drivers/net/ethernet/sfc/mcdi_filters.h
index 06426aa9f2f3..c0d6558b9fd2 100644
--- a/drivers/net/ethernet/sfc/mcdi_filters.h
+++ b/drivers/net/ethernet/sfc/mcdi_filters.h
@@ -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;
 };
 
diff --git a/drivers/net/ethernet/sfc/rx_common.c b/drivers/net/ethernet/sfc/rx_common.c
index bd21d6ac778a..4826e6a7e4ce 100644
--- a/drivers/net/ethernet/sfc/rx_common.c
+++ b/drivers/net/ethernet/sfc/rx_common.c
@@ -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

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 09/14] sfc: use a dynamic m-port for representor RX and set it promisc
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (7 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 08/14] sfc: move table locking into filter_table_{probe,remove} methods ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 10/14] sfc: look up VF's client ID when creating representor ecree
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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).

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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(-)

diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index fa459b95f367..0ae27de314b5 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -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);
diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h
index 40b2af8bfb81..4d928839d292 100644
--- a/drivers/net/ethernet/sfc/filter.h
+++ b/drivers/net/ethernet/sfc/filter.h
@@ -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)
 {
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index ea87ec83e618..97627f5e3674 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -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;
diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h
index e9651f611750..0369be4d8983 100644
--- a/drivers/net/ethernet/sfc/mae.h
+++ b/drivers/net/ethernet/sfc/mae.h
@@ -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);
diff --git a/drivers/net/ethernet/sfc/mcdi_filters.c b/drivers/net/ethernet/sfc/mcdi_filters.c
index 1523be77b9db..4ff6586116ee 100644
--- a/drivers/net/ethernet/sfc/mcdi_filters.c
+++ b/drivers/net/ethernet/sfc/mcdi_filters.c
@@ -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);
diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c
index 0fb01f73c56e..0c0aeb91f500 100644
--- a/drivers/net/ethernet/sfc/tc.c
+++ b/drivers/net/ethernet/sfc/tc.c
@@ -12,6 +12,7 @@
 #include "tc.h"
 #include "mae.h"
 #include "ef100_rep.h"
+#include "efx.h"
 
 static void efx_tc_free_action_set(struct efx_nic *efx,
 				   struct efx_tc_action_set *act, bool in_hw)
@@ -122,7 +123,7 @@ int efx_tc_configure_default_rule_rep(struct efx_rep *efv)
 	u32 ing_port, eg_port;
 
 	efx_mae_mport_mport(efx, efv->mport, &ing_port);
-	efx_mae_mport_uplink(efx, &eg_port);
+	efx_mae_mport_mport(efx, efx->tc->reps_mport_id, &eg_port);
 	return efx_tc_configure_default_rule(efx, ing_port, eg_port, rule);
 }
 
@@ -134,6 +135,68 @@ void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
 	rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
 }
 
+static int efx_tc_configure_rep_mport(struct efx_nic *efx)
+{
+	u32 rep_mport_label;
+	int rc;
+
+	rc = efx_mae_allocate_mport(efx, &efx->tc->reps_mport_id, &rep_mport_label);
+	if (rc)
+		return rc;
+	pci_dbg(efx->pci_dev, "created rep mport 0x%08x (0x%04x)\n",
+		efx->tc->reps_mport_id, rep_mport_label);
+	/* Use mport *selector* as vport ID */
+	efx_mae_mport_mport(efx, efx->tc->reps_mport_id,
+			    &efx->tc->reps_mport_vport_id);
+	return 0;
+}
+
+static void efx_tc_deconfigure_rep_mport(struct efx_nic *efx)
+{
+	efx_mae_free_mport(efx, efx->tc->reps_mport_id);
+	efx->tc->reps_mport_id = MAE_MPORT_SELECTOR_NULL;
+}
+
+int efx_tc_insert_rep_filters(struct efx_nic *efx)
+{
+	struct efx_filter_spec promisc, allmulti;
+	int rc;
+
+	if (efx->type->is_vf)
+		return 0;
+	if (!efx->tc)
+		return 0;
+	efx_filter_init_rx(&promisc, EFX_FILTER_PRI_REQUIRED, 0, 0);
+	efx_filter_set_uc_def(&promisc);
+	efx_filter_set_vport_id(&promisc, efx->tc->reps_mport_vport_id);
+	rc = efx_filter_insert_filter(efx, &promisc, false);
+	if (rc < 0)
+		return rc;
+	efx->tc->reps_filter_uc = rc;
+	efx_filter_init_rx(&allmulti, EFX_FILTER_PRI_REQUIRED, 0, 0);
+	efx_filter_set_mc_def(&allmulti);
+	efx_filter_set_vport_id(&allmulti, efx->tc->reps_mport_vport_id);
+	rc = efx_filter_insert_filter(efx, &allmulti, false);
+	if (rc < 0)
+		return rc;
+	efx->tc->reps_filter_mc = rc;
+	return 0;
+}
+
+void efx_tc_remove_rep_filters(struct efx_nic *efx)
+{
+	if (efx->type->is_vf)
+		return;
+	if (!efx->tc)
+		return;
+	if (efx->tc->reps_filter_mc >= 0)
+		efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, efx->tc->reps_filter_mc);
+	efx->tc->reps_filter_mc = -1;
+	if (efx->tc->reps_filter_uc >= 0)
+		efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED, efx->tc->reps_filter_uc);
+	efx->tc->reps_filter_uc = -1;
+}
+
 int efx_init_tc(struct efx_nic *efx)
 {
 	int rc;
@@ -141,7 +204,10 @@ int efx_init_tc(struct efx_nic *efx)
 	rc = efx_tc_configure_default_rule_pf(efx);
 	if (rc)
 		return rc;
-	return efx_tc_configure_default_rule_wire(efx);
+	rc = efx_tc_configure_default_rule_wire(efx);
+	if (rc)
+		return rc;
+	return efx_tc_configure_rep_mport(efx);
 }
 
 void efx_fini_tc(struct efx_nic *efx)
@@ -149,6 +215,7 @@ void efx_fini_tc(struct efx_nic *efx)
 	/* We can get called even if efx_init_struct_tc() failed */
 	if (!efx->tc)
 		return;
+	efx_tc_deconfigure_rep_mport(efx);
 	efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf);
 	efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire);
 }
@@ -162,6 +229,8 @@ int efx_init_struct_tc(struct efx_nic *efx)
 	if (!efx->tc)
 		return -ENOMEM;
 
+	efx->tc->reps_filter_uc = -1;
+	efx->tc->reps_filter_mc = -1;
 	INIT_LIST_HEAD(&efx->tc->dflt.pf.acts.list);
 	efx->tc->dflt.pf.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL;
 	INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list);
diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h
index 46c5101eaa8d..309123c6b386 100644
--- a/drivers/net/ethernet/sfc/tc.h
+++ b/drivers/net/ethernet/sfc/tc.h
@@ -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);
 

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 10/14] sfc: look up VF's client ID when creating representor
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (8 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 09/14] sfc: use a dynamic m-port for representor RX and set it promisc ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 11/14] sfc: fetch existing assigned MAC address from FW when creating VF rep ecree
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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(+)

diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 0ae27de314b5..7ca4e9769455 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -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;
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
index 0295933145fa..cf78a5a2b7d6 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.h
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -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);
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index eac932710c63..3c5f22a6c3b5 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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);
 }
 
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index 070f700893c1..0fa6ad6b2c92 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -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;

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 11/14] sfc: fetch existing assigned MAC address from FW when creating VF rep
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (9 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 10/14] sfc: look up VF's client ID when creating representor ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 12/14] sfc: set EF100 VF MAC address through representor ecree
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 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(-)

diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 7ca4e9769455..92908640a0a6 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -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 */
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
index cf78a5a2b7d6..5241fc1d928e 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.h
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -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);
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index 3c5f22a6c3b5..ebab4579e63b 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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);

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 12/14] sfc: set EF100 VF MAC address through representor
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (10 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 11/14] sfc: fetch existing assigned MAC address from FW when creating VF rep ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 13/14] sfc: get provisioned MAC address on EF100 VF probe ecree
  2022-07-22 16:04 ` [PATCH net-next 14/14] sfc: implement ethtool get/set RX ring size for EF100 reps ecree
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/ef100_rep.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index ebab4579e63b..58365a4c7c6a 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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,
 };
 

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 13/14] sfc: get provisioned MAC address on EF100 VF probe
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (11 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 12/14] sfc: set EF100 VF MAC address through representor ecree
@ 2022-07-22 16:04 ` ecree
  2022-07-22 16:04 ` [PATCH net-next 14/14] sfc: implement ethtool get/set RX ring size for EF100 reps ecree
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/ef100_netdev.c | 10 ++++++++++
 drivers/net/ethernet/sfc/ef100_nic.c    | 11 -----------
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
index 03aba7bd59ed..0f7447858837 100644
--- a/drivers/net/ethernet/sfc/ef100_netdev.c
+++ b/drivers/net/ethernet/sfc/ef100_netdev.c
@@ -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;
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 92908640a0a6..b74b0d60528e 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -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)

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next 14/14] sfc: implement ethtool get/set RX ring size for EF100 reps
  2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
                   ` (12 preceding siblings ...)
  2022-07-22 16:04 ` [PATCH net-next 13/14] sfc: get provisioned MAC address on EF100 VF probe ecree
@ 2022-07-22 16:04 ` ecree
  13 siblings, 0 replies; 19+ messages in thread
From: ecree @ 2022-07-22 16:04 UTC (permalink / raw)
  To: davem, kuba, pabeni, linux-net-drivers; +Cc: netdev, Edward Cree

From: Edward Cree <ecree.xilinx@gmail.com>

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.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/ef100_rep.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index 58365a4c7c6a..efbe7d482d7b 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -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,

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time
  2022-07-22 16:04 ` [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time ecree
@ 2022-07-23  3:04   ` kernel test robot
  2022-07-23  4:15   ` kernel test robot
  1 sibling, 0 replies; 19+ messages in thread
From: kernel test robot @ 2022-07-23  3:04 UTC (permalink / raw)
  To: ecree, davem, kuba, pabeni, linux-net-drivers
  Cc: kbuild-all, netdev, Edward Cree

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/202207231002.Bimz8unB-lkp@intel.com/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
Reported-by: kernel test robot <lkp@intel.com>

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'

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time
  2022-07-22 16:04 ` [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time ecree
  2022-07-23  3:04   ` kernel test robot
@ 2022-07-23  4:15   ` kernel test robot
  2022-07-26 14:21     ` Edward Cree
  1 sibling, 1 reply; 19+ messages in thread
From: kernel test robot @ 2022-07-23  4:15 UTC (permalink / raw)
  To: ecree, davem, kuba, pabeni, linux-net-drivers
  Cc: kbuild-all, netdev, Edward Cree

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/202207231215.nHYCJokG-lkp@intel.com/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
Reported-by: kernel test robot <lkp@intel.com>

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'

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next 06/14] sfc: receive packets from EF100 VFs into representors
  2022-07-22 16:04 ` [PATCH net-next 06/14] sfc: receive packets from EF100 VFs into representors ecree
@ 2022-07-23  7:18   ` kernel test robot
  0 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2022-07-23  7:18 UTC (permalink / raw)
  To: ecree, davem, kuba, pabeni, linux-net-drivers
  Cc: kbuild-all, netdev, Edward Cree

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/202207231534.YefS8hZX-lkp@intel.com/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
Reported-by: kernel test robot <lkp@intel.com>

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'

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time
  2022-07-23  4:15   ` kernel test robot
@ 2022-07-26 14:21     ` Edward Cree
  0 siblings, 0 replies; 19+ messages in thread
From: Edward Cree @ 2022-07-26 14:21 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 710 bytes --]

On 23/07/2022 05:15, kernel test robot wrote:

> 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'

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

[-- Attachment #2: attachment.htm --]
[-- Type: text/html, Size: 1181 bytes --]

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2022-07-26 14:21 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-22 16:04 [PATCH net-next 00/14] sfc: VF representors for EF100 - RX side ecree
2022-07-22 16:04 ` [PATCH net-next 01/14] sfc: plumb ef100 representor stats ecree
2022-07-22 16:04 ` [PATCH net-next 02/14] sfc: ef100 representor RX NAPI poll ecree
2022-07-22 16:04 ` [PATCH net-next 03/14] sfc: ef100 representor RX top half ecree
2022-07-22 16:04 ` [PATCH net-next 04/14] sfc: determine wire m-port at EF100 PF probe time ecree
2022-07-23  3:04   ` kernel test robot
2022-07-23  4:15   ` kernel test robot
2022-07-26 14:21     ` Edward Cree
2022-07-22 16:04 ` [PATCH net-next 05/14] sfc: check ef100 RX packets are from the wire ecree
2022-07-22 16:04 ` [PATCH net-next 06/14] sfc: receive packets from EF100 VFs into representors ecree
2022-07-23  7:18   ` kernel test robot
2022-07-22 16:04 ` [PATCH net-next 07/14] sfc: insert default MAE rules to connect VFs to representors ecree
2022-07-22 16:04 ` [PATCH net-next 08/14] sfc: move table locking into filter_table_{probe,remove} methods ecree
2022-07-22 16:04 ` [PATCH net-next 09/14] sfc: use a dynamic m-port for representor RX and set it promisc ecree
2022-07-22 16:04 ` [PATCH net-next 10/14] sfc: look up VF's client ID when creating representor ecree
2022-07-22 16:04 ` [PATCH net-next 11/14] sfc: fetch existing assigned MAC address from FW when creating VF rep ecree
2022-07-22 16:04 ` [PATCH net-next 12/14] sfc: set EF100 VF MAC address through representor ecree
2022-07-22 16:04 ` [PATCH net-next 13/14] sfc: get provisioned MAC address on EF100 VF probe ecree
2022-07-22 16:04 ` [PATCH net-next 14/14] sfc: implement ethtool get/set RX ring size for EF100 reps ecree

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.