1*8469df92Sandvar /* $NetBSD: dwc_gmac.c,v 1.95 2024/09/07 06:17:37 andvar Exp $ */ 2231538d1Sjmcneill 3971dc1a0Smartin /*- 4971dc1a0Smartin * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. 5971dc1a0Smartin * All rights reserved. 6971dc1a0Smartin * 7971dc1a0Smartin * This code is derived from software contributed to The NetBSD Foundation 8971dc1a0Smartin * by Matt Thomas of 3am Software Foundry and Martin Husemann. 9971dc1a0Smartin * 10971dc1a0Smartin * Redistribution and use in source and binary forms, with or without 11971dc1a0Smartin * modification, are permitted provided that the following conditions 12971dc1a0Smartin * are met: 13971dc1a0Smartin * 1. Redistributions of source code must retain the above copyright 14971dc1a0Smartin * notice, this list of conditions and the following disclaimer. 15971dc1a0Smartin * 2. Redistributions in binary form must reproduce the above copyright 16971dc1a0Smartin * notice, this list of conditions and the following disclaimer in the 17971dc1a0Smartin * documentation and/or other materials provided with the distribution. 18971dc1a0Smartin * 19971dc1a0Smartin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20971dc1a0Smartin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21971dc1a0Smartin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22971dc1a0Smartin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23971dc1a0Smartin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24971dc1a0Smartin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25971dc1a0Smartin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26971dc1a0Smartin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27971dc1a0Smartin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28971dc1a0Smartin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29971dc1a0Smartin * POSSIBILITY OF SUCH DAMAGE. 30971dc1a0Smartin */ 31971dc1a0Smartin 32971dc1a0Smartin /* 33971dc1a0Smartin * This driver supports the Synopsis Designware GMAC core, as found 34971dc1a0Smartin * on Allwinner A20 cores and others. 35971dc1a0Smartin * 36971dc1a0Smartin * Real documentation seems to not be available, the marketing product 37971dc1a0Smartin * documents could be found here: 38971dc1a0Smartin * 39971dc1a0Smartin * http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive 40971dc1a0Smartin */ 41971dc1a0Smartin 4296373f68Sriastradh /* 4396373f68Sriastradh * Lock order: 4496373f68Sriastradh * 4596373f68Sriastradh * IFNET_LOCK -> sc_mcast_lock 4696373f68Sriastradh * IFNET_LOCK -> sc_intr_lock -> {sc_txq.t_mtx, sc_rxq.r_mtx} 4796373f68Sriastradh */ 4896373f68Sriastradh 49971dc1a0Smartin #include <sys/cdefs.h> 50971dc1a0Smartin 51*8469df92Sandvar __KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.95 2024/09/07 06:17:37 andvar Exp $"); 5237ad3d63Smartin 5337ad3d63Smartin /* #define DWC_GMAC_DEBUG 1 */ 54971dc1a0Smartin 55fc18ade0Sskrll #ifdef _KERNEL_OPT 56971dc1a0Smartin #include "opt_inet.h" 57fc18ade0Sskrll #endif 58971dc1a0Smartin 59971dc1a0Smartin #include <sys/param.h> 60971dc1a0Smartin #include <sys/bus.h> 61971dc1a0Smartin #include <sys/device.h> 62971dc1a0Smartin #include <sys/intr.h> 63971dc1a0Smartin #include <sys/systm.h> 64971dc1a0Smartin #include <sys/sockio.h> 654f90260eSjmcneill #include <sys/cprng.h> 66f872a062Smsaitoh #include <sys/rndsource.h> 67971dc1a0Smartin 68971dc1a0Smartin #include <net/if.h> 69971dc1a0Smartin #include <net/if_ether.h> 70971dc1a0Smartin #include <net/if_media.h> 71971dc1a0Smartin #include <net/bpf.h> 72971dc1a0Smartin #ifdef INET 73971dc1a0Smartin #include <netinet/if_inarp.h> 74971dc1a0Smartin #endif 75971dc1a0Smartin 76971dc1a0Smartin #include <dev/mii/miivar.h> 77971dc1a0Smartin 78971dc1a0Smartin #include <dev/ic/dwc_gmac_reg.h> 79971dc1a0Smartin #include <dev/ic/dwc_gmac_var.h> 80971dc1a0Smartin 81a5cdd4b4Smsaitoh static int dwc_gmac_miibus_read_reg(device_t, int, int, uint16_t *); 82a5cdd4b4Smsaitoh static int dwc_gmac_miibus_write_reg(device_t, int, int, uint16_t); 83971dc1a0Smartin static void dwc_gmac_miibus_statchg(struct ifnet *); 84971dc1a0Smartin 85c34bdbc5Smsaitoh static int dwc_gmac_reset(struct dwc_gmac_softc *); 86f8570f8aSmrg static void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *, uint8_t[ETHER_ADDR_LEN]); 87c34bdbc5Smsaitoh static int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *); 88c34bdbc5Smsaitoh static void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *); 89c34bdbc5Smsaitoh static int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); 90c34bdbc5Smsaitoh static void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); 91c34bdbc5Smsaitoh static void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); 92c34bdbc5Smsaitoh static int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); 93c34bdbc5Smsaitoh static void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); 94c34bdbc5Smsaitoh static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); 95c34bdbc5Smsaitoh static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *, int, int, int); 96c34bdbc5Smsaitoh static int dwc_gmac_init(struct ifnet *); 97c34bdbc5Smsaitoh static void dwc_gmac_stop(struct ifnet *, int); 98c34bdbc5Smsaitoh static void dwc_gmac_start(struct ifnet *); 99c34bdbc5Smsaitoh static void dwc_gmac_start_locked(struct ifnet *); 100c34bdbc5Smsaitoh static int dwc_gmac_queue(struct dwc_gmac_softc *, struct mbuf *); 101971dc1a0Smartin static int dwc_gmac_ioctl(struct ifnet *, u_long, void *); 102c34bdbc5Smsaitoh static void dwc_gmac_tx_intr(struct dwc_gmac_softc *); 103c34bdbc5Smsaitoh static void dwc_gmac_rx_intr(struct dwc_gmac_softc *); 104c34bdbc5Smsaitoh static void dwc_gmac_setmulti(struct dwc_gmac_softc *); 105d1bd22e8Smartin static int dwc_gmac_ifflags_cb(struct ethercom *); 10672645925Smartin static void dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *); 10772645925Smartin static int dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *); 10872645925Smartin static void dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *, int); 10972645925Smartin static uint32_t dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *); 11072645925Smartin static void dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *); 11172645925Smartin static void dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *); 11272645925Smartin static void dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *); 11372645925Smartin static void dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *); 11472645925Smartin static int dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *); 11572645925Smartin static void dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *, int); 11672645925Smartin static uint32_t dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *); 11772645925Smartin static void dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *); 11872645925Smartin static void dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *); 11972645925Smartin static void dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *); 12072645925Smartin static void dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *); 12172645925Smartin static int dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *); 12272645925Smartin 12372645925Smartin static const struct dwc_gmac_desc_methods desc_methods_standard = { 12472645925Smartin .tx_init_flags = dwc_gmac_desc_std_tx_init_flags, 12572645925Smartin .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, 12672645925Smartin .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, 12772645925Smartin .tx_set_len = dwc_gmac_desc_std_set_len, 12872645925Smartin .tx_set_first_frag = dwc_gmac_desc_std_tx_set_first_frag, 12972645925Smartin .tx_set_last_frag = dwc_gmac_desc_std_tx_set_last_frag, 13072645925Smartin .rx_init_flags = dwc_gmac_desc_std_rx_init_flags, 13172645925Smartin .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, 13272645925Smartin .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, 13372645925Smartin .rx_set_len = dwc_gmac_desc_std_set_len, 13472645925Smartin .rx_get_len = dwc_gmac_desc_std_get_len, 13572645925Smartin .rx_has_error = dwc_gmac_desc_std_rx_has_error 13672645925Smartin }; 13772645925Smartin 13872645925Smartin static const struct dwc_gmac_desc_methods desc_methods_enhanced = { 13972645925Smartin .tx_init_flags = dwc_gmac_desc_enh_tx_init_flags, 14072645925Smartin .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, 14172645925Smartin .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, 14272645925Smartin .tx_set_len = dwc_gmac_desc_enh_set_len, 14372645925Smartin .tx_set_first_frag = dwc_gmac_desc_enh_tx_set_first_frag, 14472645925Smartin .tx_set_last_frag = dwc_gmac_desc_enh_tx_set_last_frag, 14572645925Smartin .rx_init_flags = dwc_gmac_desc_enh_rx_init_flags, 14672645925Smartin .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev, 14772645925Smartin .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev, 14872645925Smartin .rx_set_len = dwc_gmac_desc_enh_set_len, 14972645925Smartin .rx_get_len = dwc_gmac_desc_enh_get_len, 15072645925Smartin .rx_has_error = dwc_gmac_desc_enh_rx_has_error 15172645925Smartin }; 15272645925Smartin 153971dc1a0Smartin 154971dc1a0Smartin #define TX_DESC_OFFSET(N) ((AWGE_RX_RING_COUNT + (N)) \ 155971dc1a0Smartin * sizeof(struct dwc_gmac_dev_dmadesc)) 156bdbd5db8Smartin #define TX_NEXT(N) (((N) + 1) & (AWGE_TX_RING_COUNT - 1)) 157971dc1a0Smartin 158971dc1a0Smartin #define RX_DESC_OFFSET(N) ((N) * sizeof(struct dwc_gmac_dev_dmadesc)) 159bdbd5db8Smartin #define RX_NEXT(N) (((N) + 1) & (AWGE_RX_RING_COUNT - 1)) 160bdbd5db8Smartin 161bdbd5db8Smartin 162bdbd5db8Smartin 163426c40ceSmartin #define GMAC_DEF_DMA_INT_MASK (GMAC_DMA_INT_TIE | GMAC_DMA_INT_RIE | \ 164bdbd5db8Smartin GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE | \ 165bdbd5db8Smartin GMAC_DMA_INT_FBE | GMAC_DMA_INT_UNE) 166bdbd5db8Smartin 167bdbd5db8Smartin #define GMAC_DMA_INT_ERRORS (GMAC_DMA_INT_AIE | GMAC_DMA_INT_ERE | \ 1685158fc24Smartin GMAC_DMA_INT_FBE | \ 169bdbd5db8Smartin GMAC_DMA_INT_RWE | GMAC_DMA_INT_RUE | \ 170bdbd5db8Smartin GMAC_DMA_INT_UNE | GMAC_DMA_INT_OVE | \ 1715158fc24Smartin GMAC_DMA_INT_TJE) 172bdbd5db8Smartin 173bdbd5db8Smartin #define AWIN_DEF_MAC_INTRMASK \ 174bdbd5db8Smartin (AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG | \ 17572645925Smartin AWIN_GMAC_MAC_INT_LINKCHG) 176971dc1a0Smartin 17737ad3d63Smartin #ifdef DWC_GMAC_DEBUG 178c34bdbc5Smsaitoh static void dwc_gmac_dump_dma(struct dwc_gmac_softc *); 179c34bdbc5Smsaitoh static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *); 180c34bdbc5Smsaitoh static void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *); 181c34bdbc5Smsaitoh static void dwc_dump_and_abort(struct dwc_gmac_softc *, const char *); 182c34bdbc5Smsaitoh static void dwc_dump_status(struct dwc_gmac_softc *); 183c34bdbc5Smsaitoh static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *, uint32_t); 18437ad3d63Smartin #endif 18537ad3d63Smartin 18689fbd498Sjmcneill int 18735026302Smartin dwc_gmac_attach(struct dwc_gmac_softc *sc, int phy_id, uint32_t mii_clk) 188971dc1a0Smartin { 189971dc1a0Smartin uint8_t enaddr[ETHER_ADDR_LEN]; 19077147dd2Sskrll uint32_t maclo, machi, hwft; 191971dc1a0Smartin struct mii_data * const mii = &sc->sc_mii; 192971dc1a0Smartin struct ifnet * const ifp = &sc->sc_ec.ec_if; 1936224bda1Smartin prop_dictionary_t dict; 194971dc1a0Smartin 195971dc1a0Smartin mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET); 196612a2a40Smartin sc->sc_mii_clk = mii_clk & 7; 197971dc1a0Smartin 1986224bda1Smartin dict = device_properties(sc->sc_dev); 1996224bda1Smartin prop_data_t ea = dict ? prop_dictionary_get(dict, "mac-address") : NULL; 2006224bda1Smartin if (ea != NULL) { 201971dc1a0Smartin /* 202207defd0Sandvar * If the MAC address is overridden by a device property, 2036224bda1Smartin * use that. 2046224bda1Smartin */ 2056224bda1Smartin KASSERT(prop_object_type(ea) == PROP_TYPE_DATA); 2066224bda1Smartin KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN); 207423f1f50Sjmcneill memcpy(enaddr, prop_data_value(ea), ETHER_ADDR_LEN); 2086224bda1Smartin } else { 2096224bda1Smartin /* 210*8469df92Sandvar * If we did not get an externally configure address, 2116224bda1Smartin * try to read one from the current filter setup, 212971dc1a0Smartin * before resetting the chip. 213971dc1a0Smartin */ 214bdbd5db8Smartin maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 215bdbd5db8Smartin AWIN_GMAC_MAC_ADDR0LO); 216bdbd5db8Smartin machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 217bdbd5db8Smartin AWIN_GMAC_MAC_ADDR0HI); 218d4b3eb15Sjmcneill 219d4b3eb15Sjmcneill if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) { 2204f90260eSjmcneill /* fake MAC address */ 2214f90260eSjmcneill maclo = 0x00f2 | (cprng_strong32() << 16); 2224f90260eSjmcneill machi = cprng_strong32(); 223d4b3eb15Sjmcneill } 224d4b3eb15Sjmcneill 225971dc1a0Smartin enaddr[0] = maclo & 0x0ff; 226971dc1a0Smartin enaddr[1] = (maclo >> 8) & 0x0ff; 227971dc1a0Smartin enaddr[2] = (maclo >> 16) & 0x0ff; 228971dc1a0Smartin enaddr[3] = (maclo >> 24) & 0x0ff; 229971dc1a0Smartin enaddr[4] = machi & 0x0ff; 230971dc1a0Smartin enaddr[5] = (machi >> 8) & 0x0ff; 231971dc1a0Smartin } 232971dc1a0Smartin 23377147dd2Sskrll const uint32_t ver = 23477147dd2Sskrll bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_VERSION); 23577147dd2Sskrll const uint32_t snpsver = 23677147dd2Sskrll __SHIFTOUT(ver, AWIN_GMAC_MAC_VERSION_SNPSVER_MASK); 23777147dd2Sskrll aprint_normal_dev(sc->sc_dev, "Core version: %08x\n", snpsver); 23872645925Smartin 239971dc1a0Smartin /* 240a1f0cbdaSjoerg * Init chip and do initial setup 241971dc1a0Smartin */ 242971dc1a0Smartin if (dwc_gmac_reset(sc) != 0) 24389fbd498Sjmcneill return ENXIO; /* not much to cleanup, haven't attached yet */ 2446224bda1Smartin dwc_gmac_write_hwaddr(sc, enaddr); 2457ffbd423Ssevan aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n", 246971dc1a0Smartin ether_sprintf(enaddr)); 247971dc1a0Smartin 24872645925Smartin hwft = 0; 24977147dd2Sskrll if (snpsver >= 0x35) { 25072645925Smartin hwft = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 25172645925Smartin AWIN_GMAC_DMA_HWFEATURES); 25272645925Smartin aprint_normal_dev(sc->sc_dev, 25372645925Smartin "HW feature mask: %x\n", hwft); 25472645925Smartin } 255921379d2Sskrll 256921379d2Sskrll if (sizeof(bus_addr_t) > 4) { 257921379d2Sskrll int error = bus_dmatag_subregion(sc->sc_dmat, 0, __MASK(32), 258921379d2Sskrll &sc->sc_dmat, BUS_DMA_WAITOK); 259921379d2Sskrll if (error != 0) { 260921379d2Sskrll aprint_error_dev(sc->sc_dev, 261921379d2Sskrll "failed to create DMA subregion\n"); 262921379d2Sskrll return ENOMEM; 263921379d2Sskrll } 264921379d2Sskrll } 265921379d2Sskrll 26672645925Smartin if (hwft & GMAC_DMA_FEAT_ENHANCED_DESC) { 26772645925Smartin aprint_normal_dev(sc->sc_dev, 26872645925Smartin "Using enhanced descriptor format\n"); 26972645925Smartin sc->sc_descm = &desc_methods_enhanced; 27072645925Smartin } else { 27172645925Smartin sc->sc_descm = &desc_methods_standard; 27272645925Smartin } 27317e5d3c8Schs if (hwft & GMAC_DMA_FEAT_RMON) { 27417e5d3c8Schs uint32_t val; 27517e5d3c8Schs 27617e5d3c8Schs /* Mask all MMC interrupts */ 27717e5d3c8Schs val = 0xffffffff; 27817e5d3c8Schs bus_space_write_4(sc->sc_bst, sc->sc_bsh, 27917e5d3c8Schs GMAC_MMC_RX_INT_MSK, val); 28017e5d3c8Schs bus_space_write_4(sc->sc_bst, sc->sc_bsh, 28117e5d3c8Schs GMAC_MMC_TX_INT_MSK, val); 28217e5d3c8Schs } 28372645925Smartin 284971dc1a0Smartin /* 285971dc1a0Smartin * Allocate Tx and Rx rings 286971dc1a0Smartin */ 287971dc1a0Smartin if (dwc_gmac_alloc_dma_rings(sc) != 0) { 288971dc1a0Smartin aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n"); 289971dc1a0Smartin goto fail; 290971dc1a0Smartin } 291971dc1a0Smartin 292971dc1a0Smartin if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) { 293971dc1a0Smartin aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n"); 294971dc1a0Smartin goto fail; 295971dc1a0Smartin } 296971dc1a0Smartin 297971dc1a0Smartin if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) { 298971dc1a0Smartin aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n"); 299971dc1a0Smartin goto fail; 300971dc1a0Smartin } 301971dc1a0Smartin 302c9ba1e93Sskrll sc->sc_stopping = false; 303c9ba1e93Sskrll sc->sc_txbusy = false; 304c9ba1e93Sskrll 30596373f68Sriastradh sc->sc_mcast_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET); 306c9ba1e93Sskrll sc->sc_intr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); 307fc18ade0Sskrll mutex_init(&sc->sc_txq.t_mtx, MUTEX_DEFAULT, IPL_NET); 308fc18ade0Sskrll mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET); 309fc18ade0Sskrll 310971dc1a0Smartin /* 311971dc1a0Smartin * Prepare interface data 312971dc1a0Smartin */ 313971dc1a0Smartin ifp->if_softc = sc; 314971dc1a0Smartin strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); 315971dc1a0Smartin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 316ab3cd725Sozaki-r ifp->if_extflags = IFEF_MPSAFE; 317971dc1a0Smartin ifp->if_ioctl = dwc_gmac_ioctl; 318971dc1a0Smartin ifp->if_start = dwc_gmac_start; 319971dc1a0Smartin ifp->if_init = dwc_gmac_init; 320971dc1a0Smartin ifp->if_stop = dwc_gmac_stop; 321971dc1a0Smartin IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 322971dc1a0Smartin IFQ_SET_READY(&ifp->if_snd); 323971dc1a0Smartin 324971dc1a0Smartin /* 325971dc1a0Smartin * Attach MII subdevices 326971dc1a0Smartin */ 32783658911Smartin sc->sc_ec.ec_mii = &sc->sc_mii; 328971dc1a0Smartin ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); 329971dc1a0Smartin mii->mii_ifp = ifp; 330971dc1a0Smartin mii->mii_readreg = dwc_gmac_miibus_read_reg; 331971dc1a0Smartin mii->mii_writereg = dwc_gmac_miibus_write_reg; 332971dc1a0Smartin mii->mii_statchg = dwc_gmac_miibus_statchg; 33348fb522fSmsaitoh mii_attach(sc->sc_dev, mii, 0xffffffff, phy_id, MII_OFFSET_ANY, 33424d51e99Sjmcneill MIIF_DOPAUSE); 335971dc1a0Smartin 336971dc1a0Smartin if (LIST_EMPTY(&mii->mii_phys)) { 337971dc1a0Smartin aprint_error_dev(sc->sc_dev, "no PHY found!\n"); 338971dc1a0Smartin ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL); 339971dc1a0Smartin ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL); 340971dc1a0Smartin } else { 341971dc1a0Smartin ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 342971dc1a0Smartin } 343971dc1a0Smartin 344971dc1a0Smartin /* 345845d2aa5Stnn * We can support 802.1Q VLAN-sized frames. 346845d2aa5Stnn */ 347845d2aa5Stnn sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU; 348845d2aa5Stnn 349845d2aa5Stnn /* 350971dc1a0Smartin * Ready, attach interface 351971dc1a0Smartin */ 352fc18ade0Sskrll /* Attach the interface. */ 353076e3579Sriastradh if_initialize(ifp); 354fc18ade0Sskrll sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if); 3551c82c572Sozaki-r if_deferred_start_init(ifp, NULL); 356971dc1a0Smartin ether_ifattach(ifp, enaddr); 357d1bd22e8Smartin ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb); 358fc18ade0Sskrll if_register(ifp); 359f872a062Smsaitoh rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 360f872a062Smsaitoh RND_TYPE_NET, RND_FLAG_DEFAULT); 361971dc1a0Smartin 362971dc1a0Smartin /* 363971dc1a0Smartin * Enable interrupts 364971dc1a0Smartin */ 365c9ba1e93Sskrll mutex_enter(sc->sc_intr_lock); 36624d51e99Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK, 367bdbd5db8Smartin AWIN_DEF_MAC_INTRMASK); 368bdbd5db8Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE, 369bdbd5db8Smartin GMAC_DEF_DMA_INT_MASK); 370c9ba1e93Sskrll mutex_exit(sc->sc_intr_lock); 371971dc1a0Smartin 37289fbd498Sjmcneill return 0; 37389fbd498Sjmcneill 374971dc1a0Smartin fail: 375971dc1a0Smartin dwc_gmac_free_rx_ring(sc, &sc->sc_rxq); 376971dc1a0Smartin dwc_gmac_free_tx_ring(sc, &sc->sc_txq); 377a80b2b73Smsaitoh dwc_gmac_free_dma_rings(sc); 378a80b2b73Smsaitoh mutex_destroy(&sc->sc_mdio_lock); 37989fbd498Sjmcneill 38089fbd498Sjmcneill return ENXIO; 381971dc1a0Smartin } 382971dc1a0Smartin 383971dc1a0Smartin 384971dc1a0Smartin 385971dc1a0Smartin static int 386971dc1a0Smartin dwc_gmac_reset(struct dwc_gmac_softc *sc) 387971dc1a0Smartin { 388971dc1a0Smartin size_t cnt; 389971dc1a0Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, 390c34bdbc5Smsaitoh bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) 391c34bdbc5Smsaitoh | GMAC_BUSMODE_RESET); 392b3feca02Sryo for (cnt = 0; cnt < 30000; cnt++) { 393971dc1a0Smartin if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) 394971dc1a0Smartin & GMAC_BUSMODE_RESET) == 0) 395971dc1a0Smartin return 0; 396971dc1a0Smartin delay(10); 397971dc1a0Smartin } 398971dc1a0Smartin 399971dc1a0Smartin aprint_error_dev(sc->sc_dev, "reset timed out\n"); 400971dc1a0Smartin return EIO; 401971dc1a0Smartin } 402971dc1a0Smartin 403971dc1a0Smartin static void 404971dc1a0Smartin dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc, 405971dc1a0Smartin uint8_t enaddr[ETHER_ADDR_LEN]) 406971dc1a0Smartin { 40773ce4049Sjmcneill uint32_t hi, lo; 408971dc1a0Smartin 40973ce4049Sjmcneill hi = enaddr[4] | (enaddr[5] << 8); 410971dc1a0Smartin lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) 4112f8b3c43Smsaitoh | ((uint32_t)enaddr[3] << 24); 412971dc1a0Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi); 41373ce4049Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo); 414971dc1a0Smartin } 415971dc1a0Smartin 416971dc1a0Smartin static int 417a5cdd4b4Smsaitoh dwc_gmac_miibus_read_reg(device_t self, int phy, int reg, uint16_t *val) 418971dc1a0Smartin { 419971dc1a0Smartin struct dwc_gmac_softc * const sc = device_private(self); 420518bac49Smartin uint16_t mii; 421971dc1a0Smartin size_t cnt; 422971dc1a0Smartin 423518bac49Smartin mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK) 424518bac49Smartin | __SHIFTIN(reg, GMAC_MII_REG_MASK) 425518bac49Smartin | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK) 426518bac49Smartin | GMAC_MII_BUSY; 427971dc1a0Smartin 428971dc1a0Smartin mutex_enter(&sc->sc_mdio_lock); 429518bac49Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); 430971dc1a0Smartin 431971dc1a0Smartin for (cnt = 0; cnt < 1000; cnt++) { 432612a2a40Smartin if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, 433612a2a40Smartin AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) { 434a5cdd4b4Smsaitoh *val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 435612a2a40Smartin AWIN_GMAC_MAC_MIIDATA); 436971dc1a0Smartin break; 437971dc1a0Smartin } 438971dc1a0Smartin delay(10); 439971dc1a0Smartin } 440971dc1a0Smartin 441971dc1a0Smartin mutex_exit(&sc->sc_mdio_lock); 442971dc1a0Smartin 443a5cdd4b4Smsaitoh if (cnt >= 1000) 444a5cdd4b4Smsaitoh return ETIMEDOUT; 445a5cdd4b4Smsaitoh 446a5cdd4b4Smsaitoh return 0; 447971dc1a0Smartin } 448971dc1a0Smartin 449a5cdd4b4Smsaitoh static int 450a5cdd4b4Smsaitoh dwc_gmac_miibus_write_reg(device_t self, int phy, int reg, uint16_t val) 451971dc1a0Smartin { 452971dc1a0Smartin struct dwc_gmac_softc * const sc = device_private(self); 453518bac49Smartin uint16_t mii; 454971dc1a0Smartin size_t cnt; 455971dc1a0Smartin 456518bac49Smartin mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK) 457518bac49Smartin | __SHIFTIN(reg, GMAC_MII_REG_MASK) 458518bac49Smartin | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK) 459518bac49Smartin | GMAC_MII_BUSY | GMAC_MII_WRITE; 460971dc1a0Smartin 461971dc1a0Smartin mutex_enter(&sc->sc_mdio_lock); 462971dc1a0Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIDATA, val); 463518bac49Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); 464971dc1a0Smartin 465971dc1a0Smartin for (cnt = 0; cnt < 1000; cnt++) { 466612a2a40Smartin if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, 467612a2a40Smartin AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) 468971dc1a0Smartin break; 469971dc1a0Smartin delay(10); 470971dc1a0Smartin } 471971dc1a0Smartin 472971dc1a0Smartin mutex_exit(&sc->sc_mdio_lock); 473a5cdd4b4Smsaitoh 474a5cdd4b4Smsaitoh if (cnt >= 1000) 475a5cdd4b4Smsaitoh return ETIMEDOUT; 476a5cdd4b4Smsaitoh 477a5cdd4b4Smsaitoh return 0; 478971dc1a0Smartin } 479971dc1a0Smartin 480971dc1a0Smartin static int 481971dc1a0Smartin dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc, 482971dc1a0Smartin struct dwc_gmac_rx_ring *ring) 483971dc1a0Smartin { 484971dc1a0Smartin struct dwc_gmac_rx_data *data; 485971dc1a0Smartin bus_addr_t physaddr; 48640044749Sskrll const size_t rxringsz = AWGE_RX_RING_COUNT * sizeof(*ring->r_desc); 487971dc1a0Smartin int error, i, next; 488971dc1a0Smartin 489971dc1a0Smartin ring->r_cur = ring->r_next = 0; 49040044749Sskrll memset(ring->r_desc, 0, rxringsz); 491971dc1a0Smartin 492971dc1a0Smartin /* 493971dc1a0Smartin * Pre-allocate Rx buffers and populate Rx ring. 494971dc1a0Smartin */ 495971dc1a0Smartin for (i = 0; i < AWGE_RX_RING_COUNT; i++) { 496971dc1a0Smartin struct dwc_gmac_dev_dmadesc *desc; 497971dc1a0Smartin 498971dc1a0Smartin data = &sc->sc_rxq.r_data[i]; 499971dc1a0Smartin 500971dc1a0Smartin MGETHDR(data->rd_m, M_DONTWAIT, MT_DATA); 501971dc1a0Smartin if (data->rd_m == NULL) { 502971dc1a0Smartin aprint_error_dev(sc->sc_dev, 503971dc1a0Smartin "could not allocate rx mbuf #%d\n", i); 504971dc1a0Smartin error = ENOMEM; 505971dc1a0Smartin goto fail; 506971dc1a0Smartin } 507971dc1a0Smartin error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 508971dc1a0Smartin MCLBYTES, 0, BUS_DMA_NOWAIT, &data->rd_map); 509971dc1a0Smartin if (error != 0) { 510971dc1a0Smartin aprint_error_dev(sc->sc_dev, 511971dc1a0Smartin "could not create DMA map\n"); 512971dc1a0Smartin data->rd_map = NULL; 513971dc1a0Smartin goto fail; 514971dc1a0Smartin } 515971dc1a0Smartin MCLGET(data->rd_m, M_DONTWAIT); 516971dc1a0Smartin if (!(data->rd_m->m_flags & M_EXT)) { 517971dc1a0Smartin aprint_error_dev(sc->sc_dev, 518971dc1a0Smartin "could not allocate mbuf cluster #%d\n", i); 519971dc1a0Smartin error = ENOMEM; 520971dc1a0Smartin goto fail; 521971dc1a0Smartin } 5223c96a2beStnn data->rd_m->m_len = data->rd_m->m_pkthdr.len 5233c96a2beStnn = data->rd_m->m_ext.ext_size; 5243c96a2beStnn if (data->rd_m->m_len > AWGE_MAX_PACKET) { 5253c96a2beStnn data->rd_m->m_len = data->rd_m->m_pkthdr.len 5263c96a2beStnn = AWGE_MAX_PACKET; 5273c96a2beStnn } 528971dc1a0Smartin 5293c96a2beStnn error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, 5303c96a2beStnn data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT); 531971dc1a0Smartin if (error != 0) { 532971dc1a0Smartin aprint_error_dev(sc->sc_dev, 533971dc1a0Smartin "could not load rx buf DMA map #%d", i); 534971dc1a0Smartin goto fail; 535971dc1a0Smartin } 5363c96a2beStnn bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, 5373c96a2beStnn data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); 538971dc1a0Smartin physaddr = data->rd_map->dm_segs[0].ds_addr; 539971dc1a0Smartin 540971dc1a0Smartin desc = &sc->sc_rxq.r_desc[i]; 541971dc1a0Smartin desc->ddesc_data = htole32(physaddr); 542bdbd5db8Smartin next = RX_NEXT(i); 543971dc1a0Smartin desc->ddesc_next = htole32(ring->r_physaddr 544971dc1a0Smartin + next * sizeof(*desc)); 54572645925Smartin sc->sc_descm->rx_init_flags(desc); 5463c96a2beStnn sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); 54772645925Smartin sc->sc_descm->rx_set_owned_by_dev(desc); 548971dc1a0Smartin } 549971dc1a0Smartin 55040044749Sskrll bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 55140044749Sskrll RX_DESC_OFFSET(0), 552971dc1a0Smartin AWGE_RX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc), 5539893fe95Sskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 554971dc1a0Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, 555518bac49Smartin ring->r_physaddr); 556971dc1a0Smartin 557971dc1a0Smartin return 0; 558971dc1a0Smartin 559971dc1a0Smartin fail: 560971dc1a0Smartin dwc_gmac_free_rx_ring(sc, ring); 561971dc1a0Smartin return error; 562971dc1a0Smartin } 563971dc1a0Smartin 564971dc1a0Smartin static void 565971dc1a0Smartin dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc, 566971dc1a0Smartin struct dwc_gmac_rx_ring *ring) 567971dc1a0Smartin { 568971dc1a0Smartin struct dwc_gmac_dev_dmadesc *desc; 5693c96a2beStnn struct dwc_gmac_rx_data *data; 570971dc1a0Smartin int i; 571971dc1a0Smartin 572fc18ade0Sskrll mutex_enter(&ring->r_mtx); 573971dc1a0Smartin for (i = 0; i < AWGE_RX_RING_COUNT; i++) { 574971dc1a0Smartin desc = &sc->sc_rxq.r_desc[i]; 5753c96a2beStnn data = &sc->sc_rxq.r_data[i]; 57672645925Smartin sc->sc_descm->rx_init_flags(desc); 5773c96a2beStnn sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); 57872645925Smartin sc->sc_descm->rx_set_owned_by_dev(desc); 579971dc1a0Smartin } 580971dc1a0Smartin 581971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, 582971dc1a0Smartin AWGE_RX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc), 5830c8fe4ccSmatt BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 584971dc1a0Smartin 585971dc1a0Smartin ring->r_cur = ring->r_next = 0; 586426c40ceSmartin /* reset DMA address to start of ring */ 587426c40ceSmartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, 588426c40ceSmartin sc->sc_rxq.r_physaddr); 589fc18ade0Sskrll mutex_exit(&ring->r_mtx); 590971dc1a0Smartin } 591971dc1a0Smartin 592971dc1a0Smartin static int 593971dc1a0Smartin dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc) 594971dc1a0Smartin { 59540044749Sskrll const size_t ringsize = AWGE_TOTAL_RING_COUNT * 596971dc1a0Smartin sizeof(struct dwc_gmac_dev_dmadesc); 597971dc1a0Smartin int error, nsegs; 598971dc1a0Smartin void *rings; 599971dc1a0Smartin 60040044749Sskrll error = bus_dmamap_create(sc->sc_dmat, ringsize, 1, ringsize, 0, 601971dc1a0Smartin BUS_DMA_NOWAIT, &sc->sc_dma_ring_map); 602971dc1a0Smartin if (error != 0) { 603971dc1a0Smartin aprint_error_dev(sc->sc_dev, 604971dc1a0Smartin "could not create desc DMA map\n"); 605971dc1a0Smartin sc->sc_dma_ring_map = NULL; 606971dc1a0Smartin goto fail; 607971dc1a0Smartin } 608971dc1a0Smartin 60940044749Sskrll error = bus_dmamem_alloc(sc->sc_dmat, ringsize, PAGE_SIZE, 0, 610971dc1a0Smartin &sc->sc_dma_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT |BUS_DMA_COHERENT); 611971dc1a0Smartin if (error != 0) { 612971dc1a0Smartin aprint_error_dev(sc->sc_dev, 613971dc1a0Smartin "could not map DMA memory\n"); 614971dc1a0Smartin goto fail; 615971dc1a0Smartin } 616971dc1a0Smartin 617971dc1a0Smartin error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_ring_seg, nsegs, 61840044749Sskrll ringsize, &rings, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 619971dc1a0Smartin if (error != 0) { 620971dc1a0Smartin aprint_error_dev(sc->sc_dev, 621971dc1a0Smartin "could not allocate DMA memory\n"); 622971dc1a0Smartin goto fail; 623971dc1a0Smartin } 624971dc1a0Smartin 625971dc1a0Smartin error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_ring_map, rings, 62640044749Sskrll ringsize, NULL, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 627971dc1a0Smartin if (error != 0) { 628971dc1a0Smartin aprint_error_dev(sc->sc_dev, 629971dc1a0Smartin "could not load desc DMA map\n"); 630971dc1a0Smartin goto fail; 631971dc1a0Smartin } 632971dc1a0Smartin 633971dc1a0Smartin /* give first AWGE_RX_RING_COUNT to the RX side */ 634971dc1a0Smartin sc->sc_rxq.r_desc = rings; 635971dc1a0Smartin sc->sc_rxq.r_physaddr = sc->sc_dma_ring_map->dm_segs[0].ds_addr; 636971dc1a0Smartin 637971dc1a0Smartin /* and next rings to the TX side */ 638971dc1a0Smartin sc->sc_txq.t_desc = sc->sc_rxq.r_desc + AWGE_RX_RING_COUNT; 639971dc1a0Smartin sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr + 640971dc1a0Smartin AWGE_RX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc); 641971dc1a0Smartin 642971dc1a0Smartin return 0; 643971dc1a0Smartin 644971dc1a0Smartin fail: 645971dc1a0Smartin dwc_gmac_free_dma_rings(sc); 646971dc1a0Smartin return error; 647971dc1a0Smartin } 648971dc1a0Smartin 649971dc1a0Smartin static void 650971dc1a0Smartin dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc) 651971dc1a0Smartin { 652971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, 653971dc1a0Smartin sc->sc_dma_ring_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 654971dc1a0Smartin bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_ring_map); 655971dc1a0Smartin bus_dmamem_unmap(sc->sc_dmat, sc->sc_rxq.r_desc, 656971dc1a0Smartin AWGE_TOTAL_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc)); 657971dc1a0Smartin bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_ring_seg, 1); 658971dc1a0Smartin } 659971dc1a0Smartin 660971dc1a0Smartin static void 661971dc1a0Smartin dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *ring) 662971dc1a0Smartin { 663971dc1a0Smartin struct dwc_gmac_rx_data *data; 664971dc1a0Smartin int i; 665971dc1a0Smartin 666971dc1a0Smartin if (ring->r_desc == NULL) 667971dc1a0Smartin return; 668971dc1a0Smartin 669971dc1a0Smartin for (i = 0; i < AWGE_RX_RING_COUNT; i++) { 670971dc1a0Smartin data = &ring->r_data[i]; 671971dc1a0Smartin 672971dc1a0Smartin if (data->rd_map != NULL) { 673971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, 674971dc1a0Smartin AWGE_RX_RING_COUNT 675971dc1a0Smartin * sizeof(struct dwc_gmac_dev_dmadesc), 676971dc1a0Smartin BUS_DMASYNC_POSTREAD); 677971dc1a0Smartin bus_dmamap_unload(sc->sc_dmat, data->rd_map); 678971dc1a0Smartin bus_dmamap_destroy(sc->sc_dmat, data->rd_map); 679971dc1a0Smartin } 680971dc1a0Smartin m_freem(data->rd_m); 681971dc1a0Smartin } 682971dc1a0Smartin } 683971dc1a0Smartin 684971dc1a0Smartin static int 685971dc1a0Smartin dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc, 686971dc1a0Smartin struct dwc_gmac_tx_ring *ring) 687971dc1a0Smartin { 688971dc1a0Smartin int i, error = 0; 689971dc1a0Smartin 690971dc1a0Smartin ring->t_queued = 0; 691971dc1a0Smartin ring->t_cur = ring->t_next = 0; 692971dc1a0Smartin 693971dc1a0Smartin memset(ring->t_desc, 0, AWGE_TX_RING_COUNT * sizeof(*ring->t_desc)); 694971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 695971dc1a0Smartin TX_DESC_OFFSET(0), 696971dc1a0Smartin AWGE_TX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc), 69740044749Sskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 698971dc1a0Smartin 699971dc1a0Smartin for (i = 0; i < AWGE_TX_RING_COUNT; i++) { 700971dc1a0Smartin error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 701971dc1a0Smartin AWGE_TX_RING_COUNT, MCLBYTES, 0, 702971dc1a0Smartin BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 703971dc1a0Smartin &ring->t_data[i].td_map); 704971dc1a0Smartin if (error != 0) { 705971dc1a0Smartin aprint_error_dev(sc->sc_dev, 706971dc1a0Smartin "could not create TX DMA map #%d\n", i); 707971dc1a0Smartin ring->t_data[i].td_map = NULL; 708971dc1a0Smartin goto fail; 709971dc1a0Smartin } 710971dc1a0Smartin ring->t_desc[i].ddesc_next = htole32( 711971dc1a0Smartin ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc) 712bdbd5db8Smartin * TX_NEXT(i)); 713971dc1a0Smartin } 71440044749Sskrll bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 71540044749Sskrll TX_DESC_OFFSET(0), 71640044749Sskrll AWGE_TX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc), 71740044749Sskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 718971dc1a0Smartin 719971dc1a0Smartin return 0; 720971dc1a0Smartin 721971dc1a0Smartin fail: 722971dc1a0Smartin dwc_gmac_free_tx_ring(sc, ring); 723971dc1a0Smartin return error; 724971dc1a0Smartin } 725971dc1a0Smartin 726971dc1a0Smartin static void 727971dc1a0Smartin dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops) 728971dc1a0Smartin { 729ba5b08dfSmrg /* 'end' is pointing one descriptor beyond the last we want to sync */ 730971dc1a0Smartin if (end > start) { 731971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 732971dc1a0Smartin TX_DESC_OFFSET(start), 733971dc1a0Smartin TX_DESC_OFFSET(end) - TX_DESC_OFFSET(start), 734971dc1a0Smartin ops); 735971dc1a0Smartin return; 736971dc1a0Smartin } 737971dc1a0Smartin /* sync from 'start' to end of ring */ 738971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 739971dc1a0Smartin TX_DESC_OFFSET(start), 7408bddfabdSjmcneill TX_DESC_OFFSET(AWGE_TX_RING_COUNT) - TX_DESC_OFFSET(start), 741971dc1a0Smartin ops); 74269e07b1eSjmcneill if (TX_DESC_OFFSET(end) - TX_DESC_OFFSET(0) > 0) { 743971dc1a0Smartin /* sync from start of ring to 'end' */ 744971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 745971dc1a0Smartin TX_DESC_OFFSET(0), 746971dc1a0Smartin TX_DESC_OFFSET(end) - TX_DESC_OFFSET(0), 747971dc1a0Smartin ops); 748971dc1a0Smartin } 74969e07b1eSjmcneill } 750971dc1a0Smartin 751971dc1a0Smartin static void 752971dc1a0Smartin dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc, 753971dc1a0Smartin struct dwc_gmac_tx_ring *ring) 754971dc1a0Smartin { 755971dc1a0Smartin int i; 756971dc1a0Smartin 757fc18ade0Sskrll mutex_enter(&ring->t_mtx); 758971dc1a0Smartin for (i = 0; i < AWGE_TX_RING_COUNT; i++) { 759971dc1a0Smartin struct dwc_gmac_tx_data *data = &ring->t_data[i]; 760971dc1a0Smartin 761971dc1a0Smartin if (data->td_m != NULL) { 762971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, data->td_active, 763971dc1a0Smartin 0, data->td_active->dm_mapsize, 764971dc1a0Smartin BUS_DMASYNC_POSTWRITE); 765971dc1a0Smartin bus_dmamap_unload(sc->sc_dmat, data->td_active); 766971dc1a0Smartin m_freem(data->td_m); 767971dc1a0Smartin data->td_m = NULL; 768971dc1a0Smartin } 769971dc1a0Smartin } 770971dc1a0Smartin 771971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 772971dc1a0Smartin TX_DESC_OFFSET(0), 773971dc1a0Smartin AWGE_TX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc), 7740c8fe4ccSmatt BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 775518bac49Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, 776518bac49Smartin sc->sc_txq.t_physaddr); 777971dc1a0Smartin 778971dc1a0Smartin ring->t_queued = 0; 779971dc1a0Smartin ring->t_cur = ring->t_next = 0; 780fc18ade0Sskrll mutex_exit(&ring->t_mtx); 781971dc1a0Smartin } 782971dc1a0Smartin 783971dc1a0Smartin static void 784971dc1a0Smartin dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, 785971dc1a0Smartin struct dwc_gmac_tx_ring *ring) 786971dc1a0Smartin { 787971dc1a0Smartin int i; 788971dc1a0Smartin 789971dc1a0Smartin /* unload the maps */ 790971dc1a0Smartin for (i = 0; i < AWGE_TX_RING_COUNT; i++) { 791971dc1a0Smartin struct dwc_gmac_tx_data *data = &ring->t_data[i]; 792971dc1a0Smartin 793971dc1a0Smartin if (data->td_m != NULL) { 794971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, data->td_active, 795971dc1a0Smartin 0, data->td_map->dm_mapsize, 796971dc1a0Smartin BUS_DMASYNC_POSTWRITE); 797971dc1a0Smartin bus_dmamap_unload(sc->sc_dmat, data->td_active); 798971dc1a0Smartin m_freem(data->td_m); 799971dc1a0Smartin data->td_m = NULL; 800971dc1a0Smartin } 801971dc1a0Smartin } 802971dc1a0Smartin 803971dc1a0Smartin /* and actually free them */ 804971dc1a0Smartin for (i = 0; i < AWGE_TX_RING_COUNT; i++) { 805971dc1a0Smartin struct dwc_gmac_tx_data *data = &ring->t_data[i]; 806971dc1a0Smartin 807971dc1a0Smartin bus_dmamap_destroy(sc->sc_dmat, data->td_map); 808971dc1a0Smartin } 809971dc1a0Smartin } 810971dc1a0Smartin 811971dc1a0Smartin static void 812971dc1a0Smartin dwc_gmac_miibus_statchg(struct ifnet *ifp) 813971dc1a0Smartin { 814971dc1a0Smartin struct dwc_gmac_softc * const sc = ifp->if_softc; 815971dc1a0Smartin struct mii_data * const mii = &sc->sc_mii; 81624d51e99Sjmcneill uint32_t conf, flow; 817971dc1a0Smartin 818971dc1a0Smartin /* 819971dc1a0Smartin * Set MII or GMII interface based on the speed 820971dc1a0Smartin * negotiated by the PHY. 821971dc1a0Smartin */ 8228277fba8Smartin conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF); 8238277fba8Smartin conf &= ~(AWIN_GMAC_MAC_CONF_FES100 | AWIN_GMAC_MAC_CONF_MIISEL 8248277fba8Smartin | AWIN_GMAC_MAC_CONF_FULLDPLX); 825426c40ceSmartin conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST 826426c40ceSmartin | AWIN_GMAC_MAC_CONF_DISABLERXOWN 82724d51e99Sjmcneill | AWIN_GMAC_MAC_CONF_DISABLEJABBER 828426c40ceSmartin | AWIN_GMAC_MAC_CONF_RXENABLE 829426c40ceSmartin | AWIN_GMAC_MAC_CONF_TXENABLE; 830971dc1a0Smartin switch (IFM_SUBTYPE(mii->mii_media_active)) { 831971dc1a0Smartin case IFM_10_T: 83272e2d70fSjmcneill conf |= AWIN_GMAC_MAC_CONF_MIISEL; 8338277fba8Smartin break; 834971dc1a0Smartin case IFM_100_TX: 83572e2d70fSjmcneill conf |= AWIN_GMAC_MAC_CONF_FES100 | 83672e2d70fSjmcneill AWIN_GMAC_MAC_CONF_MIISEL; 837971dc1a0Smartin break; 838971dc1a0Smartin case IFM_1000_T: 839971dc1a0Smartin break; 840971dc1a0Smartin } 841041c183aSjmcneill if (sc->sc_set_speed) 842041c183aSjmcneill sc->sc_set_speed(sc, IFM_SUBTYPE(mii->mii_media_active)); 84324d51e99Sjmcneill 84424d51e99Sjmcneill flow = 0; 84524d51e99Sjmcneill if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { 8468277fba8Smartin conf |= AWIN_GMAC_MAC_CONF_FULLDPLX; 84724d51e99Sjmcneill flow |= __SHIFTIN(0x200, AWIN_GMAC_MAC_FLOWCTRL_PAUSE); 84824d51e99Sjmcneill } 84924d51e99Sjmcneill if (mii->mii_media_active & IFM_ETH_TXPAUSE) { 85024d51e99Sjmcneill flow |= AWIN_GMAC_MAC_FLOWCTRL_TFE; 85124d51e99Sjmcneill } 85224d51e99Sjmcneill if (mii->mii_media_active & IFM_ETH_RXPAUSE) { 85324d51e99Sjmcneill flow |= AWIN_GMAC_MAC_FLOWCTRL_RFE; 85424d51e99Sjmcneill } 85524d51e99Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, 85624d51e99Sjmcneill AWIN_GMAC_MAC_FLOWCTRL, flow); 8578277fba8Smartin 8588277fba8Smartin #ifdef DWC_GMAC_DEBUG 8598277fba8Smartin aprint_normal_dev(sc->sc_dev, 8608277fba8Smartin "setting MAC conf register: %08x\n", conf); 8618277fba8Smartin #endif 8628277fba8Smartin 8638277fba8Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, 8648277fba8Smartin AWIN_GMAC_MAC_CONF, conf); 865971dc1a0Smartin } 866971dc1a0Smartin 867971dc1a0Smartin static int 868971dc1a0Smartin dwc_gmac_init(struct ifnet *ifp) 869971dc1a0Smartin { 870eb43ba5fSskrll struct dwc_gmac_softc * const sc = ifp->if_softc; 871a0ef5e67Sjmcneill uint32_t ffilt; 872971dc1a0Smartin 873c9ba1e93Sskrll ASSERT_SLEEPABLE(); 874c9ba1e93Sskrll KASSERT(IFNET_LOCKED(ifp)); 875c9ba1e93Sskrll KASSERT(ifp == &sc->sc_ec.ec_if); 876971dc1a0Smartin 87796373f68Sriastradh dwc_gmac_stop(ifp, 0); 878971dc1a0Smartin 879971dc1a0Smartin /* 880426c40ceSmartin * Configure DMA burst/transfer mode and RX/TX priorities. 881426c40ceSmartin * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented. 882426c40ceSmartin */ 883426c40ceSmartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, 88424d51e99Sjmcneill GMAC_BUSMODE_FIXEDBURST | GMAC_BUSMODE_4PBL | 88524d51e99Sjmcneill __SHIFTIN(2, GMAC_BUSMODE_RPBL) | 88624d51e99Sjmcneill __SHIFTIN(2, GMAC_BUSMODE_PBL)); 887426c40ceSmartin 888426c40ceSmartin /* 889a0ef5e67Sjmcneill * Set up address filter 890426c40ceSmartin */ 891f8c640e7Sjmcneill ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); 892f8c640e7Sjmcneill if (ifp->if_flags & IFF_PROMISC) { 893a0ef5e67Sjmcneill ffilt |= AWIN_GMAC_MAC_FFILT_PR; 894f8c640e7Sjmcneill } else { 895f8c640e7Sjmcneill ffilt &= ~AWIN_GMAC_MAC_FFILT_PR; 896f8c640e7Sjmcneill } 897f8c640e7Sjmcneill if (ifp->if_flags & IFF_BROADCAST) { 898f8c640e7Sjmcneill ffilt &= ~AWIN_GMAC_MAC_FFILT_DBF; 899f8c640e7Sjmcneill } else { 900f8c640e7Sjmcneill ffilt |= AWIN_GMAC_MAC_FFILT_DBF; 901f8c640e7Sjmcneill } 902a0ef5e67Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); 903426c40ceSmartin 904426c40ceSmartin /* 905f8c640e7Sjmcneill * Set up multicast filter 906f8c640e7Sjmcneill */ 90796373f68Sriastradh mutex_enter(sc->sc_mcast_lock); 908f8c640e7Sjmcneill dwc_gmac_setmulti(sc); 90996373f68Sriastradh mutex_exit(sc->sc_mcast_lock); 910f8c640e7Sjmcneill 911f8c640e7Sjmcneill /* 912518bac49Smartin * Set up dma pointer for RX and TX ring 913971dc1a0Smartin */ 914518bac49Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, 915518bac49Smartin sc->sc_rxq.r_physaddr); 916518bac49Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, 917518bac49Smartin sc->sc_txq.t_physaddr); 918518bac49Smartin 919518bac49Smartin /* 9205158fc24Smartin * Start RX/TX part 921518bac49Smartin */ 922041c183aSjmcneill uint32_t opmode = GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART; 923041c183aSjmcneill if ((sc->sc_flags & DWC_GMAC_FORCE_THRESH_DMA_MODE) == 0) { 924041c183aSjmcneill opmode |= GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD; 925041c183aSjmcneill } 926041c183aSjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE, opmode); 92704b7b2c1Sskrll #ifdef DWC_GMAC_DEBUG 92804b7b2c1Sskrll aprint_normal_dev(sc->sc_dev, 92904b7b2c1Sskrll "setting DMA opmode register: %08x\n", opmode); 93004b7b2c1Sskrll #endif 931971dc1a0Smartin 932c9ba1e93Sskrll ifp->if_flags |= IFF_RUNNING; 933c9ba1e93Sskrll sc->sc_if_flags = ifp->if_flags; 934c9ba1e93Sskrll 935c9ba1e93Sskrll mutex_enter(sc->sc_intr_lock); 936fc18ade0Sskrll sc->sc_stopping = false; 93796373f68Sriastradh mutex_exit(sc->sc_intr_lock); 938fc18ade0Sskrll 939c9ba1e93Sskrll mutex_enter(&sc->sc_txq.t_mtx); 940bdb3207bSthorpej sc->sc_txbusy = false; 941c9ba1e93Sskrll mutex_exit(&sc->sc_txq.t_mtx); 942971dc1a0Smartin 943971dc1a0Smartin return 0; 944971dc1a0Smartin } 945971dc1a0Smartin 946971dc1a0Smartin static void 947971dc1a0Smartin dwc_gmac_start(struct ifnet *ifp) 948971dc1a0Smartin { 949eb43ba5fSskrll struct dwc_gmac_softc * const sc = ifp->if_softc; 950ab3cd725Sozaki-r KASSERT(if_is_mpsafe(ifp)); 951fc18ade0Sskrll 952c9ba1e93Sskrll mutex_enter(sc->sc_intr_lock); 953fc18ade0Sskrll if (!sc->sc_stopping) { 954fc18ade0Sskrll dwc_gmac_start_locked(ifp); 955fc18ade0Sskrll } 956c9ba1e93Sskrll mutex_exit(sc->sc_intr_lock); 957fc18ade0Sskrll } 958fc18ade0Sskrll 959fc18ade0Sskrll static void 960fc18ade0Sskrll dwc_gmac_start_locked(struct ifnet *ifp) 961fc18ade0Sskrll { 962eb43ba5fSskrll struct dwc_gmac_softc * const sc = ifp->if_softc; 963971dc1a0Smartin int old = sc->sc_txq.t_queued; 964ef110221Smartin int start = sc->sc_txq.t_cur; 965971dc1a0Smartin struct mbuf *m0; 966971dc1a0Smartin 967c9ba1e93Sskrll KASSERT(mutex_owned(sc->sc_intr_lock)); 968c9ba1e93Sskrll 969c9ba1e93Sskrll mutex_enter(&sc->sc_txq.t_mtx); 970c9ba1e93Sskrll if (sc->sc_txbusy) { 971c9ba1e93Sskrll mutex_exit(&sc->sc_txq.t_mtx); 972bdb3207bSthorpej return; 973c9ba1e93Sskrll } 974971dc1a0Smartin 975971dc1a0Smartin for (;;) { 976971dc1a0Smartin IFQ_POLL(&ifp->if_snd, m0); 977971dc1a0Smartin if (m0 == NULL) 978971dc1a0Smartin break; 979971dc1a0Smartin if (dwc_gmac_queue(sc, m0) != 0) { 980bdb3207bSthorpej sc->sc_txbusy = true; 981971dc1a0Smartin break; 982971dc1a0Smartin } 983971dc1a0Smartin IFQ_DEQUEUE(&ifp->if_snd, m0); 9843cd62456Smsaitoh bpf_mtap(ifp, m0, BPF_D_OUT); 9858132f7b2Smartin if (sc->sc_txq.t_queued == AWGE_TX_RING_COUNT) { 986bdb3207bSthorpej sc->sc_txbusy = true; 9878132f7b2Smartin break; 9888132f7b2Smartin } 989971dc1a0Smartin } 990971dc1a0Smartin 991971dc1a0Smartin if (sc->sc_txq.t_queued != old) { 992971dc1a0Smartin /* packets have been queued, kick it off */ 993ef110221Smartin dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur, 994971dc1a0Smartin BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 995518bac49Smartin 9965158fc24Smartin #ifdef DWC_GMAC_DEBUG 9975158fc24Smartin dwc_dump_status(sc); 9985158fc24Smartin #endif 99972645925Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, 100072645925Smartin AWIN_GMAC_DMA_TXPOLL, ~0U); 1001971dc1a0Smartin } 1002c9ba1e93Sskrll mutex_exit(&sc->sc_txq.t_mtx); 1003971dc1a0Smartin } 1004971dc1a0Smartin 1005971dc1a0Smartin static void 1006971dc1a0Smartin dwc_gmac_stop(struct ifnet *ifp, int disable) 1007971dc1a0Smartin { 1008eb43ba5fSskrll struct dwc_gmac_softc * const sc = ifp->if_softc; 1009971dc1a0Smartin 1010c9ba1e93Sskrll ASSERT_SLEEPABLE(); 1011c9ba1e93Sskrll KASSERT(IFNET_LOCKED(ifp)); 101296373f68Sriastradh 101396373f68Sriastradh ifp->if_flags &= ~IFF_RUNNING; 101496373f68Sriastradh 101596373f68Sriastradh mutex_enter(sc->sc_mcast_lock); 101696373f68Sriastradh sc->sc_if_flags = ifp->if_flags; 101796373f68Sriastradh mutex_exit(sc->sc_mcast_lock); 1018c9ba1e93Sskrll 1019c9ba1e93Sskrll mutex_enter(sc->sc_intr_lock); 1020fc18ade0Sskrll sc->sc_stopping = true; 102196373f68Sriastradh mutex_exit(sc->sc_intr_lock); 1022fc18ade0Sskrll 1023c9ba1e93Sskrll mutex_enter(&sc->sc_txq.t_mtx); 1024c9ba1e93Sskrll sc->sc_txbusy = false; 1025c9ba1e93Sskrll mutex_exit(&sc->sc_txq.t_mtx); 1026c9ba1e93Sskrll 1027518bac49Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, 1028518bac49Smartin AWIN_GMAC_DMA_OPMODE, 1029518bac49Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, 1030518bac49Smartin AWIN_GMAC_DMA_OPMODE) 1031518bac49Smartin & ~(GMAC_DMA_OP_TXSTART | GMAC_DMA_OP_RXSTART)); 1032518bac49Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, 1033518bac49Smartin AWIN_GMAC_DMA_OPMODE, 1034518bac49Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, 1035518bac49Smartin AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_FLUSHTX); 1036518bac49Smartin 1037971dc1a0Smartin mii_down(&sc->sc_mii); 1038971dc1a0Smartin dwc_gmac_reset_tx_ring(sc, &sc->sc_txq); 1039971dc1a0Smartin dwc_gmac_reset_rx_ring(sc, &sc->sc_rxq); 1040971dc1a0Smartin } 1041971dc1a0Smartin 1042971dc1a0Smartin /* 1043971dc1a0Smartin * Add m0 to the TX ring 1044971dc1a0Smartin */ 1045971dc1a0Smartin static int 1046971dc1a0Smartin dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0) 1047971dc1a0Smartin { 1048971dc1a0Smartin struct dwc_gmac_dev_dmadesc *desc = NULL; 1049971dc1a0Smartin struct dwc_gmac_tx_data *data = NULL; 1050971dc1a0Smartin bus_dmamap_t map; 1051971dc1a0Smartin int error, i, first; 1052971dc1a0Smartin 1053bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG 1054bdbd5db8Smartin aprint_normal_dev(sc->sc_dev, 1055bdbd5db8Smartin "dwc_gmac_queue: adding mbuf chain %p\n", m0); 1056bdbd5db8Smartin #endif 1057bdbd5db8Smartin 1058971dc1a0Smartin first = sc->sc_txq.t_cur; 1059971dc1a0Smartin map = sc->sc_txq.t_data[first].td_map; 1060971dc1a0Smartin 1061971dc1a0Smartin error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, 1062971dc1a0Smartin BUS_DMA_WRITE | BUS_DMA_NOWAIT); 1063971dc1a0Smartin if (error != 0) { 1064971dc1a0Smartin aprint_error_dev(sc->sc_dev, "could not map mbuf " 1065971dc1a0Smartin "(len: %d, error %d)\n", m0->m_pkthdr.len, error); 1066971dc1a0Smartin return error; 1067971dc1a0Smartin } 1068971dc1a0Smartin 10698132f7b2Smartin if (sc->sc_txq.t_queued + map->dm_nsegs > AWGE_TX_RING_COUNT) { 1070971dc1a0Smartin bus_dmamap_unload(sc->sc_dmat, map); 1071971dc1a0Smartin return ENOBUFS; 1072971dc1a0Smartin } 1073971dc1a0Smartin 1074971dc1a0Smartin for (i = 0; i < map->dm_nsegs; i++) { 1075971dc1a0Smartin data = &sc->sc_txq.t_data[sc->sc_txq.t_cur]; 1076971dc1a0Smartin desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur]; 1077971dc1a0Smartin 1078971dc1a0Smartin desc->ddesc_data = htole32(map->dm_segs[i].ds_addr); 1079bdbd5db8Smartin 1080bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG 1081b29c5071Sskrll aprint_normal_dev(sc->sc_dev, "enqueuing desc #%d data %08lx " 108272645925Smartin "len %lu\n", sc->sc_txq.t_cur, 1083bdbd5db8Smartin (unsigned long)map->dm_segs[i].ds_addr, 108472645925Smartin (unsigned long)map->dm_segs[i].ds_len); 1085bdbd5db8Smartin #endif 1086bdbd5db8Smartin 108772645925Smartin sc->sc_descm->tx_init_flags(desc); 108872645925Smartin sc->sc_descm->tx_set_len(desc, map->dm_segs[i].ds_len); 108972645925Smartin 109072645925Smartin if (i == 0) 109172645925Smartin sc->sc_descm->tx_set_first_frag(desc); 1092971dc1a0Smartin 1093971dc1a0Smartin /* 1094971dc1a0Smartin * Defer passing ownership of the first descriptor 1095480d5fceSjoerg * until we are done. 1096971dc1a0Smartin */ 109772645925Smartin if (i != 0) 109872645925Smartin sc->sc_descm->tx_set_owned_by_dev(desc); 1099971dc1a0Smartin 1100bdbd5db8Smartin sc->sc_txq.t_queued++; 1101bdbd5db8Smartin sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur); 1102971dc1a0Smartin } 1103971dc1a0Smartin 110472645925Smartin sc->sc_descm->tx_set_last_frag(desc); 1105971dc1a0Smartin 1106971dc1a0Smartin data->td_m = m0; 1107971dc1a0Smartin data->td_active = map; 1108971dc1a0Smartin 110940044749Sskrll /* sync the packet buffer */ 1110971dc1a0Smartin bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 11114a5c3abbSjmcneill BUS_DMASYNC_PREWRITE); 1112971dc1a0Smartin 111340044749Sskrll /* sync the new descriptors - ownership not transferred yet */ 111440044749Sskrll dwc_gmac_txdesc_sync(sc, first, sc->sc_txq.t_cur, 111540044749Sskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 111640044749Sskrll 11178132f7b2Smartin /* Pass first to device */ 111872645925Smartin sc->sc_descm->tx_set_owned_by_dev(&sc->sc_txq.t_desc[first]); 111972645925Smartin 1120971dc1a0Smartin return 0; 1121971dc1a0Smartin } 1122971dc1a0Smartin 1123d1bd22e8Smartin /* 1124d1bd22e8Smartin * If the interface is up and running, only modify the receive 1125d1bd22e8Smartin * filter when setting promiscuous or debug mode. Otherwise fall 1126d1bd22e8Smartin * through to ether_ioctl, which will reset the chip. 1127d1bd22e8Smartin */ 1128d1bd22e8Smartin static int 1129d1bd22e8Smartin dwc_gmac_ifflags_cb(struct ethercom *ec) 1130d1bd22e8Smartin { 1131eb43ba5fSskrll struct ifnet * const ifp = &ec->ec_if; 1132eb43ba5fSskrll struct dwc_gmac_softc * const sc = ifp->if_softc; 1133fc18ade0Sskrll int ret = 0; 1134d1bd22e8Smartin 1135c9ba1e93Sskrll KASSERT(IFNET_LOCKED(ifp)); 113696373f68Sriastradh mutex_enter(sc->sc_mcast_lock); 1137c9ba1e93Sskrll 113870b25bc9Smsaitoh u_short change = ifp->if_flags ^ sc->sc_if_flags; 1139fc18ade0Sskrll sc->sc_if_flags = ifp->if_flags; 1140fc18ade0Sskrll 1141fc18ade0Sskrll if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { 1142fc18ade0Sskrll ret = ENETRESET; 1143c9ba1e93Sskrll } else if ((change & IFF_PROMISC) != 0) { 1144d1bd22e8Smartin dwc_gmac_setmulti(sc); 1145fc18ade0Sskrll } 1146c9ba1e93Sskrll 114796373f68Sriastradh mutex_exit(sc->sc_mcast_lock); 1148fc18ade0Sskrll 1149fc18ade0Sskrll return ret; 1150d1bd22e8Smartin } 1151d1bd22e8Smartin 1152971dc1a0Smartin static int 1153971dc1a0Smartin dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data) 1154971dc1a0Smartin { 1155eb43ba5fSskrll struct dwc_gmac_softc * const sc = ifp->if_softc; 1156fc18ade0Sskrll int error = 0; 1157971dc1a0Smartin 1158c9ba1e93Sskrll switch (cmd) { 1159c9ba1e93Sskrll case SIOCADDMULTI: 1160c9ba1e93Sskrll case SIOCDELMULTI: 1161c9ba1e93Sskrll break; 1162c9ba1e93Sskrll default: 1163c9ba1e93Sskrll KASSERT(IFNET_LOCKED(ifp)); 1164c9ba1e93Sskrll } 1165971dc1a0Smartin 1166c9ba1e93Sskrll const int s = splnet(); 1167c9ba1e93Sskrll error = ether_ioctl(ifp, cmd, data); 1168fc18ade0Sskrll splx(s); 1169fc18ade0Sskrll 1170fc18ade0Sskrll if (error == ENETRESET) { 1171971dc1a0Smartin error = 0; 1172c9ba1e93Sskrll if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) { 117396373f68Sriastradh mutex_enter(sc->sc_mcast_lock); 1174c9ba1e93Sskrll if (sc->sc_if_flags & IFF_RUNNING) { 1175d1bd22e8Smartin /* 1176c9ba1e93Sskrll * Multicast list has changed; set the hardware 1177c9ba1e93Sskrll * filter accordingly. 1178d1bd22e8Smartin */ 1179f8c640e7Sjmcneill dwc_gmac_setmulti(sc); 1180c9ba1e93Sskrll } 118196373f68Sriastradh mutex_exit(sc->sc_mcast_lock); 1182d1bd22e8Smartin } 1183971dc1a0Smartin } 1184971dc1a0Smartin 1185971dc1a0Smartin return error; 1186971dc1a0Smartin } 1187971dc1a0Smartin 1188bdbd5db8Smartin static void 1189bdbd5db8Smartin dwc_gmac_tx_intr(struct dwc_gmac_softc *sc) 1190bdbd5db8Smartin { 1191eb43ba5fSskrll struct ifnet * const ifp = &sc->sc_ec.ec_if; 1192bdbd5db8Smartin struct dwc_gmac_tx_data *data; 1193bdbd5db8Smartin struct dwc_gmac_dev_dmadesc *desc; 11948132f7b2Smartin int i, nsegs; 1195bdbd5db8Smartin 1196fc18ade0Sskrll mutex_enter(&sc->sc_txq.t_mtx); 1197fc18ade0Sskrll 11988132f7b2Smartin for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) { 1199bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG 1200bdbd5db8Smartin aprint_normal_dev(sc->sc_dev, 120104b7b2c1Sskrll "%s: checking desc #%d (t_queued: %d)\n", __func__, 1202bdbd5db8Smartin i, sc->sc_txq.t_queued); 1203bdbd5db8Smartin #endif 1204bdbd5db8Smartin 12052d00f56cSmartin /* 12062d00f56cSmartin * i + 1 does not need to be a valid descriptor, 12072d00f56cSmartin * this is just a special notion to just sync 12082d00f56cSmartin * a single tx descriptor (i) 12092d00f56cSmartin */ 12102d00f56cSmartin dwc_gmac_txdesc_sync(sc, i, i + 1, 1211bdbd5db8Smartin BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1212426c40ceSmartin 12138132f7b2Smartin desc = &sc->sc_txq.t_desc[i]; 121472645925Smartin if (sc->sc_descm->tx_is_owned_by_dev(desc)) 1215bdbd5db8Smartin break; 1216426c40ceSmartin 1217bdbd5db8Smartin data = &sc->sc_txq.t_data[i]; 1218bdbd5db8Smartin if (data->td_m == NULL) 1219bdbd5db8Smartin continue; 12208132f7b2Smartin 12212d501ecfSthorpej if_statinc(ifp, if_opackets); 12228132f7b2Smartin nsegs = data->td_active->dm_nsegs; 1223bdbd5db8Smartin bus_dmamap_sync(sc->sc_dmat, data->td_active, 0, 1224bdbd5db8Smartin data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1225bdbd5db8Smartin bus_dmamap_unload(sc->sc_dmat, data->td_active); 1226bdbd5db8Smartin 1227bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG 1228bdbd5db8Smartin aprint_normal_dev(sc->sc_dev, 122904b7b2c1Sskrll "%s: done with packet at desc #%d, freeing mbuf %p\n", 123004b7b2c1Sskrll __func__, i, data->td_m); 1231bdbd5db8Smartin #endif 1232bdbd5db8Smartin 1233bdbd5db8Smartin m_freem(data->td_m); 1234bdbd5db8Smartin data->td_m = NULL; 12358132f7b2Smartin 12368132f7b2Smartin sc->sc_txq.t_queued -= nsegs; 1237bdbd5db8Smartin } 1238bdbd5db8Smartin 1239bdbd5db8Smartin sc->sc_txq.t_next = i; 1240bdbd5db8Smartin 1241bdbd5db8Smartin if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) { 1242bdb3207bSthorpej sc->sc_txbusy = false; 1243bdbd5db8Smartin } 1244fc18ade0Sskrll mutex_exit(&sc->sc_txq.t_mtx); 1245bdbd5db8Smartin } 1246bdbd5db8Smartin 1247bdbd5db8Smartin static void 1248bdbd5db8Smartin dwc_gmac_rx_intr(struct dwc_gmac_softc *sc) 1249bdbd5db8Smartin { 1250eb43ba5fSskrll struct ifnet * const ifp = &sc->sc_ec.ec_if; 1251426c40ceSmartin struct dwc_gmac_dev_dmadesc *desc; 1252426c40ceSmartin struct dwc_gmac_rx_data *data; 1253426c40ceSmartin bus_addr_t physaddr; 1254426c40ceSmartin struct mbuf *m, *mnew; 1255426c40ceSmartin int i, len, error; 1256426c40ceSmartin 1257fc18ade0Sskrll mutex_enter(&sc->sc_rxq.r_mtx); 1258426c40ceSmartin for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) { 125904b7b2c1Sskrll #ifdef DWC_GMAC_DEBUG 126004b7b2c1Sskrll aprint_normal_dev(sc->sc_dev, "%s: checking desc #%d\n", 126104b7b2c1Sskrll __func__, i); 126204b7b2c1Sskrll #endif 1263426c40ceSmartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 1264426c40ceSmartin RX_DESC_OFFSET(i), sizeof(*desc), 1265426c40ceSmartin BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1266426c40ceSmartin desc = &sc->sc_rxq.r_desc[i]; 1267426c40ceSmartin data = &sc->sc_rxq.r_data[i]; 1268426c40ceSmartin 126972645925Smartin if (sc->sc_descm->rx_is_owned_by_dev(desc)) 1270426c40ceSmartin break; 1271426c40ceSmartin 127272645925Smartin if (sc->sc_descm->rx_has_error(desc)) { 1273426c40ceSmartin #ifdef DWC_GMAC_DEBUG 12743131c860Smartin aprint_normal_dev(sc->sc_dev, 127504b7b2c1Sskrll "%s: RX error: status %08x, skipping\n", 127604b7b2c1Sskrll __func__, le32toh(desc->ddesc_status0)); 1277426c40ceSmartin #endif 12782d501ecfSthorpej if_statinc(ifp, if_ierrors); 1279426c40ceSmartin goto skip; 1280426c40ceSmartin } 1281426c40ceSmartin 128272645925Smartin len = sc->sc_descm->rx_get_len(desc); 1283426c40ceSmartin 1284426c40ceSmartin #ifdef DWC_GMAC_DEBUG 12853131c860Smartin aprint_normal_dev(sc->sc_dev, 128604b7b2c1Sskrll "%s: device is done with descriptor #%d, len: %d\n", 128704b7b2c1Sskrll __func__, i, len); 1288426c40ceSmartin #endif 1289426c40ceSmartin 1290426c40ceSmartin /* 1291426c40ceSmartin * Try to get a new mbuf before passing this one 1292426c40ceSmartin * up, if that fails, drop the packet and reuse 1293426c40ceSmartin * the existing one. 1294426c40ceSmartin */ 1295426c40ceSmartin MGETHDR(mnew, M_DONTWAIT, MT_DATA); 1296426c40ceSmartin if (mnew == NULL) { 12972d501ecfSthorpej if_statinc(ifp, if_ierrors); 1298426c40ceSmartin goto skip; 1299426c40ceSmartin } 1300426c40ceSmartin MCLGET(mnew, M_DONTWAIT); 1301426c40ceSmartin if ((mnew->m_flags & M_EXT) == 0) { 1302426c40ceSmartin m_freem(mnew); 13032d501ecfSthorpej if_statinc(ifp, if_ierrors); 1304426c40ceSmartin goto skip; 1305426c40ceSmartin } 13063c96a2beStnn mnew->m_len = mnew->m_pkthdr.len = mnew->m_ext.ext_size; 13073c96a2beStnn if (mnew->m_len > AWGE_MAX_PACKET) { 13083c96a2beStnn mnew->m_len = mnew->m_pkthdr.len = AWGE_MAX_PACKET; 13093c96a2beStnn } 1310426c40ceSmartin 1311426c40ceSmartin /* unload old DMA map */ 1312426c40ceSmartin bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, 1313426c40ceSmartin data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1314426c40ceSmartin bus_dmamap_unload(sc->sc_dmat, data->rd_map); 1315426c40ceSmartin 1316426c40ceSmartin /* and reload with new mbuf */ 13173c96a2beStnn error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, 13183c96a2beStnn mnew, BUS_DMA_READ | BUS_DMA_NOWAIT); 1319426c40ceSmartin if (error != 0) { 1320426c40ceSmartin m_freem(mnew); 1321426c40ceSmartin /* try to reload old mbuf */ 13223c96a2beStnn error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map, 13233c96a2beStnn data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT); 1324426c40ceSmartin if (error != 0) { 1325426c40ceSmartin panic("%s: could not load old rx mbuf", 1326426c40ceSmartin device_xname(sc->sc_dev)); 1327426c40ceSmartin } 13282d501ecfSthorpej if_statinc(ifp, if_ierrors); 1329426c40ceSmartin goto skip; 1330426c40ceSmartin } 1331426c40ceSmartin physaddr = data->rd_map->dm_segs[0].ds_addr; 1332426c40ceSmartin 133304b7b2c1Sskrll #ifdef DWC_GMAC_DEBUG 133404b7b2c1Sskrll aprint_normal_dev(sc->sc_dev, 133504b7b2c1Sskrll "%s: receiving packet at desc #%d, using mbuf %p\n", 133604b7b2c1Sskrll __func__, i, data->rd_m); 133704b7b2c1Sskrll #endif 1338426c40ceSmartin /* 1339426c40ceSmartin * New mbuf loaded, update RX ring and continue 1340426c40ceSmartin */ 1341426c40ceSmartin m = data->rd_m; 1342426c40ceSmartin data->rd_m = mnew; 1343426c40ceSmartin desc->ddesc_data = htole32(physaddr); 1344426c40ceSmartin 1345426c40ceSmartin /* finalize mbuf */ 1346426c40ceSmartin m->m_pkthdr.len = m->m_len = len; 1347d938d837Sozaki-r m_set_rcvif(m, ifp); 1348e40fc052Ssekiya m->m_flags |= M_HASFCS; 1349426c40ceSmartin 1350a70a0336Sskrll if_percpuq_enqueue(sc->sc_ipq, m); 1351426c40ceSmartin 1352426c40ceSmartin skip: 13530c8fe4ccSmatt bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, 13540c8fe4ccSmatt data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); 135572645925Smartin 135672645925Smartin sc->sc_descm->rx_init_flags(desc); 13573c96a2beStnn sc->sc_descm->rx_set_len(desc, data->rd_m->m_len); 135840044749Sskrll 135940044749Sskrll bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 136040044749Sskrll RX_DESC_OFFSET(i), sizeof(*desc), 136140044749Sskrll BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 136240044749Sskrll 136372645925Smartin sc->sc_descm->rx_set_owned_by_dev(desc); 136472645925Smartin 1365426c40ceSmartin bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 1366426c40ceSmartin RX_DESC_OFFSET(i), sizeof(*desc), 1367426c40ceSmartin BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1368426c40ceSmartin } 1369426c40ceSmartin 1370426c40ceSmartin /* update RX pointer */ 1371426c40ceSmartin sc->sc_rxq.r_cur = i; 1372426c40ceSmartin 1373fc18ade0Sskrll mutex_exit(&sc->sc_rxq.r_mtx); 1374bdbd5db8Smartin } 1375bdbd5db8Smartin 1376f8c640e7Sjmcneill static void 1377f8c640e7Sjmcneill dwc_gmac_setmulti(struct dwc_gmac_softc *sc) 1378f8c640e7Sjmcneill { 1379f8c640e7Sjmcneill struct ether_multi *enm; 1380f8c640e7Sjmcneill struct ether_multistep step; 1381390d6c3dSozaki-r struct ethercom *ec = &sc->sc_ec; 1382f8c640e7Sjmcneill uint32_t hashes[2] = { 0, 0 }; 1383d1bd22e8Smartin uint32_t ffilt, h; 1384fc18ade0Sskrll int mcnt; 1385d1bd22e8Smartin 138696373f68Sriastradh KASSERT(mutex_owned(sc->sc_mcast_lock)); 1387f8c640e7Sjmcneill 1388f8c640e7Sjmcneill ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); 1389f8c640e7Sjmcneill 1390c9ba1e93Sskrll if (sc->sc_if_flags & IFF_PROMISC) { 1391d1bd22e8Smartin ffilt |= AWIN_GMAC_MAC_FFILT_PR; 1392d1bd22e8Smartin goto special_filter; 1393f8c640e7Sjmcneill } 1394f8c640e7Sjmcneill 1395d1bd22e8Smartin ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM | AWIN_GMAC_MAC_FFILT_PR); 1396f8c640e7Sjmcneill 1397f8c640e7Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0); 1398f8c640e7Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0); 1399f8c640e7Sjmcneill 1400390d6c3dSozaki-r ETHER_LOCK(ec); 140199ec0af5Sozaki-r ec->ec_flags &= ~ETHER_F_ALLMULTI; 1402390d6c3dSozaki-r ETHER_FIRST_MULTI(step, ec, enm); 1403f8c640e7Sjmcneill mcnt = 0; 1404f8c640e7Sjmcneill while (enm != NULL) { 1405f8c640e7Sjmcneill if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 1406d1bd22e8Smartin ETHER_ADDR_LEN) != 0) { 1407d1bd22e8Smartin ffilt |= AWIN_GMAC_MAC_FFILT_PM; 140899ec0af5Sozaki-r ec->ec_flags |= ETHER_F_ALLMULTI; 140999ec0af5Sozaki-r ETHER_UNLOCK(ec); 1410d1bd22e8Smartin goto special_filter; 1411d1bd22e8Smartin } 1412f8c640e7Sjmcneill 1413fb93b87aSjakllsch h = ~ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26; 1414f8c640e7Sjmcneill hashes[h >> 5] |= (1 << (h & 0x1f)); 1415f8c640e7Sjmcneill 1416f8c640e7Sjmcneill mcnt++; 1417f8c640e7Sjmcneill ETHER_NEXT_MULTI(step, enm); 1418f8c640e7Sjmcneill } 1419390d6c3dSozaki-r ETHER_UNLOCK(ec); 1420f8c640e7Sjmcneill 1421f8c640e7Sjmcneill if (mcnt) 1422f8c640e7Sjmcneill ffilt |= AWIN_GMAC_MAC_FFILT_HMC; 1423f8c640e7Sjmcneill else 1424f8c640e7Sjmcneill ffilt &= ~AWIN_GMAC_MAC_FFILT_HMC; 1425f8c640e7Sjmcneill 1426f8c640e7Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); 1427f8c640e7Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 1428f8c640e7Sjmcneill hashes[0]); 1429f8c640e7Sjmcneill bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 1430f8c640e7Sjmcneill hashes[1]); 1431d1bd22e8Smartin 1432d1bd22e8Smartin #ifdef DWC_GMAC_DEBUG 1433d1bd22e8Smartin dwc_gmac_dump_ffilt(sc, ffilt); 1434d1bd22e8Smartin #endif 1435d1bd22e8Smartin return; 1436d1bd22e8Smartin 1437d1bd22e8Smartin special_filter: 1438d1bd22e8Smartin #ifdef DWC_GMAC_DEBUG 1439d1bd22e8Smartin dwc_gmac_dump_ffilt(sc, ffilt); 1440d1bd22e8Smartin #endif 1441d1bd22e8Smartin /* no MAC hashes, ALLMULTI or PROMISC */ 1442d1bd22e8Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, 1443d1bd22e8Smartin ffilt); 1444d1bd22e8Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 1445d1bd22e8Smartin 0xffffffff); 1446d1bd22e8Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 1447d1bd22e8Smartin 0xffffffff); 1448f8c640e7Sjmcneill } 1449f8c640e7Sjmcneill 1450971dc1a0Smartin int 1451971dc1a0Smartin dwc_gmac_intr(struct dwc_gmac_softc *sc) 1452971dc1a0Smartin { 1453971dc1a0Smartin uint32_t status, dma_status; 1454bdbd5db8Smartin int rv = 0; 1455971dc1a0Smartin 1456c9ba1e93Sskrll mutex_enter(sc->sc_intr_lock); 1457c9ba1e93Sskrll if (sc->sc_stopping) { 1458c9ba1e93Sskrll mutex_exit(sc->sc_intr_lock); 1459fc18ade0Sskrll return 0; 1460c9ba1e93Sskrll } 1461fc18ade0Sskrll 1462971dc1a0Smartin status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR); 146383658911Smartin if (status & AWIN_GMAC_MII_IRQ) { 1464971dc1a0Smartin (void)bus_space_read_4(sc->sc_bst, sc->sc_bsh, 1465971dc1a0Smartin AWIN_GMAC_MII_STATUS); 1466bdbd5db8Smartin rv = 1; 146783658911Smartin mii_pollstat(&sc->sc_mii); 146883658911Smartin } 1469971dc1a0Smartin 1470971dc1a0Smartin dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 1471971dc1a0Smartin AWIN_GMAC_DMA_STATUS); 1472971dc1a0Smartin 1473bdbd5db8Smartin if (dma_status & (GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE)) 1474bdbd5db8Smartin rv = 1; 1475971dc1a0Smartin 1476bdbd5db8Smartin if (dma_status & GMAC_DMA_INT_TIE) 1477bdbd5db8Smartin dwc_gmac_tx_intr(sc); 1478971dc1a0Smartin 1479bdbd5db8Smartin if (dma_status & GMAC_DMA_INT_RIE) 1480bdbd5db8Smartin dwc_gmac_rx_intr(sc); 1481bdbd5db8Smartin 1482bdbd5db8Smartin /* 1483bdbd5db8Smartin * Check error conditions 1484bdbd5db8Smartin */ 1485bdbd5db8Smartin if (dma_status & GMAC_DMA_INT_ERRORS) { 14862d501ecfSthorpej if_statinc(&sc->sc_ec.ec_if, if_oerrors); 1487bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG 1488bdbd5db8Smartin dwc_dump_and_abort(sc, "interrupt error condition"); 1489bdbd5db8Smartin #endif 1490bdbd5db8Smartin } 1491bdbd5db8Smartin 1492f872a062Smsaitoh rnd_add_uint32(&sc->rnd_source, dma_status); 1493f872a062Smsaitoh 1494bdbd5db8Smartin /* ack interrupt */ 1495bdbd5db8Smartin if (dma_status) 1496bdbd5db8Smartin bus_space_write_4(sc->sc_bst, sc->sc_bsh, 1497bdbd5db8Smartin AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK); 1498bdbd5db8Smartin 1499ce7dba4dSmartin /* 1500ce7dba4dSmartin * Get more packets 1501ce7dba4dSmartin */ 1502ce7dba4dSmartin if (rv) 15031c82c572Sozaki-r if_schedule_deferred_start(&sc->sc_ec.ec_if); 1504ce7dba4dSmartin 1505c9ba1e93Sskrll mutex_exit(sc->sc_intr_lock); 1506c9ba1e93Sskrll 1507bdbd5db8Smartin return rv; 1508971dc1a0Smartin } 150937ad3d63Smartin 151072645925Smartin static void 151172645925Smartin dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) 151272645925Smartin { 151372645925Smartin 151472645925Smartin desc->ddesc_status0 |= htole32(DDESC_STATUS_OWNEDBYDEV); 151572645925Smartin } 151672645925Smartin 151772645925Smartin static int 151872645925Smartin dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) 151972645925Smartin { 152072645925Smartin 152172645925Smartin return !!(le32toh(desc->ddesc_status0) & DDESC_STATUS_OWNEDBYDEV); 152272645925Smartin } 152372645925Smartin 152472645925Smartin static void 152572645925Smartin dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *desc, int len) 152672645925Smartin { 152772645925Smartin uint32_t cntl = le32toh(desc->ddesc_cntl1); 152872645925Smartin 152972645925Smartin desc->ddesc_cntl1 = htole32((cntl & ~DDESC_CNTL_SIZE1MASK) | 153072645925Smartin __SHIFTIN(len, DDESC_CNTL_SIZE1MASK)); 153172645925Smartin } 153272645925Smartin 153372645925Smartin static uint32_t 153472645925Smartin dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *desc) 153572645925Smartin { 153672645925Smartin 153772645925Smartin return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_STATUS_FRMLENMSK); 153872645925Smartin } 153972645925Smartin 154072645925Smartin static void 154172645925Smartin dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc) 154272645925Smartin { 154372645925Smartin 154472645925Smartin desc->ddesc_status0 = 0; 154572645925Smartin desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN); 154672645925Smartin } 154772645925Smartin 154872645925Smartin static void 154972645925Smartin dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc) 155072645925Smartin { 155172645925Smartin uint32_t cntl = le32toh(desc->ddesc_cntl1); 155272645925Smartin 155372645925Smartin desc->ddesc_cntl1 = htole32(cntl | DDESC_CNTL_TXFIRST); 155472645925Smartin } 155572645925Smartin 155672645925Smartin static void 155772645925Smartin dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc) 155872645925Smartin { 155972645925Smartin uint32_t cntl = le32toh(desc->ddesc_cntl1); 156072645925Smartin 156172645925Smartin desc->ddesc_cntl1 = htole32(cntl | 156272645925Smartin DDESC_CNTL_TXLAST | DDESC_CNTL_TXINT); 156372645925Smartin } 156472645925Smartin 156572645925Smartin static void 156672645925Smartin dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc) 156772645925Smartin { 156872645925Smartin 156972645925Smartin desc->ddesc_status0 = 0; 157072645925Smartin desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN); 157172645925Smartin } 157272645925Smartin 157372645925Smartin static int 157472645925Smartin dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *desc) { 157572645925Smartin return !!(le32toh(desc->ddesc_status0) & 157672645925Smartin (DDESC_STATUS_RXERROR | DDESC_STATUS_RXTRUNCATED)); 157772645925Smartin } 157872645925Smartin 157972645925Smartin static void 158072645925Smartin dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *desc, int len) 158172645925Smartin { 158272645925Smartin uint32_t tdes1 = le32toh(desc->ddesc_cntl1); 158372645925Smartin 158472645925Smartin desc->ddesc_cntl1 = htole32((tdes1 & ~DDESC_DES1_SIZE1MASK) | 158572645925Smartin __SHIFTIN(len, DDESC_DES1_SIZE1MASK)); 158672645925Smartin } 158772645925Smartin 158872645925Smartin static uint32_t 158972645925Smartin dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *desc) 159072645925Smartin { 159172645925Smartin 159272645925Smartin return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_RDES0_FL); 159372645925Smartin } 159472645925Smartin 159572645925Smartin static void 159672645925Smartin dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc) 159772645925Smartin { 159872645925Smartin 159972645925Smartin desc->ddesc_status0 = htole32(DDESC_TDES0_TCH); 160072645925Smartin desc->ddesc_cntl1 = 0; 160172645925Smartin } 160272645925Smartin 160372645925Smartin static void 160472645925Smartin dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc) 160572645925Smartin { 160672645925Smartin uint32_t tdes0 = le32toh(desc->ddesc_status0); 160772645925Smartin 160872645925Smartin desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_FS); 160972645925Smartin } 161072645925Smartin 161172645925Smartin static void 161272645925Smartin dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc) 161372645925Smartin { 161472645925Smartin uint32_t tdes0 = le32toh(desc->ddesc_status0); 161572645925Smartin 161672645925Smartin desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_LS | DDESC_TDES0_IC); 161772645925Smartin } 161872645925Smartin 161972645925Smartin static void 162072645925Smartin dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc) 162172645925Smartin { 162272645925Smartin 162372645925Smartin desc->ddesc_status0 = 0; 162472645925Smartin desc->ddesc_cntl1 = htole32(DDESC_RDES1_RCH); 162572645925Smartin } 162672645925Smartin 162772645925Smartin static int 162872645925Smartin dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *desc) 162972645925Smartin { 163072645925Smartin 163172645925Smartin return !!(le32toh(desc->ddesc_status0) & 163272645925Smartin (DDESC_RDES0_ES | DDESC_RDES0_LE)); 163372645925Smartin } 163472645925Smartin 163537ad3d63Smartin #ifdef DWC_GMAC_DEBUG 163637ad3d63Smartin static void 163737ad3d63Smartin dwc_gmac_dump_dma(struct dwc_gmac_softc *sc) 163837ad3d63Smartin { 163937ad3d63Smartin aprint_normal_dev(sc->sc_dev, "busmode: %08x\n", 164037ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)); 164137ad3d63Smartin aprint_normal_dev(sc->sc_dev, "tx poll: %08x\n", 164237ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TXPOLL)); 164337ad3d63Smartin aprint_normal_dev(sc->sc_dev, "rx poll: %08x\n", 164437ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RXPOLL)); 164537ad3d63Smartin aprint_normal_dev(sc->sc_dev, "rx descriptors: %08x\n", 164637ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR)); 164737ad3d63Smartin aprint_normal_dev(sc->sc_dev, "tx descriptors: %08x\n", 164837ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR)); 164937ad3d63Smartin aprint_normal_dev(sc->sc_dev, " status: %08x\n", 165037ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_STATUS)); 165137ad3d63Smartin aprint_normal_dev(sc->sc_dev, "op mode: %08x\n", 165237ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE)); 165304b7b2c1Sskrll aprint_normal_dev(sc->sc_dev, "int en.: %08x\n", 165437ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE)); 165537ad3d63Smartin aprint_normal_dev(sc->sc_dev, " cur tx: %08x\n", 165637ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_DESC)); 165737ad3d63Smartin aprint_normal_dev(sc->sc_dev, " cur rx: %08x\n", 165837ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_DESC)); 165904b7b2c1Sskrll aprint_normal_dev(sc->sc_dev, "cur txb: %08x\n", 166037ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_BUFADDR)); 166104b7b2c1Sskrll aprint_normal_dev(sc->sc_dev, "cur rxb: %08x\n", 166237ad3d63Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_BUFADDR)); 166337ad3d63Smartin } 166437ad3d63Smartin 166537ad3d63Smartin static void 166637ad3d63Smartin dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc) 166737ad3d63Smartin { 166840044749Sskrll const size_t descsz = sizeof(struct dwc_gmac_dev_dmadesc); 166937ad3d63Smartin 1670bdbd5db8Smartin aprint_normal_dev(sc->sc_dev, "TX queue: cur=%d, next=%d, queued=%d\n", 1671bdbd5db8Smartin sc->sc_txq.t_cur, sc->sc_txq.t_next, sc->sc_txq.t_queued); 167237ad3d63Smartin aprint_normal_dev(sc->sc_dev, "TX DMA descriptors:\n"); 167340044749Sskrll 167440044749Sskrll bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 167540044749Sskrll TX_DESC_OFFSET(0), AWGE_TX_RING_COUNT * descsz, 167640044749Sskrll BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 167740044749Sskrll 167804b7b2c1Sskrll for (size_t i = 0; i < AWGE_TX_RING_COUNT; i++) { 167937ad3d63Smartin struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i]; 168004b7b2c1Sskrll aprint_normal("#%3zu (%08lx): status: %08x cntl: %08x " 16813131c860Smartin "data: %08x next: %08x\n", 168204b7b2c1Sskrll i, sc->sc_txq.t_physaddr + i * descsz, 168372645925Smartin le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1), 168437ad3d63Smartin le32toh(desc->ddesc_data), le32toh(desc->ddesc_next)); 168537ad3d63Smartin } 168637ad3d63Smartin } 1687bdbd5db8Smartin 1688bdbd5db8Smartin static void 1689426c40ceSmartin dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc) 1690426c40ceSmartin { 169140044749Sskrll const size_t descsz = sizeof(struct dwc_gmac_dev_dmadesc); 1692426c40ceSmartin 1693426c40ceSmartin aprint_normal_dev(sc->sc_dev, "RX queue: cur=%d, next=%d\n", 1694426c40ceSmartin sc->sc_rxq.r_cur, sc->sc_rxq.r_next); 1695426c40ceSmartin aprint_normal_dev(sc->sc_dev, "RX DMA descriptors:\n"); 169640044749Sskrll 169740044749Sskrll bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 169840044749Sskrll RX_DESC_OFFSET(0), AWGE_RX_RING_COUNT * descsz, 169940044749Sskrll BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 170040044749Sskrll 170104b7b2c1Sskrll for (size_t i = 0; i < AWGE_RX_RING_COUNT; i++) { 1702426c40ceSmartin struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i]; 170304b7b2c1Sskrll char buf[200]; 170404b7b2c1Sskrll 170504b7b2c1Sskrll if (!sc->sc_descm->rx_is_owned_by_dev(desc)) { 170604b7b2c1Sskrll /* print interrupt state */ 170704b7b2c1Sskrll snprintb(buf, sizeof(buf), 170804b7b2c1Sskrll "\177\20" 170904b7b2c1Sskrll "b\x1e" "daff\0" 171004b7b2c1Sskrll "f\x10\xe" "frlen\0" 171104b7b2c1Sskrll "b\x0f" "error\0" 171204b7b2c1Sskrll "b\x0e" "rxtrunc\0" /* descriptor error? */ 171304b7b2c1Sskrll "b\x0d" "saff\0" 171404b7b2c1Sskrll "b\x0c" "giantframe\0" /* length error? */ 171504b7b2c1Sskrll "b\x0b" "damaged\0" 171604b7b2c1Sskrll "b\x0a" "vlan\0" 171704b7b2c1Sskrll "b\x09" "first\0" 171804b7b2c1Sskrll "b\x08" "last\0" 171904b7b2c1Sskrll "b\x07" "giant\0" 172004b7b2c1Sskrll "b\x06" "collison\0" 172104b7b2c1Sskrll "b\x05" "ether\0" 172204b7b2c1Sskrll "b\x04" "watchdog\0" 172304b7b2c1Sskrll "b\x03" "miierror\0" 172404b7b2c1Sskrll "b\x02" "dribbling\0" 172504b7b2c1Sskrll "b\x01" "crc\0" 172604b7b2c1Sskrll "\0", le32toh(desc->ddesc_status0)); 172704b7b2c1Sskrll } 172804b7b2c1Sskrll 172904b7b2c1Sskrll aprint_normal("#%3zu (%08lx): status: %08x cntl: %08x " 173004b7b2c1Sskrll "data: %08x next: %08x %s\n", 173104b7b2c1Sskrll i, sc->sc_rxq.r_physaddr + i * descsz, 173272645925Smartin le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1), 173304b7b2c1Sskrll le32toh(desc->ddesc_data), le32toh(desc->ddesc_next), 173404b7b2c1Sskrll sc->sc_descm->rx_is_owned_by_dev(desc) ? "" : buf); 1735426c40ceSmartin } 1736426c40ceSmartin } 1737426c40ceSmartin 1738426c40ceSmartin static void 17395158fc24Smartin dwc_dump_status(struct dwc_gmac_softc *sc) 1740bdbd5db8Smartin { 1741bdbd5db8Smartin uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 1742bdbd5db8Smartin AWIN_GMAC_MAC_INTR); 1743bdbd5db8Smartin uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 1744bdbd5db8Smartin AWIN_GMAC_DMA_STATUS); 1745bdbd5db8Smartin char buf[200]; 1746bdbd5db8Smartin 1747bdbd5db8Smartin /* print interrupt state */ 174804b7b2c1Sskrll snprintb(buf, sizeof(buf), 174904b7b2c1Sskrll "\177\20" 175004b7b2c1Sskrll "b\x1c" "GPI\0" 175104b7b2c1Sskrll "b\x1b" "GMC\0" 175204b7b2c1Sskrll "b\x1a" "GLI\0" 175304b7b2c1Sskrll "f\x17\x3" "EB\0" 175404b7b2c1Sskrll "f\x14\x3" "TPS\0" 175504b7b2c1Sskrll "f\x11\x3" "RPS\0" 17565158fc24Smartin "b\x10" "NI\0" 17575158fc24Smartin "b\x0f" "AI\0" 17585158fc24Smartin "b\x0e" "ER\0" 17595158fc24Smartin "b\x0d" "FB\0" 17605158fc24Smartin "b\x0a" "ET\0" 17615158fc24Smartin "b\x09" "RW\0" 17625158fc24Smartin "b\x08" "RS\0" 17635158fc24Smartin "b\x07" "RU\0" 17645158fc24Smartin "b\x06" "RI\0" 17655158fc24Smartin "b\x05" "UN\0" 17665158fc24Smartin "b\x04" "OV\0" 17675158fc24Smartin "b\x03" "TJ\0" 17685158fc24Smartin "b\x02" "TU\0" 17695158fc24Smartin "b\x01" "TS\0" 17705158fc24Smartin "b\x00" "TI\0" 1771bdbd5db8Smartin "\0", dma_status); 17725158fc24Smartin aprint_normal_dev(sc->sc_dev, "INTR status: %08x, DMA status: %s\n", 1773bdbd5db8Smartin status, buf); 17745158fc24Smartin } 1775bdbd5db8Smartin 17765158fc24Smartin static void 17775158fc24Smartin dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg) 17785158fc24Smartin { 17795158fc24Smartin dwc_dump_status(sc); 1780d1bd22e8Smartin dwc_gmac_dump_ffilt(sc, 1781d1bd22e8Smartin bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT)); 1782bdbd5db8Smartin dwc_gmac_dump_dma(sc); 1783bdbd5db8Smartin dwc_gmac_dump_tx_desc(sc); 1784426c40ceSmartin dwc_gmac_dump_rx_desc(sc); 1785bdbd5db8Smartin 1786a1f0cbdaSjoerg panic("%s", msg); 1787bdbd5db8Smartin } 1788d1bd22e8Smartin 1789d1bd22e8Smartin static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt) 1790d1bd22e8Smartin { 1791d1bd22e8Smartin char buf[200]; 1792d1bd22e8Smartin 1793d1bd22e8Smartin /* print filter setup */ 1794d1bd22e8Smartin snprintb(buf, sizeof(buf), "\177\20" 1795d1bd22e8Smartin "b\x1f""RA\0" 1796d1bd22e8Smartin "b\x0a""HPF\0" 1797d1bd22e8Smartin "b\x09""SAF\0" 1798d1bd22e8Smartin "b\x08""SAIF\0" 1799d1bd22e8Smartin "b\x05""DBF\0" 1800d1bd22e8Smartin "b\x04""PM\0" 1801d1bd22e8Smartin "b\x03""DAIF\0" 1802d1bd22e8Smartin "b\x02""HMC\0" 1803d1bd22e8Smartin "b\x01""HUC\0" 1804d1bd22e8Smartin "b\x00""PR\0" 1805d1bd22e8Smartin "\0", ffilt); 1806d1bd22e8Smartin aprint_normal_dev(sc->sc_dev, "FFILT: %s\n", buf); 1807d1bd22e8Smartin } 180837ad3d63Smartin #endif 1809