1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2016,2017 SoftIron Inc. 5 * Copyright (c) 2020 Advanced Micro Devices, Inc. 6 * 7 * This software was developed by Andrew Turner under 8 * the sponsorship of SoftIron Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 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 static struct xgbe_version_data xgbe_v1 = { 118 .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v1, 119 .xpcs_access = XGBE_XPCS_ACCESS_V1, 120 .tx_max_fifo_size = 81920, 121 .rx_max_fifo_size = 81920, 122 .tx_tstamp_workaround = 1, 123 }; 124 125 MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data"); 126 127 static void 128 axgbe_init(void *p) 129 { 130 struct axgbe_softc *sc; 131 if_t ifp; 132 133 sc = p; 134 ifp = sc->prv.netdev; 135 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 136 return; 137 138 if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 139 } 140 141 static int 142 axgbe_ioctl(if_t ifp, unsigned long command, caddr_t data) 143 { 144 struct axgbe_softc *sc = if_getsoftc(ifp); 145 struct ifreq *ifr = (struct ifreq *)data; 146 int error = 0; 147 148 switch(command) { 149 case SIOCSIFMTU: 150 if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU_JUMBO) 151 error = EINVAL; 152 /* TODO - change it to iflib way */ 153 break; 154 case SIOCSIFFLAGS: 155 error = 0; 156 break; 157 case SIOCSIFMEDIA: 158 case SIOCGIFMEDIA: 159 error = ifmedia_ioctl(ifp, ifr, &sc->media, command); 160 break; 161 default: 162 error = ether_ioctl(ifp, command, data); 163 break; 164 } 165 166 return (error); 167 } 168 169 static void 170 axgbe_qflush(if_t ifp) 171 { 172 173 if_qflush(ifp); 174 } 175 176 static int 177 axgbe_media_change(if_t ifp) 178 { 179 struct axgbe_softc *sc; 180 int cur_media; 181 182 sc = if_getsoftc(ifp); 183 184 sx_xlock(&sc->prv.an_mutex); 185 cur_media = sc->media.ifm_cur->ifm_media; 186 187 switch (IFM_SUBTYPE(cur_media)) { 188 case IFM_10G_KR: 189 sc->prv.phy.speed = SPEED_10000; 190 sc->prv.phy.autoneg = AUTONEG_DISABLE; 191 break; 192 case IFM_2500_KX: 193 sc->prv.phy.speed = SPEED_2500; 194 sc->prv.phy.autoneg = AUTONEG_DISABLE; 195 break; 196 case IFM_1000_KX: 197 sc->prv.phy.speed = SPEED_1000; 198 sc->prv.phy.autoneg = AUTONEG_DISABLE; 199 break; 200 case IFM_AUTO: 201 sc->prv.phy.autoneg = AUTONEG_ENABLE; 202 break; 203 } 204 sx_xunlock(&sc->prv.an_mutex); 205 206 return (-sc->prv.phy_if.phy_config_aneg(&sc->prv)); 207 } 208 209 static void 210 axgbe_media_status(if_t ifp, struct ifmediareq *ifmr) 211 { 212 struct axgbe_softc *sc; 213 214 sc = if_getsoftc(ifp); 215 216 ifmr->ifm_status = IFM_AVALID; 217 if (!sc->prv.phy.link) 218 return; 219 220 ifmr->ifm_status |= IFM_ACTIVE; 221 ifmr->ifm_active = IFM_ETHER; 222 223 if (sc->prv.phy.duplex == DUPLEX_FULL) 224 ifmr->ifm_active |= IFM_FDX; 225 else 226 ifmr->ifm_active |= IFM_HDX; 227 228 switch (sc->prv.phy.speed) { 229 case SPEED_10000: 230 ifmr->ifm_active |= IFM_10G_KR; 231 break; 232 case SPEED_2500: 233 ifmr->ifm_active |= IFM_2500_KX; 234 break; 235 case SPEED_1000: 236 ifmr->ifm_active |= IFM_1000_KX; 237 break; 238 } 239 } 240 241 static uint64_t 242 axgbe_get_counter(if_t ifp, ift_counter c) 243 { 244 struct xgbe_prv_data *pdata = if_getsoftc(ifp); 245 struct xgbe_mmc_stats *pstats = &pdata->mmc_stats; 246 247 DBGPR("-->%s\n", __func__); 248 249 pdata->hw_if.read_mmc_stats(pdata); 250 251 switch(c) { 252 case IFCOUNTER_IPACKETS: 253 return (pstats->rxframecount_gb); 254 case IFCOUNTER_IERRORS: 255 return (pstats->rxframecount_gb - 256 pstats->rxbroadcastframes_g - 257 pstats->rxmulticastframes_g - 258 pstats->rxunicastframes_g); 259 case IFCOUNTER_OPACKETS: 260 return (pstats->txframecount_gb); 261 case IFCOUNTER_OERRORS: 262 return (pstats->txframecount_gb - pstats->txframecount_g); 263 case IFCOUNTER_IBYTES: 264 return (pstats->rxoctetcount_gb); 265 case IFCOUNTER_OBYTES: 266 return (pstats->txoctetcount_gb); 267 default: 268 return (if_get_counter_default(ifp, c)); 269 } 270 } 271 272 static int 273 axgbe_probe(device_t dev) 274 { 275 276 if (!ofw_bus_status_okay(dev)) 277 return (ENXIO); 278 279 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 280 return (ENXIO); 281 282 device_set_desc(dev, "AMD 10 Gigabit Ethernet"); 283 return (BUS_PROBE_DEFAULT); 284 } 285 286 static int 287 axgbe_get_optional_prop(device_t dev, phandle_t node, const char *name, 288 int *data, size_t len) 289 { 290 291 if (!OF_hasprop(node, name)) 292 return (-1); 293 294 if (OF_getencprop(node, name, data, len) <= 0) { 295 device_printf(dev,"%s property is invalid\n", name); 296 return (ENXIO); 297 } 298 299 return (0); 300 } 301 302 static int 303 axgbe_attach(device_t dev) 304 { 305 struct axgbe_softc *sc; 306 if_t ifp; 307 pcell_t phy_handle; 308 device_t phydev; 309 phandle_t node, phy_node; 310 struct resource *mac_res[11]; 311 struct resource *phy_res[4]; 312 ssize_t len; 313 int error, i, j; 314 315 sc = device_get_softc(dev); 316 317 sc->prv.vdata = &xgbe_v1; 318 node = ofw_bus_get_node(dev); 319 if (OF_getencprop(node, "phy-handle", &phy_handle, 320 sizeof(phy_handle)) <= 0) { 321 phy_node = node; 322 323 if (bus_alloc_resources(dev, mac_spec, mac_res)) { 324 device_printf(dev, 325 "could not allocate phy resources\n"); 326 return (ENXIO); 327 } 328 329 sc->prv.xgmac_res = mac_res[0]; 330 sc->prv.xpcs_res = mac_res[1]; 331 sc->prv.rxtx_res = mac_res[2]; 332 sc->prv.sir0_res = mac_res[3]; 333 sc->prv.sir1_res = mac_res[4]; 334 335 sc->prv.dev_irq_res = mac_res[5]; 336 sc->prv.per_channel_irq = OF_hasprop(node, 337 XGBE_DMA_IRQS_PROPERTY); 338 for (i = 0, j = 6; j < nitems(mac_res) - 1 && 339 mac_res[j + 1] != NULL; i++, j++) { 340 if (sc->prv.per_channel_irq) { 341 sc->prv.chan_irq_res[i] = mac_res[j]; 342 } 343 } 344 345 /* The last entry is the auto-negotiation interrupt */ 346 sc->prv.an_irq_res = mac_res[j]; 347 } else { 348 phydev = OF_device_from_xref(phy_handle); 349 phy_node = ofw_bus_get_node(phydev); 350 351 if (bus_alloc_resources(phydev, old_phy_spec, phy_res)) { 352 device_printf(dev, 353 "could not allocate phy resources\n"); 354 return (ENXIO); 355 } 356 357 if (bus_alloc_resources(dev, old_mac_spec, mac_res)) { 358 device_printf(dev, 359 "could not allocate mac resources\n"); 360 return (ENXIO); 361 } 362 363 sc->prv.rxtx_res = phy_res[0]; 364 sc->prv.sir0_res = phy_res[1]; 365 sc->prv.sir1_res = phy_res[2]; 366 sc->prv.an_irq_res = phy_res[3]; 367 368 sc->prv.xgmac_res = mac_res[0]; 369 sc->prv.xpcs_res = mac_res[1]; 370 sc->prv.dev_irq_res = mac_res[2]; 371 sc->prv.per_channel_irq = OF_hasprop(node, 372 XGBE_DMA_IRQS_PROPERTY); 373 if (sc->prv.per_channel_irq) { 374 for (i = 0, j = 3; i < nitems(sc->prv.chan_irq_res) && 375 mac_res[j] != NULL; i++, j++) { 376 sc->prv.chan_irq_res[i] = mac_res[j]; 377 } 378 } 379 } 380 381 if ((len = OF_getproplen(node, "mac-address")) < 0) { 382 device_printf(dev, "No mac-address property\n"); 383 return (EINVAL); 384 } 385 386 if (len != ETHER_ADDR_LEN) 387 return (EINVAL); 388 389 OF_getprop(node, "mac-address", sc->mac_addr, ETHER_ADDR_LEN); 390 391 sc->prv.netdev = ifp = if_alloc(IFT_ETHER); 392 if (ifp == NULL) { 393 device_printf(dev, "Cannot alloc ifnet\n"); 394 return (ENXIO); 395 } 396 397 sc->prv.dev = dev; 398 sc->prv.dmat = bus_get_dma_tag(dev); 399 sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full | 400 ADVERTISED_1000baseKX_Full; 401 402 403 /* 404 * Read the needed properties from the phy node. 405 */ 406 407 /* This is documented as optional, but Linux requires it */ 408 if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set, 409 sizeof(sc->prv.speed_set)) <= 0) { 410 device_printf(dev, "%s property is missing\n", 411 XGBE_SPEEDSET_PROPERTY); 412 return (EINVAL); 413 } 414 415 error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY, 416 sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc)); 417 if (error > 0) { 418 return (error); 419 } else if (error < 0) { 420 sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC; 421 sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC; 422 sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC; 423 } 424 425 error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY, 426 sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate)); 427 if (error > 0) { 428 return (error); 429 } else if (error < 0) { 430 sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR; 431 sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR; 432 sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR; 433 } 434 435 error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY, 436 sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew)); 437 if (error > 0) { 438 return (error); 439 } else if (error < 0) { 440 sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ; 441 sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ; 442 sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ; 443 } 444 445 error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY, 446 sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp)); 447 if (error > 0) { 448 return (error); 449 } else if (error < 0) { 450 sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP; 451 sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP; 452 sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP; 453 } 454 455 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY, 456 sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg)); 457 if (error > 0) { 458 return (error); 459 } else if (error < 0) { 460 sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG; 461 sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG; 462 sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG; 463 } 464 465 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY, 466 sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena)); 467 if (error > 0) { 468 return (error); 469 } else if (error < 0) { 470 sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE; 471 sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE; 472 sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE; 473 } 474 475 /* Check if the NIC is DMA coherent */ 476 sc->prv.coherent = OF_hasprop(node, "dma-coherent"); 477 if (sc->prv.coherent) { 478 sc->prv.arcr = XGBE_DMA_OS_ARCR; 479 sc->prv.awcr = XGBE_DMA_OS_AWCR; 480 } else { 481 sc->prv.arcr = XGBE_DMA_SYS_ARCR; 482 sc->prv.awcr = XGBE_DMA_SYS_AWCR; 483 } 484 485 /* Create the lock & workqueues */ 486 spin_lock_init(&sc->prv.xpcs_lock); 487 sc->prv.dev_workqueue = taskqueue_create("axgbe", M_WAITOK, 488 taskqueue_thread_enqueue, &sc->prv.dev_workqueue); 489 taskqueue_start_threads(&sc->prv.dev_workqueue, 1, PI_NET, 490 "axgbe taskq"); 491 492 /* Set the needed pointers */ 493 xgbe_init_function_ptrs_phy(&sc->prv.phy_if); 494 xgbe_init_function_ptrs_dev(&sc->prv.hw_if); 495 xgbe_init_function_ptrs_desc(&sc->prv.desc_if); 496 sc->prv.vdata->init_function_ptrs_phy_impl(&sc->prv.phy_if); 497 498 /* Reset the hardware */ 499 sc->prv.hw_if.exit(&sc->prv); 500 501 /* Read the hardware features */ 502 xgbe_get_all_hw_features(&sc->prv); 503 504 /* Set default values */ 505 sc->prv.tx_desc_count = XGBE_TX_DESC_CNT; 506 sc->prv.tx_sf_mode = MTL_TSF_ENABLE; 507 sc->prv.tx_threshold = MTL_TX_THRESHOLD_64; 508 sc->prv.tx_osp_mode = DMA_OSP_ENABLE; 509 sc->prv.rx_desc_count = XGBE_RX_DESC_CNT; 510 sc->prv.rx_sf_mode = MTL_RSF_DISABLE; 511 sc->prv.rx_threshold = MTL_RX_THRESHOLD_64; 512 sc->prv.pbl = DMA_PBL_128; 513 sc->prv.pause_autoneg = 1; 514 sc->prv.tx_pause = 1; 515 sc->prv.rx_pause = 1; 516 sc->prv.phy_speed = SPEED_UNKNOWN; 517 sc->prv.power_down = 0; 518 519 /* TODO: Limit to min(ncpus, hw rings) */ 520 sc->prv.tx_ring_count = 1; 521 sc->prv.tx_q_count = 1; 522 sc->prv.rx_ring_count = 1; 523 sc->prv.rx_q_count = sc->prv.hw_feat.rx_q_cnt; 524 525 /* Init the PHY */ 526 sc->prv.phy_if.phy_init(&sc->prv); 527 528 /* Set the coalescing */ 529 xgbe_init_rx_coalesce(&sc->prv); 530 xgbe_init_tx_coalesce(&sc->prv); 531 532 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 533 if_setinitfn(ifp, axgbe_init); 534 if_setsoftc(ifp, sc); 535 if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 536 if_setioctlfn(ifp, axgbe_ioctl); 537 /* TODO - change it to iflib way */ 538 if_setqflushfn(ifp, axgbe_qflush); 539 if_setgetcounterfn(ifp, axgbe_get_counter); 540 541 /* TODO: Support HW offload */ 542 if_setcapabilities(ifp, 0); 543 if_setcapenable(ifp, 0); 544 if_sethwassist(ifp, 0); 545 546 ether_ifattach(ifp, sc->mac_addr); 547 548 ifmedia_init(&sc->media, IFM_IMASK, axgbe_media_change, 549 axgbe_media_status); 550 #ifdef notyet 551 ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 552 #endif 553 ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 554 ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 555 ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 556 557 set_bit(XGBE_DOWN, &sc->prv.dev_state); 558 559 /* TODO - change it to iflib way */ 560 return (0); 561 } 562 563 static device_method_t axgbe_methods[] = { 564 /* Device interface */ 565 DEVMETHOD(device_probe, axgbe_probe), 566 DEVMETHOD(device_attach, axgbe_attach), 567 568 { 0, 0 } 569 }; 570 571 DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods, 572 sizeof(struct axgbe_softc)); 573 DRIVER_MODULE(axa, simplebus, axgbe_driver, 0, 0); 574 575 576 static struct ofw_compat_data phy_compat_data[] = { 577 { "amd,xgbe-phy-seattle-v1a", true }, 578 { NULL, false } 579 }; 580 581 static int 582 axgbephy_probe(device_t dev) 583 { 584 585 if (!ofw_bus_status_okay(dev)) 586 return (ENXIO); 587 588 if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data) 589 return (ENXIO); 590 591 device_set_desc(dev, "AMD 10 Gigabit Ethernet"); 592 return (BUS_PROBE_DEFAULT); 593 } 594 595 static int 596 axgbephy_attach(device_t dev) 597 { 598 phandle_t node; 599 600 node = ofw_bus_get_node(dev); 601 OF_device_register_xref(OF_xref_from_node(node), dev); 602 603 return (0); 604 } 605 606 static device_method_t axgbephy_methods[] = { 607 /* Device interface */ 608 DEVMETHOD(device_probe, axgbephy_probe), 609 DEVMETHOD(device_attach, axgbephy_attach), 610 611 { 0, 0 } 612 }; 613 614 DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0); 615 EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver, 616 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); 617