| 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* 10G controller driver for Samsung SoCs |
| 3 | * |
| 4 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. |
| 5 | * http://www.samsung.com |
| 6 | * |
| 7 | * Author: Siva Reddy Kallam <siva.kallam@samsung.com> |
| 8 | */ |
| 9 | #include <linux/delay.h> |
| 10 | #include <linux/export.h> |
| 11 | #include <linux/io.h> |
| 12 | #include <linux/netdevice.h> |
| 13 | #include <linux/phy.h> |
| 14 | |
| 15 | #include "sxgbe_common.h" |
| 16 | #include "sxgbe_dma.h" |
| 17 | #include "sxgbe_reg.h" |
| 18 | #include "sxgbe_desc.h" |
| 19 | |
| 20 | /* DMA core initialization */ |
| 21 | static int sxgbe_dma_init(void __iomem *ioaddr, int fix_burst, int burst_map) |
| 22 | { |
| 23 | u32 reg_val; |
| 24 | |
| 25 | reg_val = readl(addr: ioaddr + SXGBE_DMA_SYSBUS_MODE_REG); |
| 26 | |
| 27 | /* if fix_burst = 0, Set UNDEF = 1 of DMA_Sys_Mode Register. |
| 28 | * if fix_burst = 1, Set UNDEF = 0 of DMA_Sys_Mode Register. |
| 29 | * burst_map is bitmap for BLEN[4, 8, 16, 32, 64, 128 and 256]. |
| 30 | * Set burst_map irrespective of fix_burst value. |
| 31 | */ |
| 32 | if (!fix_burst) |
| 33 | reg_val |= SXGBE_DMA_AXI_UNDEF_BURST; |
| 34 | |
| 35 | /* write burst len map */ |
| 36 | reg_val |= (burst_map << SXGBE_DMA_BLENMAP_LSHIFT); |
| 37 | |
| 38 | writel(val: reg_val, addr: ioaddr + SXGBE_DMA_SYSBUS_MODE_REG); |
| 39 | |
| 40 | return 0; |
| 41 | } |
| 42 | |
| 43 | static void sxgbe_dma_channel_init(void __iomem *ioaddr, int cha_num, |
| 44 | int fix_burst, int pbl, dma_addr_t dma_tx, |
| 45 | dma_addr_t dma_rx, int t_rsize, int r_rsize) |
| 46 | { |
| 47 | u32 reg_val; |
| 48 | dma_addr_t dma_addr; |
| 49 | |
| 50 | reg_val = readl(addr: ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num)); |
| 51 | /* set the pbl */ |
| 52 | if (fix_burst) { |
| 53 | reg_val |= SXGBE_DMA_PBL_X8MODE; |
| 54 | writel(val: reg_val, addr: ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num)); |
| 55 | /* program the TX pbl */ |
| 56 | reg_val = readl(addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num)); |
| 57 | reg_val |= (pbl << SXGBE_DMA_TXPBL_LSHIFT); |
| 58 | writel(val: reg_val, addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num)); |
| 59 | /* program the RX pbl */ |
| 60 | reg_val = readl(addr: ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num)); |
| 61 | reg_val |= (pbl << SXGBE_DMA_RXPBL_LSHIFT); |
| 62 | writel(val: reg_val, addr: ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num)); |
| 63 | } |
| 64 | |
| 65 | /* program desc registers */ |
| 66 | writel(upper_32_bits(dma_tx), |
| 67 | addr: ioaddr + SXGBE_DMA_CHA_TXDESC_HADD_REG(cha_num)); |
| 68 | writel(lower_32_bits(dma_tx), |
| 69 | addr: ioaddr + SXGBE_DMA_CHA_TXDESC_LADD_REG(cha_num)); |
| 70 | |
| 71 | writel(upper_32_bits(dma_rx), |
| 72 | addr: ioaddr + SXGBE_DMA_CHA_RXDESC_HADD_REG(cha_num)); |
| 73 | writel(lower_32_bits(dma_rx), |
| 74 | addr: ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num)); |
| 75 | |
| 76 | /* program tail pointers */ |
| 77 | /* assumption: upper 32 bits are constant and |
| 78 | * same as TX/RX desc list |
| 79 | */ |
| 80 | dma_addr = dma_tx + ((t_rsize - 1) * SXGBE_DESC_SIZE_BYTES); |
| 81 | writel(lower_32_bits(dma_addr), |
| 82 | addr: ioaddr + SXGBE_DMA_CHA_TXDESC_TAILPTR_REG(cha_num)); |
| 83 | |
| 84 | dma_addr = dma_rx + ((r_rsize - 1) * SXGBE_DESC_SIZE_BYTES); |
| 85 | writel(lower_32_bits(dma_addr), |
| 86 | addr: ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num)); |
| 87 | /* program the ring sizes */ |
| 88 | writel(val: t_rsize - 1, addr: ioaddr + SXGBE_DMA_CHA_TXDESC_RINGLEN_REG(cha_num)); |
| 89 | writel(val: r_rsize - 1, addr: ioaddr + SXGBE_DMA_CHA_RXDESC_RINGLEN_REG(cha_num)); |
| 90 | |
| 91 | /* Enable TX/RX interrupts */ |
| 92 | writel(SXGBE_DMA_ENA_INT, |
| 93 | addr: ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(cha_num)); |
| 94 | } |
| 95 | |
| 96 | static void sxgbe_enable_dma_transmission(void __iomem *ioaddr, int cha_num) |
| 97 | { |
| 98 | u32 tx_config; |
| 99 | |
| 100 | tx_config = readl(addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num)); |
| 101 | tx_config |= SXGBE_TX_START_DMA; |
| 102 | writel(val: tx_config, addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num)); |
| 103 | } |
| 104 | |
| 105 | static void sxgbe_enable_dma_irq(void __iomem *ioaddr, int dma_cnum) |
| 106 | { |
| 107 | /* Enable TX/RX interrupts */ |
| 108 | writel(SXGBE_DMA_ENA_INT, |
| 109 | addr: ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum)); |
| 110 | } |
| 111 | |
| 112 | static void sxgbe_disable_dma_irq(void __iomem *ioaddr, int dma_cnum) |
| 113 | { |
| 114 | /* Disable TX/RX interrupts */ |
| 115 | writel(val: 0, addr: ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum)); |
| 116 | } |
| 117 | |
| 118 | static void sxgbe_dma_start_tx(void __iomem *ioaddr, int tchannels) |
| 119 | { |
| 120 | int cnum; |
| 121 | u32 tx_ctl_reg; |
| 122 | |
| 123 | for (cnum = 0; cnum < tchannels; cnum++) { |
| 124 | tx_ctl_reg = readl(addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum)); |
| 125 | tx_ctl_reg |= SXGBE_TX_ENABLE; |
| 126 | writel(val: tx_ctl_reg, |
| 127 | addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum)); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | static void sxgbe_dma_start_tx_queue(void __iomem *ioaddr, int dma_cnum) |
| 132 | { |
| 133 | u32 tx_ctl_reg; |
| 134 | |
| 135 | tx_ctl_reg = readl(addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum)); |
| 136 | tx_ctl_reg |= SXGBE_TX_ENABLE; |
| 137 | writel(val: tx_ctl_reg, addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum)); |
| 138 | } |
| 139 | |
| 140 | static void sxgbe_dma_stop_tx_queue(void __iomem *ioaddr, int dma_cnum) |
| 141 | { |
| 142 | u32 tx_ctl_reg; |
| 143 | |
| 144 | tx_ctl_reg = readl(addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum)); |
| 145 | tx_ctl_reg &= ~(SXGBE_TX_ENABLE); |
| 146 | writel(val: tx_ctl_reg, addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum)); |
| 147 | } |
| 148 | |
| 149 | static void sxgbe_dma_stop_tx(void __iomem *ioaddr, int tchannels) |
| 150 | { |
| 151 | int cnum; |
| 152 | u32 tx_ctl_reg; |
| 153 | |
| 154 | for (cnum = 0; cnum < tchannels; cnum++) { |
| 155 | tx_ctl_reg = readl(addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum)); |
| 156 | tx_ctl_reg &= ~(SXGBE_TX_ENABLE); |
| 157 | writel(val: tx_ctl_reg, addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum)); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | static void sxgbe_dma_start_rx(void __iomem *ioaddr, int rchannels) |
| 162 | { |
| 163 | int cnum; |
| 164 | u32 rx_ctl_reg; |
| 165 | |
| 166 | for (cnum = 0; cnum < rchannels; cnum++) { |
| 167 | rx_ctl_reg = readl(addr: ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum)); |
| 168 | rx_ctl_reg |= SXGBE_RX_ENABLE; |
| 169 | writel(val: rx_ctl_reg, |
| 170 | addr: ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum)); |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | static void sxgbe_dma_stop_rx(void __iomem *ioaddr, int rchannels) |
| 175 | { |
| 176 | int cnum; |
| 177 | u32 rx_ctl_reg; |
| 178 | |
| 179 | for (cnum = 0; cnum < rchannels; cnum++) { |
| 180 | rx_ctl_reg = readl(addr: ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum)); |
| 181 | rx_ctl_reg &= ~(SXGBE_RX_ENABLE); |
| 182 | writel(val: rx_ctl_reg, addr: ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum)); |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | static int sxgbe_tx_dma_int_status(void __iomem *ioaddr, int channel_no, |
| 187 | struct sxgbe_extra_stats *x) |
| 188 | { |
| 189 | u32 int_status = readl(addr: ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no)); |
| 190 | u32 clear_val = 0; |
| 191 | u32 ret_val = 0; |
| 192 | |
| 193 | /* TX Normal Interrupt Summary */ |
| 194 | if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) { |
| 195 | x->normal_irq_n++; |
| 196 | if (int_status & SXGBE_DMA_INT_STATUS_TI) { |
| 197 | ret_val |= handle_tx; |
| 198 | x->tx_normal_irq_n++; |
| 199 | clear_val |= SXGBE_DMA_INT_STATUS_TI; |
| 200 | } |
| 201 | |
| 202 | if (int_status & SXGBE_DMA_INT_STATUS_TBU) { |
| 203 | x->tx_underflow_irq++; |
| 204 | ret_val |= tx_bump_tc; |
| 205 | clear_val |= SXGBE_DMA_INT_STATUS_TBU; |
| 206 | } |
| 207 | } else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) { |
| 208 | /* TX Abnormal Interrupt Summary */ |
| 209 | if (int_status & SXGBE_DMA_INT_STATUS_TPS) { |
| 210 | ret_val |= tx_hard_error; |
| 211 | clear_val |= SXGBE_DMA_INT_STATUS_TPS; |
| 212 | x->tx_process_stopped_irq++; |
| 213 | } |
| 214 | |
| 215 | if (int_status & SXGBE_DMA_INT_STATUS_FBE) { |
| 216 | ret_val |= tx_hard_error; |
| 217 | x->fatal_bus_error_irq++; |
| 218 | |
| 219 | /* Assumption: FBE bit is the combination of |
| 220 | * all the bus access erros and cleared when |
| 221 | * the respective error bits cleared |
| 222 | */ |
| 223 | |
| 224 | /* check for actual cause */ |
| 225 | if (int_status & SXGBE_DMA_INT_STATUS_TEB0) { |
| 226 | x->tx_read_transfer_err++; |
| 227 | clear_val |= SXGBE_DMA_INT_STATUS_TEB0; |
| 228 | } else { |
| 229 | x->tx_write_transfer_err++; |
| 230 | } |
| 231 | |
| 232 | if (int_status & SXGBE_DMA_INT_STATUS_TEB1) { |
| 233 | x->tx_desc_access_err++; |
| 234 | clear_val |= SXGBE_DMA_INT_STATUS_TEB1; |
| 235 | } else { |
| 236 | x->tx_buffer_access_err++; |
| 237 | } |
| 238 | |
| 239 | if (int_status & SXGBE_DMA_INT_STATUS_TEB2) { |
| 240 | x->tx_data_transfer_err++; |
| 241 | clear_val |= SXGBE_DMA_INT_STATUS_TEB2; |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | /* context descriptor error */ |
| 246 | if (int_status & SXGBE_DMA_INT_STATUS_CTXTERR) { |
| 247 | x->tx_ctxt_desc_err++; |
| 248 | clear_val |= SXGBE_DMA_INT_STATUS_CTXTERR; |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | /* clear the served bits */ |
| 253 | writel(val: clear_val, addr: ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no)); |
| 254 | |
| 255 | return ret_val; |
| 256 | } |
| 257 | |
| 258 | static int sxgbe_rx_dma_int_status(void __iomem *ioaddr, int channel_no, |
| 259 | struct sxgbe_extra_stats *x) |
| 260 | { |
| 261 | u32 int_status = readl(addr: ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no)); |
| 262 | u32 clear_val = 0; |
| 263 | u32 ret_val = 0; |
| 264 | |
| 265 | /* RX Normal Interrupt Summary */ |
| 266 | if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) { |
| 267 | x->normal_irq_n++; |
| 268 | if (int_status & SXGBE_DMA_INT_STATUS_RI) { |
| 269 | ret_val |= handle_rx; |
| 270 | x->rx_normal_irq_n++; |
| 271 | clear_val |= SXGBE_DMA_INT_STATUS_RI; |
| 272 | } |
| 273 | } else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) { |
| 274 | /* RX Abnormal Interrupt Summary */ |
| 275 | if (int_status & SXGBE_DMA_INT_STATUS_RBU) { |
| 276 | ret_val |= rx_bump_tc; |
| 277 | clear_val |= SXGBE_DMA_INT_STATUS_RBU; |
| 278 | x->rx_underflow_irq++; |
| 279 | } |
| 280 | |
| 281 | if (int_status & SXGBE_DMA_INT_STATUS_RPS) { |
| 282 | ret_val |= rx_hard_error; |
| 283 | clear_val |= SXGBE_DMA_INT_STATUS_RPS; |
| 284 | x->rx_process_stopped_irq++; |
| 285 | } |
| 286 | |
| 287 | if (int_status & SXGBE_DMA_INT_STATUS_FBE) { |
| 288 | ret_val |= rx_hard_error; |
| 289 | x->fatal_bus_error_irq++; |
| 290 | |
| 291 | /* Assumption: FBE bit is the combination of |
| 292 | * all the bus access erros and cleared when |
| 293 | * the respective error bits cleared |
| 294 | */ |
| 295 | |
| 296 | /* check for actual cause */ |
| 297 | if (int_status & SXGBE_DMA_INT_STATUS_REB0) { |
| 298 | x->rx_read_transfer_err++; |
| 299 | clear_val |= SXGBE_DMA_INT_STATUS_REB0; |
| 300 | } else { |
| 301 | x->rx_write_transfer_err++; |
| 302 | } |
| 303 | |
| 304 | if (int_status & SXGBE_DMA_INT_STATUS_REB1) { |
| 305 | x->rx_desc_access_err++; |
| 306 | clear_val |= SXGBE_DMA_INT_STATUS_REB1; |
| 307 | } else { |
| 308 | x->rx_buffer_access_err++; |
| 309 | } |
| 310 | |
| 311 | if (int_status & SXGBE_DMA_INT_STATUS_REB2) { |
| 312 | x->rx_data_transfer_err++; |
| 313 | clear_val |= SXGBE_DMA_INT_STATUS_REB2; |
| 314 | } |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | /* clear the served bits */ |
| 319 | writel(val: clear_val, addr: ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no)); |
| 320 | |
| 321 | return ret_val; |
| 322 | } |
| 323 | |
| 324 | /* Program the HW RX Watchdog */ |
| 325 | static void sxgbe_dma_rx_watchdog(void __iomem *ioaddr, u32 riwt) |
| 326 | { |
| 327 | u32 que_num; |
| 328 | |
| 329 | SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, que_num) { |
| 330 | writel(val: riwt, |
| 331 | addr: ioaddr + SXGBE_DMA_CHA_INT_RXWATCHTMR_REG(que_num)); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | static void sxgbe_enable_tso(void __iomem *ioaddr, u8 chan_num) |
| 336 | { |
| 337 | u32 ctrl; |
| 338 | |
| 339 | ctrl = readl(addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num)); |
| 340 | ctrl |= SXGBE_DMA_CHA_TXCTL_TSE_ENABLE; |
| 341 | writel(val: ctrl, addr: ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num)); |
| 342 | } |
| 343 | |
| 344 | static const struct sxgbe_dma_ops sxgbe_dma_ops = { |
| 345 | .init = sxgbe_dma_init, |
| 346 | .cha_init = sxgbe_dma_channel_init, |
| 347 | .enable_dma_transmission = sxgbe_enable_dma_transmission, |
| 348 | .enable_dma_irq = sxgbe_enable_dma_irq, |
| 349 | .disable_dma_irq = sxgbe_disable_dma_irq, |
| 350 | .start_tx = sxgbe_dma_start_tx, |
| 351 | .start_tx_queue = sxgbe_dma_start_tx_queue, |
| 352 | .stop_tx = sxgbe_dma_stop_tx, |
| 353 | .stop_tx_queue = sxgbe_dma_stop_tx_queue, |
| 354 | .start_rx = sxgbe_dma_start_rx, |
| 355 | .stop_rx = sxgbe_dma_stop_rx, |
| 356 | .tx_dma_int_status = sxgbe_tx_dma_int_status, |
| 357 | .rx_dma_int_status = sxgbe_rx_dma_int_status, |
| 358 | .rx_watchdog = sxgbe_dma_rx_watchdog, |
| 359 | .enable_tso = sxgbe_enable_tso, |
| 360 | }; |
| 361 | |
| 362 | const struct sxgbe_dma_ops *sxgbe_get_dma_ops(void) |
| 363 | { |
| 364 | return &sxgbe_dma_ops; |
| 365 | } |
| 366 | |