diff mbox series

[net-next,6/8] octeontx2-pf: Support to enable EDSA/Higig2 pkts parsing

Message ID 20210321120958.17531-7-hkelam@marvell.com
State New
Headers show
Series configuration support for switch headers & phy | expand

Commit Message

Hariprasad Kelam March 21, 2021, 12:09 p.m. UTC
When switch headers like EDSA, Higig2 etc are present in ingress
or egress pkts the pkt parsing done by NPC needs to take additional
headers into account. KPU profile handles these using specific PKINDs
(the iKPU index) to start parsing pkts differently.

This patch enables user to configure these PKINDs into hardware for
proper pkt parsing. Patch also handles changes to max frame size due to
additional headers in pkt.

higig2:
            ethtool --set-priv-flags eth0 higig2 on/off
edsa:
            ethtool --set-priv-flags eth0 edsa on/off

Signed-off-by: Hariprasad Kelam <hkelam@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
---
 .../marvell/octeontx2/nic/otx2_common.c       |   2 +
 .../marvell/octeontx2/nic/otx2_common.h       |  22 +++
 .../marvell/octeontx2/nic/otx2_ethtool.c      | 153 +++++++++++++++++-
 .../ethernet/marvell/octeontx2/nic/otx2_pf.c  |   8 +
 .../marvell/octeontx2/nic/otx2_txrx.c         |   1 +
 .../ethernet/marvell/octeontx2/nic/otx2_vf.c  |  10 ++
 6 files changed, 188 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
index cf7875d51d8..b9a5cd35061 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
@@ -230,6 +230,8 @@  int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
 		return -ENOMEM;
 	}
 
+	/* Add EDSA/HIGIG2 header len to maxlen */
+	pfvf->max_frs = mtu + OTX2_ETH_HLEN + pfvf->addl_mtu;
 	req->maxlen = pfvf->max_frs;
 
 	err = otx2_sync_mbox_msg(&pfvf->mbox);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
index 45730d0d92f..73e927a7843 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
@@ -303,6 +303,7 @@  struct otx2_nic {
 	struct net_device	*netdev;
 	struct dev_hw_ops	*hw_ops;
 	void			*iommu_domain;
+	u16			xtra_hdr;
 	u16			max_frs;
 	u16			rbsize; /* Receive buffer size */
 
@@ -345,6 +346,25 @@  struct otx2_nic {
 	struct refill_work	*refill_wrk;
 	struct workqueue_struct	*otx2_wq;
 	struct work_struct	rx_mode_work;
+
+#define OTX2_PRIV_FLAG_PAM4			BIT(0)
+#define OTX2_PRIV_FLAG_EDSA_HDR			BIT(1)
+#define OTX2_PRIV_FLAG_HIGIG2_HDR		BIT(2)
+#define OTX2_PRIV_FLAG_DEF_MODE			BIT(3)
+#define OTX2_IS_EDSA_ENABLED(flags)		((flags) &              \
+						 OTX2_PRIV_FLAG_EDSA_HDR)
+#define OTX2_IS_HIGIG2_ENABLED(flags)		((flags) &              \
+						 OTX2_PRIV_FLAG_HIGIG2_HDR)
+#define OTX2_IS_DEF_MODE_ENABLED(flags)		((flags) &              \
+						 OTX2_PRIV_FLAG_DEF_MODE)
+	u32		        ethtool_flags;
+
+	/* extended DSA and EDSA  header lengths are 8/16 bytes
+	 * so take max length 16 bytes here
+	 */
+#define OTX2_EDSA_HDR_LEN			16
+#define OTX2_HIGIG2_HDR_LEN			16
+	u32			addl_mtu;
 	struct otx2_mac_table	*mac_table;
 
 	/* Ethtool stuff */
@@ -796,6 +816,8 @@  int otx2_open(struct net_device *netdev);
 int otx2_stop(struct net_device *netdev);
 int otx2_set_real_num_queues(struct net_device *netdev,
 			     int tx_queues, int rx_queues);
+int otx2_set_npc_parse_mode(struct otx2_nic *pfvf, bool unbind);
+
 /* MCAM filter related APIs */
 int otx2_mcam_flow_init(struct otx2_nic *pf);
 int otx2_alloc_mcam_entries(struct otx2_nic *pfvf);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
index 552ecae1dbe..c1405611489 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
@@ -23,8 +23,9 @@ 
 #define DRV_VF_NAME	"octeontx2-nicvf"
 
 static const char otx2_priv_flags_strings[][ETH_GSTRING_LEN] = {
-#define OTX2_PRIV_FLAGS_PAM4 BIT(0)
 	"pam4",
+	"edsa",
+	"higig2",
 };
 
 struct otx2_stat {
@@ -1233,7 +1234,7 @@  static int otx2_set_link_ksettings(struct net_device *netdev,
 	return err;
 }
 
-static int otx2_set_priv_flags(struct net_device *netdev, u32 priv_flags)
+static int otx2_set_phy_mod_type(struct net_device *netdev, bool enable)
 {
 	struct otx2_nic *pfvf = netdev_priv(netdev);
 	struct cgx_phy_mod_type *req;
@@ -1253,7 +1254,7 @@  static int otx2_set_priv_flags(struct net_device *netdev, u32 priv_flags)
 	if (!req)
 		goto end;
 
-	req->mod = priv_flags & OTX2_PRIV_FLAGS_PAM4;
+	req->mod = enable;
 	if (!otx2_sync_mbox_msg(&pfvf->mbox))
 		rc = 0;
 
@@ -1262,21 +1263,157 @@  static int otx2_set_priv_flags(struct net_device *netdev, u32 priv_flags)
 	return rc;
 }
 
+int otx2_set_npc_parse_mode(struct otx2_nic *pfvf, bool unbind)
+{
+	struct npc_set_pkind *req;
+	u32 interface_mode = 0;
+	int rc = -ENOMEM;
+
+	if (OTX2_IS_DEF_MODE_ENABLED(pfvf->ethtool_flags))
+		return 0;
+
+	mutex_lock(&pfvf->mbox.lock);
+	req = otx2_mbox_alloc_msg_npc_set_pkind(&pfvf->mbox);
+	if (!req)
+		goto end;
+
+	if (unbind) {
+		req->mode = OTX2_PRIV_FLAGS_DEFAULT;
+		interface_mode = OTX2_PRIV_FLAG_DEF_MODE;
+	} else if (OTX2_IS_HIGIG2_ENABLED(pfvf->ethtool_flags)) {
+		req->mode = OTX2_PRIV_FLAGS_HIGIG;
+		interface_mode = OTX2_PRIV_FLAG_HIGIG2_HDR;
+	} else if (OTX2_IS_EDSA_ENABLED(pfvf->ethtool_flags)) {
+		req->mode = OTX2_PRIV_FLAGS_EDSA;
+		interface_mode = OTX2_PRIV_FLAG_EDSA_HDR;
+	} else {
+		req->mode = OTX2_PRIV_FLAGS_DEFAULT;
+		interface_mode = OTX2_PRIV_FLAG_DEF_MODE;
+	}
+
+	req->dir  = PKIND_RX;
+
+	/* req AF to change pkind on both the dir */
+	if (req->mode == OTX2_PRIV_FLAGS_HIGIG ||
+	    req->mode == OTX2_PRIV_FLAGS_DEFAULT)
+		req->dir |= PKIND_TX;
+
+	if (!otx2_sync_mbox_msg(&pfvf->mbox))
+		rc = 0;
+	else
+		pfvf->ethtool_flags &= ~interface_mode;
+end:
+	mutex_unlock(&pfvf->mbox.lock);
+	return rc;
+}
+
 static u32 otx2_get_priv_flags(struct net_device *netdev)
 {
 	struct otx2_nic *pfvf = netdev_priv(netdev);
 	struct cgx_fw_data *rsp;
-	u32 priv_flags = 0;
 
 	rsp = otx2_get_fwdata(pfvf);
 
-	if (IS_ERR(rsp))
+	if (IS_ERR(rsp)) {
+		pfvf->ethtool_flags &= ~OTX2_PRIV_FLAG_PAM4;
+	} else {
+		if (rsp->fwdata.phy.misc.mod_type)
+			pfvf->ethtool_flags |= OTX2_PRIV_FLAG_PAM4;
+		else
+			pfvf->ethtool_flags &= ~OTX2_PRIV_FLAG_PAM4;
+	}
+	return pfvf->ethtool_flags;
+}
+
+static int otx2_enable_addl_header(struct net_device *netdev, int bitpos,
+				   u32 len, bool enable)
+{
+	struct otx2_nic *pfvf = netdev_priv(netdev);
+	bool if_up = netif_running(netdev);
+
+	if (enable) {
+		pfvf->ethtool_flags |= BIT(bitpos);
+		pfvf->ethtool_flags &= ~OTX2_PRIV_FLAG_DEF_MODE;
+	} else {
+		pfvf->ethtool_flags &= ~BIT(bitpos);
+		len = 0;
+	}
+
+	if (if_up)
+		otx2_stop(netdev);
+
+	/* Update max FRS so that additional hdrs are considered */
+	pfvf->addl_mtu = len;
+
+	/* Incase HIGIG2 mode is set packet will have 16 bytes of
+	 * extra header at start of packet which stack does not need.
+	 */
+	if (OTX2_IS_HIGIG2_ENABLED(pfvf->ethtool_flags))
+		pfvf->xtra_hdr = 16;
+	else
+		pfvf->xtra_hdr = 0;
+
+	/* NPC parse mode will be updated here */
+	if (if_up) {
+		otx2_open(netdev);
+
+		if (!enable)
+			pfvf->ethtool_flags |= OTX2_PRIV_FLAG_DEF_MODE;
+	}
+
+	return 0;
+}
+
+static int otx2_set_priv_flags(struct net_device *netdev, u32 new_flags)
+{
+	struct otx2_nic *pfvf = netdev_priv(netdev);
+	bool enable = false;
+	int bitnr, rc = 0;
+	u32 chg_flags;
+
+	/* Get latest PAM4 settings */
+	otx2_get_priv_flags(netdev);
+
+	chg_flags = new_flags ^ pfvf->ethtool_flags;
+	if (!chg_flags)
 		return 0;
 
-	if (rsp->fwdata.phy.misc.mod_type)
-		priv_flags |= OTX2_PRIV_FLAGS_PAM4;
+	/* Some are mutually exclusive, so allow only change at a time */
+	if (hweight32(chg_flags) != 1)
+		return -EINVAL;
+
+	bitnr = ffs(chg_flags) - 1;
+	if (new_flags & BIT(bitnr))
+		enable = true;
+
+	switch (BIT(bitnr)) {
+	case OTX2_PRIV_FLAG_PAM4:
+		rc = otx2_set_phy_mod_type(netdev, enable);
+		break;
+	case OTX2_PRIV_FLAG_EDSA_HDR:
+		/* HIGIG & EDSA  are mutual exclusive */
+		if (enable && OTX2_IS_HIGIG2_ENABLED(pfvf->ethtool_flags))
+			return -EINVAL;
+		return otx2_enable_addl_header(netdev, bitnr,
+					       OTX2_EDSA_HDR_LEN, enable);
+	case OTX2_PRIV_FLAG_HIGIG2_HDR:
+		if (enable && OTX2_IS_EDSA_ENABLED(pfvf->ethtool_flags))
+			return -EINVAL;
+		return otx2_enable_addl_header(netdev, bitnr,
+					       OTX2_HIGIG2_HDR_LEN, enable);
+	default:
+		break;
+	}
+
+	/* save the change */
+	if (!rc) {
+		if (enable)
+			pfvf->ethtool_flags |= BIT(bitnr);
+		else
+			pfvf->ethtool_flags &= ~BIT(bitnr);
+	}
 
-	return priv_flags;
+	return rc;
 }
 
 static const struct ethtool_ops otx2_ethtool_ops = {
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index 772a29ba850..977da158f1d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1639,6 +1639,9 @@  int otx2_open(struct net_device *netdev)
 	/* Restore pause frame settings */
 	otx2_config_pause_frm(pf);
 
+	/* Set NPC parsing mode */
+	otx2_set_npc_parse_mode(pf, false);
+
 	err = otx2_rxtx_enable(pf, true);
 	if (err)
 		goto err_tx_stop_queues;
@@ -2511,6 +2514,9 @@  static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	pf->flags |= OTX2_FLAG_RX_PAUSE_ENABLED;
 	pf->flags |= OTX2_FLAG_TX_PAUSE_ENABLED;
 
+	/* Set interface mode as Default */
+	pf->ethtool_flags |= OTX2_PRIV_FLAG_DEF_MODE;
+
 	return 0;
 
 err_mcam_flow_del:
@@ -2671,6 +2677,8 @@  static void otx2_remove(struct pci_dev *pdev)
 	if (pf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED)
 		otx2_config_hw_rx_tstamp(pf, false);
 
+	otx2_set_npc_parse_mode(pf, true);
+
 	cancel_work_sync(&pf->reset_task);
 	/* Disable link notifications */
 	otx2_cgx_config_linkevents(pf, false);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index 22ec03a618b..14292e35ace 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -154,6 +154,7 @@  static void otx2_skb_add_frag(struct otx2_nic *pfvf, struct sk_buff *skb,
 			otx2_set_rxtstamp(pfvf, skb, va);
 			off = OTX2_HW_TIMESTAMP_LEN;
 		}
+		off += pfvf->xtra_hdr;
 	}
 
 	page = virt_to_page(va);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
index 085be90a03e..eb0c009357f 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
@@ -377,6 +377,13 @@  static netdev_tx_t otx2vf_xmit(struct sk_buff *skb, struct net_device *netdev)
 	struct otx2_snd_queue *sq;
 	struct netdev_queue *txq;
 
+	/* Check for minimum and maximum packet length */
+	if (skb->len <= ETH_HLEN ||
+	    (!skb_shinfo(skb)->gso_size && skb->len > vf->max_frs)) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
 	sq = &vf->qset.sq[qidx];
 	txq = netdev_get_tx_queue(netdev, qidx);
 
@@ -612,6 +619,9 @@  static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	vf->flags |= OTX2_FLAG_RX_PAUSE_ENABLED;
 	vf->flags |= OTX2_FLAG_TX_PAUSE_ENABLED;
 
+	/* Set interface mode as Default */
+	vf->ethtool_flags |= OTX2_PRIV_FLAG_DEF_MODE;
+
 	return 0;
 
 err_detach_rsrc: