[PATCH net-next v2 3/5] net: ipqess: Add out-of-band DSA tagging support

Maxime Chevallier
2022-05-14T15:08:28Z

On the IPQ4019, there's an 5 ports switch connected to the CPU through
the IPQESS Ethernet controller. The way the DSA tag is sent-out to that
switch is through the DMA descriptor, due to how tightly it is
integrated with the switch.

This commit uses the out-of-band tagging protocol by getting the source
port from the descriptor, push it into the skb, and have the tagger pull
it to infer the destination netdev. The reverse process is done on the
TX side, where the driver pulls the tag from the skb and builds the
descriptor accordingly.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
V1->V2:
- Use the new tagger, and the dsa_oob_tag_* helpers

drivers/net/ethernet/qualcomm/Kconfig | 3 ++-
drivers/net/ethernet/qualcomm/ipqess/ipqess.c | 27 +++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig
index a723ddbea248..eeb2c608d6b9 100644
--- a/drivers/net/ethernet/qualcomm/Kconfig
+++ b/drivers/net/ethernet/qualcomm/Kconfig
@@ -62,8 +62,9 @@ config QCOM_EMAC

config QCOM_IPQ4019_ESS_EDMA
tristate "Qualcomm Atheros IPQ4019 ESS EDMA support"
- depends on OF
+ depends on OF && NET_DSA
select PHYLINK
+ select NET_DSA_TAG_OOB
help
This driver supports the Qualcomm Atheros IPQ40xx built-in
ESS EDMA ethernet controller.
diff --git a/drivers/net/ethernet/qualcomm/ipqess/ipqess.c b/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
index b11f11f23c11..a068dff19943 100644
--- a/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
+++ b/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
@@ -9,6 +9,7 @@

#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/dsa/oob.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -22,6 +23,7 @@
#include <linux/skbuff.h>
#include <linux/vmalloc.h>
#include <net/checksum.h>
+#include <net/dsa.h>
#include <net/ip6_checksum.h>

#include "ipqess.h"
@@ -334,6 +336,7 @@ static int ipqess_rx_poll(struct ipqess_rx_ring *rx_ring, int budget)
tail &= IPQESS_RFD_CONS_IDX_MASK;

while (done < budget) {
+ struct dsa_oob_tag_info tag_info;
struct ipqess_rx_desc *rd;
struct sk_buff *skb;

@@ -413,6 +416,12 @@ static int ipqess_rx_poll(struct ipqess_rx_ring *rx_ring, int budget)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD),
rd->rrd4);

+ if (netdev_uses_dsa(rx_ring->ess->netdev)) {
+ tag_info.dp = FIELD_GET(IPQESS_RRD_PORT_ID_MASK, rd->rrd1);
+ tag_info.proto = DSA_TAG_PROTO_OOB;
+ dsa_oob_tag_push(skb, &tag_info);
+ }
+
napi_gro_receive(&rx_ring->napi_rx, skb);

rx_ring->ess->stats.rx_packets++;
@@ -727,6 +736,22 @@ static void ipqess_rollback_tx(struct ipqess *eth,
tx_ring->head = start_index;
}

+static void ipqess_process_dsa_tag_sh(struct ipqess *ess, struct sk_buff *skb,
+ u32 *word3)
+{
+ struct dsa_oob_tag_info tag_info;
+
+ if (!netdev_uses_dsa(ess->netdev))
+ return;
+
+ if (dsa_oob_tag_pop(skb, &tag_info))
+ return;
+
+ *word3 |= tag_info.dp << IPQESS_TPD_PORT_BITMAP_SHIFT;
+ *word3 |= BIT(IPQESS_TPD_FROM_CPU_SHIFT);
+ *word3 |= 0x3e << IPQESS_TPD_PORT_BITMAP_SHIFT;
+}
+
static int ipqess_tx_map_and_fill(struct ipqess_tx_ring *tx_ring,
struct sk_buff *skb)
{
@@ -737,6 +762,8 @@ static int ipqess_tx_map_and_fill(struct ipqess_tx_ring *tx_ring,
u16 len;
int i;

+ ipqess_process_dsa_tag_sh(tx_ring->ess, skb, &word3);
+
if (skb_is_gso(skb)) {
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
lso_word1 |= IPQESS_TPD_IPV4_EN;
--
2.36.1