xref: /freebsd/sys/dev/axgbe/if_axgbe.c (revision c697fb7f)
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 	/*
396 	 * Read the needed properties from the phy node.
397 	 */
398 
399 	/* This is documented as optional, but Linux requires it */
400 	if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set,
401 	    sizeof(sc->prv.speed_set)) <= 0) {
402 		device_printf(dev, "%s property is missing\n",
403 		    XGBE_SPEEDSET_PROPERTY);
404 		return (EINVAL);
405 	}
406 
407 	error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY,
408 	    sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc));
409 	if (error > 0) {
410 		return (error);
411 	} else if (error < 0) {
412 		sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC;
413 		sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC;
414 		sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC;
415 	}
416 
417 	error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY,
418 	    sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate));
419 	if (error > 0) {
420 		return (error);
421 	} else if (error < 0) {
422 		sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR;
423 		sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR;
424 		sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR;
425 	}
426 
427 	error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY,
428 	    sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew));
429 	if (error > 0) {
430 		return (error);
431 	} else if (error < 0) {
432 		sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ;
433 		sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ;
434 		sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ;
435 	}
436 
437 	error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY,
438 	    sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp));
439 	if (error > 0) {
440 		return (error);
441 	} else if (error < 0) {
442 		sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP;
443 		sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP;
444 		sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP;
445 	}
446 
447 	error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY,
448 	    sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg));
449 	if (error > 0) {
450 		return (error);
451 	} else if (error < 0) {
452 		sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG;
453 		sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG;
454 		sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG;
455 	}
456 
457 	error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY,
458 	    sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena));
459 	if (error > 0) {
460 		return (error);
461 	} else if (error < 0) {
462 		sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE;
463 		sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE;
464 		sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE;
465 	}
466 
467 	/* Check if the NIC is DMA coherent */
468 	sc->prv.coherent = OF_hasprop(node, "dma-coherent");
469 	if (sc->prv.coherent) {
470 		sc->prv.axdomain = XGBE_DMA_OS_AXDOMAIN;
471 		sc->prv.arcache = XGBE_DMA_OS_ARCACHE;
472 		sc->prv.awcache = XGBE_DMA_OS_AWCACHE;
473 	} else {
474 		sc->prv.axdomain = XGBE_DMA_SYS_AXDOMAIN;
475 		sc->prv.arcache = XGBE_DMA_SYS_ARCACHE;
476 		sc->prv.awcache = XGBE_DMA_SYS_AWCACHE;
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 
491 	/* Reset the hardware */
492 	sc->prv.hw_if.exit(&sc->prv);
493 
494 	/* Read the hardware features */
495 	xgbe_get_all_hw_features(&sc->prv);
496 
497 	/* Set default values */
498 	sc->prv.pblx8 = DMA_PBL_X8_ENABLE;
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_pbl = DMA_PBL_16;
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.rx_pbl = DMA_PBL_16;
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 	ifp->if_init = axgbe_init;
529         ifp->if_softc = sc;
530 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
531 	ifp->if_ioctl = axgbe_ioctl;
532 	ifp->if_transmit = xgbe_xmit;
533 	ifp->if_qflush = axgbe_qflush;
534 	ifp->if_get_counter = axgbe_get_counter;
535 
536 	/* TODO: Support HW offload */
537 	ifp->if_capabilities = 0;
538 	ifp->if_capenable = 0;
539 	ifp->if_hwassist = 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 	if (xgbe_open(ifp) < 0) {
555 		device_printf(dev, "ndo_open failed\n");
556 		return (ENXIO);
557 	}
558 
559 	return (0);
560 }
561 
562 static device_method_t axgbe_methods[] = {
563 	/* Device interface */
564 	DEVMETHOD(device_probe,		axgbe_probe),
565 	DEVMETHOD(device_attach,	axgbe_attach),
566 
567 	{ 0, 0 }
568 };
569 
570 static devclass_t axgbe_devclass;
571 
572 DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods,
573     sizeof(struct axgbe_softc));
574 DRIVER_MODULE(axgbe, simplebus, axgbe_driver, axgbe_devclass, 0, 0);
575 
576 
577 static struct ofw_compat_data phy_compat_data[] = {
578 	{ "amd,xgbe-phy-seattle-v1a",	true },
579 	{ NULL,				false }
580 };
581 
582 static int
583 axgbephy_probe(device_t dev)
584 {
585 
586 	if (!ofw_bus_status_okay(dev))
587 		return (ENXIO);
588 
589 	if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data)
590 		return (ENXIO);
591 
592 	device_set_desc(dev, "AMD 10 Gigabit Ethernet");
593 	return (BUS_PROBE_DEFAULT);
594 }
595 
596 static int
597 axgbephy_attach(device_t dev)
598 {
599 	phandle_t node;
600 
601 	node = ofw_bus_get_node(dev);
602 	OF_device_register_xref(OF_xref_from_node(node), dev);
603 
604 	return (0);
605 }
606 
607 static device_method_t axgbephy_methods[] = {
608 	/* Device interface */
609 	DEVMETHOD(device_probe,		axgbephy_probe),
610 	DEVMETHOD(device_attach,	axgbephy_attach),
611 
612 	{ 0, 0 }
613 };
614 
615 static devclass_t axgbephy_devclass;
616 
617 DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0);
618 EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver, axgbephy_devclass,
619     0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);
620