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
axgbe_init(void * p)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
axgbe_ioctl(if_t ifp,unsigned long command,caddr_t data)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
axgbe_qflush(if_t ifp)170 axgbe_qflush(if_t ifp)
171 {
172
173 if_qflush(ifp);
174 }
175
176 static int
axgbe_media_change(if_t ifp)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
axgbe_media_status(if_t ifp,struct ifmediareq * ifmr)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
axgbe_get_counter(if_t ifp,ift_counter c)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
axgbe_probe(device_t dev)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
axgbe_get_optional_prop(device_t dev,phandle_t node,const char * name,int * data,size_t len)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
axgbe_attach(device_t dev)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 sc->prv.dev = dev;
393 sc->prv.dmat = bus_get_dma_tag(dev);
394 sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full |
395 ADVERTISED_1000baseKX_Full;
396
397
398 /*
399 * Read the needed properties from the phy node.
400 */
401
402 /* This is documented as optional, but Linux requires it */
403 if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set,
404 sizeof(sc->prv.speed_set)) <= 0) {
405 device_printf(dev, "%s property is missing\n",
406 XGBE_SPEEDSET_PROPERTY);
407 return (EINVAL);
408 }
409
410 error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY,
411 sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc));
412 if (error > 0) {
413 return (error);
414 } else if (error < 0) {
415 sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC;
416 sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC;
417 sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC;
418 }
419
420 error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY,
421 sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate));
422 if (error > 0) {
423 return (error);
424 } else if (error < 0) {
425 sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR;
426 sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR;
427 sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR;
428 }
429
430 error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY,
431 sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew));
432 if (error > 0) {
433 return (error);
434 } else if (error < 0) {
435 sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ;
436 sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ;
437 sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ;
438 }
439
440 error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY,
441 sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp));
442 if (error > 0) {
443 return (error);
444 } else if (error < 0) {
445 sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP;
446 sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP;
447 sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP;
448 }
449
450 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY,
451 sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg));
452 if (error > 0) {
453 return (error);
454 } else if (error < 0) {
455 sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG;
456 sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG;
457 sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG;
458 }
459
460 error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY,
461 sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena));
462 if (error > 0) {
463 return (error);
464 } else if (error < 0) {
465 sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE;
466 sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE;
467 sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE;
468 }
469
470 /* Check if the NIC is DMA coherent */
471 sc->prv.coherent = OF_hasprop(node, "dma-coherent");
472 if (sc->prv.coherent) {
473 sc->prv.arcr = XGBE_DMA_OS_ARCR;
474 sc->prv.awcr = XGBE_DMA_OS_AWCR;
475 } else {
476 sc->prv.arcr = XGBE_DMA_SYS_ARCR;
477 sc->prv.awcr = XGBE_DMA_SYS_AWCR;
478 }
479
480 /* Create the lock & workqueues */
481 spin_lock_init(&sc->prv.xpcs_lock);
482 sc->prv.dev_workqueue = taskqueue_create("axgbe", M_WAITOK,
483 taskqueue_thread_enqueue, &sc->prv.dev_workqueue);
484 taskqueue_start_threads(&sc->prv.dev_workqueue, 1, PI_NET,
485 "axgbe taskq");
486
487 /* Set the needed pointers */
488 xgbe_init_function_ptrs_phy(&sc->prv.phy_if);
489 xgbe_init_function_ptrs_dev(&sc->prv.hw_if);
490 xgbe_init_function_ptrs_desc(&sc->prv.desc_if);
491 sc->prv.vdata->init_function_ptrs_phy_impl(&sc->prv.phy_if);
492
493 /* Reset the hardware */
494 sc->prv.hw_if.exit(&sc->prv);
495
496 /* Read the hardware features */
497 xgbe_get_all_hw_features(&sc->prv);
498
499 /* Set default values */
500 sc->prv.tx_desc_count = XGBE_TX_DESC_CNT;
501 sc->prv.tx_sf_mode = MTL_TSF_ENABLE;
502 sc->prv.tx_threshold = MTL_TX_THRESHOLD_64;
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.pbl = DMA_PBL_128;
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 if_setinitfn(ifp, axgbe_init);
529 if_setsoftc(ifp, sc);
530 if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
531 if_setioctlfn(ifp, axgbe_ioctl);
532 /* TODO - change it to iflib way */
533 if_setqflushfn(ifp, axgbe_qflush);
534 if_setgetcounterfn(ifp, axgbe_get_counter);
535
536 /* TODO: Support HW offload */
537 if_setcapabilities(ifp, 0);
538 if_setcapenable(ifp, 0);
539 if_sethwassist(ifp, 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 /* TODO - change it to iflib way */
555 return (0);
556 }
557
558 static device_method_t axgbe_methods[] = {
559 /* Device interface */
560 DEVMETHOD(device_probe, axgbe_probe),
561 DEVMETHOD(device_attach, axgbe_attach),
562
563 { 0, 0 }
564 };
565
566 DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods,
567 sizeof(struct axgbe_softc));
568 DRIVER_MODULE(axa, simplebus, axgbe_driver, 0, 0);
569
570
571 static struct ofw_compat_data phy_compat_data[] = {
572 { "amd,xgbe-phy-seattle-v1a", true },
573 { NULL, false }
574 };
575
576 static int
axgbephy_probe(device_t dev)577 axgbephy_probe(device_t dev)
578 {
579
580 if (!ofw_bus_status_okay(dev))
581 return (ENXIO);
582
583 if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data)
584 return (ENXIO);
585
586 device_set_desc(dev, "AMD 10 Gigabit Ethernet");
587 return (BUS_PROBE_DEFAULT);
588 }
589
590 static int
axgbephy_attach(device_t dev)591 axgbephy_attach(device_t dev)
592 {
593 phandle_t node;
594
595 node = ofw_bus_get_node(dev);
596 OF_device_register_xref(OF_xref_from_node(node), dev);
597
598 return (0);
599 }
600
601 static device_method_t axgbephy_methods[] = {
602 /* Device interface */
603 DEVMETHOD(device_probe, axgbephy_probe),
604 DEVMETHOD(device_attach, axgbephy_attach),
605
606 { 0, 0 }
607 };
608
609 DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0);
610 EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver,
611 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
612