Module Name: src Committed By: skrll Date: Sun Jun 12 07:18:52 UTC 2016
Modified Files: src/sys/arch/arm/allwinner [nick-nhusb]: awin_gige.c src/sys/arch/arm/amlogic [nick-nhusb]: amlogic_gmac.c src/sys/dev/ic [nick-nhusb]: dwc_gmac.c dwc_gmac_var.h Log Message: First pass at making this driver and attachments NET_MPSAFE aware. I've not tested this yet. To generate a diff of this commit: cvs rdiff -u -r1.19.2.1 -r1.19.2.2 src/sys/arch/arm/allwinner/awin_gige.c cvs rdiff -u -r1.2.4.2 -r1.2.4.3 src/sys/arch/arm/amlogic/amlogic_gmac.c cvs rdiff -u -r1.28.2.3 -r1.28.2.4 src/sys/dev/ic/dwc_gmac.c cvs rdiff -u -r1.6 -r1.6.2.1 src/sys/dev/ic/dwc_gmac_var.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/allwinner/awin_gige.c diff -u src/sys/arch/arm/allwinner/awin_gige.c:1.19.2.1 src/sys/arch/arm/allwinner/awin_gige.c:1.19.2.2 --- src/sys/arch/arm/allwinner/awin_gige.c:1.19.2.1 Mon Apr 6 15:17:51 2015 +++ src/sys/arch/arm/allwinner/awin_gige.c Sun Jun 12 07:18:52 2016 @@ -34,7 +34,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: awin_gige.c,v 1.19.2.1 2015/04/06 15:17:51 skrll Exp $"); +__KERNEL_RCSID(1, "$NetBSD: awin_gige.c,v 1.19.2.2 2016/06/12 07:18:52 skrll Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -153,7 +153,11 @@ awin_gige_attach(device_t parent, device /* * Interrupt handler */ - sc->sc_ih = intr_establish(loc->loc_intr, IPL_NET, IST_LEVEL, + int mpsafe = 0; +#ifdef NET_MPSAFE + mpsafe |= IST_MPSAFE; +#endif + sc->sc_ih = intr_establish(loc->loc_intr, IPL_NET, IST_LEVEL | mpsafe, awin_gige_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "failed to establish interrupt %d\n", Index: src/sys/arch/arm/amlogic/amlogic_gmac.c diff -u src/sys/arch/arm/amlogic/amlogic_gmac.c:1.2.4.2 src/sys/arch/arm/amlogic/amlogic_gmac.c:1.2.4.3 --- src/sys/arch/arm/amlogic/amlogic_gmac.c:1.2.4.2 Mon Apr 6 15:17:51 2015 +++ src/sys/arch/arm/amlogic/amlogic_gmac.c Sun Jun 12 07:18:52 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: amlogic_gmac.c,v 1.2.4.2 2015/04/06 15:17:51 skrll Exp $ */ +/* $NetBSD: amlogic_gmac.c,v 1.2.4.3 2016/06/12 07:18:52 skrll Exp $ */ /*- * Copyright (c) 2013, 2014, 2015 The NetBSD Foundation, Inc. @@ -33,7 +33,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: amlogic_gmac.c,v 1.2.4.2 2015/04/06 15:17:51 skrll Exp $"); +__KERNEL_RCSID(1, "$NetBSD: amlogic_gmac.c,v 1.2.4.3 2016/06/12 07:18:52 skrll Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -92,7 +92,11 @@ amlogic_gmac_attach(device_t parent, dev /* * Interrupt handler */ - sc->sc_ih = intr_establish(loc->loc_intr, IPL_NET, IST_EDGE, + int mpsafe = 0; +#ifdef NET_MPSAFE + mpsafe |= IST_MPSAFE; +#endif + sc->sc_ih = intr_establish(loc->loc_intr, IPL_NET, IST_EDGE | mpsafe, amlogic_gmac_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "failed to establish interrupt %d\n", Index: src/sys/dev/ic/dwc_gmac.c diff -u src/sys/dev/ic/dwc_gmac.c:1.28.2.3 src/sys/dev/ic/dwc_gmac.c:1.28.2.4 --- src/sys/dev/ic/dwc_gmac.c:1.28.2.3 Sat Mar 19 11:30:09 2016 +++ src/sys/dev/ic/dwc_gmac.c Sun Jun 12 07:18:52 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: dwc_gmac.c,v 1.28.2.3 2016/03/19 11:30:09 skrll Exp $ */ +/* $NetBSD: dwc_gmac.c,v 1.28.2.4 2016/06/12 07:18:52 skrll Exp $ */ /*- * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. @@ -41,11 +41,14 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.28.2.3 2016/03/19 11:30:09 skrll Exp $"); +__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.28.2.4 2016/06/12 07:18:52 skrll Exp $"); /* #define DWC_GMAC_DEBUG 1 */ +#ifdef _KERNEL_OPT #include "opt_inet.h" +#include "opt_net_mpsafe.h" +#endif #include <sys/param.h> #include <sys/bus.h> @@ -85,8 +88,11 @@ static void dwc_gmac_reset_tx_ring(struc static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *); static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops); static int dwc_gmac_init(struct ifnet *ifp); +static int dwc_gmac_init_locked(struct ifnet *ifp); static void dwc_gmac_stop(struct ifnet *ifp, int disable); +static void dwc_gmac_stop_locked(struct ifnet *ifp, int disable); static void dwc_gmac_start(struct ifnet *ifp); +static void dwc_gmac_start_locked(struct ifnet *ifp); static int dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0); static int dwc_gmac_ioctl(struct ifnet *, u_long, void *); static void dwc_gmac_tx_intr(struct dwc_gmac_softc *sc); @@ -128,6 +134,10 @@ static void dwc_dump_status(struct dwc_g static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt); #endif +#ifdef NET_MPSAFE +#define DWCGMAC_MPSAFE 1 +#endif + void dwc_gmac_attach(struct dwc_gmac_softc *sc, uint32_t mii_clk) { @@ -136,7 +146,6 @@ dwc_gmac_attach(struct dwc_gmac_softc *s struct mii_data * const mii = &sc->sc_mii; struct ifnet * const ifp = &sc->sc_ec.ec_if; prop_dictionary_t dict; - int s; mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET); sc->sc_mii_clk = mii_clk & 7; @@ -198,12 +207,15 @@ dwc_gmac_attach(struct dwc_gmac_softc *s goto fail; } - mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET); if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) { aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n"); goto fail; } + sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET); + mutex_init(&sc->sc_txq.t_mtx, MUTEX_DEFAULT, IPL_NET); + mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET); + /* * Prepare interface data */ @@ -245,19 +257,22 @@ dwc_gmac_attach(struct dwc_gmac_softc *s /* * Ready, attach interface */ - if_attach(ifp); + /* Attach the interface. */ + if_initialize(ifp); + sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if); ether_ifattach(ifp, enaddr); ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb); + if_register(ifp); /* * Enable interrupts */ - s = splnet(); + mutex_enter(sc->sc_lock); bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK, AWIN_DEF_MAC_INTRMASK); bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE, GMAC_DEF_DMA_INT_MASK); - splx(s); + mutex_exit(sc->sc_lock); return; @@ -439,6 +454,7 @@ dwc_gmac_reset_rx_ring(struct dwc_gmac_s struct dwc_gmac_dev_dmadesc *desc; int i; + mutex_enter(&ring->r_mtx); for (i = 0; i < AWGE_RX_RING_COUNT; i++) { desc = &sc->sc_rxq.r_desc[i]; desc->ddesc_cntl = htole32( @@ -455,6 +471,7 @@ dwc_gmac_reset_rx_ring(struct dwc_gmac_s /* reset DMA address to start of ring */ bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, sc->sc_rxq.r_physaddr); + mutex_exit(&ring->r_mtx); } static int @@ -618,6 +635,7 @@ dwc_gmac_reset_tx_ring(struct dwc_gmac_s { int i; + mutex_enter(&ring->t_mtx); for (i = 0; i < AWGE_TX_RING_COUNT; i++) { struct dwc_gmac_tx_data *data = &ring->t_data[i]; @@ -640,6 +658,7 @@ dwc_gmac_reset_tx_ring(struct dwc_gmac_s ring->t_queued = 0; ring->t_cur = ring->t_next = 0; + mutex_exit(&ring->t_mtx); } static void @@ -729,6 +748,18 @@ static int dwc_gmac_init(struct ifnet *ifp) { struct dwc_gmac_softc *sc = ifp->if_softc; + + mutex_enter(sc->sc_lock); + int ret = dwc_gmac_init_locked(ifp); + mutex_exit(sc->sc_lock); + + return ret; +} + +static int +dwc_gmac_init_locked(struct ifnet *ifp) +{ + struct dwc_gmac_softc *sc = ifp->if_softc; uint32_t ffilt; if (ifp->if_flags & IFF_RUNNING) @@ -781,6 +812,8 @@ dwc_gmac_init(struct ifnet *ifp) AWIN_GMAC_DMA_OPMODE, GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART | GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD); + sc->sc_stopping = false; + ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; @@ -791,6 +824,20 @@ static void dwc_gmac_start(struct ifnet *ifp) { struct dwc_gmac_softc *sc = ifp->if_softc; + + mutex_enter(sc->sc_lock); + if (!sc->sc_stopping) { + mutex_enter(&sc->sc_txq.t_mtx); + dwc_gmac_start_locked(ifp); + mutex_exit(&sc->sc_txq.t_mtx); + } + mutex_exit(sc->sc_lock); +} + +static void +dwc_gmac_start_locked(struct ifnet *ifp) +{ + struct dwc_gmac_softc *sc = ifp->if_softc; int old = sc->sc_txq.t_queued; int start = sc->sc_txq.t_cur; struct mbuf *m0; @@ -832,6 +879,18 @@ dwc_gmac_stop(struct ifnet *ifp, int dis { struct dwc_gmac_softc *sc = ifp->if_softc; + mutex_enter(sc->sc_lock); + dwc_gmac_stop_locked(ifp, disable); + mutex_exit(sc->sc_lock); +} + +static void +dwc_gmac_stop_locked(struct ifnet *ifp, int disable) +{ + struct dwc_gmac_softc *sc = ifp->if_softc; + + sc->sc_stopping = true; + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE, bus_space_read_4(sc->sc_bst, sc->sc_bsh, @@ -940,8 +999,11 @@ dwc_gmac_ifflags_cb(struct ethercom *ec) if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0) return ENETRESET; - if ((change & IFF_PROMISC) != 0) + if ((change & IFF_PROMISC) != 0) { + mutex_enter(sc->sc_lock); dwc_gmac_setmulti(sc); + mutex_exit(sc->sc_lock); + } return 0; } @@ -949,11 +1011,16 @@ static int dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data) { struct dwc_gmac_softc *sc = ifp->if_softc; - int s, error = 0; + int error = 0; - s = splnet(); + int s = splnet(); + error = ether_ioctl(ifp, cmd, data); - if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { +#ifdef DWCGMAC_MPSAFE + splx(s); +#endif + + if (error == ENETRESET) { error = 0; if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) ; @@ -962,7 +1029,9 @@ dwc_gmac_ioctl(struct ifnet *ifp, u_long * Multicast list has changed; set the hardware filter * accordingly. */ + mutex_enter(sc->sc_lock); dwc_gmac_setmulti(sc); + mutex_exit(sc->sc_lock); } } @@ -970,7 +1039,11 @@ dwc_gmac_ioctl(struct ifnet *ifp, u_long if (ifp->if_flags & IFF_UP) dwc_gmac_start(ifp); sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; + +#ifndef DWCGMAC_MPSAFE splx(s); +#endif + return error; } @@ -983,6 +1056,8 @@ dwc_gmac_tx_intr(struct dwc_gmac_softc * uint32_t status; int i, nsegs; + mutex_enter(&sc->sc_txq.t_mtx); + for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) { #ifdef DWC_GMAC_DEBUG aprint_normal_dev(sc->sc_dev, @@ -1030,6 +1105,7 @@ dwc_gmac_tx_intr(struct dwc_gmac_softc * if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) { ifp->if_flags &= ~IFF_OACTIVE; } + mutex_exit(&sc->sc_txq.t_mtx); } static void @@ -1043,6 +1119,7 @@ dwc_gmac_rx_intr(struct dwc_gmac_softc * struct mbuf *m, *mnew; int i, len, error; + mutex_enter(&sc->sc_rxq.r_mtx); for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) { bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, RX_DESC_OFFSET(i), sizeof(*desc), @@ -1098,7 +1175,7 @@ dwc_gmac_rx_intr(struct dwc_gmac_softc * error = bus_dmamap_load(sc->sc_dmat, data->rd_map, mtod(mnew, void*), MCLBYTES, NULL, BUS_DMA_READ | BUS_DMA_NOWAIT); - if (error != 0) { + if (error != 0) { m_freem(mnew); /* try to reload old mbuf */ error = bus_dmamap_load(sc->sc_dmat, data->rd_map, @@ -1125,10 +1202,15 @@ dwc_gmac_rx_intr(struct dwc_gmac_softc * m->m_pkthdr.rcvif = ifp; m->m_flags |= M_HASFCS; - bpf_mtap(ifp, m); ifp->if_ipackets++; + + mutex_exit(&sc->sc_rxq.r_mtx); + + bpf_mtap(ifp, m); if_percpuq_enqueue(ifp->if_percpuq, m); + mutex_enter(&sc->sc_rxq.r_mtx); + skip: bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); @@ -1144,6 +1226,7 @@ skip: /* update RX pointer */ sc->sc_rxq.r_cur = i; + mutex_exit(&sc->sc_rxq.r_mtx); } /* @@ -1168,9 +1251,9 @@ dwc_gmac_setmulti(struct dwc_gmac_softc struct ether_multistep step; uint32_t hashes[2] = { 0, 0 }; uint32_t ffilt, h; - int mcnt, s; + int mcnt; - s = splnet(); + KASSERT(mutex_owned(sc->sc_lock)); ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); @@ -1216,8 +1299,6 @@ dwc_gmac_setmulti(struct dwc_gmac_softc hashes[1]); sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; - splx(s); - #ifdef DWC_GMAC_DEBUG dwc_gmac_dump_ffilt(sc, ffilt); #endif @@ -1235,7 +1316,6 @@ special_filter: bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0xffffffff); sc->sc_if_flags = sc->sc_ec.ec_if.if_flags; - splx(s); } int @@ -1244,6 +1324,9 @@ dwc_gmac_intr(struct dwc_gmac_softc *sc) uint32_t status, dma_status; int rv = 0; + if (sc->sc_stopping) + return 0; + status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR); if (status & AWIN_GMAC_MII_IRQ) { (void)bus_space_read_4(sc->sc_bst, sc->sc_bsh, Index: src/sys/dev/ic/dwc_gmac_var.h diff -u src/sys/dev/ic/dwc_gmac_var.h:1.6 src/sys/dev/ic/dwc_gmac_var.h:1.6.2.1 --- src/sys/dev/ic/dwc_gmac_var.h:1.6 Sat Nov 22 18:31:03 2014 +++ src/sys/dev/ic/dwc_gmac_var.h Sun Jun 12 07:18:52 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: dwc_gmac_var.h,v 1.6 2014/11/22 18:31:03 jmcneill Exp $ */ +/* $NetBSD: dwc_gmac_var.h,v 1.6.2.1 2016/06/12 07:18:52 skrll Exp $ */ /*- * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. @@ -64,6 +64,7 @@ struct dwc_gmac_tx_ring { struct dwc_gmac_dev_dmadesc *t_desc; /* VA of TX ring start */ struct dwc_gmac_tx_data t_data[AWGE_TX_RING_COUNT]; int t_cur, t_next, t_queued; + kmutex_t t_mtx; }; struct dwc_gmac_rx_ring { @@ -88,6 +89,11 @@ struct dwc_gmac_softc { struct dwc_gmac_tx_ring sc_txq; short sc_if_flags; /* shadow of ether flags */ uint16_t sc_mii_clk; + bool sc_stopping; + + kmutex_t *sc_lock; /* lock for softc operations */ + + struct if_percpuq *sc_ipq; /* softint-based input queues */ }; void dwc_gmac_attach(struct dwc_gmac_softc*, uint32_t /*mii_clk*/);