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 * Read the needed properties from the phy node. 396 */ 397 398 /* This is documented as optional, but Linux requires it */ 399 if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set, 400 sizeof(sc->prv.speed_set)) <= 0) { 401 device_printf(dev, "%s property is missing\n", 402 XGBE_SPEEDSET_PROPERTY); 403 return (EINVAL); 404 } 405 406 error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY, 407 sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc)); 408 if (error > 0) { 409 return (error); 410 } else if (error < 0) { 411 sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC; 412 sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC; 413 sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC; 414 } 415 416 error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY, 417 sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate)); 418 if (error > 0) { 419 return (error); 420 } else if (error < 0) { 421 sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR; 422 sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR; 423 sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR; 424 } 425 426 error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY, 427 sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew)); 428 if (error > 0) { 429 return (error); 430 } else if (error < 0) { 431 sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ; 432 sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ; 433 sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ; 434 } 435 436 error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY, 437 sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp)); 438 if (error > 0) { 439 return (error); 440 } else if (error < 0) { 441 sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP; 442 sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP; 443 sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP; 444 } 445 446 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY, 447 sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg)); 448 if (error > 0) { 449 return (error); 450 } else if (error < 0) { 451 sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG; 452 sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG; 453 sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG; 454 } 455 456 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY, 457 sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena)); 458 if (error > 0) { 459 return (error); 460 } else if (error < 0) { 461 sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE; 462 sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE; 463 sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE; 464 } 465 466 /* Check if the NIC is DMA coherent */ 467 sc->prv.coherent = OF_hasprop(node, "dma-coherent"); 468 if (sc->prv.coherent) { 469 sc->prv.axdomain = XGBE_DMA_OS_AXDOMAIN; 470 sc->prv.arcache = XGBE_DMA_OS_ARCACHE; 471 sc->prv.awcache = XGBE_DMA_OS_AWCACHE; 472 } else { 473 sc->prv.axdomain = XGBE_DMA_SYS_AXDOMAIN; 474 sc->prv.arcache = XGBE_DMA_SYS_ARCACHE; 475 sc->prv.awcache = XGBE_DMA_SYS_AWCACHE; 476 } 477 478 /* Create the lock & workqueues */ 479 spin_lock_init(&sc->prv.xpcs_lock); 480 sc->prv.dev_workqueue = taskqueue_create("axgbe", M_WAITOK, 481 taskqueue_thread_enqueue, &sc->prv.dev_workqueue); 482 taskqueue_start_threads(&sc->prv.dev_workqueue, 1, PI_NET, 483 "axgbe taskq"); 484 485 /* Set the needed pointers */ 486 xgbe_init_function_ptrs_phy(&sc->prv.phy_if); 487 xgbe_init_function_ptrs_dev(&sc->prv.hw_if); 488 xgbe_init_function_ptrs_desc(&sc->prv.desc_if); 489 490 /* Reset the hardware */ 491 sc->prv.hw_if.exit(&sc->prv); 492 493 /* Read the hardware features */ 494 xgbe_get_all_hw_features(&sc->prv); 495 496 /* Set default values */ 497 sc->prv.pblx8 = DMA_PBL_X8_ENABLE; 498 sc->prv.tx_desc_count = XGBE_TX_DESC_CNT; 499 sc->prv.tx_sf_mode = MTL_TSF_ENABLE; 500 sc->prv.tx_threshold = MTL_TX_THRESHOLD_64; 501 sc->prv.tx_pbl = DMA_PBL_16; 502 sc->prv.tx_osp_mode = DMA_OSP_ENABLE; 503 sc->prv.rx_desc_count = XGBE_RX_DESC_CNT; 504 sc->prv.rx_sf_mode = MTL_RSF_DISABLE; 505 sc->prv.rx_threshold = MTL_RX_THRESHOLD_64; 506 sc->prv.rx_pbl = DMA_PBL_16; 507 sc->prv.pause_autoneg = 1; 508 sc->prv.tx_pause = 1; 509 sc->prv.rx_pause = 1; 510 sc->prv.phy_speed = SPEED_UNKNOWN; 511 sc->prv.power_down = 0; 512 513 /* TODO: Limit to min(ncpus, hw rings) */ 514 sc->prv.tx_ring_count = 1; 515 sc->prv.tx_q_count = 1; 516 sc->prv.rx_ring_count = 1; 517 sc->prv.rx_q_count = sc->prv.hw_feat.rx_q_cnt; 518 519 /* Init the PHY */ 520 sc->prv.phy_if.phy_init(&sc->prv); 521 522 /* Set the coalescing */ 523 xgbe_init_rx_coalesce(&sc->prv); 524 xgbe_init_tx_coalesce(&sc->prv); 525 526 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 527 ifp->if_init = axgbe_init; 528 ifp->if_softc = sc; 529 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 530 ifp->if_ioctl = axgbe_ioctl; 531 ifp->if_transmit = xgbe_xmit; 532 ifp->if_qflush = axgbe_qflush; 533 ifp->if_get_counter = axgbe_get_counter; 534 535 /* TODO: Support HW offload */ 536 ifp->if_capabilities = 0; 537 ifp->if_capenable = 0; 538 ifp->if_hwassist = 0; 539 540 ether_ifattach(ifp, sc->mac_addr); 541 542 ifmedia_init(&sc->media, IFM_IMASK, axgbe_media_change, 543 axgbe_media_status); 544 #ifdef notyet 545 ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL); 546 #endif 547 ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL); 548 ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 549 ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 550 551 set_bit(XGBE_DOWN, &sc->prv.dev_state); 552 553 if (xgbe_open(ifp) < 0) { 554 device_printf(dev, "ndo_open failed\n"); 555 return (ENXIO); 556 } 557 558 return (0); 559 } 560 561 static device_method_t axgbe_methods[] = { 562 /* Device interface */ 563 DEVMETHOD(device_probe, axgbe_probe), 564 DEVMETHOD(device_attach, axgbe_attach), 565 { 0, 0 } 566 }; 567 568 static devclass_t axgbe_devclass; 569 570 DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods, 571 sizeof(struct axgbe_softc)); 572 DRIVER_MODULE(axgbe, simplebus, axgbe_driver, axgbe_devclass, 0, 0); 573 574 static struct ofw_compat_data phy_compat_data[] = { 575 { "amd,xgbe-phy-seattle-v1a", true }, 576 { NULL, false } 577 }; 578 579 static int 580 axgbephy_probe(device_t dev) 581 { 582 583 if (!ofw_bus_status_okay(dev)) 584 return (ENXIO); 585 586 if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data) 587 return (ENXIO); 588 589 device_set_desc(dev, "AMD 10 Gigabit Ethernet"); 590 return (BUS_PROBE_DEFAULT); 591 } 592 593 static int 594 axgbephy_attach(device_t dev) 595 { 596 phandle_t node; 597 598 node = ofw_bus_get_node(dev); 599 OF_device_register_xref(OF_xref_from_node(node), dev); 600 601 return (0); 602 } 603 604 static device_method_t axgbephy_methods[] = { 605 /* Device interface */ 606 DEVMETHOD(device_probe, axgbephy_probe), 607 DEVMETHOD(device_attach, axgbephy_attach), 608 { 0, 0 } 609 }; 610 611 static devclass_t axgbephy_devclass; 612 613 DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0); 614 EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver, axgbephy_devclass, 615 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE); 616