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 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/bus.h> 35 #include <sys/rman.h> 36 #include <sys/malloc.h> 37 #include <sys/mbuf.h> 38 #include <sys/socket.h> 39 #include <sys/sysctl.h> 40 #include <sys/sockio.h> 41 42 #include <machine/bus.h> 43 #include <machine/resource.h> 44 45 #include <net/ethernet.h> 46 #include <net/if.h> 47 #include <net/if_dl.h> 48 #include <net/if_media.h> 49 #include <net/if_types.h> 50 #include <net/if_arp.h> 51 52 #include <dev/mii/mii.h> 53 #include <dev/mii/miivar.h> 54 #include <dev/ofw/ofw_bus.h> 55 #include <dev/ofw/ofw_bus_subr.h> 56 #include <dev/ofw/openfirm.h> 57 58 #include "miibus_if.h" 59 60 #include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h> 61 #include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h> 62 #include <contrib/ncsw/inc/Peripherals/fm_port_ext.h> 63 #include <contrib/ncsw/inc/xx_ext.h> 64 65 #include "fman.h" 66 #include "if_dtsec.h" 67 #include "if_dtsec_im.h" 68 #include "if_dtsec_rm.h" 69 70 #define DTSEC_MIN_FRAME_SIZE 64 71 #define DTSEC_MAX_FRAME_SIZE 9600 72 73 #define DTSEC_REG_MAXFRM 0x110 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 int 344 dtsec_if_enable_locked(struct dtsec_softc *sc) 345 { 346 int error; 347 348 DTSEC_LOCK_ASSERT(sc); 349 350 error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 351 if (error != E_OK) 352 return (EIO); 353 354 error = FM_PORT_Enable(sc->sc_rxph); 355 if (error != E_OK) 356 return (EIO); 357 358 error = FM_PORT_Enable(sc->sc_txph); 359 if (error != E_OK) 360 return (EIO); 361 362 sc->sc_ifnet->if_drv_flags |= IFF_DRV_RUNNING; 363 364 /* Refresh link state */ 365 dtsec_miibus_statchg(sc->sc_dev); 366 367 return (0); 368 } 369 370 static int 371 dtsec_if_disable_locked(struct dtsec_softc *sc) 372 { 373 int error; 374 375 DTSEC_LOCK_ASSERT(sc); 376 377 error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 378 if (error != E_OK) 379 return (EIO); 380 381 error = FM_PORT_Disable(sc->sc_rxph); 382 if (error != E_OK) 383 return (EIO); 384 385 error = FM_PORT_Disable(sc->sc_txph); 386 if (error != E_OK) 387 return (EIO); 388 389 sc->sc_ifnet->if_drv_flags &= ~IFF_DRV_RUNNING; 390 391 return (0); 392 } 393 394 static int 395 dtsec_if_ioctl(if_t ifp, u_long command, caddr_t data) 396 { 397 struct dtsec_softc *sc; 398 struct ifreq *ifr; 399 int error; 400 401 sc = if_getsoftc(ifp); 402 ifr = (struct ifreq *)data; 403 error = 0; 404 405 /* Basic functionality to achieve media status reports */ 406 switch (command) { 407 case SIOCSIFMTU: 408 DTSEC_LOCK(sc); 409 if (dtsec_set_mtu(sc, ifr->ifr_mtu)) 410 if_setmtu(ifp, ifr->ifr_mtu); 411 else 412 error = EINVAL; 413 DTSEC_UNLOCK(sc); 414 break; 415 case SIOCSIFFLAGS: 416 DTSEC_LOCK(sc); 417 418 if (sc->sc_ifnet->if_flags & IFF_UP) 419 error = dtsec_if_enable_locked(sc); 420 else 421 error = dtsec_if_disable_locked(sc); 422 423 DTSEC_UNLOCK(sc); 424 break; 425 426 case SIOCGIFMEDIA: 427 case SIOCSIFMEDIA: 428 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, 429 command); 430 break; 431 432 default: 433 error = ether_ioctl(ifp, command, data); 434 } 435 436 return (error); 437 } 438 439 static void 440 dtsec_if_tick(void *arg) 441 { 442 struct dtsec_softc *sc; 443 444 sc = arg; 445 446 /* TODO */ 447 DTSEC_LOCK(sc); 448 449 mii_tick(sc->sc_mii); 450 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); 451 452 DTSEC_UNLOCK(sc); 453 } 454 455 static void 456 dtsec_if_deinit_locked(struct dtsec_softc *sc) 457 { 458 459 DTSEC_LOCK_ASSERT(sc); 460 461 DTSEC_UNLOCK(sc); 462 callout_drain(&sc->sc_tick_callout); 463 DTSEC_LOCK(sc); 464 } 465 466 static void 467 dtsec_if_init_locked(struct dtsec_softc *sc) 468 { 469 int error; 470 471 DTSEC_LOCK_ASSERT(sc); 472 473 /* Set MAC address */ 474 error = FM_MAC_ModifyMacAddr(sc->sc_mach, 475 (t_EnetAddr *)if_getlladdr(sc->sc_ifnet)); 476 if (error != E_OK) { 477 device_printf(sc->sc_dev, "couldn't set MAC address.\n"); 478 goto err; 479 } 480 481 /* Start MII polling */ 482 if (sc->sc_mii) 483 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); 484 485 if (sc->sc_ifnet->if_flags & IFF_UP) { 486 error = dtsec_if_enable_locked(sc); 487 if (error != 0) 488 goto err; 489 } else { 490 error = dtsec_if_disable_locked(sc); 491 if (error != 0) 492 goto err; 493 } 494 495 return; 496 497 err: 498 dtsec_if_deinit_locked(sc); 499 device_printf(sc->sc_dev, "initialization error.\n"); 500 return; 501 } 502 503 static void 504 dtsec_if_init(void *data) 505 { 506 struct dtsec_softc *sc; 507 508 sc = data; 509 510 DTSEC_LOCK(sc); 511 dtsec_if_init_locked(sc); 512 DTSEC_UNLOCK(sc); 513 } 514 515 static void 516 dtsec_if_start(if_t ifp) 517 { 518 struct dtsec_softc *sc; 519 520 sc = if_getsoftc(ifp); 521 DTSEC_LOCK(sc); 522 sc->sc_start_locked(sc); 523 DTSEC_UNLOCK(sc); 524 } 525 526 static void 527 dtsec_if_watchdog(if_t ifp) 528 { 529 /* TODO */ 530 } 531 /** @} */ 532 533 534 /** 535 * @group IFmedia routines. 536 * @{ 537 */ 538 static int 539 dtsec_ifmedia_upd(if_t ifp) 540 { 541 struct dtsec_softc *sc = if_getsoftc(ifp); 542 543 DTSEC_LOCK(sc); 544 mii_mediachg(sc->sc_mii); 545 DTSEC_UNLOCK(sc); 546 547 return (0); 548 } 549 550 static void 551 dtsec_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 552 { 553 struct dtsec_softc *sc = if_getsoftc(ifp); 554 555 DTSEC_LOCK(sc); 556 557 mii_pollstat(sc->sc_mii); 558 559 ifmr->ifm_active = sc->sc_mii->mii_media_active; 560 ifmr->ifm_status = sc->sc_mii->mii_media_status; 561 562 DTSEC_UNLOCK(sc); 563 } 564 /** @} */ 565 566 567 /** 568 * @group dTSEC bus interface. 569 * @{ 570 */ 571 static void 572 dtsec_configure_mode(struct dtsec_softc *sc) 573 { 574 char tunable[64]; 575 576 snprintf(tunable, sizeof(tunable), "%s.independent_mode", 577 device_get_nameunit(sc->sc_dev)); 578 579 sc->sc_mode = DTSEC_MODE_REGULAR; 580 TUNABLE_INT_FETCH(tunable, &sc->sc_mode); 581 582 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 583 sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init; 584 sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init; 585 sc->sc_start_locked = dtsec_rm_if_start_locked; 586 } else { 587 sc->sc_port_rx_init = dtsec_im_fm_port_rx_init; 588 sc->sc_port_tx_init = dtsec_im_fm_port_tx_init; 589 sc->sc_start_locked = dtsec_im_if_start_locked; 590 } 591 592 device_printf(sc->sc_dev, "Configured for %s mode.\n", 593 (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent"); 594 } 595 596 int 597 dtsec_attach(device_t dev) 598 { 599 struct dtsec_softc *sc; 600 device_t parent; 601 int error; 602 if_t ifp; 603 604 sc = device_get_softc(dev); 605 606 parent = device_get_parent(dev); 607 sc->sc_dev = dev; 608 sc->sc_mac_mdio_irq = NO_IRQ; 609 610 /* Check if MallocSmart allocator is ready */ 611 if (XX_MallocSmartInit() != E_OK) 612 return (ENXIO); 613 614 /* Init locks */ 615 mtx_init(&sc->sc_lock, device_get_nameunit(dev), 616 "DTSEC Global Lock", MTX_DEF); 617 618 mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev), 619 "DTSEC MII Lock", MTX_DEF); 620 621 /* Init callouts */ 622 callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE); 623 624 /* Read configuraton */ 625 if ((error = fman_get_handle(parent, &sc->sc_fmh)) != 0) 626 return (error); 627 628 if ((error = fman_get_muram_handle(parent, &sc->sc_muramh)) != 0) 629 return (error); 630 631 if ((error = fman_get_bushandle(parent, &sc->sc_fm_base)) != 0) 632 return (error); 633 634 /* Configure working mode */ 635 dtsec_configure_mode(sc); 636 637 /* If we are working in regular mode configure BMAN and QMAN */ 638 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 639 /* Create RX buffer pool */ 640 error = dtsec_rm_pool_rx_init(sc); 641 if (error != 0) 642 return (EIO); 643 644 /* Create RX frame queue range */ 645 error = dtsec_rm_fqr_rx_init(sc); 646 if (error != 0) 647 return (EIO); 648 649 /* Create frame info pool */ 650 error = dtsec_rm_fi_pool_init(sc); 651 if (error != 0) 652 return (EIO); 653 654 /* Create TX frame queue range */ 655 error = dtsec_rm_fqr_tx_init(sc); 656 if (error != 0) 657 return (EIO); 658 } 659 660 /* Init FMan MAC module. */ 661 error = dtsec_fm_mac_init(sc, sc->sc_mac_addr); 662 if (error != 0) { 663 dtsec_detach(dev); 664 return (ENXIO); 665 } 666 667 /* Init FMan TX port */ 668 error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev)); 669 if (error != 0) { 670 dtsec_detach(dev); 671 return (ENXIO); 672 } 673 674 /* Init FMan RX port */ 675 error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev)); 676 if (error != 0) { 677 dtsec_detach(dev); 678 return (ENXIO); 679 } 680 681 /* Create network interface for upper layers */ 682 ifp = sc->sc_ifnet = if_alloc(IFT_ETHER); 683 if (ifp == NULL) { 684 device_printf(sc->sc_dev, "if_alloc() failed.\n"); 685 dtsec_detach(dev); 686 return (ENOMEM); 687 } 688 689 if_setsoftc(ifp, sc); 690 691 if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST); 692 if_setinitfn(ifp, dtsec_if_init); 693 if_setstartfn(ifp, dtsec_if_start); 694 if_setioctlfn(ifp, dtsec_if_ioctl); 695 if_setsendqlen(ifp, IFQ_MAXLEN); 696 697 if (sc->sc_phy_addr >= 0) 698 if_initname(ifp, device_get_name(sc->sc_dev), 699 device_get_unit(sc->sc_dev)); 700 else 701 if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev)); 702 703 /* TODO */ 704 #if 0 705 if_setsendqlen(ifp, TSEC_TX_NUM_DESC - 1); 706 if_setsendqready(ifp); 707 #endif 708 709 if_setcapenable(ifp, if_getcapabilities(ifp)); 710 711 /* Attach PHY(s) */ 712 error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd, 713 dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr, 714 MII_OFFSET_ANY, 0); 715 if (error) { 716 device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error); 717 dtsec_detach(sc->sc_dev); 718 return (error); 719 } 720 sc->sc_mii = device_get_softc(sc->sc_mii_dev); 721 722 /* Attach to stack */ 723 ether_ifattach(ifp, sc->sc_mac_addr); 724 725 return (0); 726 } 727 728 int 729 dtsec_detach(device_t dev) 730 { 731 struct dtsec_softc *sc; 732 if_t ifp; 733 734 sc = device_get_softc(dev); 735 ifp = sc->sc_ifnet; 736 737 if (device_is_attached(dev)) { 738 ether_ifdetach(ifp); 739 /* Shutdown interface */ 740 DTSEC_LOCK(sc); 741 dtsec_if_deinit_locked(sc); 742 DTSEC_UNLOCK(sc); 743 } 744 745 if (sc->sc_ifnet) { 746 if_free(sc->sc_ifnet); 747 sc->sc_ifnet = NULL; 748 } 749 750 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 751 /* Free RX/TX FQRs */ 752 dtsec_rm_fqr_rx_free(sc); 753 dtsec_rm_fqr_tx_free(sc); 754 755 /* Free frame info pool */ 756 dtsec_rm_fi_pool_free(sc); 757 758 /* Free RX buffer pool */ 759 dtsec_rm_pool_rx_free(sc); 760 } 761 762 dtsec_fm_mac_free(sc); 763 dtsec_fm_port_free_both(sc); 764 765 /* Destroy lock */ 766 mtx_destroy(&sc->sc_lock); 767 768 return (0); 769 } 770 771 int 772 dtsec_suspend(device_t dev) 773 { 774 775 return (0); 776 } 777 778 int 779 dtsec_resume(device_t dev) 780 { 781 782 return (0); 783 } 784 785 int 786 dtsec_shutdown(device_t dev) 787 { 788 789 return (0); 790 } 791 /** @} */ 792 793 794 /** 795 * @group MII bus interface. 796 * @{ 797 */ 798 int 799 dtsec_miibus_readreg(device_t dev, int phy, int reg) 800 { 801 struct dtsec_softc *sc; 802 803 sc = device_get_softc(dev); 804 805 return (MIIBUS_READREG(sc->sc_mdio, phy, reg)); 806 } 807 808 int 809 dtsec_miibus_writereg(device_t dev, int phy, int reg, int value) 810 { 811 812 struct dtsec_softc *sc; 813 814 sc = device_get_softc(dev); 815 816 return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value)); 817 } 818 819 void 820 dtsec_miibus_statchg(device_t dev) 821 { 822 struct dtsec_softc *sc; 823 e_EnetSpeed speed; 824 bool duplex; 825 int error; 826 827 sc = device_get_softc(dev); 828 829 DTSEC_LOCK_ASSERT(sc); 830 831 duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX); 832 833 switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) { 834 case IFM_1000_T: 835 case IFM_1000_SX: 836 speed = e_ENET_SPEED_1000; 837 break; 838 839 case IFM_100_TX: 840 speed = e_ENET_SPEED_100; 841 break; 842 843 case IFM_10_T: 844 speed = e_ENET_SPEED_10; 845 break; 846 847 default: 848 speed = e_ENET_SPEED_10; 849 } 850 851 error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex); 852 if (error != E_OK) 853 device_printf(sc->sc_dev, "error while adjusting MAC speed.\n"); 854 } 855 /** @} */ 856