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