svn commit: r313768 - in head/sys: arm64/conf conf dev/axgbe

Andrew Turner andrew at FreeBSD.org
Wed Feb 15 13:56:06 UTC 2017


Author: andrew
Date: Wed Feb 15 13:56:04 2017
New Revision: 313768
URL: https://svnweb.freebsd.org/changeset/base/313768

Log:
  Port the Linux AMX 10G network driver to FreeBSD as axgbe. It is unlikely
  we will import a newer version of the Linux code so the linuxkpi was not
  used.
  
  This is still missing 10G support, and multicast has not been tested.
  
  Reviewed by:	gnn
  Obtained from:	ABT Systems Ltd
  Sponsored by:	SoftIron Inc
  Differential Revision:	https://reviews.freebsd.org/D8549

Added:
  head/sys/dev/axgbe/if_axgbe.c   (contents, props changed)
  head/sys/dev/axgbe/xgbe_osdep.h   (contents, props changed)
Modified:
  head/sys/arm64/conf/GENERIC
  head/sys/conf/files.arm64
  head/sys/dev/axgbe/xgbe-common.h   (contents, props changed)
  head/sys/dev/axgbe/xgbe-desc.c   (contents, props changed)
  head/sys/dev/axgbe/xgbe-dev.c   (contents, props changed)
  head/sys/dev/axgbe/xgbe-drv.c   (contents, props changed)
  head/sys/dev/axgbe/xgbe-mdio.c   (contents, props changed)
  head/sys/dev/axgbe/xgbe.h   (contents, props changed)

Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC	Wed Feb 15 13:37:32 2017	(r313767)
+++ head/sys/arm64/conf/GENERIC	Wed Feb 15 13:56:04 2017	(r313768)
@@ -119,6 +119,7 @@ options 	PCI_IOV		# PCI SR-IOV support
 device		mii
 device		miibus		# MII bus support
 device		awg		# Allwinner EMAC Gigabit Ethernet
+device		axgbe		# AMD Opteron A1100 integrated NIC
 device		em		# Intel PRO/1000 Gigabit Ethernet Family
 device		ix		# Intel 10Gb Ethernet Family
 device		msk		# Marvell/SysKonnect Yukon II Gigabit Ethernet

Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64	Wed Feb 15 13:37:32 2017	(r313767)
+++ head/sys/conf/files.arm64	Wed Feb 15 13:56:04 2017	(r313768)
@@ -146,6 +146,11 @@ crypto/blowfish/bf_enc.c	optional	crypto
 crypto/des/des_enc.c		optional	crypto | ipsec | ipsec_support | netsmb
 dev/acpica/acpi_if.m		optional	acpi
 dev/ahci/ahci_generic.c		optional	ahci
+dev/axgbe/if_axgbe.c		optional	axgbe
+dev/axgbe/xgbe-desc.c		optional	axgbe
+dev/axgbe/xgbe-dev.c		optional	axgbe
+dev/axgbe/xgbe-drv.c		optional	axgbe
+dev/axgbe/xgbe-mdio.c		optional	axgbe
 dev/cpufreq/cpufreq_dt.c	optional	cpufreq fdt
 dev/hwpmc/hwpmc_arm64.c		optional	hwpmc
 dev/hwpmc/hwpmc_arm64_md.c	optional	hwpmc

Added: head/sys/dev/axgbe/if_axgbe.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/axgbe/if_axgbe.c	Wed Feb 15 13:56:04 2017	(r313768)
@@ -0,0 +1,619 @@
+/*-
+ * Copyright (c) 2016,2017 SoftIron Inc.
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under
+ * the sponsorship of SoftIron Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+
+#include "miibus_if.h"
+
+#include "xgbe.h"
+#include "xgbe-common.h"
+
+static device_probe_t	axgbe_probe;
+static device_attach_t	axgbe_attach;
+
+struct axgbe_softc {
+	/* Must be first */
+	struct xgbe_prv_data	prv;
+
+	uint8_t			mac_addr[ETHER_ADDR_LEN];
+	struct ifmedia		media;
+};
+
+static struct ofw_compat_data compat_data[] = {
+	{ "amd,xgbe-seattle-v1a",	true },
+	{ NULL,				false }
+};
+
+static struct resource_spec old_phy_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE }, /* Rx/Tx regs */
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE }, /* Integration regs */
+	{ SYS_RES_MEMORY,	2,	RF_ACTIVE }, /* Integration regs */
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE }, /* Interrupt */
+	{ -1, 0 }
+};
+
+static struct resource_spec old_mac_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE }, /* MAC regs */
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE }, /* PCS regs */
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE }, /* Device interrupt */
+	/* Per-channel interrupts */
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,		2,	RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,		3,	RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,		4,	RF_ACTIVE | RF_OPTIONAL },
+	{ -1, 0 }
+};
+
+static struct resource_spec mac_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE }, /* MAC regs */
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE }, /* PCS regs */
+	{ SYS_RES_MEMORY,	2,	RF_ACTIVE }, /* Rx/Tx regs */
+	{ SYS_RES_MEMORY,	3,	RF_ACTIVE }, /* Integration regs */
+	{ SYS_RES_MEMORY,	4,	RF_ACTIVE }, /* Integration regs */
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE }, /* Device interrupt */
+	/* Per-channel and auto-negotiation interrupts */
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		2,	RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,		3,	RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,		4,	RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,		5,	RF_ACTIVE | RF_OPTIONAL },
+	{ -1, 0 }
+};
+
+MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data");
+
+static void
+axgbe_init(void *p)
+{
+	struct axgbe_softc *sc;
+	struct ifnet *ifp;
+
+	sc = p;
+	ifp = sc->prv.netdev;
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		return;
+
+	ifp->if_drv_flags |= IFF_DRV_RUNNING;
+}
+
+static int
+axgbe_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
+{
+	struct axgbe_softc *sc = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *)data;
+	int error;
+
+	switch(command) {
+	case SIOCSIFMTU:
+		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU_JUMBO)
+			error = EINVAL;
+		else
+			error = xgbe_change_mtu(ifp, ifr->ifr_mtu);
+		break;
+	case SIOCSIFFLAGS:
+		error = 0;
+		break;
+	case SIOCSIFMEDIA:
+	case SIOCGIFMEDIA:
+		error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
+		break;
+	default:
+		error = ether_ioctl(ifp, command, data);
+		break;
+	}
+
+	return (error);
+}
+
+static void
+axgbe_qflush(struct ifnet *ifp)
+{
+
+	if_qflush(ifp);
+}
+
+static int
+axgbe_media_change(struct ifnet *ifp)
+{
+	struct axgbe_softc *sc;
+	int cur_media;
+
+	sc = ifp->if_softc;
+
+	sx_xlock(&sc->prv.an_mutex);
+	cur_media = sc->media.ifm_cur->ifm_media;
+
+	switch (IFM_SUBTYPE(cur_media)) {
+	case IFM_10G_KR:
+		sc->prv.phy.speed = SPEED_10000;
+		sc->prv.phy.autoneg = AUTONEG_DISABLE;
+		break;
+	case IFM_2500_KX:
+		sc->prv.phy.speed = SPEED_2500;
+		sc->prv.phy.autoneg = AUTONEG_DISABLE;
+		break;
+	case IFM_1000_KX:
+		sc->prv.phy.speed = SPEED_1000;
+		sc->prv.phy.autoneg = AUTONEG_DISABLE;
+		break;
+	case IFM_AUTO:
+		sc->prv.phy.autoneg = AUTONEG_ENABLE;
+		break;
+	}
+	sx_xunlock(&sc->prv.an_mutex);
+
+	return (-sc->prv.phy_if.phy_config_aneg(&sc->prv));
+}
+
+static void
+axgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct axgbe_softc *sc;
+
+	sc = ifp->if_softc;
+
+	ifmr->ifm_status = IFM_AVALID;
+	if (!sc->prv.phy.link)
+		return;
+
+	ifmr->ifm_status |= IFM_ACTIVE;
+	ifmr->ifm_active = IFM_ETHER;
+
+	if (sc->prv.phy.duplex == DUPLEX_FULL)
+		ifmr->ifm_active |= IFM_FDX;
+	else
+		ifmr->ifm_active |= IFM_HDX;
+
+	switch (sc->prv.phy.speed) {
+	case SPEED_10000:
+		ifmr->ifm_active |= IFM_10G_KR;
+		break;
+	case SPEED_2500:
+		ifmr->ifm_active |= IFM_2500_KX;
+		break;
+	case SPEED_1000:
+		ifmr->ifm_active |= IFM_1000_KX;
+		break;
+	}
+}
+
+static uint64_t
+axgbe_get_counter(struct ifnet *ifp, ift_counter c)
+{
+	struct xgbe_prv_data *pdata = ifp->if_softc;
+	struct xgbe_mmc_stats *pstats = &pdata->mmc_stats;
+
+	DBGPR("-->%s\n", __func__);
+
+	pdata->hw_if.read_mmc_stats(pdata);
+
+	switch(c) {
+	case IFCOUNTER_IPACKETS:
+		return (pstats->rxframecount_gb);
+	case IFCOUNTER_IERRORS:
+		return (pstats->rxframecount_gb -
+		    pstats->rxbroadcastframes_g -
+		    pstats->rxmulticastframes_g -
+		    pstats->rxunicastframes_g);
+	case IFCOUNTER_OPACKETS:
+		return (pstats->txframecount_gb);
+	case IFCOUNTER_OERRORS:
+		return (pstats->txframecount_gb - pstats->txframecount_g);
+	case IFCOUNTER_IBYTES:
+		return (pstats->rxoctetcount_gb);
+	case IFCOUNTER_OBYTES:
+		return (pstats->txoctetcount_gb);
+	default:
+		return (if_get_counter_default(ifp, c));
+	}
+}
+
+static int
+axgbe_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+		return (ENXIO);
+
+	device_set_desc(dev, "AMD 10 Gigabit Ethernet");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+axgbe_get_optional_prop(device_t dev, phandle_t node, const char *name,
+    int *data, size_t len)
+{
+
+	if (!OF_hasprop(node, name))
+		return (-1);
+
+	if (OF_getencprop(node, name, data, len) <= 0) {
+		device_printf(dev,"%s property is invalid\n", name);
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+axgbe_attach(device_t dev)
+{
+	struct axgbe_softc *sc;
+	struct ifnet *ifp;
+	pcell_t phy_handle;
+	device_t phydev;
+	phandle_t node, phy_node;
+	struct resource *mac_res[11];
+	struct resource *phy_res[4];
+	ssize_t len;
+	int error, i, j;
+
+	sc = device_get_softc(dev);
+
+	node = ofw_bus_get_node(dev);
+	if (OF_getencprop(node, "phy-handle", &phy_handle,
+	    sizeof(phy_handle)) <= 0) {
+		phy_node = node;
+
+		if (bus_alloc_resources(dev, mac_spec, mac_res)) {
+			device_printf(dev,
+			    "could not allocate phy resources\n");
+			return (ENXIO);
+		}
+
+		sc->prv.xgmac_res = mac_res[0];
+		sc->prv.xpcs_res = mac_res[1];
+		sc->prv.rxtx_res = mac_res[2];
+		sc->prv.sir0_res = mac_res[3];
+		sc->prv.sir1_res = mac_res[4];
+
+		sc->prv.dev_irq_res = mac_res[5];
+		sc->prv.per_channel_irq = OF_hasprop(node,
+		    XGBE_DMA_IRQS_PROPERTY);
+		for (i = 0, j = 6; j < nitems(mac_res) - 1 &&
+		    mac_res[j + 1] != NULL; i++, j++) {
+			if (sc->prv.per_channel_irq) {
+				sc->prv.chan_irq_res[i] = mac_res[j];
+			}
+		}
+
+		/* The last entry is the auto-negotiation interrupt */
+		sc->prv.an_irq_res = mac_res[j];
+	} else {
+		phydev = OF_device_from_xref(phy_handle);
+		phy_node = ofw_bus_get_node(phydev);
+
+		if (bus_alloc_resources(phydev, old_phy_spec, phy_res)) {
+			device_printf(dev,
+			    "could not allocate phy resources\n");
+			return (ENXIO);
+		}
+
+		if (bus_alloc_resources(dev, old_mac_spec, mac_res)) {
+			device_printf(dev,
+			    "could not allocate mac resources\n");
+			return (ENXIO);
+		}
+
+		sc->prv.rxtx_res = phy_res[0];
+		sc->prv.sir0_res = phy_res[1];
+		sc->prv.sir1_res = phy_res[2];
+		sc->prv.an_irq_res = phy_res[3];
+
+		sc->prv.xgmac_res = mac_res[0];
+		sc->prv.xpcs_res = mac_res[1];
+		sc->prv.dev_irq_res = mac_res[2];
+		sc->prv.per_channel_irq = OF_hasprop(node,
+		    XGBE_DMA_IRQS_PROPERTY);
+		if (sc->prv.per_channel_irq) {
+			for (i = 0, j = 3; i < nitems(sc->prv.chan_irq_res) &&
+			    mac_res[j] != NULL; i++, j++) {
+				sc->prv.chan_irq_res[i] = mac_res[j];
+			}
+		}
+	}
+
+	if ((len = OF_getproplen(node, "mac-address")) < 0) {
+		device_printf(dev, "No mac-address property\n");
+		return (EINVAL);
+	}
+
+	if (len != ETHER_ADDR_LEN)
+		return (EINVAL);
+
+	OF_getprop(node, "mac-address", sc->mac_addr, ETHER_ADDR_LEN);
+
+	sc->prv.netdev = ifp = if_alloc(IFT_ETHER);
+	if (ifp == NULL) {
+		device_printf(dev, "Cannot alloc ifnet\n");
+		return (ENXIO);
+	}
+
+	sc->prv.dev = dev;
+	sc->prv.dmat = bus_get_dma_tag(dev);
+	sc->prv.phy.advertising = ADVERTISED_10000baseKR_Full |
+	    ADVERTISED_1000baseKX_Full;
+
+
+	/*
+	 * Read the needed properties from the phy node.
+	 */
+
+	/* This is documented as optional, but Linux requires it */
+	if (OF_getencprop(phy_node, XGBE_SPEEDSET_PROPERTY, &sc->prv.speed_set,
+	    sizeof(sc->prv.speed_set)) <= 0) {
+		device_printf(dev, "%s property is missing\n",
+		    XGBE_SPEEDSET_PROPERTY);
+		return (EINVAL);
+	}
+
+	error = axgbe_get_optional_prop(dev, phy_node, XGBE_BLWC_PROPERTY,
+	    sc->prv.serdes_blwc, sizeof(sc->prv.serdes_blwc));
+	if (error > 0) {
+		return (error);
+	} else if (error < 0) {
+		sc->prv.serdes_blwc[0] = XGBE_SPEED_1000_BLWC;
+		sc->prv.serdes_blwc[1] = XGBE_SPEED_2500_BLWC;
+		sc->prv.serdes_blwc[2] = XGBE_SPEED_10000_BLWC;
+	}
+
+	error = axgbe_get_optional_prop(dev, phy_node, XGBE_CDR_RATE_PROPERTY,
+	    sc->prv.serdes_cdr_rate, sizeof(sc->prv.serdes_cdr_rate));
+	if (error > 0) {
+		return (error);
+	} else if (error < 0) {
+		sc->prv.serdes_cdr_rate[0] = XGBE_SPEED_1000_CDR;
+		sc->prv.serdes_cdr_rate[1] = XGBE_SPEED_2500_CDR;
+		sc->prv.serdes_cdr_rate[2] = XGBE_SPEED_10000_CDR;
+	}
+
+	error = axgbe_get_optional_prop(dev, phy_node, XGBE_PQ_SKEW_PROPERTY,
+	    sc->prv.serdes_pq_skew, sizeof(sc->prv.serdes_pq_skew));
+	if (error > 0) {
+		return (error);
+	} else if (error < 0) {
+		sc->prv.serdes_pq_skew[0] = XGBE_SPEED_1000_PQ;
+		sc->prv.serdes_pq_skew[1] = XGBE_SPEED_2500_PQ;
+		sc->prv.serdes_pq_skew[2] = XGBE_SPEED_10000_PQ;
+	}
+
+	error = axgbe_get_optional_prop(dev, phy_node, XGBE_TX_AMP_PROPERTY,
+	    sc->prv.serdes_tx_amp, sizeof(sc->prv.serdes_tx_amp));
+	if (error > 0) {
+		return (error);
+	} else if (error < 0) {
+		sc->prv.serdes_tx_amp[0] = XGBE_SPEED_1000_TXAMP;
+		sc->prv.serdes_tx_amp[1] = XGBE_SPEED_2500_TXAMP;
+		sc->prv.serdes_tx_amp[2] = XGBE_SPEED_10000_TXAMP;
+	}
+
+	error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_CFG_PROPERTY,
+	    sc->prv.serdes_dfe_tap_cfg, sizeof(sc->prv.serdes_dfe_tap_cfg));
+	if (error > 0) {
+		return (error);
+	} else if (error < 0) {
+		sc->prv.serdes_dfe_tap_cfg[0] = XGBE_SPEED_1000_DFE_TAP_CONFIG;
+		sc->prv.serdes_dfe_tap_cfg[1] = XGBE_SPEED_2500_DFE_TAP_CONFIG;
+		sc->prv.serdes_dfe_tap_cfg[2] = XGBE_SPEED_10000_DFE_TAP_CONFIG;
+	}
+
+	error = axgbe_get_optional_prop(dev, phy_node, XGBE_DFE_ENA_PROPERTY,
+	    sc->prv.serdes_dfe_tap_ena, sizeof(sc->prv.serdes_dfe_tap_ena));
+	if (error > 0) {
+		return (error);
+	} else if (error < 0) {
+		sc->prv.serdes_dfe_tap_ena[0] = XGBE_SPEED_1000_DFE_TAP_ENABLE;
+		sc->prv.serdes_dfe_tap_ena[1] = XGBE_SPEED_2500_DFE_TAP_ENABLE;
+		sc->prv.serdes_dfe_tap_ena[2] = XGBE_SPEED_10000_DFE_TAP_ENABLE;
+	}
+
+	/* Check if the NIC is DMA coherent */
+	sc->prv.coherent = OF_hasprop(node, "dma-coherent");
+	if (sc->prv.coherent) {
+		sc->prv.axdomain = XGBE_DMA_OS_AXDOMAIN;
+		sc->prv.arcache = XGBE_DMA_OS_ARCACHE;
+		sc->prv.awcache = XGBE_DMA_OS_AWCACHE;
+	} else {
+		sc->prv.axdomain = XGBE_DMA_SYS_AXDOMAIN;
+		sc->prv.arcache = XGBE_DMA_SYS_ARCACHE;
+		sc->prv.awcache = XGBE_DMA_SYS_AWCACHE;
+	}
+
+	/* Create the lock & workqueues */
+	spin_lock_init(&sc->prv.xpcs_lock);
+	sc->prv.dev_workqueue = taskqueue_create("axgbe", M_WAITOK,
+	    taskqueue_thread_enqueue, &sc->prv.dev_workqueue);
+	taskqueue_start_threads(&sc->prv.dev_workqueue, 1, PI_NET,
+	    "axgbe taskq");
+
+	/* Set the needed pointers */
+	xgbe_init_function_ptrs_phy(&sc->prv.phy_if);
+	xgbe_init_function_ptrs_dev(&sc->prv.hw_if);
+	xgbe_init_function_ptrs_desc(&sc->prv.desc_if);
+
+	/* Reset the hardware */
+	sc->prv.hw_if.exit(&sc->prv);
+
+	/* Read the hardware features */
+	xgbe_get_all_hw_features(&sc->prv);
+
+	/* Set default values */
+	sc->prv.pblx8 = DMA_PBL_X8_ENABLE;
+	sc->prv.tx_desc_count = XGBE_TX_DESC_CNT;
+	sc->prv.tx_sf_mode = MTL_TSF_ENABLE;
+	sc->prv.tx_threshold = MTL_TX_THRESHOLD_64;
+	sc->prv.tx_pbl = DMA_PBL_16;
+	sc->prv.tx_osp_mode = DMA_OSP_ENABLE;
+	sc->prv.rx_desc_count = XGBE_RX_DESC_CNT;
+	sc->prv.rx_sf_mode = MTL_RSF_DISABLE;
+	sc->prv.rx_threshold = MTL_RX_THRESHOLD_64;
+	sc->prv.rx_pbl = DMA_PBL_16;
+	sc->prv.pause_autoneg = 1;
+	sc->prv.tx_pause = 1;
+	sc->prv.rx_pause = 1;
+	sc->prv.phy_speed = SPEED_UNKNOWN;
+	sc->prv.power_down = 0;
+
+	/* TODO: Limit to min(ncpus, hw rings) */
+	sc->prv.tx_ring_count = 1;
+	sc->prv.tx_q_count = 1;
+	sc->prv.rx_ring_count = 1;
+	sc->prv.rx_q_count = sc->prv.hw_feat.rx_q_cnt;
+
+	/* Init the PHY */
+	sc->prv.phy_if.phy_init(&sc->prv);
+
+	/* Set the coalescing */
+	xgbe_init_rx_coalesce(&sc->prv);
+	xgbe_init_tx_coalesce(&sc->prv);
+
+	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+	ifp->if_init = axgbe_init;
+        ifp->if_softc = sc;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_ioctl = axgbe_ioctl;
+	ifp->if_transmit = xgbe_xmit;
+	ifp->if_qflush = axgbe_qflush;
+	ifp->if_get_counter = axgbe_get_counter;
+
+	/* TODO: Support HW offload */
+	ifp->if_capabilities = 0;
+	ifp->if_capenable = 0;
+	ifp->if_hwassist = 0;
+
+	ether_ifattach(ifp, sc->mac_addr);
+
+	ifmedia_init(&sc->media, IFM_IMASK, axgbe_media_change,
+	    axgbe_media_status);
+#ifdef notyet
+	ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_KR, 0, NULL);
+#endif
+	ifmedia_add(&sc->media, IFM_ETHER | IFM_1000_KX, 0, NULL);
+	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
+	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
+
+	set_bit(XGBE_DOWN, &sc->prv.dev_state);
+
+	if (xgbe_open(ifp) < 0) {
+		device_printf(dev, "ndo_open failed\n");
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static device_method_t axgbe_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		axgbe_probe),
+	DEVMETHOD(device_attach,	axgbe_attach),
+
+	{ 0, 0 }
+};
+
+static devclass_t axgbe_devclass;
+
+DEFINE_CLASS_0(axgbe, axgbe_driver, axgbe_methods,
+    sizeof(struct axgbe_softc));
+DRIVER_MODULE(axgbe, simplebus, axgbe_driver, axgbe_devclass, 0, 0);
+
+
+static struct ofw_compat_data phy_compat_data[] = {
+	{ "amd,xgbe-phy-seattle-v1a",	true },
+	{ NULL,				false }
+};
+
+static int
+axgbephy_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (!ofw_bus_search_compatible(dev, phy_compat_data)->ocd_data)
+		return (ENXIO);
+
+	device_set_desc(dev, "AMD 10 Gigabit Ethernet");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+axgbephy_attach(device_t dev)
+{
+	phandle_t node;
+
+	node = ofw_bus_get_node(dev);
+	OF_device_register_xref(OF_xref_from_node(node), dev);
+
+	return (0);
+}
+
+static device_method_t axgbephy_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		axgbephy_probe),
+	DEVMETHOD(device_attach,	axgbephy_attach),
+
+	{ 0, 0 }
+};
+
+static devclass_t axgbephy_devclass;
+
+DEFINE_CLASS_0(axgbephy, axgbephy_driver, axgbephy_methods, 0);
+EARLY_DRIVER_MODULE(axgbephy, simplebus, axgbephy_driver, axgbephy_devclass,
+    0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);

Modified: head/sys/dev/axgbe/xgbe-common.h
==============================================================================
--- head/sys/dev/axgbe/xgbe-common.h	Wed Feb 15 13:37:32 2017	(r313767)
+++ head/sys/dev/axgbe/xgbe-common.h	Wed Feb 15 13:56:04 2017	(r313768)
@@ -112,11 +112,16 @@
  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  *     THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
  */
 
 #ifndef __XGBE_COMMON_H__
 #define __XGBE_COMMON_H__
 
+#include <sys/bus.h>
+#include <sys/rman.h>
+
 /* DMA register offsets */
 #define DMA_MR				0x3000
 #define DMA_SBMR			0x3004
@@ -1123,7 +1128,7 @@ do {									\
  *  register definitions formed using the input names
  */
 #define XGMAC_IOREAD(_pdata, _reg)					\
-	ioread32((_pdata)->xgmac_regs + _reg)
+	bus_read_4((_pdata)->xgmac_res, _reg)
 
 #define XGMAC_IOREAD_BITS(_pdata, _reg, _field)				\
 	GET_BITS(XGMAC_IOREAD((_pdata), _reg),				\
@@ -1131,7 +1136,7 @@ do {									\
 		 _reg##_##_field##_WIDTH)
 
 #define XGMAC_IOWRITE(_pdata, _reg, _val)				\
-	iowrite32((_val), (_pdata)->xgmac_regs + _reg)
+	bus_write_4((_pdata)->xgmac_res, _reg, (_val))
 
 #define XGMAC_IOWRITE_BITS(_pdata, _reg, _field, _val)			\
 do {									\
@@ -1147,7 +1152,7 @@ do {									\
  *  base register value is calculated by the queue or traffic class number
  */
 #define XGMAC_MTL_IOREAD(_pdata, _n, _reg)				\
-	ioread32((_pdata)->xgmac_regs +					\
+	bus_read_4((_pdata)->xgmac_res,					\
 		 MTL_Q_BASE + ((_n) * MTL_Q_INC) + _reg)
 
 #define XGMAC_MTL_IOREAD_BITS(_pdata, _n, _reg, _field)			\
@@ -1156,8 +1161,8 @@ do {									\
 		 _reg##_##_field##_WIDTH)
 
 #define XGMAC_MTL_IOWRITE(_pdata, _n, _reg, _val)			\
-	iowrite32((_val), (_pdata)->xgmac_regs +			\
-		  MTL_Q_BASE + ((_n) * MTL_Q_INC) + _reg)
+	bus_write_4((_pdata)->xgmac_res,				\
+		  MTL_Q_BASE + ((_n) * MTL_Q_INC) + _reg, (_val))
 
 #define XGMAC_MTL_IOWRITE_BITS(_pdata, _n, _reg, _field, _val)		\
 do {									\
@@ -1173,7 +1178,7 @@ do {									\
  *  base register value is obtained from the ring
  */
 #define XGMAC_DMA_IOREAD(_channel, _reg)				\
-	ioread32((_channel)->dma_regs + _reg)
+	bus_space_read_4((_channel)->dma_tag, (_channel)->dma_handle, _reg)
 
 #define XGMAC_DMA_IOREAD_BITS(_channel, _reg, _field)			\
 	GET_BITS(XGMAC_DMA_IOREAD((_channel), _reg),			\
@@ -1181,7 +1186,8 @@ do {									\
 		 _reg##_##_field##_WIDTH)
 
 #define XGMAC_DMA_IOWRITE(_channel, _reg, _val)				\
-	iowrite32((_val), (_channel)->dma_regs + _reg)
+	bus_space_write_4((_channel)->dma_tag, (_channel)->dma_handle,	\
+	    _reg, (_val))
 
 #define XGMAC_DMA_IOWRITE_BITS(_channel, _reg, _field, _val)		\
 do {									\
@@ -1196,10 +1202,10 @@ do {									\
  * within the register values of XPCS registers.
  */
 #define XPCS_IOWRITE(_pdata, _off, _val)				\
-	iowrite32(_val, (_pdata)->xpcs_regs + (_off))
+	bus_write_4((_pdata)->xpcs_res, (_off), _val)
 
 #define XPCS_IOREAD(_pdata, _off)					\
-	ioread32((_pdata)->xpcs_regs + (_off))
+	bus_read_4((_pdata)->xpcs_res, (_off))
 
 /* Macros for building, reading or writing register values or bits
  * within the register values of SerDes integration registers.
@@ -1215,7 +1221,7 @@ do {									\
 		 _prefix##_##_field##_WIDTH, (_val))
 
 #define XSIR0_IOREAD(_pdata, _reg)					\
-	ioread16((_pdata)->sir0_regs + _reg)
+	bus_read_2((_pdata)->sir0_res, _reg)
 
 #define XSIR0_IOREAD_BITS(_pdata, _reg, _field)				\
 	GET_BITS(XSIR0_IOREAD((_pdata), _reg),				\
@@ -1223,7 +1229,7 @@ do {									\
 		 _reg##_##_field##_WIDTH)
 
 #define XSIR0_IOWRITE(_pdata, _reg, _val)				\
-	iowrite16((_val), (_pdata)->sir0_regs + _reg)
+	bus_write_2((_pdata)->sir0_res, _reg, (_val))
 
 #define XSIR0_IOWRITE_BITS(_pdata, _reg, _field, _val)			\
 do {									\
@@ -1235,7 +1241,7 @@ do {									\
 } while (0)
 
 #define XSIR1_IOREAD(_pdata, _reg)					\
-	ioread16((_pdata)->sir1_regs + _reg)
+	bus_read_2((_pdata)->sir1_res, _reg)
 
 #define XSIR1_IOREAD_BITS(_pdata, _reg, _field)				\
 	GET_BITS(XSIR1_IOREAD((_pdata), _reg),				\
@@ -1243,7 +1249,7 @@ do {									\
 		 _reg##_##_field##_WIDTH)
 
 #define XSIR1_IOWRITE(_pdata, _reg, _val)				\
-	iowrite16((_val), (_pdata)->sir1_regs + _reg)
+	bus_write_2((_pdata)->sir1_res, _reg, (_val))
 
 #define XSIR1_IOWRITE_BITS(_pdata, _reg, _field, _val)			\
 do {									\
@@ -1258,7 +1264,7 @@ do {									\
  * within the register values of SerDes RxTx registers.
  */
 #define XRXTX_IOREAD(_pdata, _reg)					\
-	ioread16((_pdata)->rxtx_regs + _reg)
+	bus_read_2((_pdata)->rxtx_res, _reg)
 
 #define XRXTX_IOREAD_BITS(_pdata, _reg, _field)				\
 	GET_BITS(XRXTX_IOREAD((_pdata), _reg),				\
@@ -1266,7 +1272,7 @@ do {									\
 		 _reg##_##_field##_WIDTH)
 
 #define XRXTX_IOWRITE(_pdata, _reg, _val)				\
-	iowrite16((_val), (_pdata)->rxtx_regs + _reg)
+	bus_write_2((_pdata)->rxtx_res, _reg, (_val))
 
 #define XRXTX_IOWRITE_BITS(_pdata, _reg, _field, _val)			\
 do {									\

Modified: head/sys/dev/axgbe/xgbe-desc.c
==============================================================================
--- head/sys/dev/axgbe/xgbe-desc.c	Wed Feb 15 13:37:32 2017	(r313767)
+++ head/sys/dev/axgbe/xgbe-desc.c	Wed Feb 15 13:56:04 2017	(r313768)
@@ -114,6 +114,9 @@
  *     THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
 #include "xgbe.h"
 #include "xgbe-common.h"
 
@@ -128,45 +131,29 @@ static void xgbe_free_ring(struct xgbe_p
 	if (!ring)
 		return;
 
+	bus_dmamap_destroy(ring->mbuf_dmat, ring->mbuf_map);
+	bus_dma_tag_destroy(ring->mbuf_dmat);
+
+	ring->mbuf_map = NULL;
+	ring->mbuf_dmat = NULL;
+
 	if (ring->rdata) {
 		for (i = 0; i < ring->rdesc_count; i++) {
 			rdata = XGBE_GET_DESC_DATA(ring, i);
 			xgbe_unmap_rdata(pdata, rdata);
 		}
 
-		kfree(ring->rdata);
+		free(ring->rdata, M_AXGBE);
 		ring->rdata = NULL;
 	}
 
-	if (ring->rx_hdr_pa.pages) {
-		dma_unmap_page(pdata->dev, ring->rx_hdr_pa.pages_dma,
-			       ring->rx_hdr_pa.pages_len, DMA_FROM_DEVICE);
-		put_page(ring->rx_hdr_pa.pages);
-
-		ring->rx_hdr_pa.pages = NULL;
-		ring->rx_hdr_pa.pages_len = 0;
-		ring->rx_hdr_pa.pages_offset = 0;
-		ring->rx_hdr_pa.pages_dma = 0;
-	}
-
-	if (ring->rx_buf_pa.pages) {
-		dma_unmap_page(pdata->dev, ring->rx_buf_pa.pages_dma,
-			       ring->rx_buf_pa.pages_len, DMA_FROM_DEVICE);
-		put_page(ring->rx_buf_pa.pages);
-
-		ring->rx_buf_pa.pages = NULL;
-		ring->rx_buf_pa.pages_len = 0;
-		ring->rx_buf_pa.pages_offset = 0;
-		ring->rx_buf_pa.pages_dma = 0;
-	}
-
-	if (ring->rdesc) {
-		dma_free_coherent(pdata->dev,
-				  (sizeof(struct xgbe_ring_desc) *
-				   ring->rdesc_count),
-				  ring->rdesc, ring->rdesc_dma);
-		ring->rdesc = NULL;
-	}
+	bus_dmamap_unload(ring->rdesc_dmat, ring->rdesc_map);
+	bus_dmamem_free(ring->rdesc_dmat, ring->rdesc, ring->rdesc_map);
+	bus_dma_tag_destroy(ring->rdesc_dmat);
+
+	ring->rdesc_map = NULL;
+	ring->rdesc_dmat = NULL;
+	ring->rdesc = NULL;
 }
 
 static void xgbe_free_ring_resources(struct xgbe_prv_data *pdata)
@@ -185,32 +172,71 @@ static void xgbe_free_ring_resources(str
 	DBGPR("<--xgbe_free_ring_resources\n");
 }
 
+static void xgbe_ring_dmamap_cb(void *arg, bus_dma_segment_t * segs, int nseg,
+                                int error)
+{
+	if (error)
+		return;
+	*(bus_addr_t *) arg = segs->ds_addr;
+}
+
 static int xgbe_init_ring(struct xgbe_prv_data *pdata,
 			  struct xgbe_ring *ring, unsigned int rdesc_count)
 {
+	bus_size_t len;
+	int err, flags;
+
 	DBGPR("-->xgbe_init_ring\n");
 
 	if (!ring)
 		return 0;
 
+	flags = 0;
+	if (pdata->coherent)
+		flags = BUS_DMA_COHERENT;
+
 	/* Descriptors */
 	ring->rdesc_count = rdesc_count;
-	ring->rdesc = dma_alloc_coherent(pdata->dev,
-					 (sizeof(struct xgbe_ring_desc) *
-					  rdesc_count), &ring->rdesc_dma,
-					 GFP_KERNEL);
-	if (!ring->rdesc)
-		return -ENOMEM;
+	len = sizeof(struct xgbe_ring_desc) * rdesc_count;
+	err = bus_dma_tag_create(pdata->dmat, 512, 0, BUS_SPACE_MAXADDR,
+	    BUS_SPACE_MAXADDR, NULL, NULL, len, 1, len, flags, NULL, NULL,
+	    &ring->rdesc_dmat);
+	if (err != 0) {
+		printf("Unable to create the DMA tag: %d\n", err);
+		return -err;
+	}
+
+	err = bus_dmamem_alloc(ring->rdesc_dmat, (void **)&ring->rdesc,
+	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &ring->rdesc_map);
+	if (err != 0) {
+		bus_dma_tag_destroy(ring->rdesc_dmat);
+		printf("Unable to allocate DMA memory: %d\n", err);
+		return -err;
+	}
+	err = bus_dmamap_load(ring->rdesc_dmat, ring->rdesc_map, ring->rdesc,
+	    len, xgbe_ring_dmamap_cb, &ring->rdesc_paddr, 0);
+	if (err != 0) {
+		bus_dmamem_free(ring->rdesc_dmat, ring->rdesc, ring->rdesc_map);
+		bus_dma_tag_destroy(ring->rdesc_dmat);
+		printf("Unable to load DMA memory\n");
+		return -err;
+	}
 
 	/* Descriptor information */
-	ring->rdata = kcalloc(rdesc_count, sizeof(struct xgbe_ring_data),
-			      GFP_KERNEL);
-	if (!ring->rdata)
-		return -ENOMEM;
-
-	netif_dbg(pdata, drv, pdata->netdev,
-		  "rdesc=%p, rdesc_dma=%pad, rdata=%p\n",
-		  ring->rdesc, &ring->rdesc_dma, ring->rdata);
+	ring->rdata = malloc(rdesc_count * sizeof(struct xgbe_ring_data),
+	    M_AXGBE, M_WAITOK | M_ZERO);
+
+	/* Create the space DMA tag for mbufs */
+	err = bus_dma_tag_create(pdata->dmat, 1, 0, BUS_SPACE_MAXADDR,
+	    BUS_SPACE_MAXADDR, NULL, NULL, XGBE_TX_MAX_BUF_SIZE * rdesc_count,
+	    rdesc_count, XGBE_TX_MAX_BUF_SIZE, flags, NULL, NULL,
+	    &ring->mbuf_dmat);
+	if (err != 0)
+		return -err;
+
+	err = bus_dmamap_create(ring->mbuf_dmat, 0, &ring->mbuf_map);
+	if (err != 0)
+		return -err;
 
 	DBGPR("<--xgbe_init_ring\n");
 
@@ -227,25 +253,17 @@ static int xgbe_alloc_ring_resources(str
 
 	channel = pdata->channel;
 	for (i = 0; i < pdata->channel_count; i++, channel++) {
-		netif_dbg(pdata, drv, pdata->netdev, "%s - Tx ring:\n",
-			  channel->name);
-
 		ret = xgbe_init_ring(pdata, channel->tx_ring,
 				     pdata->tx_desc_count);
 		if (ret) {
-			netdev_alert(pdata->netdev,
-				     "error initializing Tx ring\n");
+			printf("error initializing Tx ring\n");
 			goto err_ring;
 		}
 
-		netif_dbg(pdata, drv, pdata->netdev, "%s - Rx ring:\n",
-			  channel->name);
-
 		ret = xgbe_init_ring(pdata, channel->rx_ring,
 				     pdata->rx_desc_count);
 		if (ret) {
-			netdev_alert(pdata->netdev,
-				     "error initializing Rx ring\n");
+			printf("error initializing Rx ring\n");
 			goto err_ring;
 		}
 	}
@@ -260,93 +278,58 @@ err_ring:
 	return ret;
 }
 
-static int xgbe_alloc_pages(struct xgbe_prv_data *pdata,
-			    struct xgbe_page_alloc *pa, gfp_t gfp, int order)
-{
-	struct page *pages = NULL;
-	dma_addr_t pages_dma;
-	int ret;
-
-	/* Try to obtain pages, decreasing order if necessary */
-	gfp |= __GFP_COLD | __GFP_COMP | __GFP_NOWARN;
-	while (order >= 0) {
-		pages = alloc_pages(gfp, order);
-		if (pages)
-			break;
-
-		order--;
-	}
-	if (!pages)
-		return -ENOMEM;
-
-	/* Map the pages */
-	pages_dma = dma_map_page(pdata->dev, pages, 0,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list