Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/axgbe/if_axgbe.c
39507 views
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/param.h>
33
#include <sys/systm.h>
34
#include <sys/bus.h>
35
#include <sys/kernel.h>
36
#include <sys/lock.h>
37
#include <sys/malloc.h>
38
#include <sys/module.h>
39
#include <sys/mutex.h>
40
#include <sys/queue.h>
41
#include <sys/rman.h>
42
#include <sys/socket.h>
43
#include <sys/sockio.h>
44
#include <sys/sx.h>
45
#include <sys/taskqueue.h>
46
47
#include <net/ethernet.h>
48
#include <net/if.h>
49
#include <net/if_var.h>
50
#include <net/if_media.h>
51
#include <net/if_types.h>
52
53
#include <dev/ofw/openfirm.h>
54
#include <dev/ofw/ofw_bus.h>
55
#include <dev/ofw/ofw_bus_subr.h>
56
57
#include <machine/bus.h>
58
59
#include "miibus_if.h"
60
61
#include "xgbe.h"
62
#include "xgbe-common.h"
63
64
static device_probe_t axgbe_probe;
65
static device_attach_t axgbe_attach;
66
67
struct axgbe_softc {
68
/* Must be first */
69
struct xgbe_prv_data prv;
70
71
uint8_t mac_addr[ETHER_ADDR_LEN];
72
struct ifmedia media;
73
};
74
75
static struct ofw_compat_data compat_data[] = {
76
{ "amd,xgbe-seattle-v1a", true },
77
{ NULL, false }
78
};
79
80
static struct resource_spec old_phy_spec[] = {
81
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Rx/Tx regs */
82
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* Integration regs */
83
{ SYS_RES_MEMORY, 2, RF_ACTIVE }, /* Integration regs */
84
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* Interrupt */
85
{ -1, 0 }
86
};
87
88
static struct resource_spec old_mac_spec[] = {
89
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* MAC regs */
90
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* PCS regs */
91
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* Device interrupt */
92
/* Per-channel interrupts */
93
{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL },
94
{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL },
95
{ SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL },
96
{ SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL },
97
{ -1, 0 }
98
};
99
100
static struct resource_spec mac_spec[] = {
101
{ SYS_RES_MEMORY, 0, RF_ACTIVE }, /* MAC regs */
102
{ SYS_RES_MEMORY, 1, RF_ACTIVE }, /* PCS regs */
103
{ SYS_RES_MEMORY, 2, RF_ACTIVE }, /* Rx/Tx regs */
104
{ SYS_RES_MEMORY, 3, RF_ACTIVE }, /* Integration regs */
105
{ SYS_RES_MEMORY, 4, RF_ACTIVE }, /* Integration regs */
106
{ SYS_RES_IRQ, 0, RF_ACTIVE }, /* Device interrupt */
107
/* Per-channel and auto-negotiation interrupts */
108
{ SYS_RES_IRQ, 1, RF_ACTIVE },
109
{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL },
110
{ SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL },
111
{ SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL },
112
{ SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL },
113
{ -1, 0 }
114
};
115
116
static struct xgbe_version_data xgbe_v1 = {
117
.init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v1,
118
.xpcs_access = XGBE_XPCS_ACCESS_V1,
119
.tx_max_fifo_size = 81920,
120
.rx_max_fifo_size = 81920,
121
.tx_tstamp_workaround = 1,
122
};
123
124
MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data");
125
126
static void
127
axgbe_init(void *p)
128
{
129
struct axgbe_softc *sc;
130
if_t ifp;
131
132
sc = p;
133
ifp = sc->prv.netdev;
134
if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
135
return;
136
137
if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
138
}
139
140
static int
141
axgbe_ioctl(if_t ifp, unsigned long command, caddr_t data)
142
{
143
struct axgbe_softc *sc = if_getsoftc(ifp);
144
struct ifreq *ifr = (struct ifreq *)data;
145
int error = 0;
146
147
switch(command) {
148
case SIOCSIFMTU:
149
if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU_JUMBO)
150
error = EINVAL;
151
/* TODO - change it to iflib way */
152
break;
153
case SIOCSIFFLAGS:
154
error = 0;
155
break;
156
case SIOCSIFMEDIA:
157
case SIOCGIFMEDIA:
158
error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
159
break;
160
default:
161
error = ether_ioctl(ifp, command, data);
162
break;
163
}
164
165
return (error);
166
}
167
168
static void
169
axgbe_qflush(if_t ifp)
170
{
171
172
if_qflush(ifp);
173
}
174
175
static int
176
axgbe_media_change(if_t ifp)
177
{
178
struct axgbe_softc *sc;
179
int cur_media;
180
181
sc = if_getsoftc(ifp);
182
183
sx_xlock(&sc->prv.an_mutex);
184
cur_media = sc->media.ifm_cur->ifm_media;
185
186
switch (IFM_SUBTYPE(cur_media)) {
187
case IFM_10G_KR:
188
sc->prv.phy.speed = SPEED_10000;
189
sc->prv.phy.autoneg = AUTONEG_DISABLE;
190
break;
191
case IFM_2500_KX:
192
sc->prv.phy.speed = SPEED_2500;
193
sc->prv.phy.autoneg = AUTONEG_DISABLE;
194
break;
195
case IFM_1000_KX:
196
sc->prv.phy.speed = SPEED_1000;
197
sc->prv.phy.autoneg = AUTONEG_DISABLE;
198
break;
199
case IFM_AUTO:
200
sc->prv.phy.autoneg = AUTONEG_ENABLE;
201
break;
202
}
203
sx_xunlock(&sc->prv.an_mutex);
204
205
return (-sc->prv.phy_if.phy_config_aneg(&sc->prv));
206
}
207
208
static void
209
axgbe_media_status(if_t ifp, struct ifmediareq *ifmr)
210
{
211
struct axgbe_softc *sc;
212
213
sc = if_getsoftc(ifp);
214
215
ifmr->ifm_status = IFM_AVALID;
216
if (!sc->prv.phy.link)
217
return;
218
219
ifmr->ifm_status |= IFM_ACTIVE;
220
ifmr->ifm_active = IFM_ETHER;
221
222
if (sc->prv.phy.duplex == DUPLEX_FULL)
223
ifmr->ifm_active |= IFM_FDX;
224
else
225
ifmr->ifm_active |= IFM_HDX;
226
227
switch (sc->prv.phy.speed) {
228
case SPEED_10000:
229
ifmr->ifm_active |= IFM_10G_KR;
230
break;
231
case SPEED_2500:
232
ifmr->ifm_active |= IFM_2500_KX;
233
break;
234
case SPEED_1000:
235
ifmr->ifm_active |= IFM_1000_KX;
236
break;
237
}
238
}
239
240
static uint64_t
241
axgbe_get_counter(if_t ifp, ift_counter c)
242
{
243
struct xgbe_prv_data *pdata = if_getsoftc(ifp);
244
struct xgbe_mmc_stats *pstats = &pdata->mmc_stats;
245
246
DBGPR("-->%s\n", __func__);
247
248
pdata->hw_if.read_mmc_stats(pdata);
249
250
switch(c) {
251
case IFCOUNTER_IPACKETS:
252
return (pstats->rxframecount_gb);
253
case IFCOUNTER_IERRORS:
254
return (pstats->rxframecount_gb -
255
pstats->rxbroadcastframes_g -
256
pstats->rxmulticastframes_g -
257
pstats->rxunicastframes_g);
258
case IFCOUNTER_OPACKETS:
259
return (pstats->txframecount_gb);
260
case IFCOUNTER_OERRORS:
261
return (pstats->txframecount_gb - pstats->txframecount_g);
262
case IFCOUNTER_IBYTES:
263
return (pstats->rxoctetcount_gb);
264
case IFCOUNTER_OBYTES:
265
return (pstats->txoctetcount_gb);
266
default:
267
return (if_get_counter_default(ifp, c));
268
}
269
}
270
271
static int
272
axgbe_probe(device_t dev)
273
{
274
275
if (!ofw_bus_status_okay(dev))
276
return (ENXIO);
277
278
if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
279
return (ENXIO);
280
281
device_set_desc(dev, "AMD 10 Gigabit Ethernet");
282
return (BUS_PROBE_DEFAULT);
283
}
284
285
static int
286
axgbe_get_optional_prop(device_t dev, phandle_t node, const char *name,
287
int *data, size_t len)
288
{
289
290
if (!OF_hasprop(node, name))
291
return (-1);
292
293
if (OF_getencprop(node, name, data, len) <= 0) {
294
device_printf(dev,"%s property is invalid\n", name);
295
return (ENXIO);
296
}
297
298
return (0);
299
}
300
301
static int
302
axgbe_attach(device_t dev)
303
{
304
struct axgbe_softc *sc;
305
if_t ifp;
306
pcell_t phy_handle;
307
device_t phydev;
308
phandle_t node, phy_node;
309
struct resource *mac_res[11];
310
struct resource *phy_res[4];
311
ssize_t len;
312
int error, i, j;
313
314
sc = device_get_softc(dev);
315
316
sc->prv.vdata = &xgbe_v1;
317
node = ofw_bus_get_node(dev);
318
if (OF_getencprop(node, "phy-handle", &phy_handle,
319
sizeof(phy_handle)) <= 0) {
320
phy_node = node;
321
322
if (bus_alloc_resources(dev, mac_spec, mac_res)) {
323
device_printf(dev,
324
"could not allocate phy resources\n");
325
return (ENXIO);
326
}
327
328
sc->prv.xgmac_res = mac_res[0];
329
sc->prv.xpcs_res = mac_res[1];
330
sc->prv.rxtx_res = mac_res[2];
331
sc->prv.sir0_res = mac_res[3];
332
sc->prv.sir1_res = mac_res[4];
333
334
sc->prv.dev_irq_res = mac_res[5];
335
sc->prv.per_channel_irq = OF_hasprop(node,
336
XGBE_DMA_IRQS_PROPERTY);
337
for (i = 0, j = 6; j < nitems(mac_res) - 1 &&
338
mac_res[j + 1] != NULL; i++, j++) {
339
if (sc->prv.per_channel_irq) {
340
sc->prv.chan_irq_res[i] = mac_res[j];
341
}
342
}
343
344
/* The last entry is the auto-negotiation interrupt */
345
sc->prv.an_irq_res = mac_res[j];
346
} else {
347
phydev = OF_device_from_xref(phy_handle);
348
phy_node = ofw_bus_get_node(phydev);
349
350
if (bus_alloc_resources(phydev, old_phy_spec, phy_res)) {
351
device_printf(dev,
352
"could not allocate phy resources\n");
353
return (ENXIO);
354
}
355
356
if (bus_alloc_resources(dev, old_mac_spec, mac_res)) {
357
device_printf(dev,
358
"could not allocate mac resources\n");
359
return (ENXIO);
360
}
361
362
sc->prv.rxtx_res = phy_res[0];
363
sc->prv.sir0_res = phy_res[1];
364
sc->prv.sir1_res = phy_res[2];
365
sc->prv.an_irq_res = phy_res[3];
366
367
sc->prv.xgmac_res = mac_res[0];
368
sc->prv.xpcs_res = mac_res[1];
369
sc->prv.dev_irq_res = mac_res[2];
370
sc->prv.per_channel_irq = OF_hasprop(node,
371
XGBE_DMA_IRQS_PROPERTY);
372
if (sc->prv.per_channel_irq) {
373
for (i = 0, j = 3; i < nitems(sc->prv.chan_irq_res) &&
374
mac_res[j] != NULL; i++, j++) {
375
sc->prv.chan_irq_res[i] = mac_res[j];
376
}
377
}
378
}
379
380
if ((len = OF_getproplen(node, "mac-address")) < 0) {
381
device_printf(dev, "No mac-address property\n");
382
return (EINVAL);
383
}
384
385
if (len != ETHER_ADDR_LEN)
386
return (EINVAL);
387
388
OF_getprop(node, "mac-address", sc->mac_addr, ETHER_ADDR_LEN);
389
390
sc->prv.netdev = ifp = if_alloc(IFT_ETHER);
391
sc->prv.dev = dev;
392
sc->prv.dmat = bus_get_dma_tag(dev);
393
sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full |
394
ADVERTISED_1000baseKX_Full;
395
396
397
/*
398
* Read the needed properties from the phy node.
399
*/
400
401
/* This is documented as optional, but Linux requires it */
402
if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set,
403
sizeof(sc->prv.speed_set)) <= 0) {
404
device_printf(dev, "%s property is missing\n",
405
XGBE_SPEEDSET_PROPERTY);
406
return (EINVAL);
407
}
408
409
error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY,
410
sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc));
411
if (error > 0) {
412
return (error);
413
} else if (error < 0) {
414
sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC;
415
sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC;
416
sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC;
417
}
418
419
error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY,
420
sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate));
421
if (error > 0) {
422
return (error);
423
} else if (error < 0) {
424
sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR;
425
sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR;
426
sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR;
427
}
428
429
error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY,
430
sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew));
431
if (error > 0) {
432
return (error);
433
} else if (error < 0) {
434
sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ;
435
sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ;
436
sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ;
437
}
438
439
error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY,
440
sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp));
441
if (error > 0) {
442
return (error);
443
} else if (error < 0) {
444
sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP;
445
sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP;
446
sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP;
447
}
448
449
error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY,
450
sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg));
451
if (error > 0) {
452
return (error);
453
} else if (error < 0) {
454
sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG;
455
sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG;
456
sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG;
457
}
458
459
error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY,
460
sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena));
461
if (error > 0) {
462
return (error);
463
} else if (error < 0) {
464
sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE;
465
sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE;
466
sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE;
467
}
468
469
/* Check if the NIC is DMA coherent */
470
sc->prv.coherent = OF_hasprop(node, "dma-coherent");
471
if (sc->prv.coherent) {
472
sc->prv.arcr = XGBE_DMA_OS_ARCR;
473
sc->prv.awcr = XGBE_DMA_OS_AWCR;
474
} else {
475
sc->prv.arcr = XGBE_DMA_SYS_ARCR;
476
sc->prv.awcr = XGBE_DMA_SYS_AWCR;
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
sc->prv.vdata->init_function_ptrs_phy_impl(&sc->prv.phy_if);
491
492
/* Reset the hardware */
493
sc->prv.hw_if.exit(&sc->prv);
494
495
/* Read the hardware features */
496
xgbe_get_all_hw_features(&sc->prv);
497
498
/* Set default values */
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_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.pbl = DMA_PBL_128;
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
if_setinitfn(ifp, axgbe_init);
528
if_setsoftc(ifp, sc);
529
if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
530
if_setioctlfn(ifp, axgbe_ioctl);
531
/* TODO - change it to iflib way */
532
if_setqflushfn(ifp, axgbe_qflush);
533
if_setgetcounterfn(ifp, axgbe_get_counter);
534
535
/* TODO: Support HW offload */
536
if_setcapabilities(ifp, 0);
537
if_setcapenable(ifp, 0);
538
if_sethwassist(ifp, 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
/* TODO - change it to iflib way */
554
return (0);
555
}
556
557
static device_method_t axgbe_methods[] = {
558
/* Device interface */
559
DEVMETHOD(device_probe, axgbe_probe),
560
DEVMETHOD(device_attach, axgbe_attach),
561
562
{ 0, 0 }
563
};
564
565
DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods,
566
sizeof(struct axgbe_softc));
567
DRIVER_MODULE(axa, simplebus, axgbe_driver, 0, 0);
568
569
570
static struct ofw_compat_data phy_compat_data[] = {
571
{ "amd,xgbe-phy-seattle-v1a", true },
572
{ NULL, false }
573
};
574
575
static int
576
axgbephy_probe(device_t dev)
577
{
578
579
if (!ofw_bus_status_okay(dev))
580
return (ENXIO);
581
582
if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data)
583
return (ENXIO);
584
585
device_set_desc(dev, "AMD 10 Gigabit Ethernet");
586
return (BUS_PROBE_DEFAULT);
587
}
588
589
static int
590
axgbephy_attach(device_t dev)
591
{
592
phandle_t node;
593
594
node = ofw_bus_get_node(dev);
595
OF_device_register_xref(OF_xref_from_node(node), dev);
596
597
return (0);
598
}
599
600
static device_method_t axgbephy_methods[] = {
601
/* Device interface */
602
DEVMETHOD(device_probe, axgbephy_probe),
603
DEVMETHOD(device_attach, axgbephy_attach),
604
605
{ 0, 0 }
606
};
607
608
DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0);
609
EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver,
610
0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
611
612