]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/axgbe/if_axgbe.c
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[FreeBSD/FreeBSD.git] / sys / dev / axgbe / if_axgbe.c
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);