spl2sw_int.c (7396B)
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright Sunplus Technology Co., Ltd. 3 * All rights reserved. 4 */ 5 6#include <linux/platform_device.h> 7#include <linux/etherdevice.h> 8#include <linux/netdevice.h> 9#include <linux/bitfield.h> 10#include <linux/spinlock.h> 11#include <linux/of_mdio.h> 12 13#include "spl2sw_register.h" 14#include "spl2sw_define.h" 15#include "spl2sw_int.h" 16 17int spl2sw_rx_poll(struct napi_struct *napi, int budget) 18{ 19 struct spl2sw_common *comm = container_of(napi, struct spl2sw_common, rx_napi); 20 struct spl2sw_mac_desc *desc, *h_desc; 21 struct net_device_stats *stats; 22 struct sk_buff *skb, *new_skb; 23 struct spl2sw_skb_info *sinfo; 24 int budget_left = budget; 25 unsigned long flags; 26 u32 rx_pos, pkg_len; 27 u32 num, rx_count; 28 s32 queue; 29 u32 mask; 30 int port; 31 u32 cmd; 32 u32 len; 33 34 /* Process high-priority queue and then low-priority queue. */ 35 for (queue = 0; queue < RX_DESC_QUEUE_NUM; queue++) { 36 rx_pos = comm->rx_pos[queue]; 37 rx_count = comm->rx_desc_num[queue]; 38 39 for (num = 0; num < rx_count && budget_left; num++) { 40 sinfo = comm->rx_skb_info[queue] + rx_pos; 41 desc = comm->rx_desc[queue] + rx_pos; 42 cmd = desc->cmd1; 43 44 if (cmd & RXD_OWN) 45 break; 46 47 port = FIELD_GET(RXD_PKT_SP, cmd); 48 if (port < MAX_NETDEV_NUM && comm->ndev[port]) 49 stats = &comm->ndev[port]->stats; 50 else 51 goto spl2sw_rx_poll_rec_err; 52 53 pkg_len = FIELD_GET(RXD_PKT_LEN, cmd); 54 if (unlikely((cmd & RXD_ERR_CODE) || pkg_len < ETH_ZLEN + 4)) { 55 stats->rx_length_errors++; 56 stats->rx_dropped++; 57 goto spl2sw_rx_poll_rec_err; 58 } 59 60 dma_unmap_single(&comm->pdev->dev, sinfo->mapping, 61 comm->rx_desc_buff_size, DMA_FROM_DEVICE); 62 63 skb = sinfo->skb; 64 skb_put(skb, pkg_len - 4); /* Minus FCS */ 65 skb->ip_summed = CHECKSUM_NONE; 66 skb->protocol = eth_type_trans(skb, comm->ndev[port]); 67 len = skb->len; 68 netif_receive_skb(skb); 69 70 stats->rx_packets++; 71 stats->rx_bytes += len; 72 73 /* Allocate a new skb for receiving. */ 74 new_skb = netdev_alloc_skb(NULL, comm->rx_desc_buff_size); 75 if (unlikely(!new_skb)) { 76 desc->cmd2 = (rx_pos == comm->rx_desc_num[queue] - 1) ? 77 RXD_EOR : 0; 78 sinfo->skb = NULL; 79 sinfo->mapping = 0; 80 desc->addr1 = 0; 81 goto spl2sw_rx_poll_alloc_err; 82 } 83 84 sinfo->mapping = dma_map_single(&comm->pdev->dev, new_skb->data, 85 comm->rx_desc_buff_size, 86 DMA_FROM_DEVICE); 87 if (dma_mapping_error(&comm->pdev->dev, sinfo->mapping)) { 88 dev_kfree_skb_irq(new_skb); 89 desc->cmd2 = (rx_pos == comm->rx_desc_num[queue] - 1) ? 90 RXD_EOR : 0; 91 sinfo->skb = NULL; 92 sinfo->mapping = 0; 93 desc->addr1 = 0; 94 goto spl2sw_rx_poll_alloc_err; 95 } 96 97 sinfo->skb = new_skb; 98 desc->addr1 = sinfo->mapping; 99 100spl2sw_rx_poll_rec_err: 101 desc->cmd2 = (rx_pos == comm->rx_desc_num[queue] - 1) ? 102 RXD_EOR | comm->rx_desc_buff_size : 103 comm->rx_desc_buff_size; 104 105 wmb(); /* Set RXD_OWN after other fields are effective. */ 106 desc->cmd1 = RXD_OWN; 107 108spl2sw_rx_poll_alloc_err: 109 /* Move rx_pos to next position */ 110 rx_pos = ((rx_pos + 1) == comm->rx_desc_num[queue]) ? 0 : rx_pos + 1; 111 112 budget_left--; 113 114 /* If there are packets in high-priority queue, 115 * stop processing low-priority queue. 116 */ 117 if (queue == 1 && !(h_desc->cmd1 & RXD_OWN)) 118 break; 119 } 120 121 comm->rx_pos[queue] = rx_pos; 122 123 /* Save pointer to last rx descriptor of high-priority queue. */ 124 if (queue == 0) 125 h_desc = comm->rx_desc[queue] + rx_pos; 126 } 127 128 spin_lock_irqsave(&comm->int_mask_lock, flags); 129 mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 130 mask &= ~MAC_INT_RX; 131 writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 132 spin_unlock_irqrestore(&comm->int_mask_lock, flags); 133 134 napi_complete(napi); 135 return budget - budget_left; 136} 137 138int spl2sw_tx_poll(struct napi_struct *napi, int budget) 139{ 140 struct spl2sw_common *comm = container_of(napi, struct spl2sw_common, tx_napi); 141 struct spl2sw_skb_info *skbinfo; 142 struct net_device_stats *stats; 143 int budget_left = budget; 144 unsigned long flags; 145 u32 tx_done_pos; 146 u32 mask; 147 u32 cmd; 148 int i; 149 150 spin_lock(&comm->tx_lock); 151 152 tx_done_pos = comm->tx_done_pos; 153 while (((tx_done_pos != comm->tx_pos) || (comm->tx_desc_full == 1)) && budget_left) { 154 cmd = comm->tx_desc[tx_done_pos].cmd1; 155 if (cmd & TXD_OWN) 156 break; 157 158 skbinfo = &comm->tx_temp_skb_info[tx_done_pos]; 159 if (unlikely(!skbinfo->skb)) 160 goto spl2sw_tx_poll_next; 161 162 i = ffs(FIELD_GET(TXD_VLAN, cmd)) - 1; 163 if (i < MAX_NETDEV_NUM && comm->ndev[i]) 164 stats = &comm->ndev[i]->stats; 165 else 166 goto spl2sw_tx_poll_unmap; 167 168 if (unlikely(cmd & (TXD_ERR_CODE))) { 169 stats->tx_errors++; 170 } else { 171 stats->tx_packets++; 172 stats->tx_bytes += skbinfo->len; 173 } 174 175spl2sw_tx_poll_unmap: 176 dma_unmap_single(&comm->pdev->dev, skbinfo->mapping, skbinfo->len, 177 DMA_TO_DEVICE); 178 skbinfo->mapping = 0; 179 dev_kfree_skb_irq(skbinfo->skb); 180 skbinfo->skb = NULL; 181 182spl2sw_tx_poll_next: 183 /* Move tx_done_pos to next position */ 184 tx_done_pos = ((tx_done_pos + 1) == TX_DESC_NUM) ? 0 : tx_done_pos + 1; 185 186 if (comm->tx_desc_full == 1) 187 comm->tx_desc_full = 0; 188 189 budget_left--; 190 } 191 192 comm->tx_done_pos = tx_done_pos; 193 if (!comm->tx_desc_full) 194 for (i = 0; i < MAX_NETDEV_NUM; i++) 195 if (comm->ndev[i]) 196 if (netif_queue_stopped(comm->ndev[i])) 197 netif_wake_queue(comm->ndev[i]); 198 199 spin_unlock(&comm->tx_lock); 200 201 spin_lock_irqsave(&comm->int_mask_lock, flags); 202 mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 203 mask &= ~MAC_INT_TX; 204 writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 205 spin_unlock_irqrestore(&comm->int_mask_lock, flags); 206 207 napi_complete(napi); 208 return budget - budget_left; 209} 210 211irqreturn_t spl2sw_ethernet_interrupt(int irq, void *dev_id) 212{ 213 struct spl2sw_common *comm = (struct spl2sw_common *)dev_id; 214 u32 status; 215 u32 mask; 216 int i; 217 218 status = readl(comm->l2sw_reg_base + L2SW_SW_INT_STATUS_0); 219 if (unlikely(!status)) { 220 dev_dbg(&comm->pdev->dev, "Interrupt status is null!\n"); 221 goto spl2sw_ethernet_int_out; 222 } 223 writel(status, comm->l2sw_reg_base + L2SW_SW_INT_STATUS_0); 224 225 if (status & MAC_INT_RX) { 226 /* Disable RX interrupts. */ 227 spin_lock(&comm->int_mask_lock); 228 mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 229 mask |= MAC_INT_RX; 230 writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 231 spin_unlock(&comm->int_mask_lock); 232 233 if (unlikely(status & MAC_INT_RX_DES_ERR)) { 234 for (i = 0; i < MAX_NETDEV_NUM; i++) 235 if (comm->ndev[i]) { 236 comm->ndev[i]->stats.rx_fifo_errors++; 237 break; 238 } 239 dev_dbg(&comm->pdev->dev, "Illegal RX Descriptor!\n"); 240 } 241 242 napi_schedule(&comm->rx_napi); 243 } 244 245 if (status & MAC_INT_TX) { 246 /* Disable TX interrupts. */ 247 spin_lock(&comm->int_mask_lock); 248 mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 249 mask |= MAC_INT_TX; 250 writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 251 spin_unlock(&comm->int_mask_lock); 252 253 if (unlikely(status & MAC_INT_TX_DES_ERR)) { 254 for (i = 0; i < MAX_NETDEV_NUM; i++) 255 if (comm->ndev[i]) { 256 comm->ndev[i]->stats.tx_fifo_errors++; 257 break; 258 } 259 dev_dbg(&comm->pdev->dev, "Illegal TX Descriptor Error\n"); 260 261 spin_lock(&comm->int_mask_lock); 262 mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 263 mask &= ~MAC_INT_TX; 264 writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 265 spin_unlock(&comm->int_mask_lock); 266 } else { 267 napi_schedule(&comm->tx_napi); 268 } 269 } 270 271spl2sw_ethernet_int_out: 272 return IRQ_HANDLED; 273}