1 /*- 2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3 * 4 * This software was developed by SRI International and the University of 5 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 6 * ("CTSRD"), as part of the DARPA CRASH research programme. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * Ethernet media access controller (EMAC) 32 * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22) 33 * 34 * EMAC is an instance of the Synopsys DesignWare 3504-0 35 * Universal 10/100/1000 Ethernet MAC (DWC_gmac). 36 */ 37 38 #include <sys/cdefs.h> 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/bus.h> 42 #include <sys/kernel.h> 43 #include <sys/lock.h> 44 #include <sys/malloc.h> 45 #include <sys/mbuf.h> 46 #include <sys/module.h> 47 #include <sys/mutex.h> 48 #include <sys/rman.h> 49 #include <sys/socket.h> 50 51 #include <net/if.h> 52 #include <net/ethernet.h> 53 #include <net/if_dl.h> 54 #include <net/if_media.h> 55 56 #include <machine/bus.h> 57 58 #include <dev/extres/clk/clk.h> 59 #include <dev/extres/hwreset/hwreset.h> 60 61 #include <dev/mii/mii.h> 62 #include <dev/mii/miivar.h> 63 #include <dev/ofw/ofw_bus.h> 64 #include <dev/ofw/ofw_bus_subr.h> 65 #include <dev/mii/mii_fdt.h> 66 67 #include <dev/dwc/if_dwcvar.h> 68 #include <dev/dwc/dwc1000_reg.h> 69 #include <dev/dwc/dwc1000_core.h> 70 #include <dev/dwc/dwc1000_dma.h> 71 72 #include "if_dwc_if.h" 73 74 struct dwc_hash_maddr_ctx { 75 struct dwc_softc *sc; 76 uint32_t hash[8]; 77 }; 78 79 #define STATS_HARVEST_INTERVAL 2 80 81 /* Pause time field in the transmitted control frame */ 82 static int dwc_pause_time = 0xffff; 83 TUNABLE_INT("hw.dwc.pause_time", &dwc_pause_time); 84 85 /* 86 * MIIBUS functions 87 */ 88 89 int 90 dwc1000_miibus_read_reg(device_t dev, int phy, int reg) 91 { 92 struct dwc_softc *sc; 93 uint16_t mii; 94 size_t cnt; 95 int rv = 0; 96 97 sc = device_get_softc(dev); 98 99 mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) 100 | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) 101 | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) 102 | GMII_ADDRESS_GB; /* Busy flag */ 103 104 WRITE4(sc, GMII_ADDRESS, mii); 105 106 for (cnt = 0; cnt < 1000; cnt++) { 107 if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { 108 rv = READ4(sc, GMII_DATA); 109 break; 110 } 111 DELAY(10); 112 } 113 114 return rv; 115 } 116 117 int 118 dwc1000_miibus_write_reg(device_t dev, int phy, int reg, int val) 119 { 120 struct dwc_softc *sc; 121 uint16_t mii; 122 size_t cnt; 123 124 sc = device_get_softc(dev); 125 126 mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) 127 | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) 128 | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) 129 | GMII_ADDRESS_GB | GMII_ADDRESS_GW; 130 131 WRITE4(sc, GMII_DATA, val); 132 WRITE4(sc, GMII_ADDRESS, mii); 133 134 for (cnt = 0; cnt < 1000; cnt++) { 135 if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { 136 break; 137 } 138 DELAY(10); 139 } 140 141 return (0); 142 } 143 144 void 145 dwc1000_miibus_statchg(device_t dev) 146 { 147 struct dwc_softc *sc; 148 struct mii_data *mii; 149 uint32_t reg; 150 151 /* 152 * Called by the MII bus driver when the PHY establishes 153 * link to set the MAC interface registers. 154 */ 155 156 sc = device_get_softc(dev); 157 158 DWC_ASSERT_LOCKED(sc); 159 160 mii = sc->mii_softc; 161 162 if (mii->mii_media_status & IFM_ACTIVE) 163 sc->link_is_up = true; 164 else 165 sc->link_is_up = false; 166 167 reg = READ4(sc, MAC_CONFIGURATION); 168 switch (IFM_SUBTYPE(mii->mii_media_active)) { 169 case IFM_1000_T: 170 case IFM_1000_SX: 171 reg &= ~(CONF_FES | CONF_PS); 172 break; 173 case IFM_100_TX: 174 reg |= (CONF_FES | CONF_PS); 175 break; 176 case IFM_10_T: 177 reg &= ~(CONF_FES); 178 reg |= (CONF_PS); 179 break; 180 case IFM_NONE: 181 sc->link_is_up = false; 182 return; 183 default: 184 sc->link_is_up = false; 185 device_printf(dev, "Unsupported media %u\n", 186 IFM_SUBTYPE(mii->mii_media_active)); 187 return; 188 } 189 if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 190 reg |= (CONF_DM); 191 else 192 reg &= ~(CONF_DM); 193 WRITE4(sc, MAC_CONFIGURATION, reg); 194 195 reg = FLOW_CONTROL_UP; 196 if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 197 reg |= FLOW_CONTROL_TX; 198 if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 199 reg |= FLOW_CONTROL_RX; 200 if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 201 reg |= dwc_pause_time << FLOW_CONTROL_PT_SHIFT; 202 WRITE4(sc, FLOW_CONTROL, reg); 203 204 IF_DWC_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active)); 205 206 } 207 208 void 209 dwc1000_core_setup(struct dwc_softc *sc) 210 { 211 uint32_t reg; 212 213 DWC_ASSERT_LOCKED(sc); 214 215 /* Enable core */ 216 reg = READ4(sc, MAC_CONFIGURATION); 217 reg |= (CONF_JD | CONF_ACS | CONF_BE); 218 WRITE4(sc, MAC_CONFIGURATION, reg); 219 } 220 221 void 222 dwc1000_enable_mac(struct dwc_softc *sc, bool enable) 223 { 224 uint32_t reg; 225 226 DWC_ASSERT_LOCKED(sc); 227 reg = READ4(sc, MAC_CONFIGURATION); 228 if (enable) 229 reg |= CONF_TE | CONF_RE; 230 else 231 reg &= ~(CONF_TE | CONF_RE); 232 WRITE4(sc, MAC_CONFIGURATION, reg); 233 } 234 235 void 236 dwc1000_enable_csum_offload(struct dwc_softc *sc) 237 { 238 uint32_t reg; 239 240 DWC_ASSERT_LOCKED(sc); 241 reg = READ4(sc, MAC_CONFIGURATION); 242 if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0) 243 reg |= CONF_IPC; 244 else 245 reg &= ~CONF_IPC; 246 WRITE4(sc, MAC_CONFIGURATION, reg); 247 } 248 249 static const uint8_t nibbletab[] = { 250 /* 0x0 0000 -> 0000 */ 0x0, 251 /* 0x1 0001 -> 1000 */ 0x8, 252 /* 0x2 0010 -> 0100 */ 0x4, 253 /* 0x3 0011 -> 1100 */ 0xc, 254 /* 0x4 0100 -> 0010 */ 0x2, 255 /* 0x5 0101 -> 1010 */ 0xa, 256 /* 0x6 0110 -> 0110 */ 0x6, 257 /* 0x7 0111 -> 1110 */ 0xe, 258 /* 0x8 1000 -> 0001 */ 0x1, 259 /* 0x9 1001 -> 1001 */ 0x9, 260 /* 0xa 1010 -> 0101 */ 0x5, 261 /* 0xb 1011 -> 1101 */ 0xd, 262 /* 0xc 1100 -> 0011 */ 0x3, 263 /* 0xd 1101 -> 1011 */ 0xb, 264 /* 0xe 1110 -> 0111 */ 0x7, 265 /* 0xf 1111 -> 1111 */ 0xf, }; 266 267 static uint8_t 268 bitreverse(uint8_t x) 269 { 270 271 return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4]; 272 } 273 274 static u_int 275 dwc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 276 { 277 struct dwc_hash_maddr_ctx *ctx = arg; 278 uint32_t crc, hashbit, hashreg; 279 uint8_t val; 280 281 crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); 282 /* Take lower 8 bits and reverse it */ 283 val = bitreverse(~crc & 0xff); 284 /* 285 * TODO: There is probably a HW_FEATURES bit which isn't 286 * related to the extended descriptors that describe this 287 */ 288 if (!ctx->sc->dma_ext_desc) 289 val >>= 2; /* Only need lower 6 bits */ 290 hashreg = (val >> 5); 291 hashbit = (val & 31); 292 ctx->hash[hashreg] |= (1 << hashbit); 293 294 return (1); 295 } 296 297 void 298 dwc1000_setup_rxfilter(struct dwc_softc *sc) 299 { 300 struct dwc_hash_maddr_ctx ctx; 301 if_t ifp; 302 uint8_t *eaddr; 303 uint32_t ffval, hi, lo; 304 int nhash, i; 305 306 DWC_ASSERT_LOCKED(sc); 307 308 ifp = sc->ifp; 309 /* 310 * TODO: There is probably a HW_FEATURES bit which isn't 311 * related to the extended descriptors that describe this 312 */ 313 nhash = sc->dma_ext_desc == false ? 2 : 8; 314 315 /* 316 * Set the multicast (group) filter hash. 317 */ 318 if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) { 319 ffval = (FRAME_FILTER_PM); 320 for (i = 0; i < nhash; i++) 321 ctx.hash[i] = ~0; 322 } else { 323 ffval = (FRAME_FILTER_HMC); 324 for (i = 0; i < nhash; i++) 325 ctx.hash[i] = 0; 326 ctx.sc = sc; 327 if_foreach_llmaddr(ifp, dwc_hash_maddr, &ctx); 328 } 329 330 /* 331 * Set the individual address filter hash. 332 */ 333 if ((if_getflags(ifp) & IFF_PROMISC) != 0) 334 ffval |= (FRAME_FILTER_PR); 335 336 /* 337 * Set the primary address. 338 */ 339 eaddr = if_getlladdr(ifp); 340 lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) | 341 (eaddr[3] << 24); 342 hi = eaddr[4] | (eaddr[5] << 8); 343 WRITE4(sc, MAC_ADDRESS_LOW(0), lo); 344 WRITE4(sc, MAC_ADDRESS_HIGH(0), hi); 345 WRITE4(sc, MAC_FRAME_FILTER, ffval); 346 if (!sc->dma_ext_desc) { 347 WRITE4(sc, GMAC_MAC_HTLOW, ctx.hash[0]); 348 WRITE4(sc, GMAC_MAC_HTHIGH, ctx.hash[1]); 349 } else { 350 for (i = 0; i < nhash; i++) 351 WRITE4(sc, HASH_TABLE_REG(i), ctx.hash[i]); 352 } 353 } 354 355 void 356 dwc1000_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) 357 { 358 uint32_t hi, lo, rnd; 359 360 /* 361 * Try to recover a MAC address from the running hardware. If there's 362 * something non-zero there, assume the bootloader did the right thing 363 * and just use it. 364 * 365 * Otherwise, set the address to a convenient locally assigned address, 366 * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally 367 * assigned bit set, and the broadcast/multicast bit clear. 368 */ 369 lo = READ4(sc, MAC_ADDRESS_LOW(0)); 370 hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff; 371 if ((lo != 0xffffffff) || (hi != 0xffff)) { 372 hwaddr[0] = (lo >> 0) & 0xff; 373 hwaddr[1] = (lo >> 8) & 0xff; 374 hwaddr[2] = (lo >> 16) & 0xff; 375 hwaddr[3] = (lo >> 24) & 0xff; 376 hwaddr[4] = (hi >> 0) & 0xff; 377 hwaddr[5] = (hi >> 8) & 0xff; 378 } else { 379 rnd = arc4random() & 0x00ffffff; 380 hwaddr[0] = 'b'; 381 hwaddr[1] = 's'; 382 hwaddr[2] = 'd'; 383 hwaddr[3] = rnd >> 16; 384 hwaddr[4] = rnd >> 8; 385 hwaddr[5] = rnd >> 0; 386 } 387 } 388 389 /* 390 * Stats 391 */ 392 393 static void 394 dwc1000_clear_stats(struct dwc_softc *sc) 395 { 396 uint32_t reg; 397 398 reg = READ4(sc, MMC_CONTROL); 399 reg |= (MMC_CONTROL_CNTRST); 400 WRITE4(sc, MMC_CONTROL, reg); 401 } 402 403 void 404 dwc1000_harvest_stats(struct dwc_softc *sc) 405 { 406 if_t ifp; 407 408 /* We don't need to harvest too often. */ 409 if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL) 410 return; 411 412 sc->stats_harvest_count = 0; 413 ifp = sc->ifp; 414 415 if_inc_counter(ifp, IFCOUNTER_IERRORS, 416 READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) + 417 READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) + 418 READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) + 419 READ4(sc, RXLENGTHERROR)); 420 421 if_inc_counter(ifp, IFCOUNTER_OERRORS, 422 READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) + 423 READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR)); 424 425 if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 426 READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL)); 427 428 dwc1000_clear_stats(sc); 429 } 430 431 void 432 dwc1000_intr(struct dwc_softc *sc) 433 { 434 uint32_t reg; 435 436 DWC_ASSERT_LOCKED(sc); 437 438 reg = READ4(sc, INTERRUPT_STATUS); 439 if (reg) 440 READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS); 441 } 442 443 void 444 dwc1000_intr_disable(struct dwc_softc *sc) 445 { 446 447 WRITE4(sc, INTERRUPT_ENABLE, 0); 448 } 449