Module Name:    src
Committed By:   skrll
Date:           Sat Jan 21 10:30:15 UTC 2017

Modified Files:
        src/sys/dev/ic: dwc_gmac.c dwc_gmac_var.h

Log Message:
Merge from nick-nhusb - some MPification


To generate a diff of this commit:
cvs rdiff -u -r1.37 -r1.38 src/sys/dev/ic/dwc_gmac.c
cvs rdiff -u -r1.6 -r1.7 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/dev/ic/dwc_gmac.c
diff -u src/sys/dev/ic/dwc_gmac.c:1.37 src/sys/dev/ic/dwc_gmac.c:1.38
--- src/sys/dev/ic/dwc_gmac.c:1.37	Thu Dec 15 09:28:05 2016
+++ src/sys/dev/ic/dwc_gmac.c	Sat Jan 21 10:30:15 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_gmac.c,v 1.37 2016/12/15 09:28:05 ozaki-r Exp $ */
+/* $NetBSD: dwc_gmac.c,v 1.38 2017/01/21 10:30:15 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.37 2016/12/15 09:28:05 ozaki-r Exp $");
+__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.38 2017/01/21 10:30:15 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;
@@ -192,24 +201,28 @@ dwc_gmac_attach(struct dwc_gmac_softc *s
 		aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n");
 		goto fail;
 	}
-		
+
 	if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) {
 		aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n");
 		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
 	 */
 	ifp->if_softc = sc;
 	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_extflags = IFEF_START_MPSAFE;
 	ifp->if_ioctl = dwc_gmac_ioctl;
 	ifp->if_start = dwc_gmac_start;
 	ifp->if_init = dwc_gmac_init;
@@ -229,7 +242,7 @@ dwc_gmac_attach(struct dwc_gmac_softc *s
         mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
 	    MIIF_DOPAUSE);
 
-        if (LIST_EMPTY(&mii->mii_phys)) { 
+        if (LIST_EMPTY(&mii->mii_phys)) {
                 aprint_error_dev(sc->sc_dev, "no PHY found!\n");
                 ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
                 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL);
@@ -245,19 +258,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;
 
@@ -351,7 +367,7 @@ dwc_gmac_miibus_write_reg(device_t self,
 			break;
 		delay(10);
 	}
-	
+
 	mutex_exit(&sc->sc_mdio_lock);
 }
 
@@ -411,7 +427,7 @@ dwc_gmac_alloc_rx_ring(struct dwc_gmac_s
 		desc = &sc->sc_rxq.r_desc[i];
 		desc->ddesc_data = htole32(physaddr);
 		next = RX_NEXT(i);
-		desc->ddesc_next = htole32(ring->r_physaddr 
+		desc->ddesc_next = htole32(ring->r_physaddr
 		    + next * sizeof(*desc));
 		desc->ddesc_cntl = htole32(
 		    __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
@@ -439,6 +455,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 +472,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
@@ -504,7 +522,7 @@ dwc_gmac_alloc_dma_rings(struct dwc_gmac
 
 	/* and next rings to the TX side */
 	sc->sc_txq.t_desc = sc->sc_rxq.r_desc + AWGE_RX_RING_COUNT;
-	sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr + 
+	sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr +
 	    AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc);
 
 	return 0;
@@ -618,6 +636,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 +659,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
@@ -679,7 +699,7 @@ dwc_gmac_miibus_statchg(struct ifnet *if
 
 	/*
 	 * Set MII or GMII interface based on the speed
-	 * negotiated by the PHY.                                           
+	 * negotiated by the PHY.
 	 */
 	conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF);
 	conf &= ~(AWIN_GMAC_MAC_CONF_FES100|AWIN_GMAC_MAC_CONF_MIISEL
@@ -729,12 +749,24 @@ 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)
 		return 0;
 
-	dwc_gmac_stop(ifp, 0);
+	dwc_gmac_stop_locked(ifp, 0);
 
 	/*
 	 * Configure DMA burst/transfer mode and RX/TX priorities.
@@ -781,6 +813,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 +825,21 @@ static void
 dwc_gmac_start(struct ifnet *ifp)
 {
 	struct dwc_gmac_softc *sc = ifp->if_softc;
+	KASSERT(ifp->if_extflags & IFEF_START_MPSAFE);
+
+	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 +881,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,
@@ -936,24 +997,39 @@ dwc_gmac_ifflags_cb(struct ethercom *ec)
 {
 	struct ifnet *ifp = &ec->ec_if;
 	struct dwc_gmac_softc *sc = ifp->if_softc;
+	int ret = 0;
+
+	mutex_enter(sc->sc_lock);
 	int change = ifp->if_flags ^ sc->sc_if_flags;
+	sc->sc_if_flags = ifp->if_flags;
 
-	if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0)
-		return ENETRESET;
-	if ((change & IFF_PROMISC) != 0)
+	if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0) {
+		ret = ENETRESET;
+		goto out;
+	}
+	if ((change & IFF_PROMISC) != 0) {
 		dwc_gmac_setmulti(sc);
-	return 0;
+	}
+out:
+	mutex_exit(sc->sc_lock);
+
+	return ret;
 }
 
 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;
+
+	int s = splnet();
+	error = ether_ioctl(ifp, cmd, data);
 
-	s = splnet();
+#ifdef DWCGMAC_MPSAFE
+	splx(s);
+#endif
 
-	if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
+	if (error == ENETRESET) {
 		error = 0;
 		if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
 			;
@@ -962,7 +1038,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 +1048,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 +1065,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 +1114,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 +1128,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),
@@ -1142,6 +1228,7 @@ skip:
 	/* update RX pointer */
 	sc->sc_rxq.r_cur = i;
 
+	mutex_exit(&sc->sc_rxq.r_mtx);
 }
 
 /*
@@ -1166,12 +1253,12 @@ 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);
-	
+
 	if (ifp->if_flags & IFF_PROMISC) {
 		ffilt |= AWIN_GMAC_MAC_FFILT_PR;
 		goto special_filter;
@@ -1214,8 +1301,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
@@ -1233,7 +1318,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
@@ -1242,6 +1326,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.7
--- 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	Sat Jan 21 10:30:15 2017
@@ -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.7 2017/01/21 10:30:15 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*/);

Reply via email to