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