1 /*- 2 * Copyright (c) 2016,2017 SoftIron Inc. 3 * All rights reserved. 4 * 5 * This software was developed by Andrew Turner under 6 * the sponsorship of SoftIron Inc. 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 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/bus.h> 36 #include <sys/kernel.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/module.h> 40 #include <sys/mutex.h> 41 #include <sys/queue.h> 42 #include <sys/rman.h> 43 #include <sys/socket.h> 44 #include <sys/sockio.h> 45 #include <sys/sx.h> 46 #include <sys/taskqueue.h> 47 48 #include <net/ethernet.h> 49 #include <net/if.h> 50 #include <net/if_var.h> 51 #include <net/if_media.h> 52 #include <net/if_types.h> 53 54 #include <dev/ofw/openfirm.h> 55 #include <dev/ofw/ofw_bus.h> 56 #include <dev/ofw/ofw_bus_subr.h> 57 58 #include <machine/bus.h> 59 60 #include "miibus_if.h" 61 62 #include "xgbe.h" 63 #include "xgbe-common.h" 64 65 static device_probe_t axgbe_probe; 66 static device_attach_t axgbe_attach; 67 68 struct axgbe_softc { 69 /* Must be first */ 70 struct xgbe_prv_data prv; 71 72 uint8_t mac_addr[ETHER_ADDR_LEN]; 73 struct ifmedia media; 74 }; 75 76 static struct ofw_compat_data compat_data[] = { 77 { "amd,xgbe-seattle-v1a", true }, 78 { NULL, false } 79 }; 80 81 static struct resource_spec old_phy_spec[] = { 82 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Rx/Tx regs */ 83 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* Integration regs */ 84 { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* Integration regs */ 85 { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Interrupt */ 86 { -1, 0 } 87 }; 88 89 static struct resource_spec old_mac_spec[] = { 90 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* MAC regs */ 91 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* PCS regs */ 92 { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Device interrupt */ 93 /* Per-channel interrupts */ 94 { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL }, 95 { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, 96 { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, 97 { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, 98 { -1, 0 } 99 }; 100 101 static struct resource_spec mac_spec[] = { 102 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* MAC regs */ 103 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* PCS regs */ 104 { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* Rx/Tx regs */ 105 { SYS_RES_MEMORY, 3, RF_ACTIVE }, /* Integration regs */ 106 { SYS_RES_MEMORY, 4, RF_ACTIVE }, /* Integration regs */ 107 { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Device interrupt */ 108 /* Per-channel and auto-negotiation interrupts */ 109 { SYS_RES_IRQ, 1, RF_ACTIVE }, 110 { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, 111 { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, 112 { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, 113 { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, 114 { -1, 0 } 115 }; 116 117 MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data"); 118 119 static void 120 axgbe_init(void *p) 121 { 122 struct axgbe_softc *sc; 123 struct ifnet *ifp; 124 125 sc = p; 126 ifp = sc->prv.netdev; 127 if (ifp->if_drv_flags & IFF_DRV_RUNNING) 128 return; 129 130 ifp->if_drv_flags |= IFF_DRV_RUNNING; 131 } 132 133 static int 134 axgbe_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 135 { 136 struct axgbe_softc *sc = ifp->if_softc; 137 struct ifreq *ifr = (struct ifreq *)data; 138 int error; 139 140 switch(command) { 141 case SIOCSIFMTU: 142 if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU_JUMBO) 143 error = EINVAL; 144 else 145 error = xgbe_change_mtu(ifp, ifr->ifr_mtu); 146 break; 147 case SIOCSIFFLAGS: 148 error = 0; 149 break; 150 case SIOCSIFMEDIA: 151 case SIOCGIFMEDIA: 152 error = ifmedia_ioctl(ifp, ifr, &sc->media, command); 153 break; 154 default: 155 error = ether_ioctl(ifp, command, data); 156 break; 157 } 158 159 return (error); 160 } 161 162 static void 163 axgbe_qflush(struct ifnet *ifp) 164 { 165 166 if_qflush(ifp); 167 } 168 169 static int 170 axgbe_media_change(struct ifnet *ifp) 171 { 172 struct axgbe_softc *sc; 173 int cur_media; 174 175 sc = ifp->if_softc; 176 177 sx_xlock(&sc->prv.an_mutex); 178 cur_media = sc->media.ifm_cur->ifm_media; 179 180 switch (IFM_SUBTYPE(cur_media)) { 181 case IFM_10G_KR: 182 sc->prv.phy.speed = SPEED_10000; 183 sc->prv.phy.autoneg = AUTONEG_DISABLE; 184 break; 185 case IFM_2500_KX: 186 sc->prv.phy.speed = SPEED_2500; 187 sc->prv.phy.autoneg = AUTONEG_DISABLE; 188 break; 189 case IFM_1000_KX: 190 sc->prv.phy.speed = SPEED_1000; 191 sc->prv.phy.autoneg = AUTONEG_DISABLE; 192 break; 193 case IFM_AUTO: 194 sc->prv.phy.autoneg = AUTONEG_ENABLE; 195 break; 196 } 197 sx_xunlock(&sc->prv.an_mutex); 198 199 return (-sc->prv.phy_if.phy_config_aneg(&sc->prv)); 200 } 201 202 static void 203 axgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 204 { 205 struct axgbe_softc *sc; 206 207 sc = ifp->if_softc; 208 209 ifmr->ifm_status = IFM_AVALID; 210 if (!sc->prv.phy.link) 211 return; 212 213 ifmr->ifm_status |= IFM_ACTIVE; 214 ifmr->ifm_active = IFM_ETHER; 215 216 if (sc->prv.phy.duplex == DUPLEX_FULL) 217 ifmr->ifm_active |= IFM_FDX; 218 else 219 ifmr->ifm_active |= IFM_HDX; 220 221 switch (sc->prv.phy.speed) { 222 case SPEED_10000: 223 ifmr->ifm_active |= IFM_10G_KR; 224 break; 225 case SPEED_2500: 226 ifmr->ifm_active |= IFM_2500_KX; 227 break; 228 case SPEED_1000: 229 ifmr->ifm_active |= IFM_1000_KX; 230 break; 231 } 232 } 233 234 static uint64_t 235 axgbe_get_counter(struct ifnet *ifp, ift_counter c) 236 { 237 struct xgbe_prv_data *pdata = ifp->if_softc; 238 struct xgbe_mmc_stats *pstats = &pdata->mmc_stats; 239 240 DBGPR("-->%s\n", __func__); 241 242 pdata->hw_if.read_mmc_stats(pdata); 243 244 switch(c) { 245 case IFCOUNTER_IPACKETS: 246 return (pstats->rxframecount_gb); 247 case IFCOUNTER_IERRORS: 248 return (pstats->rxframecount_gb - 249 pstats->rxbroadcastframes_g - 250 pstats->rxmulticastframes_g - 251 pstats->rxunicastframes_g); 252 case IFCOUNTER_OPACKETS: 253 return (pstats->txframecount_gb); 254 case IFCOUNTER_OERRORS: 255 return (pstats->txframecount_gb - pstats->txframecount_g); 256 case IFCOUNTER_IBYTES: 257 return (pstats->rxoctetcount_gb); 258 case IFCOUNTER_OBYTES: 259 return (pstats->txoctetcount_gb); 260 default: 261 return (if_get_counter_default(ifp, c)); 262 } 263 } 264 265 static int 266 axgbe_probe(device_t dev) 267 { 268 269 if (!ofw_bus_status_okay(dev)) 270 return (ENXIO); 271 272 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 273 return (ENXIO); 274 275 device_set_desc(dev, "AMD 10 Gigabit Ethernet"); 276 return (BUS_PROBE_DEFAULT); 277 } 278 279 static int 280 axgbe_get_optional_prop(device_t dev, phandle_t node, const char *name, 281 int *data, size_t len) 282 { 283 284 if (!OF_hasprop(node, name)) 285 return (-1); 286 287 if (OF_getencprop(node, name, data, len) <= 0) { 288 device_printf(dev,"%s property is invalid\n", name); 289 return (ENXIO); 290 } 291 292 return (0); 293 } 294 295 static int 296 axgbe_attach(device_t dev) 297 { 298 struct axgbe_softc *sc; 299 struct ifnet *ifp; 300 pcell_t phy_handle; 301 device_t phydev; 302 phandle_t node, phy_node; 303 struct resource *mac_res[11]; 304 struct resource *phy_res[4]; 305 ssize_t len; 306 int error, i, j; 307 308 sc = device_get_softc(dev); 309 310 node = ofw_bus_get_node(dev); 311 if (OF_getencprop(node, "phy-handle", &phy_handle, 312 sizeof(phy_handle)) <= 0) { 313 phy_node = node; 314 315 if (bus_alloc_resources(dev, mac_spec, mac_res)) { 316 device_printf(dev, 317 "could not allocate phy resources\n"); 318 return (ENXIO); 319 } 320 321 sc->prv.xgmac_res = mac_res[0]; 322 sc->prv.xpcs_res = mac_res[1]; 323 sc->prv.rxtx_res = mac_res[2]; 324 sc->prv.sir0_res = mac_res[3]; 325 sc->prv.sir1_res = mac_res[4]; 326 327 sc->prv.dev_irq_res = mac_res[5]; 328 sc->prv.per_channel_irq = OF_hasprop(node, 329 XGBE_DMA_IRQS_PROPERTY); 330 for (i = 0, j = 6; j < nitems(mac_res) - 1 && 331 mac_res[j + 1] != NULL; i++, j++) { 332 if (sc->prv.per_channel_irq) { 333 sc->prv.chan_irq_res[i] = mac_res[j]; 334 } 335 } 336 337 /* The last entry is the auto-negotiation interrupt */ 338 sc->prv.an_irq_res = mac_res[j]; 339 } else { 340 phydev = OF_device_from_xref(phy_handle); 341 phy_node = ofw_bus_get_node(phydev); 342 343 if (bus_alloc_resources(phydev, old_phy_spec, phy_res)) { 344 device_printf(dev, 345 "could not allocate phy resources\n"); 346 return (ENXIO); 347 } 348 349 if (bus_alloc_resources(dev, old_mac_spec, mac_res)) { 350 device_printf(dev, 351 "could not allocate mac resources\n"); 352 return (ENXIO); 353 } 354 355 sc->prv.rxtx_res = phy_res[0]; 356 sc->prv.sir0_res = phy_res[1]; 357 sc->prv.sir1_res = phy_res[2]; 358 sc->prv.an_irq_res = phy_res[3]; 359 360 sc->prv.xgmac_res = mac_res[0]; 361 sc->prv.xpcs_res = mac_res[1]; 362 sc->prv.dev_irq_res = mac_res[2]; 363 sc->prv.per_channel_irq = OF_hasprop(node, 364 XGBE_DMA_IRQS_PROPERTY); 365 if (sc->prv.per_channel_irq) { 366 for (i = 0, j = 3; i < nitems(sc->prv.chan_irq_res) && 367 mac_res[j] != NULL; i++, j++) { 368 sc->prv.chan_irq_res[i] = mac_res[j]; 369 } 370 } 371 } 372 373 if ((len = OF_getproplen(node, "mac-address")) < 0) { 374 device_printf(dev, "No mac-address property\n"); 375 return (EINVAL); 376 } 377 378 if (len != ETHER_ADDR_LEN) 379 return (EINVAL); 380 381 OF_getprop(node, "mac-address", sc->mac_addr, ETHER_ADDR_LEN); 382 383 sc->prv.netdev = ifp = if_alloc(IFT_ETHER); 384 if (ifp == NULL) { 385 device_printf(dev, "Cannot alloc ifnet\n"); 386 return (ENXIO); 387 } 388 389 sc->prv.dev = dev; 390 sc->prv.dmat = bus_get_dma_tag(dev); 391 sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full | 392 ADVERTISED_1000baseKX_Full; 393 394 395 /* 396 * Read the needed properties from the phy node. 397 */ 398 399 /* This is documented as optional, but Linux requires it */ 400 if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set, 401 sizeof(sc->prv.speed_set)) <= 0) { 402 device_printf(dev, "%s property is missing\n", 403 XGBE_SPEEDSET_PROPERTY); 404 return (EINVAL); 405 } 406 407 error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY, 408 sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc)); 409 if (error > 0) { 410 return (error); 411 } else if (error < 0) { 412 sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC; 413 sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC; 414 sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC; 415 } 416 417 error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY, 418 sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate)); 419 if (error > 0) { 420 return (error); 421 } else if (error < 0) { 422 sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR; 423 sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR; 424 sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR; 425 } 426 427 error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY, 428 sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew)); 429 if (error > 0) { 430 return (error); 431 } else if (error < 0) { 432 sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ; 433 sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ; 434 sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ; 435 } 436 437 error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY, 438 sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp)); 439 if (error > 0) { 440 return (error); 441 } else if (error < 0) { 442 sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP; 443 sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP; 444 sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP; 445 } 446 447 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY, 448 sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg)); 449 if (error > 0) { 450 return (error); 451 } else if (error < 0) { 452 sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG; 453 sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG; 454 sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG; 455 } 456 457 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY, 458 sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena)); 459 if (error > 0) { 460 return (error); 461 } else if (error < 0) { 462 sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE; 463 sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE; 464 sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE; 465 } 466 467 /* Check if the NIC is DMA coherent */ 468 sc->prv.coherent = OF_hasprop(node, "dma-coherent"); 469 if (sc->prv.coherent) { 470 sc->prv.axdomain = XGBE_DMA_OS_AXDOMAIN; 471 sc->prv.arcache = XGBE_DMA_OS_ARCACHE; 472 sc->prv.awcache = XGBE_DMA_OS_AWCACHE; 473 } else { 474 sc->prv.axdomain = XGBE_DMA_SYS_AXDOMAIN; 475 sc->prv.arcache = XGBE_DMA_SYS_ARCACHE; 476 sc->prv.awcache = XGBE_DMA_SYS_AWCACHE; 477 } 478 479 /* Create the lock & workqueues */ 480 spin_lock_init(&sc->prv.xpcs_lock); 481 sc->prv.dev_workqueue = taskqueue_create("axgbe", M_WAITOK, 482 taskqueue_thread_enqueue, &sc->prv.dev_workqueue); 483 taskqueue_start_threads(&sc->prv.dev_workqueue, 1, PI_NET, 484 "axgbe taskq"); 485 486 /* Set the needed pointers */ 487 xgbe_init_function_ptrs_phy(&sc->prv.phy_if); 488 xgbe_init_function_ptrs_dev(&sc->prv.hw_if); 489 xgbe_init_function_ptrs_desc(&sc->prv.desc_if); 490 491 /* Reset the hardware */ 492 sc->prv.hw_if.exit(&sc->prv); 493 494 /* Read the hardware features */ 495 xgbe_get_all_hw_features(&sc->prv); 496 497 /* Set default values */ 498 sc->prv.pblx8 = DMA_PBL_X8_ENABLE; 499 sc->prv.tx_desc_count = XGBE_TX_DESC_CNT; 500 sc->prv.tx_sf_mode = MTL_TSF_ENABLE; 501 sc->prv.tx_threshold = MTL_TX_THRESHOLD_64; 502 sc->prv.tx_pbl = DMA_PBL_16; 503 sc->prv.tx_osp_mode = DMA_OSP_ENABLE; 504 sc->prv.rx_desc_count = XGBE_RX_DESC_CNT; 505 sc->prv.rx_sf_mode = MTL_RSF_DISABLE; 506 sc->prv.rx_threshold = MTL_RX_THRESHOLD_64; 507 sc->prv.rx_pbl = DMA_PBL_16; 508 sc->prv.pause_autoneg = 1; 509 sc->prv.tx_pause = 1; 510 sc->prv.rx_pause = 1; 511 sc->prv.phy_speed = SPEED_UNKNOWN; 512 sc->prv.power_down = 0; 513 514 /* TODO: Limit to min(ncpus, hw rings) */ 515 sc->prv.tx_ring_count = 1; 516 sc->prv.tx_q_count = 1; 517 sc->prv.rx_ring_count = 1; 518 sc->prv.rx_q_count = sc->prv.hw_feat.rx_q_cnt; 519 520 /* Init the PHY */ 521 sc->prv.phy_if.phy_init(&sc->prv); 522 523 /* Set the coalescing */ 524 xgbe_init_rx_coalesce(&sc->prv); 525 xgbe_init_tx_coalesce(&sc->prv); 526 527 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 528 ifp->if_init = axgbe_init; 529 ifp->if_softc = sc; 530 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 531 ifp->if_ioctl = axgbe_ioctl; 532 ifp->if_transmit = xgbe_xmit; 533 ifp->if_qflush = axgbe_qflush; 534 ifp->if_get_counter = axgbe_get_counter; 535 536 /* TODO: Support HW offload */ 537 ifp->if_capabilities = 0; 538 ifp->if_capenable = 0; 539 ifp->if_hwassist = 0; 540 541 ether_ifattach(ifp, sc->mac_addr); 542 543 ifmedia_init(&sc->media, IFM_IMASK, axgbe_media_change, 544 axgbe_media_status); 545 #ifdef notyet 546 ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 547 #endif 548 ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 549 ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 550 ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 551 552 set_bit(XGBE_DOWN, &sc->prv.dev_state); 553 554 if (xgbe_open(ifp) < 0) { 555 device_printf(dev, "ndo_open failed\n"); 556 return (ENXIO); 557 } 558 559 return (0); 560 } 561 562 static device_method_t axgbe_methods[] = { 563 /* Device interface */ 564 DEVMETHOD(device_probe, axgbe_probe), 565 DEVMETHOD(device_attach, axgbe_attach), 566 567 { 0, 0 } 568 }; 569 570 static devclass_t axgbe_devclass; 571 572 DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods, 573 sizeof(struct axgbe_softc)); 574 DRIVER_MODULE(axgbe, simplebus, axgbe_driver, axgbe_devclass, 0, 0); 575 576 577 static struct ofw_compat_data phy_compat_data[] = { 578 { "amd,xgbe-phy-seattle-v1a", true }, 579 { NULL, false } 580 }; 581 582 static int 583 axgbephy_probe(device_t dev) 584 { 585 586 if (!ofw_bus_status_okay(dev)) 587 return (ENXIO); 588 589 if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data) 590 return (ENXIO); 591 592 device_set_desc(dev, "AMD 10 Gigabit Ethernet"); 593 return (BUS_PROBE_DEFAULT); 594 } 595 596 static int 597 axgbephy_attach(device_t dev) 598 { 599 phandle_t node; 600 601 node = ofw_bus_get_node(dev); 602 OF_device_register_xref(OF_xref_from_node(node), dev); 603 604 return (0); 605 } 606 607 static device_method_t axgbephy_methods[] = { 608 /* Device interface */ 609 DEVMETHOD(device_probe, axgbephy_probe), 610 DEVMETHOD(device_attach, axgbephy_attach), 611 612 { 0, 0 } 613 }; 614 615 static devclass_t axgbephy_devclass; 616 617 DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0); 618 EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver, axgbephy_devclass, 619 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); 620