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