162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/* Microchip Sparx5 Switch driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "sparx5_main_regs.h"
862306a36Sopenharmony_ci#include "sparx5_main.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define XTR_EOF_0     ntohl((__force __be32)0x80000000u)
1162306a36Sopenharmony_ci#define XTR_EOF_1     ntohl((__force __be32)0x80000001u)
1262306a36Sopenharmony_ci#define XTR_EOF_2     ntohl((__force __be32)0x80000002u)
1362306a36Sopenharmony_ci#define XTR_EOF_3     ntohl((__force __be32)0x80000003u)
1462306a36Sopenharmony_ci#define XTR_PRUNED    ntohl((__force __be32)0x80000004u)
1562306a36Sopenharmony_ci#define XTR_ABORT     ntohl((__force __be32)0x80000005u)
1662306a36Sopenharmony_ci#define XTR_ESCAPE    ntohl((__force __be32)0x80000006u)
1762306a36Sopenharmony_ci#define XTR_NOT_READY ntohl((__force __be32)0x80000007u)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define XTR_VALID_BYTES(x)      (4 - ((x) & 3))
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define INJ_TIMEOUT_NS 50000
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_civoid sparx5_xtr_flush(struct sparx5 *sparx5, u8 grp)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	/* Start flush */
2662306a36Sopenharmony_ci	spx5_wr(QS_XTR_FLUSH_FLUSH_SET(BIT(grp)), sparx5, QS_XTR_FLUSH);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	/* Allow to drain */
2962306a36Sopenharmony_ci	mdelay(1);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	/* All Queues normal */
3262306a36Sopenharmony_ci	spx5_wr(0, sparx5, QS_XTR_FLUSH);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_civoid sparx5_ifh_parse(u32 *ifh, struct frame_info *info)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	u8 *xtr_hdr = (u8 *)ifh;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* FWD is bit 45-72 (28 bits), but we only read the 27 LSB for now */
4062306a36Sopenharmony_ci	u32 fwd =
4162306a36Sopenharmony_ci		((u32)xtr_hdr[27] << 24) |
4262306a36Sopenharmony_ci		((u32)xtr_hdr[28] << 16) |
4362306a36Sopenharmony_ci		((u32)xtr_hdr[29] <<  8) |
4462306a36Sopenharmony_ci		((u32)xtr_hdr[30] <<  0);
4562306a36Sopenharmony_ci	fwd = (fwd >> 5);
4662306a36Sopenharmony_ci	info->src_port = FIELD_GET(GENMASK(7, 1), fwd);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	info->timestamp =
4962306a36Sopenharmony_ci		((u64)xtr_hdr[2] << 24) |
5062306a36Sopenharmony_ci		((u64)xtr_hdr[3] << 16) |
5162306a36Sopenharmony_ci		((u64)xtr_hdr[4] <<  8) |
5262306a36Sopenharmony_ci		((u64)xtr_hdr[5] <<  0);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	bool eof_flag = false, pruned_flag = false, abort_flag = false;
5862306a36Sopenharmony_ci	struct net_device *netdev;
5962306a36Sopenharmony_ci	struct sparx5_port *port;
6062306a36Sopenharmony_ci	struct frame_info fi;
6162306a36Sopenharmony_ci	int i, byte_cnt = 0;
6262306a36Sopenharmony_ci	struct sk_buff *skb;
6362306a36Sopenharmony_ci	u32 ifh[IFH_LEN];
6462306a36Sopenharmony_ci	u32 *rxbuf;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Get IFH */
6762306a36Sopenharmony_ci	for (i = 0; i < IFH_LEN; i++)
6862306a36Sopenharmony_ci		ifh[i] = spx5_rd(sparx5, QS_XTR_RD(grp));
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* Decode IFH (whats needed) */
7162306a36Sopenharmony_ci	sparx5_ifh_parse(ifh, &fi);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* Map to port netdev */
7462306a36Sopenharmony_ci	port = fi.src_port < SPX5_PORTS ?
7562306a36Sopenharmony_ci		sparx5->ports[fi.src_port] : NULL;
7662306a36Sopenharmony_ci	if (!port || !port->ndev) {
7762306a36Sopenharmony_ci		dev_err(sparx5->dev, "Data on inactive port %d\n", fi.src_port);
7862306a36Sopenharmony_ci		sparx5_xtr_flush(sparx5, grp);
7962306a36Sopenharmony_ci		return;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* Have netdev, get skb */
8362306a36Sopenharmony_ci	netdev = port->ndev;
8462306a36Sopenharmony_ci	skb = netdev_alloc_skb(netdev, netdev->mtu + ETH_HLEN);
8562306a36Sopenharmony_ci	if (!skb) {
8662306a36Sopenharmony_ci		sparx5_xtr_flush(sparx5, grp);
8762306a36Sopenharmony_ci		dev_err(sparx5->dev, "No skb allocated\n");
8862306a36Sopenharmony_ci		netdev->stats.rx_dropped++;
8962306a36Sopenharmony_ci		return;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	rxbuf = (u32 *)skb->data;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* Now, pull frame data */
9462306a36Sopenharmony_ci	while (!eof_flag) {
9562306a36Sopenharmony_ci		u32 val = spx5_rd(sparx5, QS_XTR_RD(grp));
9662306a36Sopenharmony_ci		u32 cmp = val;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		if (byte_swap)
9962306a36Sopenharmony_ci			cmp = ntohl((__force __be32)val);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		switch (cmp) {
10262306a36Sopenharmony_ci		case XTR_NOT_READY:
10362306a36Sopenharmony_ci			break;
10462306a36Sopenharmony_ci		case XTR_ABORT:
10562306a36Sopenharmony_ci			/* No accompanying data */
10662306a36Sopenharmony_ci			abort_flag = true;
10762306a36Sopenharmony_ci			eof_flag = true;
10862306a36Sopenharmony_ci			break;
10962306a36Sopenharmony_ci		case XTR_EOF_0:
11062306a36Sopenharmony_ci		case XTR_EOF_1:
11162306a36Sopenharmony_ci		case XTR_EOF_2:
11262306a36Sopenharmony_ci		case XTR_EOF_3:
11362306a36Sopenharmony_ci			/* This assumes STATUS_WORD_POS == 1, Status
11462306a36Sopenharmony_ci			 * just after last data
11562306a36Sopenharmony_ci			 */
11662306a36Sopenharmony_ci			if (!byte_swap)
11762306a36Sopenharmony_ci				val = ntohl((__force __be32)val);
11862306a36Sopenharmony_ci			byte_cnt -= (4 - XTR_VALID_BYTES(val));
11962306a36Sopenharmony_ci			eof_flag = true;
12062306a36Sopenharmony_ci			break;
12162306a36Sopenharmony_ci		case XTR_PRUNED:
12262306a36Sopenharmony_ci			/* But get the last 4 bytes as well */
12362306a36Sopenharmony_ci			eof_flag = true;
12462306a36Sopenharmony_ci			pruned_flag = true;
12562306a36Sopenharmony_ci			fallthrough;
12662306a36Sopenharmony_ci		case XTR_ESCAPE:
12762306a36Sopenharmony_ci			*rxbuf = spx5_rd(sparx5, QS_XTR_RD(grp));
12862306a36Sopenharmony_ci			byte_cnt += 4;
12962306a36Sopenharmony_ci			rxbuf++;
13062306a36Sopenharmony_ci			break;
13162306a36Sopenharmony_ci		default:
13262306a36Sopenharmony_ci			*rxbuf = val;
13362306a36Sopenharmony_ci			byte_cnt += 4;
13462306a36Sopenharmony_ci			rxbuf++;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	if (abort_flag || pruned_flag || !eof_flag) {
13962306a36Sopenharmony_ci		netdev_err(netdev, "Discarded frame: abort:%d pruned:%d eof:%d\n",
14062306a36Sopenharmony_ci			   abort_flag, pruned_flag, eof_flag);
14162306a36Sopenharmony_ci		kfree_skb(skb);
14262306a36Sopenharmony_ci		netdev->stats.rx_dropped++;
14362306a36Sopenharmony_ci		return;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* Everything we see on an interface that is in the HW bridge
14762306a36Sopenharmony_ci	 * has already been forwarded
14862306a36Sopenharmony_ci	 */
14962306a36Sopenharmony_ci	if (test_bit(port->portno, sparx5->bridge_mask))
15062306a36Sopenharmony_ci		skb->offload_fwd_mark = 1;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* Finish up skb */
15362306a36Sopenharmony_ci	skb_put(skb, byte_cnt - ETH_FCS_LEN);
15462306a36Sopenharmony_ci	eth_skb_pad(skb);
15562306a36Sopenharmony_ci	sparx5_ptp_rxtstamp(sparx5, skb, fi.timestamp);
15662306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, netdev);
15762306a36Sopenharmony_ci	netdev->stats.rx_bytes += skb->len;
15862306a36Sopenharmony_ci	netdev->stats.rx_packets++;
15962306a36Sopenharmony_ci	netif_rx(skb);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int sparx5_inject(struct sparx5 *sparx5,
16362306a36Sopenharmony_ci			 u32 *ifh,
16462306a36Sopenharmony_ci			 struct sk_buff *skb,
16562306a36Sopenharmony_ci			 struct net_device *ndev)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	int grp = INJ_QUEUE;
16862306a36Sopenharmony_ci	u32 val, w, count;
16962306a36Sopenharmony_ci	u8 *buf;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	val = spx5_rd(sparx5, QS_INJ_STATUS);
17262306a36Sopenharmony_ci	if (!(QS_INJ_STATUS_FIFO_RDY_GET(val) & BIT(grp))) {
17362306a36Sopenharmony_ci		pr_err_ratelimited("Injection: Queue not ready: 0x%lx\n",
17462306a36Sopenharmony_ci				   QS_INJ_STATUS_FIFO_RDY_GET(val));
17562306a36Sopenharmony_ci		return -EBUSY;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* Indicate SOF */
17962306a36Sopenharmony_ci	spx5_wr(QS_INJ_CTRL_SOF_SET(1) |
18062306a36Sopenharmony_ci		QS_INJ_CTRL_GAP_SIZE_SET(1),
18162306a36Sopenharmony_ci		sparx5, QS_INJ_CTRL(grp));
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* Write the IFH to the chip. */
18462306a36Sopenharmony_ci	for (w = 0; w < IFH_LEN; w++)
18562306a36Sopenharmony_ci		spx5_wr(ifh[w], sparx5, QS_INJ_WR(grp));
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	/* Write words, round up */
18862306a36Sopenharmony_ci	count = DIV_ROUND_UP(skb->len, 4);
18962306a36Sopenharmony_ci	buf = skb->data;
19062306a36Sopenharmony_ci	for (w = 0; w < count; w++, buf += 4) {
19162306a36Sopenharmony_ci		val = get_unaligned((const u32 *)buf);
19262306a36Sopenharmony_ci		spx5_wr(val, sparx5, QS_INJ_WR(grp));
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* Add padding */
19662306a36Sopenharmony_ci	while (w < (60 / 4)) {
19762306a36Sopenharmony_ci		spx5_wr(0, sparx5, QS_INJ_WR(grp));
19862306a36Sopenharmony_ci		w++;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Indicate EOF and valid bytes in last word */
20262306a36Sopenharmony_ci	spx5_wr(QS_INJ_CTRL_GAP_SIZE_SET(1) |
20362306a36Sopenharmony_ci		QS_INJ_CTRL_VLD_BYTES_SET(skb->len < 60 ? 0 : skb->len % 4) |
20462306a36Sopenharmony_ci		QS_INJ_CTRL_EOF_SET(1),
20562306a36Sopenharmony_ci		sparx5, QS_INJ_CTRL(grp));
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* Add dummy CRC */
20862306a36Sopenharmony_ci	spx5_wr(0, sparx5, QS_INJ_WR(grp));
20962306a36Sopenharmony_ci	w++;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	val = spx5_rd(sparx5, QS_INJ_STATUS);
21262306a36Sopenharmony_ci	if (QS_INJ_STATUS_WMARK_REACHED_GET(val) & BIT(grp)) {
21362306a36Sopenharmony_ci		struct sparx5_port *port = netdev_priv(ndev);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		pr_err_ratelimited("Injection: Watermark reached: 0x%lx\n",
21662306a36Sopenharmony_ci				   QS_INJ_STATUS_WMARK_REACHED_GET(val));
21762306a36Sopenharmony_ci		netif_stop_queue(ndev);
21862306a36Sopenharmony_ci		hrtimer_start(&port->inj_timer, INJ_TIMEOUT_NS,
21962306a36Sopenharmony_ci			      HRTIMER_MODE_REL);
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return NETDEV_TX_OK;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cinetdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct net_device_stats *stats = &dev->stats;
22862306a36Sopenharmony_ci	struct sparx5_port *port = netdev_priv(dev);
22962306a36Sopenharmony_ci	struct sparx5 *sparx5 = port->sparx5;
23062306a36Sopenharmony_ci	u32 ifh[IFH_LEN];
23162306a36Sopenharmony_ci	netdev_tx_t ret;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	memset(ifh, 0, IFH_LEN * 4);
23462306a36Sopenharmony_ci	sparx5_set_port_ifh(ifh, port->portno);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (sparx5->ptp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
23762306a36Sopenharmony_ci		if (sparx5_ptp_txtstamp_request(port, skb) < 0)
23862306a36Sopenharmony_ci			return NETDEV_TX_BUSY;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		sparx5_set_port_ifh_rew_op(ifh, SPARX5_SKB_CB(skb)->rew_op);
24162306a36Sopenharmony_ci		sparx5_set_port_ifh_pdu_type(ifh, SPARX5_SKB_CB(skb)->pdu_type);
24262306a36Sopenharmony_ci		sparx5_set_port_ifh_pdu_w16_offset(ifh, SPARX5_SKB_CB(skb)->pdu_w16_offset);
24362306a36Sopenharmony_ci		sparx5_set_port_ifh_timestamp(ifh, SPARX5_SKB_CB(skb)->ts_id);
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	skb_tx_timestamp(skb);
24762306a36Sopenharmony_ci	spin_lock(&sparx5->tx_lock);
24862306a36Sopenharmony_ci	if (sparx5->fdma_irq > 0)
24962306a36Sopenharmony_ci		ret = sparx5_fdma_xmit(sparx5, ifh, skb);
25062306a36Sopenharmony_ci	else
25162306a36Sopenharmony_ci		ret = sparx5_inject(sparx5, ifh, skb, dev);
25262306a36Sopenharmony_ci	spin_unlock(&sparx5->tx_lock);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (ret == -EBUSY)
25562306a36Sopenharmony_ci		goto busy;
25662306a36Sopenharmony_ci	if (ret < 0)
25762306a36Sopenharmony_ci		goto drop;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	stats->tx_bytes += skb->len;
26062306a36Sopenharmony_ci	stats->tx_packets++;
26162306a36Sopenharmony_ci	sparx5->tx.packets++;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
26462306a36Sopenharmony_ci	    SPARX5_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
26562306a36Sopenharmony_ci		return NETDEV_TX_OK;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	dev_consume_skb_any(skb);
26862306a36Sopenharmony_ci	return NETDEV_TX_OK;
26962306a36Sopenharmony_cidrop:
27062306a36Sopenharmony_ci	stats->tx_dropped++;
27162306a36Sopenharmony_ci	sparx5->tx.dropped++;
27262306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
27362306a36Sopenharmony_ci	return NETDEV_TX_OK;
27462306a36Sopenharmony_cibusy:
27562306a36Sopenharmony_ci	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
27662306a36Sopenharmony_ci	    SPARX5_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP)
27762306a36Sopenharmony_ci		sparx5_ptp_txtstamp_release(port, skb);
27862306a36Sopenharmony_ci	return NETDEV_TX_BUSY;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic enum hrtimer_restart sparx5_injection_timeout(struct hrtimer *tmr)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct sparx5_port *port = container_of(tmr, struct sparx5_port,
28462306a36Sopenharmony_ci						inj_timer);
28562306a36Sopenharmony_ci	int grp = INJ_QUEUE;
28662306a36Sopenharmony_ci	u32 val;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	val = spx5_rd(port->sparx5, QS_INJ_STATUS);
28962306a36Sopenharmony_ci	if (QS_INJ_STATUS_WMARK_REACHED_GET(val) & BIT(grp)) {
29062306a36Sopenharmony_ci		pr_err_ratelimited("Injection: Reset watermark count\n");
29162306a36Sopenharmony_ci		/* Reset Watermark count to restart */
29262306a36Sopenharmony_ci		spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR_SET(1),
29362306a36Sopenharmony_ci			 DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR,
29462306a36Sopenharmony_ci			 port->sparx5,
29562306a36Sopenharmony_ci			 DSM_DEV_TX_STOP_WM_CFG(port->portno));
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci	netif_wake_queue(port->ndev);
29862306a36Sopenharmony_ci	return HRTIMER_NORESTART;
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciint sparx5_manual_injection_mode(struct sparx5 *sparx5)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	const int byte_swap = 1;
30462306a36Sopenharmony_ci	int portno;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Change mode to manual extraction and injection */
30762306a36Sopenharmony_ci	spx5_wr(QS_XTR_GRP_CFG_MODE_SET(1) |
30862306a36Sopenharmony_ci		QS_XTR_GRP_CFG_STATUS_WORD_POS_SET(1) |
30962306a36Sopenharmony_ci		QS_XTR_GRP_CFG_BYTE_SWAP_SET(byte_swap),
31062306a36Sopenharmony_ci		sparx5, QS_XTR_GRP_CFG(XTR_QUEUE));
31162306a36Sopenharmony_ci	spx5_wr(QS_INJ_GRP_CFG_MODE_SET(1) |
31262306a36Sopenharmony_ci		QS_INJ_GRP_CFG_BYTE_SWAP_SET(byte_swap),
31362306a36Sopenharmony_ci		sparx5, QS_INJ_GRP_CFG(INJ_QUEUE));
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* CPU ports capture setup */
31662306a36Sopenharmony_ci	for (portno = SPX5_PORT_CPU_0; portno <= SPX5_PORT_CPU_1; portno++) {
31762306a36Sopenharmony_ci		/* ASM CPU port: No preamble, IFH, enable padding */
31862306a36Sopenharmony_ci		spx5_wr(ASM_PORT_CFG_PAD_ENA_SET(1) |
31962306a36Sopenharmony_ci			ASM_PORT_CFG_NO_PREAMBLE_ENA_SET(1) |
32062306a36Sopenharmony_ci			ASM_PORT_CFG_INJ_FORMAT_CFG_SET(1), /* 1 = IFH */
32162306a36Sopenharmony_ci			sparx5, ASM_PORT_CFG(portno));
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		/* Reset WM cnt to unclog queued frames */
32462306a36Sopenharmony_ci		spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR_SET(1),
32562306a36Sopenharmony_ci			 DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR,
32662306a36Sopenharmony_ci			 sparx5,
32762306a36Sopenharmony_ci			 DSM_DEV_TX_STOP_WM_CFG(portno));
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		/* Set Disassembler Stop Watermark level */
33062306a36Sopenharmony_ci		spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_SET(0),
33162306a36Sopenharmony_ci			 DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM,
33262306a36Sopenharmony_ci			 sparx5,
33362306a36Sopenharmony_ci			 DSM_DEV_TX_STOP_WM_CFG(portno));
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		/* Enable Disassembler buffer underrun watchdog
33662306a36Sopenharmony_ci		 */
33762306a36Sopenharmony_ci		spx5_rmw(DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS_SET(0),
33862306a36Sopenharmony_ci			 DSM_BUF_CFG_UNDERFLOW_WATCHDOG_DIS,
33962306a36Sopenharmony_ci			 sparx5,
34062306a36Sopenharmony_ci			 DSM_BUF_CFG(portno));
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	return 0;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ciirqreturn_t sparx5_xtr_handler(int irq, void *_sparx5)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct sparx5 *s5 = _sparx5;
34862306a36Sopenharmony_ci	int poll = 64;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* Check data in queue */
35162306a36Sopenharmony_ci	while (spx5_rd(s5, QS_XTR_DATA_PRESENT) & BIT(XTR_QUEUE) && poll-- > 0)
35262306a36Sopenharmony_ci		sparx5_xtr_grp(s5, XTR_QUEUE, false);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return IRQ_HANDLED;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_civoid sparx5_port_inj_timer_setup(struct sparx5_port *port)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	hrtimer_init(&port->inj_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
36062306a36Sopenharmony_ci	port->inj_timer.function = sparx5_injection_timeout;
36162306a36Sopenharmony_ci}
362