2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2016,2017 SoftIron Inc.
5 * Copyright (c) 2020 Advanced Micro Devices, Inc.
7 * This software was developed by Andrew Turner under
8 * the sponsorship of SoftIron Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
42 #include <sys/mutex.h>
43 #include <sys/queue.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
48 #include <sys/taskqueue.h>
50 #include <net/ethernet.h>
52 #include <net/if_var.h>
53 #include <net/if_media.h>
54 #include <net/if_types.h>
56 #include <dev/ofw/openfirm.h>
57 #include <dev/ofw/ofw_bus.h>
58 #include <dev/ofw/ofw_bus_subr.h>
60 #include <machine/bus.h>
62 #include "miibus_if.h"
65 #include "xgbe-common.h"
67 static device_probe_t axgbe_probe;
68 static device_attach_t axgbe_attach;
72 struct xgbe_prv_data prv;
74 uint8_t mac_addr[ETHER_ADDR_LEN];
78 static struct ofw_compat_data compat_data[] = {
79 { "amd,xgbe-seattle-v1a", true },
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 */
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 },
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 },
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,
127 MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data");
132 struct axgbe_softc *sc;
136 ifp = sc->prv.netdev;
137 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
140 ifp->if_drv_flags |= IFF_DRV_RUNNING;
144 axgbe_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
146 struct axgbe_softc *sc = ifp->if_softc;
147 struct ifreq *ifr = (struct ifreq *)data;
152 if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU_JUMBO)
154 /* TODO - change it to iflib way */
161 error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
164 error = ether_ioctl(ifp, command, data);
172 axgbe_qflush(struct ifnet *ifp)
179 axgbe_media_change(struct ifnet *ifp)
181 struct axgbe_softc *sc;
186 sx_xlock(&sc->prv.an_mutex);
187 cur_media = sc->media.ifm_cur->ifm_media;
189 switch (IFM_SUBTYPE(cur_media)) {
191 sc->prv.phy.speed = SPEED_10000;
192 sc->prv.phy.autoneg = AUTONEG_DISABLE;
195 sc->prv.phy.speed = SPEED_2500;
196 sc->prv.phy.autoneg = AUTONEG_DISABLE;
199 sc->prv.phy.speed = SPEED_1000;
200 sc->prv.phy.autoneg = AUTONEG_DISABLE;
203 sc->prv.phy.autoneg = AUTONEG_ENABLE;
206 sx_xunlock(&sc->prv.an_mutex);
208 return (-sc->prv.phy_if.phy_config_aneg(&sc->prv));
212 axgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
214 struct axgbe_softc *sc;
218 ifmr->ifm_status = IFM_AVALID;
219 if (!sc->prv.phy.link)
222 ifmr->ifm_status |= IFM_ACTIVE;
223 ifmr->ifm_active = IFM_ETHER;
225 if (sc->prv.phy.duplex == DUPLEX_FULL)
226 ifmr->ifm_active |= IFM_FDX;
228 ifmr->ifm_active |= IFM_HDX;
230 switch (sc->prv.phy.speed) {
232 ifmr->ifm_active |= IFM_10G_KR;
235 ifmr->ifm_active |= IFM_2500_KX;
238 ifmr->ifm_active |= IFM_1000_KX;
244 axgbe_get_counter(struct ifnet *ifp, ift_counter c)
246 struct xgbe_prv_data *pdata = ifp->if_softc;
247 struct xgbe_mmc_stats *pstats = &pdata->mmc_stats;
249 DBGPR("-->%s\n", __func__);
251 pdata->hw_if.read_mmc_stats(pdata);
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);
270 return (if_get_counter_default(ifp, c));
275 axgbe_probe(device_t dev)
278 if (!ofw_bus_status_okay(dev))
281 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
284 device_set_desc(dev, "AMD 10 Gigabit Ethernet");
285 return (BUS_PROBE_DEFAULT);
289 axgbe_get_optional_prop(device_t dev, phandle_t node, const char *name,
290 int *data, size_t len)
293 if (!OF_hasprop(node, name))
296 if (OF_getencprop(node, name, data, len) <= 0) {
297 device_printf(dev,"%s property is invalid\n", name);
305 axgbe_attach(device_t dev)
307 struct axgbe_softc *sc;
311 phandle_t node, phy_node;
312 struct resource *mac_res[11];
313 struct resource *phy_res[4];
317 sc = device_get_softc(dev);
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) {
325 if (bus_alloc_resources(dev, mac_spec, mac_res)) {
327 "could not allocate phy resources\n");
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];
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];
347 /* The last entry is the auto-negotiation interrupt */
348 sc->prv.an_irq_res = mac_res[j];
350 phydev = OF_device_from_xref(phy_handle);
351 phy_node = ofw_bus_get_node(phydev);
353 if (bus_alloc_resources(phydev, old_phy_spec, phy_res)) {
355 "could not allocate phy resources\n");
359 if (bus_alloc_resources(dev, old_mac_spec, mac_res)) {
361 "could not allocate mac resources\n");
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];
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];
383 if ((len = OF_getproplen(node, "mac-address")) < 0) {
384 device_printf(dev, "No mac-address property\n");
388 if (len != ETHER_ADDR_LEN)
391 OF_getprop(node, "mac-address", sc->mac_addr, ETHER_ADDR_LEN);
393 sc->prv.netdev = ifp = if_alloc(IFT_ETHER);
395 device_printf(dev, "Cannot alloc ifnet\n");
400 sc->prv.dmat = bus_get_dma_tag(dev);
401 sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full |
402 ADVERTISED_1000baseKX_Full;
406 * Read the needed properties from the phy node.
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);
417 error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY,
418 sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc));
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;
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));
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;
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));
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;
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));
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;
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));
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;
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));
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;
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;
483 sc->prv.arcr = XGBE_DMA_SYS_ARCR;
484 sc->prv.awcr = XGBE_DMA_SYS_AWCR;
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,
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);
500 /* Reset the hardware */
501 sc->prv.hw_if.exit(&sc->prv);
503 /* Read the hardware features */
504 xgbe_get_all_hw_features(&sc->prv);
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;
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;
528 sc->prv.phy_if.phy_init(&sc->prv);
530 /* Set the coalescing */
531 xgbe_init_rx_coalesce(&sc->prv);
532 xgbe_init_tx_coalesce(&sc->prv);
534 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
535 ifp->if_init = axgbe_init;
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;
543 /* TODO: Support HW offload */
544 ifp->if_capabilities = 0;
545 ifp->if_capenable = 0;
546 ifp->if_hwassist = 0;
548 ether_ifattach(ifp, sc->mac_addr);
550 ifmedia_init(&sc->media, IFM_IMASK, axgbe_media_change,
553 ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
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);
559 set_bit(XGBE_DOWN, &sc->prv.dev_state);
561 /* TODO - change it to iflib way */
565 static device_method_t axgbe_methods[] = {
566 /* Device interface */
567 DEVMETHOD(device_probe, axgbe_probe),
568 DEVMETHOD(device_attach, axgbe_attach),
573 static devclass_t axgbe_devclass;
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);
580 static struct ofw_compat_data phy_compat_data[] = {
581 { "amd,xgbe-phy-seattle-v1a", true },
586 axgbephy_probe(device_t dev)
589 if (!ofw_bus_status_okay(dev))
592 if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data)
595 device_set_desc(dev, "AMD 10 Gigabit Ethernet");
596 return (BUS_PROBE_DEFAULT);
600 axgbephy_attach(device_t dev)
604 node = ofw_bus_get_node(dev);
605 OF_device_register_xref(OF_xref_from_node(node), dev);
610 static device_method_t axgbephy_methods[] = {
611 /* Device interface */
612 DEVMETHOD(device_probe, axgbephy_probe),
613 DEVMETHOD(device_attach, axgbephy_attach),
618 static devclass_t axgbephy_devclass;
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);