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