1 /*- 2 * Copyright (c) 2011-2012 Semihalf. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/kernel.h> 31 #include <sys/module.h> 32 #include <sys/bus.h> 33 #include <sys/rman.h> 34 #include <sys/malloc.h> 35 #include <sys/mbuf.h> 36 #include <sys/socket.h> 37 #include <sys/sysctl.h> 38 #include <sys/sockio.h> 39 40 #include <machine/bus.h> 41 #include <machine/resource.h> 42 43 #include <net/ethernet.h> 44 #include <net/if.h> 45 #include <net/if_dl.h> 46 #include <net/if_media.h> 47 #include <net/if_types.h> 48 #include <net/if_arp.h> 49 50 #include <dev/mii/mii.h> 51 #include <dev/mii/miivar.h> 52 #include <dev/ofw/ofw_bus.h> 53 #include <dev/ofw/ofw_bus_subr.h> 54 #include <dev/ofw/openfirm.h> 55 56 #include "miibus_if.h" 57 58 #include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h> 59 #include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h> 60 #include <contrib/ncsw/inc/Peripherals/fm_port_ext.h> 61 #include <contrib/ncsw/inc/flib/fsl_fman_dtsec.h> 62 #include <contrib/ncsw/inc/xx_ext.h> 63 64 #include "fman.h" 65 #include "if_dtsec.h" 66 #include "if_dtsec_im.h" 67 #include "if_dtsec_rm.h" 68 69 #define DTSEC_MIN_FRAME_SIZE 64 70 #define DTSEC_MAX_FRAME_SIZE 9600 71 72 #define DTSEC_REG_MAXFRM 0x110 73 #define DTSEC_REG_GADDR(i) (0x0a0 + 4*(i)) 74 75 /** 76 * @group dTSEC private defines. 77 * @{ 78 */ 79 /** 80 * dTSEC FMan MAC exceptions info struct. 81 */ 82 struct dtsec_fm_mac_ex_str { 83 const int num; 84 const char *str; 85 }; 86 /** @} */ 87 88 89 /** 90 * @group FMan MAC routines. 91 * @{ 92 */ 93 #define DTSEC_MAC_EXCEPTIONS_END (-1) 94 95 /** 96 * FMan MAC exceptions. 97 */ 98 static const struct dtsec_fm_mac_ex_str dtsec_fm_mac_exceptions[] = { 99 { e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO, "MDIO scan event" }, 100 { e_FM_MAC_EX_10G_MDIO_CMD_CMPL, "MDIO command completion" }, 101 { e_FM_MAC_EX_10G_REM_FAULT, "Remote fault" }, 102 { e_FM_MAC_EX_10G_LOC_FAULT, "Local fault" }, 103 { e_FM_MAC_EX_10G_1TX_ECC_ER, "Transmit frame ECC error" }, 104 { e_FM_MAC_EX_10G_TX_FIFO_UNFL, "Transmit FIFO underflow" }, 105 { e_FM_MAC_EX_10G_TX_FIFO_OVFL, "Receive FIFO overflow" }, 106 { e_FM_MAC_EX_10G_TX_ER, "Transmit frame error" }, 107 { e_FM_MAC_EX_10G_RX_FIFO_OVFL, "Receive FIFO overflow" }, 108 { e_FM_MAC_EX_10G_RX_ECC_ER, "Receive frame ECC error" }, 109 { e_FM_MAC_EX_10G_RX_JAB_FRM, "Receive jabber frame" }, 110 { e_FM_MAC_EX_10G_RX_OVRSZ_FRM, "Receive oversized frame" }, 111 { e_FM_MAC_EX_10G_RX_RUNT_FRM, "Receive runt frame" }, 112 { e_FM_MAC_EX_10G_RX_FRAG_FRM, "Receive fragment frame" }, 113 { e_FM_MAC_EX_10G_RX_LEN_ER, "Receive payload length error" }, 114 { e_FM_MAC_EX_10G_RX_CRC_ER, "Receive CRC error" }, 115 { e_FM_MAC_EX_10G_RX_ALIGN_ER, "Receive alignment error" }, 116 { e_FM_MAC_EX_1G_BAB_RX, "Babbling receive error" }, 117 { e_FM_MAC_EX_1G_RX_CTL, "Receive control (pause frame) interrupt" }, 118 { e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, "Graceful transmit stop " 119 "complete" }, 120 { e_FM_MAC_EX_1G_BAB_TX, "Babbling transmit error" }, 121 { e_FM_MAC_EX_1G_TX_CTL, "Transmit control (pause frame) interrupt" }, 122 { e_FM_MAC_EX_1G_TX_ERR, "Transmit error" }, 123 { e_FM_MAC_EX_1G_LATE_COL, "Late collision" }, 124 { e_FM_MAC_EX_1G_COL_RET_LMT, "Collision retry limit" }, 125 { e_FM_MAC_EX_1G_TX_FIFO_UNDRN, "Transmit FIFO underrun" }, 126 { e_FM_MAC_EX_1G_MAG_PCKT, "Magic Packet detected when dTSEC is in " 127 "Magic Packet detection mode" }, 128 { e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET, "MII management read completion" }, 129 { e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET, "MII management write completion" }, 130 { e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, "Graceful receive stop " 131 "complete" }, 132 { e_FM_MAC_EX_1G_TX_DATA_ERR, "Internal data error on transmit" }, 133 { e_FM_MAC_EX_1G_RX_DATA_ERR, "Internal data error on receive" }, 134 { e_FM_MAC_EX_1G_1588_TS_RX_ERR, "Time-Stamp Receive Error" }, 135 { e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, "MIB counter overflow" }, 136 { DTSEC_MAC_EXCEPTIONS_END, "" } 137 }; 138 139 static const char * 140 dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception) 141 { 142 int i; 143 144 for (i = 0; dtsec_fm_mac_exceptions[i].num != exception && 145 dtsec_fm_mac_exceptions[i].num != DTSEC_MAC_EXCEPTIONS_END; ++i) 146 ; 147 148 if (dtsec_fm_mac_exceptions[i].num == DTSEC_MAC_EXCEPTIONS_END) 149 return ("<Unknown Exception>"); 150 151 return (dtsec_fm_mac_exceptions[i].str); 152 } 153 154 static void 155 dtsec_fm_mac_mdio_event_callback(t_Handle h_App, 156 e_FmMacExceptions exception) 157 { 158 struct dtsec_softc *sc; 159 160 sc = h_App; 161 device_printf(sc->sc_dev, "MDIO event %i: %s.\n", exception, 162 dtsec_fm_mac_ex_to_str(exception)); 163 } 164 165 static void 166 dtsec_fm_mac_exception_callback(t_Handle app, e_FmMacExceptions exception) 167 { 168 struct dtsec_softc *sc; 169 170 sc = app; 171 device_printf(sc->sc_dev, "MAC exception %i: %s.\n", exception, 172 dtsec_fm_mac_ex_to_str(exception)); 173 } 174 175 static void 176 dtsec_fm_mac_free(struct dtsec_softc *sc) 177 { 178 if (sc->sc_mach == NULL) 179 return; 180 181 FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 182 FM_MAC_Free(sc->sc_mach); 183 sc->sc_mach = NULL; 184 } 185 186 static int 187 dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac) 188 { 189 t_FmMacParams params; 190 t_Error error; 191 192 memset(¶ms, 0, sizeof(params)); 193 memcpy(¶ms.addr, mac, sizeof(params.addr)); 194 195 params.baseAddr = rman_get_bushandle(sc->sc_mem); 196 params.enetMode = sc->sc_mac_enet_mode; 197 params.macId = sc->sc_eth_id; 198 params.mdioIrq = sc->sc_mac_mdio_irq; 199 params.f_Event = dtsec_fm_mac_mdio_event_callback; 200 params.f_Exception = dtsec_fm_mac_exception_callback; 201 params.h_App = sc; 202 params.h_Fm = sc->sc_fmh; 203 204 sc->sc_mach = FM_MAC_Config(¶ms); 205 if (sc->sc_mach == NULL) { 206 device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n" 207 ); 208 return (ENXIO); 209 } 210 211 error = FM_MAC_ConfigResetOnInit(sc->sc_mach, TRUE); 212 if (error != E_OK) { 213 device_printf(sc->sc_dev, "couldn't enable reset on init " 214 "feature.\n"); 215 dtsec_fm_mac_free(sc); 216 return (ENXIO); 217 } 218 219 /* Do not inform about pause frames */ 220 error = FM_MAC_ConfigException(sc->sc_mach, e_FM_MAC_EX_1G_RX_CTL, 221 FALSE); 222 if (error != E_OK) { 223 device_printf(sc->sc_dev, "couldn't disable pause frames " 224 "exception.\n"); 225 dtsec_fm_mac_free(sc); 226 return (ENXIO); 227 } 228 229 error = FM_MAC_Init(sc->sc_mach); 230 if (error != E_OK) { 231 device_printf(sc->sc_dev, "couldn't initialize FM_MAC module." 232 "\n"); 233 dtsec_fm_mac_free(sc); 234 return (ENXIO); 235 } 236 237 return (0); 238 } 239 /** @} */ 240 241 242 /** 243 * @group FMan PORT routines. 244 * @{ 245 */ 246 static const char * 247 dtsec_fm_port_ex_to_str(e_FmPortExceptions exception) 248 { 249 250 switch (exception) { 251 case e_FM_PORT_EXCEPTION_IM_BUSY: 252 return ("IM: RX busy"); 253 default: 254 return ("<Unknown Exception>"); 255 } 256 } 257 258 void 259 dtsec_fm_port_rx_exception_callback(t_Handle app, 260 e_FmPortExceptions exception) 261 { 262 struct dtsec_softc *sc; 263 264 sc = app; 265 device_printf(sc->sc_dev, "RX exception: %i: %s.\n", exception, 266 dtsec_fm_port_ex_to_str(exception)); 267 } 268 269 void 270 dtsec_fm_port_tx_exception_callback(t_Handle app, 271 e_FmPortExceptions exception) 272 { 273 struct dtsec_softc *sc; 274 275 sc = app; 276 device_printf(sc->sc_dev, "TX exception: %i: %s.\n", exception, 277 dtsec_fm_port_ex_to_str(exception)); 278 } 279 280 e_FmPortType 281 dtsec_fm_port_rx_type(enum eth_dev_type type) 282 { 283 switch (type) { 284 case ETH_DTSEC: 285 return (e_FM_PORT_TYPE_RX); 286 case ETH_10GSEC: 287 return (e_FM_PORT_TYPE_RX_10G); 288 default: 289 return (e_FM_PORT_TYPE_DUMMY); 290 } 291 } 292 293 e_FmPortType 294 dtsec_fm_port_tx_type(enum eth_dev_type type) 295 { 296 297 switch (type) { 298 case ETH_DTSEC: 299 return (e_FM_PORT_TYPE_TX); 300 case ETH_10GSEC: 301 return (e_FM_PORT_TYPE_TX_10G); 302 default: 303 return (e_FM_PORT_TYPE_DUMMY); 304 } 305 } 306 307 static void 308 dtsec_fm_port_free_both(struct dtsec_softc *sc) 309 { 310 if (sc->sc_rxph) { 311 FM_PORT_Free(sc->sc_rxph); 312 sc->sc_rxph = NULL; 313 } 314 315 if (sc->sc_txph) { 316 FM_PORT_Free(sc->sc_txph); 317 sc->sc_txph = NULL; 318 } 319 } 320 /** @} */ 321 322 323 /** 324 * @group IFnet routines. 325 * @{ 326 */ 327 static int 328 dtsec_set_mtu(struct dtsec_softc *sc, unsigned int mtu) 329 { 330 331 mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN; 332 333 DTSEC_LOCK_ASSERT(sc); 334 335 if (mtu >= DTSEC_MIN_FRAME_SIZE && mtu <= DTSEC_MAX_FRAME_SIZE) { 336 bus_write_4(sc->sc_mem, DTSEC_REG_MAXFRM, mtu); 337 return (mtu); 338 } 339 340 return (0); 341 } 342 343 static u_int 344 dtsec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 345 { 346 struct dtsec_softc *sc = arg; 347 348 FM_MAC_AddHashMacAddr(sc->sc_mach, (t_EnetAddr *)LLADDR(sdl)); 349 350 return (1); 351 } 352 353 static void 354 dtsec_setup_multicast(struct dtsec_softc *sc) 355 { 356 int i; 357 358 if (if_getflags(sc->sc_ifnet) & IFF_ALLMULTI) { 359 for (i = 0; i < 8; i++) 360 bus_write_4(sc->sc_mem, DTSEC_REG_GADDR(i), 0xFFFFFFFF); 361 362 return; 363 } 364 365 fman_dtsec_reset_filter_table(rman_get_virtual(sc->sc_mem), 366 true, false); 367 if_foreach_llmaddr(sc->sc_ifnet, dtsec_hash_maddr, sc); 368 } 369 370 static int 371 dtsec_if_enable_locked(struct dtsec_softc *sc) 372 { 373 int error; 374 375 DTSEC_LOCK_ASSERT(sc); 376 377 error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 378 if (error != E_OK) 379 return (EIO); 380 381 error = FM_PORT_Enable(sc->sc_rxph); 382 if (error != E_OK) 383 return (EIO); 384 385 error = FM_PORT_Enable(sc->sc_txph); 386 if (error != E_OK) 387 return (EIO); 388 389 dtsec_setup_multicast(sc); 390 391 if_setdrvflagbits(sc->sc_ifnet, IFF_DRV_RUNNING, 0); 392 393 /* Refresh link state */ 394 dtsec_miibus_statchg(sc->sc_dev); 395 396 return (0); 397 } 398 399 static int 400 dtsec_if_disable_locked(struct dtsec_softc *sc) 401 { 402 int error; 403 404 DTSEC_LOCK_ASSERT(sc); 405 406 error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 407 if (error != E_OK) 408 return (EIO); 409 410 error = FM_PORT_Disable(sc->sc_rxph); 411 if (error != E_OK) 412 return (EIO); 413 414 error = FM_PORT_Disable(sc->sc_txph); 415 if (error != E_OK) 416 return (EIO); 417 418 if_setdrvflagbits(sc->sc_ifnet, 0, IFF_DRV_RUNNING); 419 420 return (0); 421 } 422 423 static int 424 dtsec_if_ioctl(if_t ifp, u_long command, caddr_t data) 425 { 426 struct dtsec_softc *sc; 427 struct ifreq *ifr; 428 int error; 429 430 sc = if_getsoftc(ifp); 431 ifr = (struct ifreq *)data; 432 error = 0; 433 434 /* Basic functionality to achieve media status reports */ 435 switch (command) { 436 case SIOCSIFMTU: 437 DTSEC_LOCK(sc); 438 if (dtsec_set_mtu(sc, ifr->ifr_mtu)) 439 if_setmtu(ifp, ifr->ifr_mtu); 440 else 441 error = EINVAL; 442 DTSEC_UNLOCK(sc); 443 break; 444 case SIOCSIFFLAGS: 445 DTSEC_LOCK(sc); 446 447 if (if_getflags(sc->sc_ifnet) & IFF_UP) 448 error = dtsec_if_enable_locked(sc); 449 else 450 error = dtsec_if_disable_locked(sc); 451 452 DTSEC_UNLOCK(sc); 453 break; 454 455 case SIOCGIFMEDIA: 456 case SIOCSIFMEDIA: 457 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, 458 command); 459 break; 460 461 default: 462 error = ether_ioctl(ifp, command, data); 463 } 464 465 return (error); 466 } 467 468 static void 469 dtsec_if_tick(void *arg) 470 { 471 struct dtsec_softc *sc; 472 473 sc = arg; 474 475 /* TODO */ 476 DTSEC_LOCK(sc); 477 478 mii_tick(sc->sc_mii); 479 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); 480 481 DTSEC_UNLOCK(sc); 482 } 483 484 static void 485 dtsec_if_deinit_locked(struct dtsec_softc *sc) 486 { 487 488 DTSEC_LOCK_ASSERT(sc); 489 490 DTSEC_UNLOCK(sc); 491 callout_drain(&sc->sc_tick_callout); 492 DTSEC_LOCK(sc); 493 } 494 495 static void 496 dtsec_if_init_locked(struct dtsec_softc *sc) 497 { 498 int error; 499 500 DTSEC_LOCK_ASSERT(sc); 501 502 /* Set MAC address */ 503 error = FM_MAC_ModifyMacAddr(sc->sc_mach, 504 (t_EnetAddr *)if_getlladdr(sc->sc_ifnet)); 505 if (error != E_OK) { 506 device_printf(sc->sc_dev, "couldn't set MAC address.\n"); 507 goto err; 508 } 509 510 /* Start MII polling */ 511 if (sc->sc_mii) 512 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); 513 514 if (if_getflags(sc->sc_ifnet) & IFF_UP) { 515 error = dtsec_if_enable_locked(sc); 516 if (error != 0) 517 goto err; 518 } else { 519 error = dtsec_if_disable_locked(sc); 520 if (error != 0) 521 goto err; 522 } 523 524 return; 525 526 err: 527 dtsec_if_deinit_locked(sc); 528 device_printf(sc->sc_dev, "initialization error.\n"); 529 return; 530 } 531 532 static void 533 dtsec_if_init(void *data) 534 { 535 struct dtsec_softc *sc; 536 537 sc = data; 538 539 DTSEC_LOCK(sc); 540 dtsec_if_init_locked(sc); 541 DTSEC_UNLOCK(sc); 542 } 543 544 static void 545 dtsec_if_start(if_t ifp) 546 { 547 struct dtsec_softc *sc; 548 549 sc = if_getsoftc(ifp); 550 DTSEC_LOCK(sc); 551 sc->sc_start_locked(sc); 552 DTSEC_UNLOCK(sc); 553 } 554 555 static void 556 dtsec_if_watchdog(if_t ifp) 557 { 558 /* TODO */ 559 } 560 /** @} */ 561 562 563 /** 564 * @group IFmedia routines. 565 * @{ 566 */ 567 static int 568 dtsec_ifmedia_upd(if_t ifp) 569 { 570 struct dtsec_softc *sc = if_getsoftc(ifp); 571 572 DTSEC_LOCK(sc); 573 mii_mediachg(sc->sc_mii); 574 DTSEC_UNLOCK(sc); 575 576 return (0); 577 } 578 579 static void 580 dtsec_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 581 { 582 struct dtsec_softc *sc = if_getsoftc(ifp); 583 584 DTSEC_LOCK(sc); 585 586 mii_pollstat(sc->sc_mii); 587 588 ifmr->ifm_active = sc->sc_mii->mii_media_active; 589 ifmr->ifm_status = sc->sc_mii->mii_media_status; 590 591 DTSEC_UNLOCK(sc); 592 } 593 /** @} */ 594 595 596 /** 597 * @group dTSEC bus interface. 598 * @{ 599 */ 600 static void 601 dtsec_configure_mode(struct dtsec_softc *sc) 602 { 603 char tunable[64]; 604 605 snprintf(tunable, sizeof(tunable), "%s.independent_mode", 606 device_get_nameunit(sc->sc_dev)); 607 608 sc->sc_mode = DTSEC_MODE_REGULAR; 609 TUNABLE_INT_FETCH(tunable, &sc->sc_mode); 610 611 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 612 sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init; 613 sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init; 614 sc->sc_start_locked = dtsec_rm_if_start_locked; 615 } else { 616 sc->sc_port_rx_init = dtsec_im_fm_port_rx_init; 617 sc->sc_port_tx_init = dtsec_im_fm_port_tx_init; 618 sc->sc_start_locked = dtsec_im_if_start_locked; 619 } 620 621 device_printf(sc->sc_dev, "Configured for %s mode.\n", 622 (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent"); 623 } 624 625 int 626 dtsec_attach(device_t dev) 627 { 628 struct dtsec_softc *sc; 629 device_t parent; 630 int error; 631 if_t ifp; 632 633 sc = device_get_softc(dev); 634 635 parent = device_get_parent(dev); 636 sc->sc_dev = dev; 637 sc->sc_mac_mdio_irq = NO_IRQ; 638 639 /* Check if MallocSmart allocator is ready */ 640 if (XX_MallocSmartInit() != E_OK) 641 return (ENXIO); 642 643 /* Init locks */ 644 mtx_init(&sc->sc_lock, device_get_nameunit(dev), 645 "DTSEC Global Lock", MTX_DEF); 646 647 mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev), 648 "DTSEC MII Lock", MTX_DEF); 649 650 /* Init callouts */ 651 callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE); 652 653 /* Read configuraton */ 654 if ((error = fman_get_handle(parent, &sc->sc_fmh)) != 0) 655 return (error); 656 657 if ((error = fman_get_muram_handle(parent, &sc->sc_muramh)) != 0) 658 return (error); 659 660 if ((error = fman_get_bushandle(parent, &sc->sc_fm_base)) != 0) 661 return (error); 662 663 /* Configure working mode */ 664 dtsec_configure_mode(sc); 665 666 /* If we are working in regular mode configure BMAN and QMAN */ 667 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 668 /* Create RX buffer pool */ 669 error = dtsec_rm_pool_rx_init(sc); 670 if (error != 0) 671 return (EIO); 672 673 /* Create RX frame queue range */ 674 error = dtsec_rm_fqr_rx_init(sc); 675 if (error != 0) 676 return (EIO); 677 678 /* Create frame info pool */ 679 error = dtsec_rm_fi_pool_init(sc); 680 if (error != 0) 681 return (EIO); 682 683 /* Create TX frame queue range */ 684 error = dtsec_rm_fqr_tx_init(sc); 685 if (error != 0) 686 return (EIO); 687 } 688 689 /* Init FMan MAC module. */ 690 error = dtsec_fm_mac_init(sc, sc->sc_mac_addr); 691 if (error != 0) { 692 dtsec_detach(dev); 693 return (ENXIO); 694 } 695 696 /* Init FMan TX port */ 697 error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev)); 698 if (error != 0) { 699 dtsec_detach(dev); 700 return (ENXIO); 701 } 702 703 /* Init FMan RX port */ 704 error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev)); 705 if (error != 0) { 706 dtsec_detach(dev); 707 return (ENXIO); 708 } 709 710 /* Create network interface for upper layers */ 711 ifp = sc->sc_ifnet = if_alloc(IFT_ETHER); 712 if (ifp == NULL) { 713 device_printf(sc->sc_dev, "if_alloc() failed.\n"); 714 dtsec_detach(dev); 715 return (ENOMEM); 716 } 717 718 if_setsoftc(ifp, sc); 719 720 if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST); 721 if_setinitfn(ifp, dtsec_if_init); 722 if_setstartfn(ifp, dtsec_if_start); 723 if_setioctlfn(ifp, dtsec_if_ioctl); 724 if_setsendqlen(ifp, IFQ_MAXLEN); 725 726 if (sc->sc_phy_addr >= 0) 727 if_initname(ifp, device_get_name(sc->sc_dev), 728 device_get_unit(sc->sc_dev)); 729 else 730 if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev)); 731 732 /* TODO */ 733 #if 0 734 if_setsendqlen(ifp, TSEC_TX_NUM_DESC - 1); 735 if_setsendqready(ifp); 736 #endif 737 738 if_setcapabilities(ifp, IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU); 739 if_setcapenable(ifp, if_getcapabilities(ifp)); 740 741 /* Attach PHY(s) */ 742 error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd, 743 dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr, 744 MII_OFFSET_ANY, 0); 745 if (error) { 746 device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error); 747 dtsec_detach(sc->sc_dev); 748 return (error); 749 } 750 sc->sc_mii = device_get_softc(sc->sc_mii_dev); 751 752 /* Attach to stack */ 753 ether_ifattach(ifp, sc->sc_mac_addr); 754 755 return (0); 756 } 757 758 int 759 dtsec_detach(device_t dev) 760 { 761 struct dtsec_softc *sc; 762 if_t ifp; 763 764 sc = device_get_softc(dev); 765 ifp = sc->sc_ifnet; 766 767 if (device_is_attached(dev)) { 768 ether_ifdetach(ifp); 769 /* Shutdown interface */ 770 DTSEC_LOCK(sc); 771 dtsec_if_deinit_locked(sc); 772 DTSEC_UNLOCK(sc); 773 } 774 775 if (sc->sc_ifnet) { 776 if_free(sc->sc_ifnet); 777 sc->sc_ifnet = NULL; 778 } 779 780 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 781 /* Free RX/TX FQRs */ 782 dtsec_rm_fqr_rx_free(sc); 783 dtsec_rm_fqr_tx_free(sc); 784 785 /* Free frame info pool */ 786 dtsec_rm_fi_pool_free(sc); 787 788 /* Free RX buffer pool */ 789 dtsec_rm_pool_rx_free(sc); 790 } 791 792 dtsec_fm_mac_free(sc); 793 dtsec_fm_port_free_both(sc); 794 795 /* Destroy lock */ 796 mtx_destroy(&sc->sc_lock); 797 798 return (0); 799 } 800 801 int 802 dtsec_suspend(device_t dev) 803 { 804 805 return (0); 806 } 807 808 int 809 dtsec_resume(device_t dev) 810 { 811 812 return (0); 813 } 814 815 int 816 dtsec_shutdown(device_t dev) 817 { 818 819 return (0); 820 } 821 /** @} */ 822 823 824 /** 825 * @group MII bus interface. 826 * @{ 827 */ 828 int 829 dtsec_miibus_readreg(device_t dev, int phy, int reg) 830 { 831 struct dtsec_softc *sc; 832 833 sc = device_get_softc(dev); 834 835 return (MIIBUS_READREG(sc->sc_mdio, phy, reg)); 836 } 837 838 int 839 dtsec_miibus_writereg(device_t dev, int phy, int reg, int value) 840 { 841 842 struct dtsec_softc *sc; 843 844 sc = device_get_softc(dev); 845 846 return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value)); 847 } 848 849 void 850 dtsec_miibus_statchg(device_t dev) 851 { 852 struct dtsec_softc *sc; 853 e_EnetSpeed speed; 854 bool duplex; 855 int error; 856 857 sc = device_get_softc(dev); 858 859 DTSEC_LOCK_ASSERT(sc); 860 861 duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX); 862 863 switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) { 864 case IFM_1000_T: 865 case IFM_1000_SX: 866 speed = e_ENET_SPEED_1000; 867 break; 868 869 case IFM_100_TX: 870 speed = e_ENET_SPEED_100; 871 break; 872 873 case IFM_10_T: 874 speed = e_ENET_SPEED_10; 875 break; 876 877 default: 878 speed = e_ENET_SPEED_10; 879 } 880 881 error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex); 882 if (error != E_OK) 883 device_printf(sc->sc_dev, "error while adjusting MAC speed.\n"); 884 } 885 /** @} */ 886