Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

stmmac: add GMAC4 core support

This is the initial support for GMAC4 that includes
the main callbacks to setup the core module: including
Csum, basic filtering, mac address and interrupt (MMC,
MTL, PMT) No LPI added.

Signed-off-by: Alexandre TORGUE <alexandre.torgue@st.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Alexandre TORGUE and committed by
David S. Miller
477286b5 48863ce5

+447 -3
+1 -1
drivers/net/ethernet/stmicro/stmmac/Makefile
··· 3 3 chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ 4 4 dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ 5 5 mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \ 6 - dwmac4_dma.o dwmac4_lib.o $(stmmac-y) 6 + dwmac4_dma.o dwmac4_lib.o dwmac4_core.o $(stmmac-y) 7 7 8 8 # Ordering matters. Generic driver must be last. 9 9 obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
+8 -2
drivers/net/ethernet/stmicro/stmmac/common.h
··· 527 527 int perfect_uc_entries, 528 528 int *synopsys_id); 529 529 struct mac_device_info *dwmac100_setup(void __iomem *ioaddr, int *synopsys_id); 530 - 530 + struct mac_device_info *dwmac4_setup(void __iomem *ioaddr, int mcbins, 531 + int perfect_uc_entries, int *synopsys_id); 531 532 532 533 void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], 533 534 unsigned int high, unsigned int low); 534 535 void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, 535 536 unsigned int high, unsigned int low); 536 - 537 537 void stmmac_set_mac(void __iomem *ioaddr, bool enable); 538 + 539 + void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, u8 addr[6], 540 + unsigned int high, unsigned int low); 541 + void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, 542 + unsigned int high, unsigned int low); 543 + void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable); 538 544 539 545 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); 540 546 extern const struct stmmac_mode_ops ring_mode_ops;
+31
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
··· 221 221 /* To dump the core regs excluding the Address Registers */ 222 222 #define GMAC_REG_NUM 132 223 223 224 + /* MTL debug */ 225 + #define MTL_DEBUG_TXSTSFSTS BIT(5) 226 + #define MTL_DEBUG_TXFSTS BIT(4) 227 + #define MTL_DEBUG_TWCSTS BIT(3) 228 + 229 + /* MTL debug: Tx FIFO Read Controller Status */ 230 + #define MTL_DEBUG_TRCSTS_MASK GENMASK(2, 1) 231 + #define MTL_DEBUG_TRCSTS_SHIFT 1 232 + #define MTL_DEBUG_TRCSTS_IDLE 0 233 + #define MTL_DEBUG_TRCSTS_READ 1 234 + #define MTL_DEBUG_TRCSTS_TXW 2 235 + #define MTL_DEBUG_TRCSTS_WRITE 3 236 + #define MTL_DEBUG_TXPAUSED BIT(0) 237 + 238 + /* MAC debug: GMII or MII Transmit Protocol Engine Status */ 239 + #define MTL_DEBUG_RXFSTS_MASK GENMASK(5, 4) 240 + #define MTL_DEBUG_RXFSTS_SHIFT 4 241 + #define MTL_DEBUG_RXFSTS_EMPTY 0 242 + #define MTL_DEBUG_RXFSTS_BT 1 243 + #define MTL_DEBUG_RXFSTS_AT 2 244 + #define MTL_DEBUG_RXFSTS_FULL 3 245 + #define MTL_DEBUG_RRCSTS_MASK GENMASK(2, 1) 246 + #define MTL_DEBUG_RRCSTS_SHIFT 1 247 + #define MTL_DEBUG_RRCSTS_IDLE 0 248 + #define MTL_DEBUG_RRCSTS_RDATA 1 249 + #define MTL_DEBUG_RRCSTS_RSTAT 2 250 + #define MTL_DEBUG_RRCSTS_FLUSH 3 251 + #define MTL_DEBUG_RWCSTS BIT(0) 252 + 253 + extern const struct stmmac_dma_ops dwmac4_dma_ops; 254 + extern const struct stmmac_dma_ops dwmac410_dma_ops; 224 255 #endif /* __DWMAC4_H__ */
+407
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
··· 1 + /* 2 + * This is the driver for the GMAC on-chip Ethernet controller for ST SoCs. 3 + * DWC Ether MAC version 4.00 has been used for developing this code. 4 + * 5 + * This only implements the mac core functions for this chip. 6 + * 7 + * Copyright (C) 2015 STMicroelectronics Ltd 8 + * 9 + * This program is free software; you can redistribute it and/or modify it 10 + * under the terms and conditions of the GNU General Public License, 11 + * version 2, as published by the Free Software Foundation. 12 + * 13 + * Author: Alexandre Torgue <alexandre.torgue@st.com> 14 + */ 15 + 16 + #include <linux/crc32.h> 17 + #include <linux/slab.h> 18 + #include <linux/ethtool.h> 19 + #include <linux/io.h> 20 + #include "dwmac4.h" 21 + 22 + static void dwmac4_core_init(struct mac_device_info *hw, int mtu) 23 + { 24 + void __iomem *ioaddr = hw->pcsr; 25 + u32 value = readl(ioaddr + GMAC_CONFIG); 26 + 27 + value |= GMAC_CORE_INIT; 28 + 29 + if (mtu > 1500) 30 + value |= GMAC_CONFIG_2K; 31 + if (mtu > 2000) 32 + value |= GMAC_CONFIG_JE; 33 + 34 + writel(value, ioaddr + GMAC_CONFIG); 35 + 36 + /* Mask GMAC interrupts */ 37 + writel(GMAC_INT_PMT_EN, ioaddr + GMAC_INT_EN); 38 + } 39 + 40 + static void dwmac4_dump_regs(struct mac_device_info *hw) 41 + { 42 + void __iomem *ioaddr = hw->pcsr; 43 + int i; 44 + 45 + pr_debug("\tDWMAC4 regs (base addr = 0x%p)\n", ioaddr); 46 + 47 + for (i = 0; i < GMAC_REG_NUM; i++) { 48 + int offset = i * 4; 49 + 50 + pr_debug("\tReg No. %d (offset 0x%x): 0x%08x\n", i, 51 + offset, readl(ioaddr + offset)); 52 + } 53 + } 54 + 55 + static int dwmac4_rx_ipc_enable(struct mac_device_info *hw) 56 + { 57 + void __iomem *ioaddr = hw->pcsr; 58 + u32 value = readl(ioaddr + GMAC_CONFIG); 59 + 60 + if (hw->rx_csum) 61 + value |= GMAC_CONFIG_IPC; 62 + else 63 + value &= ~GMAC_CONFIG_IPC; 64 + 65 + writel(value, ioaddr + GMAC_CONFIG); 66 + 67 + value = readl(ioaddr + GMAC_CONFIG); 68 + 69 + return !!(value & GMAC_CONFIG_IPC); 70 + } 71 + 72 + static void dwmac4_pmt(struct mac_device_info *hw, unsigned long mode) 73 + { 74 + void __iomem *ioaddr = hw->pcsr; 75 + unsigned int pmt = 0; 76 + 77 + if (mode & WAKE_MAGIC) { 78 + pr_debug("GMAC: WOL Magic frame\n"); 79 + pmt |= power_down | magic_pkt_en; 80 + } 81 + if (mode & WAKE_UCAST) { 82 + pr_debug("GMAC: WOL on global unicast\n"); 83 + pmt |= global_unicast; 84 + } 85 + 86 + writel(pmt, ioaddr + GMAC_PMT); 87 + } 88 + 89 + static void dwmac4_set_umac_addr(struct mac_device_info *hw, 90 + unsigned char *addr, unsigned int reg_n) 91 + { 92 + void __iomem *ioaddr = hw->pcsr; 93 + 94 + stmmac_dwmac4_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), 95 + GMAC_ADDR_LOW(reg_n)); 96 + } 97 + 98 + static void dwmac4_get_umac_addr(struct mac_device_info *hw, 99 + unsigned char *addr, unsigned int reg_n) 100 + { 101 + void __iomem *ioaddr = hw->pcsr; 102 + 103 + stmmac_dwmac4_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n), 104 + GMAC_ADDR_LOW(reg_n)); 105 + } 106 + 107 + static void dwmac4_set_filter(struct mac_device_info *hw, 108 + struct net_device *dev) 109 + { 110 + void __iomem *ioaddr = (void __iomem *)dev->base_addr; 111 + unsigned int value = 0; 112 + 113 + if (dev->flags & IFF_PROMISC) { 114 + value = GMAC_PACKET_FILTER_PR; 115 + } else if ((dev->flags & IFF_ALLMULTI) || 116 + (netdev_mc_count(dev) > HASH_TABLE_SIZE)) { 117 + /* Pass all multi */ 118 + value = GMAC_PACKET_FILTER_PM; 119 + /* Set the 64 bits of the HASH tab. To be updated if taller 120 + * hash table is used 121 + */ 122 + writel(0xffffffff, ioaddr + GMAC_HASH_TAB_0_31); 123 + writel(0xffffffff, ioaddr + GMAC_HASH_TAB_32_63); 124 + } else if (!netdev_mc_empty(dev)) { 125 + u32 mc_filter[2]; 126 + struct netdev_hw_addr *ha; 127 + 128 + /* Hash filter for multicast */ 129 + value = GMAC_PACKET_FILTER_HMC; 130 + 131 + memset(mc_filter, 0, sizeof(mc_filter)); 132 + netdev_for_each_mc_addr(ha, dev) { 133 + /* The upper 6 bits of the calculated CRC are used to 134 + * index the content of the Hash Table Reg 0 and 1. 135 + */ 136 + int bit_nr = 137 + (bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26); 138 + /* The most significant bit determines the register 139 + * to use while the other 5 bits determines the bit 140 + * within the selected register 141 + */ 142 + mc_filter[bit_nr >> 5] |= (1 << (bit_nr & 0x1F)); 143 + } 144 + writel(mc_filter[0], ioaddr + GMAC_HASH_TAB_0_31); 145 + writel(mc_filter[1], ioaddr + GMAC_HASH_TAB_32_63); 146 + } 147 + 148 + /* Handle multiple unicast addresses */ 149 + if (netdev_uc_count(dev) > GMAC_MAX_PERFECT_ADDRESSES) { 150 + /* Switch to promiscuous mode if more than 128 addrs 151 + * are required 152 + */ 153 + value |= GMAC_PACKET_FILTER_PR; 154 + } else if (!netdev_uc_empty(dev)) { 155 + int reg = 1; 156 + struct netdev_hw_addr *ha; 157 + 158 + netdev_for_each_uc_addr(ha, dev) { 159 + dwmac4_set_umac_addr(ioaddr, ha->addr, reg); 160 + reg++; 161 + } 162 + } 163 + 164 + writel(value, ioaddr + GMAC_PACKET_FILTER); 165 + } 166 + 167 + static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, 168 + unsigned int fc, unsigned int pause_time) 169 + { 170 + void __iomem *ioaddr = hw->pcsr; 171 + u32 channel = STMMAC_CHAN0; /* FIXME */ 172 + unsigned int flow = 0; 173 + 174 + pr_debug("GMAC Flow-Control:\n"); 175 + if (fc & FLOW_RX) { 176 + pr_debug("\tReceive Flow-Control ON\n"); 177 + flow |= GMAC_RX_FLOW_CTRL_RFE; 178 + writel(flow, ioaddr + GMAC_RX_FLOW_CTRL); 179 + } 180 + if (fc & FLOW_TX) { 181 + pr_debug("\tTransmit Flow-Control ON\n"); 182 + flow |= GMAC_TX_FLOW_CTRL_TFE; 183 + writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(channel)); 184 + 185 + if (duplex) { 186 + pr_debug("\tduplex mode: PAUSE %d\n", pause_time); 187 + flow |= (pause_time << GMAC_TX_FLOW_CTRL_PT_SHIFT); 188 + writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(channel)); 189 + } 190 + } 191 + } 192 + 193 + static void dwmac4_ctrl_ane(struct mac_device_info *hw, bool restart) 194 + { 195 + void __iomem *ioaddr = hw->pcsr; 196 + 197 + /* auto negotiation enable and External Loopback enable */ 198 + u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE; 199 + 200 + if (restart) 201 + value |= GMAC_AN_CTRL_RAN; 202 + 203 + writel(value, ioaddr + GMAC_AN_CTRL); 204 + } 205 + 206 + static void dwmac4_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv) 207 + { 208 + void __iomem *ioaddr = hw->pcsr; 209 + u32 value = readl(ioaddr + GMAC_AN_ADV); 210 + 211 + if (value & GMAC_AN_FD) 212 + adv->duplex = DUPLEX_FULL; 213 + if (value & GMAC_AN_HD) 214 + adv->duplex |= DUPLEX_HALF; 215 + 216 + adv->pause = (value & GMAC_AN_PSE_MASK) >> GMAC_AN_PSE_SHIFT; 217 + 218 + value = readl(ioaddr + GMAC_AN_LPA); 219 + 220 + if (value & GMAC_AN_FD) 221 + adv->lp_duplex = DUPLEX_FULL; 222 + if (value & GMAC_AN_HD) 223 + adv->lp_duplex = DUPLEX_HALF; 224 + 225 + adv->lp_pause = (value & GMAC_AN_PSE_MASK) >> GMAC_AN_PSE_SHIFT; 226 + } 227 + 228 + static int dwmac4_irq_status(struct mac_device_info *hw, 229 + struct stmmac_extra_stats *x) 230 + { 231 + void __iomem *ioaddr = hw->pcsr; 232 + u32 mtl_int_qx_status; 233 + u32 intr_status; 234 + int ret = 0; 235 + 236 + intr_status = readl(ioaddr + GMAC_INT_STATUS); 237 + 238 + /* Not used events (e.g. MMC interrupts) are not handled. */ 239 + if ((intr_status & mmc_tx_irq)) 240 + x->mmc_tx_irq_n++; 241 + if (unlikely(intr_status & mmc_rx_irq)) 242 + x->mmc_rx_irq_n++; 243 + if (unlikely(intr_status & mmc_rx_csum_offload_irq)) 244 + x->mmc_rx_csum_offload_irq_n++; 245 + /* Clear the PMT bits 5 and 6 by reading the PMT status reg */ 246 + if (unlikely(intr_status & pmt_irq)) { 247 + readl(ioaddr + GMAC_PMT); 248 + x->irq_receive_pmt_irq_n++; 249 + } 250 + 251 + if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) { 252 + readl(ioaddr + GMAC_AN_STATUS); 253 + x->irq_pcs_ane_n++; 254 + } 255 + 256 + mtl_int_qx_status = readl(ioaddr + MTL_INT_STATUS); 257 + /* Check MTL Interrupt: Currently only one queue is used: Q0. */ 258 + if (mtl_int_qx_status & MTL_INT_Q0) { 259 + /* read Queue 0 Interrupt status */ 260 + u32 status = readl(ioaddr + MTL_CHAN_INT_CTRL(STMMAC_CHAN0)); 261 + 262 + if (status & MTL_RX_OVERFLOW_INT) { 263 + /* clear Interrupt */ 264 + writel(status | MTL_RX_OVERFLOW_INT, 265 + ioaddr + MTL_CHAN_INT_CTRL(STMMAC_CHAN0)); 266 + ret = CORE_IRQ_MTL_RX_OVERFLOW; 267 + } 268 + } 269 + 270 + return ret; 271 + } 272 + 273 + static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x) 274 + { 275 + u32 value; 276 + 277 + /* Currently only channel 0 is supported */ 278 + value = readl(ioaddr + MTL_CHAN_TX_DEBUG(STMMAC_CHAN0)); 279 + 280 + if (value & MTL_DEBUG_TXSTSFSTS) 281 + x->mtl_tx_status_fifo_full++; 282 + if (value & MTL_DEBUG_TXFSTS) 283 + x->mtl_tx_fifo_not_empty++; 284 + if (value & MTL_DEBUG_TWCSTS) 285 + x->mmtl_fifo_ctrl++; 286 + if (value & MTL_DEBUG_TRCSTS_MASK) { 287 + u32 trcsts = (value & MTL_DEBUG_TRCSTS_MASK) 288 + >> MTL_DEBUG_TRCSTS_SHIFT; 289 + if (trcsts == MTL_DEBUG_TRCSTS_WRITE) 290 + x->mtl_tx_fifo_read_ctrl_write++; 291 + else if (trcsts == MTL_DEBUG_TRCSTS_TXW) 292 + x->mtl_tx_fifo_read_ctrl_wait++; 293 + else if (trcsts == MTL_DEBUG_TRCSTS_READ) 294 + x->mtl_tx_fifo_read_ctrl_read++; 295 + else 296 + x->mtl_tx_fifo_read_ctrl_idle++; 297 + } 298 + if (value & MTL_DEBUG_TXPAUSED) 299 + x->mac_tx_in_pause++; 300 + 301 + value = readl(ioaddr + MTL_CHAN_RX_DEBUG(STMMAC_CHAN0)); 302 + 303 + if (value & MTL_DEBUG_RXFSTS_MASK) { 304 + u32 rxfsts = (value & MTL_DEBUG_RXFSTS_MASK) 305 + >> MTL_DEBUG_RRCSTS_SHIFT; 306 + 307 + if (rxfsts == MTL_DEBUG_RXFSTS_FULL) 308 + x->mtl_rx_fifo_fill_level_full++; 309 + else if (rxfsts == MTL_DEBUG_RXFSTS_AT) 310 + x->mtl_rx_fifo_fill_above_thresh++; 311 + else if (rxfsts == MTL_DEBUG_RXFSTS_BT) 312 + x->mtl_rx_fifo_fill_below_thresh++; 313 + else 314 + x->mtl_rx_fifo_fill_level_empty++; 315 + } 316 + if (value & MTL_DEBUG_RRCSTS_MASK) { 317 + u32 rrcsts = (value & MTL_DEBUG_RRCSTS_MASK) >> 318 + MTL_DEBUG_RRCSTS_SHIFT; 319 + 320 + if (rrcsts == MTL_DEBUG_RRCSTS_FLUSH) 321 + x->mtl_rx_fifo_read_ctrl_flush++; 322 + else if (rrcsts == MTL_DEBUG_RRCSTS_RSTAT) 323 + x->mtl_rx_fifo_read_ctrl_read_data++; 324 + else if (rrcsts == MTL_DEBUG_RRCSTS_RDATA) 325 + x->mtl_rx_fifo_read_ctrl_status++; 326 + else 327 + x->mtl_rx_fifo_read_ctrl_idle++; 328 + } 329 + if (value & MTL_DEBUG_RWCSTS) 330 + x->mtl_rx_fifo_ctrl_active++; 331 + 332 + /* GMAC debug */ 333 + value = readl(ioaddr + GMAC_DEBUG); 334 + 335 + if (value & GMAC_DEBUG_TFCSTS_MASK) { 336 + u32 tfcsts = (value & GMAC_DEBUG_TFCSTS_MASK) 337 + >> GMAC_DEBUG_TFCSTS_SHIFT; 338 + 339 + if (tfcsts == GMAC_DEBUG_TFCSTS_XFER) 340 + x->mac_tx_frame_ctrl_xfer++; 341 + else if (tfcsts == GMAC_DEBUG_TFCSTS_GEN_PAUSE) 342 + x->mac_tx_frame_ctrl_pause++; 343 + else if (tfcsts == GMAC_DEBUG_TFCSTS_WAIT) 344 + x->mac_tx_frame_ctrl_wait++; 345 + else 346 + x->mac_tx_frame_ctrl_idle++; 347 + } 348 + if (value & GMAC_DEBUG_TPESTS) 349 + x->mac_gmii_tx_proto_engine++; 350 + if (value & GMAC_DEBUG_RFCFCSTS_MASK) 351 + x->mac_rx_frame_ctrl_fifo = (value & GMAC_DEBUG_RFCFCSTS_MASK) 352 + >> GMAC_DEBUG_RFCFCSTS_SHIFT; 353 + if (value & GMAC_DEBUG_RPESTS) 354 + x->mac_gmii_rx_proto_engine++; 355 + } 356 + 357 + static const struct stmmac_ops dwmac4_ops = { 358 + .core_init = dwmac4_core_init, 359 + .rx_ipc = dwmac4_rx_ipc_enable, 360 + .dump_regs = dwmac4_dump_regs, 361 + .host_irq_status = dwmac4_irq_status, 362 + .flow_ctrl = dwmac4_flow_ctrl, 363 + .pmt = dwmac4_pmt, 364 + .set_umac_addr = dwmac4_set_umac_addr, 365 + .get_umac_addr = dwmac4_get_umac_addr, 366 + .ctrl_ane = dwmac4_ctrl_ane, 367 + .get_adv = dwmac4_get_adv, 368 + .debug = dwmac4_debug, 369 + .set_filter = dwmac4_set_filter, 370 + }; 371 + 372 + struct mac_device_info *dwmac4_setup(void __iomem *ioaddr, int mcbins, 373 + int perfect_uc_entries, int *synopsys_id) 374 + { 375 + struct mac_device_info *mac; 376 + u32 hwid = readl(ioaddr + GMAC_VERSION); 377 + 378 + mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL); 379 + if (!mac) 380 + return NULL; 381 + 382 + mac->pcsr = ioaddr; 383 + mac->multicast_filter_bins = mcbins; 384 + mac->unicast_filter_entries = perfect_uc_entries; 385 + mac->mcast_bits_log2 = 0; 386 + 387 + if (mac->multicast_filter_bins) 388 + mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); 389 + 390 + mac->mac = &dwmac4_ops; 391 + 392 + mac->link.port = GMAC_CONFIG_PS; 393 + mac->link.duplex = GMAC_CONFIG_DM; 394 + mac->link.speed = GMAC_CONFIG_FES; 395 + mac->mii.addr = GMAC_MDIO_ADDR; 396 + mac->mii.data = GMAC_MDIO_DATA; 397 + 398 + /* Get and dump the chip ID */ 399 + *synopsys_id = stmmac_get_synopsys_id(hwid); 400 + 401 + if (*synopsys_id > DWMAC_CORE_4_00) 402 + mac->dma = &dwmac410_dma_ops; 403 + else 404 + mac->dma = &dwmac4_dma_ops; 405 + 406 + return mac; 407 + }