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/fdt/fdt_common.h> 53 #include <dev/mii/mii.h> 54 #include <dev/mii/miivar.h> 55 #include <dev/ofw/ofw_bus.h> 56 #include <dev/ofw/ofw_bus_subr.h> 57 #include <dev/ofw/openfirm.h> 58 59 #include "miibus_if.h" 60 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 71 /** 72 * @group dTSEC private defines. 73 * @{ 74 */ 75 /** 76 * dTSEC FMan MAC exceptions info struct. 77 */ 78 struct dtsec_fm_mac_ex_str { 79 const int num; 80 const char *str; 81 }; 82 83 /* XXX: Handle to FM_MAC instance of dTSEC0 */ 84 /* From QorIQ Data Path Acceleration Architecture Reference Manual, Rev 2, page 85 * 3-37, "The MII management hardware is shared by all dTSECs... only through 86 * the MIIM registers of dTSEC1 can external PHY's be accessed and configured." 87 */ 88 static t_Handle dtsec_mdio_mac_handle; 89 /** @} */ 90 91 92 /** 93 * @group FMan MAC routines. 94 * @{ 95 */ 96 #define DTSEC_MAC_EXCEPTIONS_END (-1) 97 98 /** 99 * FMan MAC exceptions. 100 */ 101 static const struct dtsec_fm_mac_ex_str dtsec_fm_mac_exceptions[] = { 102 { e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO, "MDIO scan event" }, 103 { e_FM_MAC_EX_10G_MDIO_CMD_CMPL, "MDIO command completion" }, 104 { e_FM_MAC_EX_10G_REM_FAULT, "Remote fault" }, 105 { e_FM_MAC_EX_10G_LOC_FAULT, "Local fault" }, 106 { e_FM_MAC_EX_10G_1TX_ECC_ER, "Transmit frame ECC error" }, 107 { e_FM_MAC_EX_10G_TX_FIFO_UNFL, "Transmit FIFO underflow" }, 108 { e_FM_MAC_EX_10G_TX_FIFO_OVFL, "Receive FIFO overflow" }, 109 { e_FM_MAC_EX_10G_TX_ER, "Transmit frame error" }, 110 { e_FM_MAC_EX_10G_RX_FIFO_OVFL, "Receive FIFO overflow" }, 111 { e_FM_MAC_EX_10G_RX_ECC_ER, "Receive frame ECC error" }, 112 { e_FM_MAC_EX_10G_RX_JAB_FRM, "Receive jabber frame" }, 113 { e_FM_MAC_EX_10G_RX_OVRSZ_FRM, "Receive oversized frame" }, 114 { e_FM_MAC_EX_10G_RX_RUNT_FRM, "Receive runt frame" }, 115 { e_FM_MAC_EX_10G_RX_FRAG_FRM, "Receive fragment frame" }, 116 { e_FM_MAC_EX_10G_RX_LEN_ER, "Receive payload length error" }, 117 { e_FM_MAC_EX_10G_RX_CRC_ER, "Receive CRC error" }, 118 { e_FM_MAC_EX_10G_RX_ALIGN_ER, "Receive alignment error" }, 119 { e_FM_MAC_EX_1G_BAB_RX, "Babbling receive error" }, 120 { e_FM_MAC_EX_1G_RX_CTL, "Receive control (pause frame) interrupt" }, 121 { e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, "Graceful transmit stop " 122 "complete" }, 123 { e_FM_MAC_EX_1G_BAB_TX, "Babbling transmit error" }, 124 { e_FM_MAC_EX_1G_TX_CTL, "Transmit control (pause frame) interrupt" }, 125 { e_FM_MAC_EX_1G_TX_ERR, "Transmit error" }, 126 { e_FM_MAC_EX_1G_LATE_COL, "Late collision" }, 127 { e_FM_MAC_EX_1G_COL_RET_LMT, "Collision retry limit" }, 128 { e_FM_MAC_EX_1G_TX_FIFO_UNDRN, "Transmit FIFO underrun" }, 129 { e_FM_MAC_EX_1G_MAG_PCKT, "Magic Packet detected when dTSEC is in " 130 "Magic Packet detection mode" }, 131 { e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET, "MII management read completion" }, 132 { e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET, "MII management write completion" }, 133 { e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, "Graceful receive stop " 134 "complete" }, 135 { e_FM_MAC_EX_1G_TX_DATA_ERR, "Internal data error on transmit" }, 136 { e_FM_MAC_EX_1G_RX_DATA_ERR, "Internal data error on receive" }, 137 { e_FM_MAC_EX_1G_1588_TS_RX_ERR, "Time-Stamp Receive Error" }, 138 { e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, "MIB counter overflow" }, 139 { DTSEC_MAC_EXCEPTIONS_END, "" } 140 }; 141 142 static const char * 143 dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception) 144 { 145 int i; 146 147 for (i = 0; dtsec_fm_mac_exceptions[i].num != exception && 148 dtsec_fm_mac_exceptions[i].num != DTSEC_MAC_EXCEPTIONS_END; ++i) 149 ; 150 151 if (dtsec_fm_mac_exceptions[i].num == DTSEC_MAC_EXCEPTIONS_END) 152 return ("<Unknown Exception>"); 153 154 return (dtsec_fm_mac_exceptions[i].str); 155 } 156 157 static void 158 dtsec_fm_mac_mdio_event_callback(t_Handle h_App, 159 e_FmMacExceptions exception) 160 { 161 struct dtsec_softc *sc; 162 163 sc = h_App; 164 device_printf(sc->sc_dev, "MDIO event %i: %s.\n", exception, 165 dtsec_fm_mac_ex_to_str(exception)); 166 } 167 168 static void 169 dtsec_fm_mac_exception_callback(t_Handle app, e_FmMacExceptions exception) 170 { 171 struct dtsec_softc *sc; 172 173 sc = app; 174 device_printf(sc->sc_dev, "MAC exception %i: %s.\n", exception, 175 dtsec_fm_mac_ex_to_str(exception)); 176 } 177 178 static void 179 dtsec_fm_mac_free(struct dtsec_softc *sc) 180 { 181 if (sc->sc_mach == NULL) 182 return; 183 184 FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 185 FM_MAC_Free(sc->sc_mach); 186 sc->sc_mach = NULL; 187 } 188 189 static int 190 dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac) 191 { 192 t_FmMacParams params; 193 t_Error error; 194 195 memset(¶ms, 0, sizeof(params)); 196 memcpy(¶ms.addr, mac, sizeof(params.addr)); 197 198 params.baseAddr = sc->sc_fm_base + sc->sc_mac_mem_offset; 199 params.enetMode = sc->sc_mac_enet_mode; 200 params.macId = sc->sc_eth_id; 201 params.mdioIrq = sc->sc_mac_mdio_irq; 202 params.f_Event = dtsec_fm_mac_mdio_event_callback; 203 params.f_Exception = dtsec_fm_mac_exception_callback; 204 params.h_App = sc; 205 params.h_Fm = sc->sc_fmh; 206 207 sc->sc_mach = FM_MAC_Config(¶ms); 208 if (sc->sc_hidden) 209 return (0); 210 if (sc->sc_mach == NULL) { 211 device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n" 212 ); 213 return (ENXIO); 214 } 215 216 error = FM_MAC_ConfigResetOnInit(sc->sc_mach, TRUE); 217 if (error != E_OK) { 218 device_printf(sc->sc_dev, "couldn't enable reset on init " 219 "feature.\n"); 220 dtsec_fm_mac_free(sc); 221 return (ENXIO); 222 } 223 224 /* Do not inform about pause frames */ 225 error = FM_MAC_ConfigException(sc->sc_mach, e_FM_MAC_EX_1G_RX_CTL, 226 FALSE); 227 if (error != E_OK) { 228 device_printf(sc->sc_dev, "couldn't disable pause frames " 229 "exception.\n"); 230 dtsec_fm_mac_free(sc); 231 return (ENXIO); 232 } 233 234 error = FM_MAC_Init(sc->sc_mach); 235 if (error != E_OK) { 236 device_printf(sc->sc_dev, "couldn't initialize FM_MAC module." 237 "\n"); 238 dtsec_fm_mac_free(sc); 239 return (ENXIO); 240 } 241 242 return (0); 243 } 244 /** @} */ 245 246 247 /** 248 * @group FMan PORT routines. 249 * @{ 250 */ 251 static const char * 252 dtsec_fm_port_ex_to_str(e_FmPortExceptions exception) 253 { 254 255 switch (exception) { 256 case e_FM_PORT_EXCEPTION_IM_BUSY: 257 return ("IM: RX busy"); 258 default: 259 return ("<Unknown Exception>"); 260 } 261 } 262 263 void 264 dtsec_fm_port_rx_exception_callback(t_Handle app, 265 e_FmPortExceptions exception) 266 { 267 struct dtsec_softc *sc; 268 269 sc = app; 270 device_printf(sc->sc_dev, "RX exception: %i: %s.\n", exception, 271 dtsec_fm_port_ex_to_str(exception)); 272 } 273 274 void 275 dtsec_fm_port_tx_exception_callback(t_Handle app, 276 e_FmPortExceptions exception) 277 { 278 struct dtsec_softc *sc; 279 280 sc = app; 281 device_printf(sc->sc_dev, "TX exception: %i: %s.\n", exception, 282 dtsec_fm_port_ex_to_str(exception)); 283 } 284 285 e_FmPortType 286 dtsec_fm_port_rx_type(enum eth_dev_type type) 287 { 288 switch (type) { 289 case ETH_DTSEC: 290 return (e_FM_PORT_TYPE_RX); 291 case ETH_10GSEC: 292 return (e_FM_PORT_TYPE_RX_10G); 293 default: 294 return (e_FM_PORT_TYPE_DUMMY); 295 } 296 } 297 298 e_FmPortType 299 dtsec_fm_port_tx_type(enum eth_dev_type type) 300 { 301 302 switch (type) { 303 case ETH_DTSEC: 304 return (e_FM_PORT_TYPE_TX); 305 case ETH_10GSEC: 306 return (e_FM_PORT_TYPE_TX_10G); 307 default: 308 return (e_FM_PORT_TYPE_DUMMY); 309 } 310 } 311 312 static void 313 dtsec_fm_port_free_both(struct dtsec_softc *sc) 314 { 315 if (sc->sc_rxph) { 316 FM_PORT_Free(sc->sc_rxph); 317 sc->sc_rxph = NULL; 318 } 319 320 if (sc->sc_txph) { 321 FM_PORT_Free(sc->sc_txph); 322 sc->sc_txph = NULL; 323 } 324 } 325 /** @} */ 326 327 328 /** 329 * @group IFnet routines. 330 * @{ 331 */ 332 static int 333 dtsec_if_enable_locked(struct dtsec_softc *sc) 334 { 335 int error; 336 337 DTSEC_LOCK_ASSERT(sc); 338 339 error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 340 if (error != E_OK) 341 return (EIO); 342 343 error = FM_PORT_Enable(sc->sc_rxph); 344 if (error != E_OK) 345 return (EIO); 346 347 error = FM_PORT_Enable(sc->sc_txph); 348 if (error != E_OK) 349 return (EIO); 350 351 sc->sc_ifnet->if_drv_flags |= IFF_DRV_RUNNING; 352 353 /* Refresh link state */ 354 dtsec_miibus_statchg(sc->sc_dev); 355 356 return (0); 357 } 358 359 static int 360 dtsec_if_disable_locked(struct dtsec_softc *sc) 361 { 362 int error; 363 364 DTSEC_LOCK_ASSERT(sc); 365 366 error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); 367 if (error != E_OK) 368 return (EIO); 369 370 error = FM_PORT_Disable(sc->sc_rxph); 371 if (error != E_OK) 372 return (EIO); 373 374 error = FM_PORT_Disable(sc->sc_txph); 375 if (error != E_OK) 376 return (EIO); 377 378 sc->sc_ifnet->if_drv_flags &= ~IFF_DRV_RUNNING; 379 380 return (0); 381 } 382 383 static int 384 dtsec_if_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 385 { 386 struct dtsec_softc *sc; 387 struct ifreq *ifr; 388 int error; 389 390 sc = ifp->if_softc; 391 ifr = (struct ifreq *)data; 392 error = 0; 393 394 /* Basic functionality to achieve media status reports */ 395 switch (command) { 396 case SIOCSIFFLAGS: 397 DTSEC_LOCK(sc); 398 399 if (sc->sc_ifnet->if_flags & IFF_UP) 400 error = dtsec_if_enable_locked(sc); 401 else 402 error = dtsec_if_disable_locked(sc); 403 404 DTSEC_UNLOCK(sc); 405 break; 406 407 case SIOCGIFMEDIA: 408 case SIOCSIFMEDIA: 409 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, 410 command); 411 break; 412 413 default: 414 error = ether_ioctl(ifp, command, data); 415 } 416 417 return (error); 418 } 419 420 static void 421 dtsec_if_tick(void *arg) 422 { 423 struct dtsec_softc *sc; 424 425 sc = arg; 426 427 /* TODO */ 428 DTSEC_LOCK(sc); 429 430 mii_tick(sc->sc_mii); 431 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); 432 433 DTSEC_UNLOCK(sc); 434 } 435 436 static void 437 dtsec_if_deinit_locked(struct dtsec_softc *sc) 438 { 439 440 DTSEC_LOCK_ASSERT(sc); 441 442 DTSEC_UNLOCK(sc); 443 callout_drain(&sc->sc_tick_callout); 444 DTSEC_LOCK(sc); 445 } 446 447 static void 448 dtsec_if_init_locked(struct dtsec_softc *sc) 449 { 450 int error; 451 452 DTSEC_LOCK_ASSERT(sc); 453 454 /* Set MAC address */ 455 error = FM_MAC_ModifyMacAddr(sc->sc_mach, 456 (t_EnetAddr *)IF_LLADDR(sc->sc_ifnet)); 457 if (error != E_OK) { 458 device_printf(sc->sc_dev, "couldn't set MAC address.\n"); 459 goto err; 460 } 461 462 /* Start MII polling */ 463 if (sc->sc_mii) 464 callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); 465 466 if (sc->sc_ifnet->if_flags & IFF_UP) { 467 error = dtsec_if_enable_locked(sc); 468 if (error != 0) 469 goto err; 470 } else { 471 error = dtsec_if_disable_locked(sc); 472 if (error != 0) 473 goto err; 474 } 475 476 return; 477 478 err: 479 dtsec_if_deinit_locked(sc); 480 device_printf(sc->sc_dev, "initialization error.\n"); 481 return; 482 } 483 484 static void 485 dtsec_if_init(void *data) 486 { 487 struct dtsec_softc *sc; 488 489 sc = data; 490 491 DTSEC_LOCK(sc); 492 dtsec_if_init_locked(sc); 493 DTSEC_UNLOCK(sc); 494 } 495 496 static void 497 dtsec_if_start(struct ifnet *ifp) 498 { 499 struct dtsec_softc *sc; 500 501 sc = ifp->if_softc; 502 DTSEC_LOCK(sc); 503 sc->sc_start_locked(sc); 504 DTSEC_UNLOCK(sc); 505 } 506 507 static void 508 dtsec_if_watchdog(struct ifnet *ifp) 509 { 510 /* TODO */ 511 } 512 /** @} */ 513 514 515 /** 516 * @group IFmedia routines. 517 * @{ 518 */ 519 static int 520 dtsec_ifmedia_upd(struct ifnet *ifp) 521 { 522 struct dtsec_softc *sc = ifp->if_softc; 523 524 DTSEC_LOCK(sc); 525 mii_mediachg(sc->sc_mii); 526 DTSEC_UNLOCK(sc); 527 528 return (0); 529 } 530 531 static void 532 dtsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 533 { 534 struct dtsec_softc *sc = ifp->if_softc; 535 536 DTSEC_LOCK(sc); 537 538 mii_pollstat(sc->sc_mii); 539 540 ifmr->ifm_active = sc->sc_mii->mii_media_active; 541 ifmr->ifm_status = sc->sc_mii->mii_media_status; 542 543 DTSEC_UNLOCK(sc); 544 } 545 /** @} */ 546 547 548 /** 549 * @group dTSEC bus interface. 550 * @{ 551 */ 552 static void 553 dtsec_configure_mode(struct dtsec_softc *sc) 554 { 555 char tunable[64]; 556 557 snprintf(tunable, sizeof(tunable), "%s.independent_mode", 558 device_get_nameunit(sc->sc_dev)); 559 560 sc->sc_mode = DTSEC_MODE_REGULAR; 561 TUNABLE_INT_FETCH(tunable, &sc->sc_mode); 562 563 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 564 sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init; 565 sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init; 566 sc->sc_start_locked = dtsec_rm_if_start_locked; 567 } else { 568 sc->sc_port_rx_init = dtsec_im_fm_port_rx_init; 569 sc->sc_port_tx_init = dtsec_im_fm_port_tx_init; 570 sc->sc_start_locked = dtsec_im_if_start_locked; 571 } 572 573 device_printf(sc->sc_dev, "Configured for %s mode.\n", 574 (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent"); 575 } 576 577 int 578 dtsec_attach(device_t dev) 579 { 580 struct dtsec_softc *sc; 581 int error; 582 struct ifnet *ifp; 583 584 sc = device_get_softc(dev); 585 586 sc->sc_dev = dev; 587 sc->sc_mac_mdio_irq = NO_IRQ; 588 sc->sc_eth_id = device_get_unit(dev); 589 590 591 /* Check if MallocSmart allocator is ready */ 592 if (XX_MallocSmartInit() != E_OK) 593 return (ENXIO); 594 595 XX_TrackInit(); 596 597 /* Init locks */ 598 mtx_init(&sc->sc_lock, device_get_nameunit(dev), 599 "DTSEC Global Lock", MTX_DEF); 600 601 mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev), 602 "DTSEC MII Lock", MTX_DEF); 603 604 /* Init callouts */ 605 callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE); 606 607 /* Read configuraton */ 608 if ((error = fman_get_handle(&sc->sc_fmh)) != 0) 609 return (error); 610 611 if ((error = fman_get_muram_handle(&sc->sc_muramh)) != 0) 612 return (error); 613 614 if ((error = fman_get_bushandle(&sc->sc_fm_base)) != 0) 615 return (error); 616 617 /* Configure working mode */ 618 dtsec_configure_mode(sc); 619 620 /* If we are working in regular mode configure BMAN and QMAN */ 621 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 622 /* Create RX buffer pool */ 623 error = dtsec_rm_pool_rx_init(sc); 624 if (error != 0) 625 return (EIO); 626 627 /* Create RX frame queue range */ 628 error = dtsec_rm_fqr_rx_init(sc); 629 if (error != 0) 630 return (EIO); 631 632 /* Create frame info pool */ 633 error = dtsec_rm_fi_pool_init(sc); 634 if (error != 0) 635 return (EIO); 636 637 /* Create TX frame queue range */ 638 error = dtsec_rm_fqr_tx_init(sc); 639 if (error != 0) 640 return (EIO); 641 } 642 643 /* Init FMan MAC module. */ 644 error = dtsec_fm_mac_init(sc, sc->sc_mac_addr); 645 if (error != 0) { 646 dtsec_detach(dev); 647 return (ENXIO); 648 } 649 650 /* 651 * XXX: All phys are connected to MDIO interface of the first dTSEC 652 * device (dTSEC0). We have to save handle to the FM_MAC instance of 653 * dTSEC0, which is used later during phy's registers accesses. Another 654 * option would be adding new property to DTS pointing to correct dTSEC 655 * instance, of which FM_MAC handle has to be used for phy's registers 656 * accesses. We did not want to add new properties to DTS, thus this 657 * quite ugly hack. 658 */ 659 if (sc->sc_eth_id == 0) 660 dtsec_mdio_mac_handle = sc->sc_mach; 661 if (sc->sc_hidden) 662 return (0); 663 664 /* Init FMan TX port */ 665 error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev)); 666 if (error != 0) { 667 dtsec_detach(dev); 668 return (ENXIO); 669 } 670 671 /* Init FMan RX port */ 672 error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev)); 673 if (error != 0) { 674 dtsec_detach(dev); 675 return (ENXIO); 676 } 677 678 /* Create network interface for upper layers */ 679 ifp = sc->sc_ifnet = if_alloc(IFT_ETHER); 680 if (ifp == NULL) { 681 device_printf(sc->sc_dev, "if_alloc() failed.\n"); 682 dtsec_detach(dev); 683 return (ENOMEM); 684 } 685 686 ifp->if_softc = sc; 687 ifp->if_mtu = ETHERMTU; /* TODO: Configure */ 688 ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST; 689 ifp->if_init = dtsec_if_init; 690 ifp->if_start = dtsec_if_start; 691 ifp->if_ioctl = dtsec_if_ioctl; 692 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 693 694 if (sc->sc_phy_addr >= 0) 695 if_initname(ifp, device_get_name(sc->sc_dev), 696 device_get_unit(sc->sc_dev)); 697 else 698 if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev)); 699 700 /* TODO */ 701 #if 0 702 IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_TX_NUM_DESC - 1); 703 ifp->if_snd.ifq_drv_maxlen = TSEC_TX_NUM_DESC - 1; 704 IFQ_SET_READY(&ifp->if_snd); 705 #endif 706 ifp->if_capabilities = 0; /* TODO: Check */ 707 ifp->if_capenable = ifp->if_capabilities; 708 709 /* Attach PHY(s) */ 710 error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd, 711 dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr, 712 MII_OFFSET_ANY, 0); 713 if (error) { 714 device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error); 715 dtsec_detach(sc->sc_dev); 716 return (error); 717 } 718 sc->sc_mii = device_get_softc(sc->sc_mii_dev); 719 720 /* Attach to stack */ 721 ether_ifattach(ifp, sc->sc_mac_addr); 722 723 return (0); 724 } 725 726 int 727 dtsec_detach(device_t dev) 728 { 729 struct dtsec_softc *sc; 730 if_t ifp; 731 732 sc = device_get_softc(dev); 733 ifp = sc->sc_ifnet; 734 735 if (device_is_attached(dev)) { 736 ether_ifdetach(ifp); 737 /* Shutdown interface */ 738 DTSEC_LOCK(sc); 739 dtsec_if_deinit_locked(sc); 740 DTSEC_UNLOCK(sc); 741 } 742 743 if (sc->sc_ifnet) { 744 if_free(sc->sc_ifnet); 745 sc->sc_ifnet = NULL; 746 } 747 748 if (sc->sc_mode == DTSEC_MODE_REGULAR) { 749 /* Free RX/TX FQRs */ 750 dtsec_rm_fqr_rx_free(sc); 751 dtsec_rm_fqr_tx_free(sc); 752 753 /* Free frame info pool */ 754 dtsec_rm_fi_pool_free(sc); 755 756 /* Free RX buffer pool */ 757 dtsec_rm_pool_rx_free(sc); 758 } 759 760 dtsec_fm_mac_free(sc); 761 dtsec_fm_port_free_both(sc); 762 763 /* Destroy lock */ 764 mtx_destroy(&sc->sc_lock); 765 766 return (0); 767 } 768 769 int 770 dtsec_suspend(device_t dev) 771 { 772 773 return (0); 774 } 775 776 int 777 dtsec_resume(device_t dev) 778 { 779 780 return (0); 781 } 782 783 int 784 dtsec_shutdown(device_t dev) 785 { 786 787 return (0); 788 } 789 /** @} */ 790 791 792 /** 793 * @group MII bus interface. 794 * @{ 795 */ 796 int 797 dtsec_miibus_readreg(device_t dev, int phy, int reg) 798 { 799 struct dtsec_softc *sc; 800 uint16_t data; 801 t_Error error; 802 803 sc = device_get_softc(dev); 804 805 if (phy != sc->sc_phy_addr) 806 return (0xFFFF); 807 808 DTSEC_MII_LOCK(sc); 809 error = FM_MAC_MII_ReadPhyReg(dtsec_mdio_mac_handle, phy, reg, &data); 810 DTSEC_MII_UNLOCK(sc); 811 if (error != E_OK) { 812 device_printf(dev, "Error while reading from PHY (NetCommSw " 813 "error: %d)\n", error); 814 return (0xFFFF); 815 } 816 817 return ((int)data); 818 } 819 820 int 821 dtsec_miibus_writereg(device_t dev, int phy, int reg, int value) 822 { 823 struct dtsec_softc *sc; 824 t_Error error; 825 826 sc = device_get_softc(dev); 827 828 if (phy != sc->sc_phy_addr) 829 return (EINVAL); 830 831 DTSEC_MII_LOCK(sc); 832 error = FM_MAC_MII_WritePhyReg(dtsec_mdio_mac_handle, phy, reg, value); 833 DTSEC_MII_UNLOCK(sc); 834 if (error != E_OK) { 835 device_printf(dev, "Error while writing to PHY (NetCommSw " 836 "error: %d).\n", error); 837 return (EIO); 838 } 839 840 return (0); 841 } 842 843 void 844 dtsec_miibus_statchg(device_t dev) 845 { 846 struct dtsec_softc *sc; 847 e_EnetSpeed speed; 848 bool duplex; 849 int error; 850 851 sc = device_get_softc(dev); 852 853 DTSEC_LOCK_ASSERT(sc); 854 855 duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX); 856 857 switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) { 858 case IFM_1000_T: 859 case IFM_1000_SX: 860 speed = e_ENET_SPEED_1000; 861 break; 862 863 case IFM_100_TX: 864 speed = e_ENET_SPEED_100; 865 break; 866 867 case IFM_10_T: 868 speed = e_ENET_SPEED_10; 869 break; 870 871 default: 872 speed = e_ENET_SPEED_10; 873 } 874 875 error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex); 876 if (error != E_OK) 877 device_printf(sc->sc_dev, "error while adjusting MAC speed.\n"); 878 } 879 /** @} */ 880