From owner-svn-src-head@freebsd.org Wed Feb 15 13:56:06 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 2BFEDCE06EC; Wed, 15 Feb 2017 13:56:06 +0000 (UTC) (envelope-from andrew@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B7A0E1C88; Wed, 15 Feb 2017 13:56:05 +0000 (UTC) (envelope-from andrew@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v1FDu4WG059688; Wed, 15 Feb 2017 13:56:04 GMT (envelope-from andrew@FreeBSD.org) Received: (from andrew@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v1FDu4u1059682; Wed, 15 Feb 2017 13:56:04 GMT (envelope-from andrew@FreeBSD.org) Message-Id: <201702151356.v1FDu4u1059682@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: andrew set sender to andrew@FreeBSD.org using -f From: Andrew Turner Date: Wed, 15 Feb 2017 13:56:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r313768 - in head/sys: arm64/conf conf dev/axgbe X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Feb 2017 13:56:06 -0000 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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 +#include + /* 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 +__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 ***