Make _locked variant so some things can be called locked, and
non-locked which grab it.

...  dropping splfoo around alc_stop is probably wrong, oops

drop bool parameter from alc_newbuf, alc_init_rx_ring,alt_init_locked,
because we are locked and can't sleep, assume it's false.

? alc_ioctl ?

match freebsd in lots of places.

Index: if_alc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_alc.c,v
retrieving revision 1.24
diff -u -r1.24 if_alc.c
--- if_alc.c	21 Dec 2016 11:56:55 -0000	1.24
+++ if_alc.c	19 Mar 2017 22:27:18 -0000
@@ -112,11 +112,13 @@
 static int	alc_detach(device_t, int);
 
 static int	alc_init(struct ifnet *);
-static int	alc_init_backend(struct ifnet *, bool);
+static int	alc_init_locked(struct ifnet *);
 static void	alc_start(struct ifnet *);
+static void	alc_start_locked(struct ifnet *);
 static int	alc_ioctl(struct ifnet *, u_long, void *);
 static void	alc_watchdog(struct ifnet *);
 static int	alc_mediachange(struct ifnet *);
+static int	alc_mediachange_locked(struct alc_softc *);
 static void	alc_mediastatus(struct ifnet *, struct ifmediareq *);
 
 static void	alc_aspm(struct alc_softc *, int, int);
@@ -135,7 +137,7 @@
 static void	alc_get_macaddr_par(struct alc_softc *);
 static void	alc_init_cmb(struct alc_softc *);
 static void	alc_init_rr_ring(struct alc_softc *);
-static int	alc_init_rx_ring(struct alc_softc *, bool);
+static int	alc_init_rx_ring(struct alc_softc *);
 static void	alc_init_smb(struct alc_softc *);
 static void	alc_init_tx_ring(struct alc_softc *);
 static int	alc_intr(void *);
@@ -151,7 +153,7 @@
 static void	alc_miidbg_writereg(struct alc_softc *, int, int);
 static uint32_t	alc_miiext_readreg(struct alc_softc *, int, int);
 static uint32_t	alc_miiext_writereg(struct alc_softc *, int, int, int);
-static int	alc_newbuf(struct alc_softc *, struct alc_rxdesc *, bool);
+static int	alc_newbuf(struct alc_softc *, struct alc_rxdesc *);
 static void	alc_phy_down(struct alc_softc *);
 static void	alc_phy_reset(struct alc_softc *);
 static void	alc_phy_reset_813x(struct alc_softc *);
@@ -165,6 +167,7 @@
 static void	alc_stats_clear(struct alc_softc *);
 static void	alc_stats_update(struct alc_softc *);
 static void	alc_stop(struct ifnet *, int);
+static void	alc_stop_locked(struct ifnet *, int);
 static void	alc_stop_mac(struct alc_softc *);
 static void	alc_stop_queue(struct alc_softc *);
 static void	alc_tick(void *);
@@ -525,27 +528,49 @@
 static void
 alc_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
-	struct alc_softc *sc = ifp->if_softc;
-	struct mii_data *mii = &sc->sc_miibus;
+	struct alc_softc *sc;
+	struct mii_data *mii;
 
-	if ((ifp->if_flags & IFF_UP) == 0)
+	sc = ifp->if_softc;
+	ALC_LOCK(sc);
+	if ((ifp->if_flags & IFF_UP) == 0) {
+		ALC_UNLOCK(sc);
 		return;
+	}
+	mii = &sc->sc_miibus;
 
 	mii_pollstat(mii);
 	ifmr->ifm_status = mii->mii_media_status;
 	ifmr->ifm_active = mii->mii_media_active;
+	ALC_UNLOCK(sc);
 }
 
 static int
 alc_mediachange(struct ifnet *ifp)
 {
-	struct alc_softc *sc = ifp->if_softc;
-	struct mii_data *mii = &sc->sc_miibus;
+	struct alc_softc *sc;
 	int error;
 
-	if (mii->mii_instance != 0) {
-		struct mii_softc *miisc;
+	sc = ifp->if_softc;
+	ALC_LOCK(sc);
+	error = alc_mediachange_locked(sc);
+	ALC_UNLOCK(sc);
+
+	return (error);
+}
+	
 
+static int
+alc_mediachange_locked(struct alc_softc *sc)
+{
+	struct mii_data *mii;
+	struct mii_softc *miisc;
+	int error;
+
+	ALC_LOCK_ASSERT(sc);
+
+	mii = &sc->sc_miibus;
+	if (mii->mii_instance != 0) { /* XXX freebsd doesn't test this? */
 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
 			mii_phy_reset(miisc);
 	}
@@ -1392,6 +1417,7 @@
 	if (error)
 		goto fail;
 
+	mutex_init(&sc->alc_mtx, MUTEX_DEFAULT, IPL_NET);
 	callout_init(&sc->sc_tick_ch, 0);
 	callout_setfunc(&sc->sc_tick_ch, alc_tick, sc);
 
@@ -1492,11 +1518,8 @@
 {
 	struct alc_softc *sc = device_private(self);
 	struct ifnet *ifp = &sc->sc_ec.ec_if;
-	int s;
 
-	s = splnet();
 	alc_stop(ifp, 0);
-	splx(s);
 
 	mii_detach(&sc->sc_miibus, MII_PHY_ANY, MII_OFFSET_ANY);
 
@@ -1517,6 +1540,8 @@
 		sc->sc_mem_size = 0;
 	}
 
+	mutex_destroy(&sc->alc_mtx);
+
 	return (0);
 }
 
@@ -1857,6 +1882,8 @@
 	struct m_tag *mtag;
 #endif
 
+	ALC_LOCK_ASSERT(sc);
+
 	m = *m_head;
 	cflags = vtag = 0;
 	poff = 0;
@@ -1958,9 +1985,21 @@
 alc_start(struct ifnet *ifp)
 {
 	struct alc_softc *sc = ifp->if_softc;
+
+	ALC_LOCK(sc);
+	alc_start_locked(ifp);
+	ALC_UNLOCK(sc);
+}
+
+static void
+alc_start_locked(struct ifnet *ifp)
+{
+	struct alc_softc *sc = ifp->if_softc;
 	struct mbuf *m_head;
 	int enq;
 
+	ALC_LOCK_ASSERT(sc);
+
 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
 		return;
 	if ((sc->alc_flags & ALC_FLAG_LINK) == 0)
@@ -2018,18 +2057,20 @@
 {
 	struct alc_softc *sc = ifp->if_softc;
 
+	ALC_LOCK_ASSERT(sc);
+
 	if ((sc->alc_flags & ALC_FLAG_LINK) == 0) {
 		printf("%s: watchdog timeout (missed link)\n",
 		    device_xname(sc->sc_dev));
 		ifp->if_oerrors++;
-		alc_init_backend(ifp, false);
+		alc_init_locked(ifp);
 		return;
 	}
 
 	printf("%s: watchdog timeout\n", device_xname(sc->sc_dev));
 	ifp->if_oerrors++;
-	alc_init_backend(ifp, false);
-	alc_start(ifp);
+	alc_init_locked(ifp);
+	alc_start_locked(ifp);
 }
 
 static int
@@ -2038,9 +2079,7 @@
 	struct alc_softc *sc = ifp->if_softc;
 	struct mii_data *mii = &sc->sc_miibus;
 	struct ifreq *ifr = (struct ifreq *)data;
-	int s, error = 0;
-
-	s = splnet();
+	int error = 0;
 
 	error = ether_ioctl(ifp, cmd, data);
 	switch (cmd) {
@@ -2078,7 +2117,6 @@
 		error = 0;
 	}
 
-	splx(s);
 	return (error);
 }
 
@@ -2266,10 +2304,14 @@
 	struct alc_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_ec.ec_if;
 	uint32_t status;
+	int out;
 
 	status = CSR_READ_4(sc, ALC_INTR_STATUS);
-	if ((status & ALC_INTRS) == 0)
-		return (0);
+	ALC_LOCK(sc);
+	if ((status & ALC_INTRS) == 0) {
+		out = 0;
+		goto done;
+	}
 
 	/* Acknowledge and disable interrupts. */
 	CSR_WRITE_4(sc, ALC_INTR_STATUS, status | INTR_DIS_INT);
@@ -2280,8 +2322,9 @@
 
 			error = alc_rxintr(sc);
 			if (error) {
-				alc_init_backend(ifp, false);
-				return (0);
+				alc_init_locked(ifp);
+				out = 0;
+				goto done;
 			}
 		}
 
@@ -2296,17 +2339,23 @@
 			if (status & INTR_TXQ_TO_RST)
 				printf("%s: TxQ reset! -- resetting\n",
 				    device_xname(sc->sc_dev));
-			alc_init_backend(ifp, false);
-			return (0);
+			alc_init_locked(ifp);
+			out = 0;
+			goto done;
 		}
 
 		alc_txeof(sc);
 		if_schedule_deferred_start(ifp);
 	}
 
-	/* Re-enable interrupts. */
-	CSR_WRITE_4(sc, ALC_INTR_STATUS, 0x7FFFFFFF);
-	return (1);
+	out = 1;
+done:
+	if ((ifp->if_flags & IFF_RUNNING) != 0) {
+		/* Re-enable interrupts if we're running. */
+		CSR_WRITE_4(sc, ALC_INTR_STATUS, 0x7FFFFFFF);
+	}
+	ALC_UNLOCK(sc);
+	return out;
 }
 
 static void
@@ -2368,16 +2417,16 @@
 }
 
 static int
-alc_newbuf(struct alc_softc *sc, struct alc_rxdesc *rxd, bool init)
+alc_newbuf(struct alc_softc *sc, struct alc_rxdesc *rxd)
 {
 	struct mbuf *m;
 	bus_dmamap_t map;
 	int error;
 
-	MGETHDR(m, init ? M_WAITOK : M_DONTWAIT, MT_DATA);
+	MGETHDR(m, M_DONTWAIT, MT_DATA);
 	if (m == NULL)
 		return (ENOBUFS);
-	MCLGET(m, init ? M_WAITOK : M_DONTWAIT);
+	MCLGET(m, M_DONTWAIT);
 	if (!(m->m_flags & M_EXT)) {
 		m_freem(m);
 		return (ENOBUFS);
@@ -2391,8 +2440,8 @@
 	if (error != 0) {
 		m_freem(m);
 
-		if (init)
-			printf("%s: can't load RX mbuf\n", device_xname(sc->sc_dev));
+		aprint_error_dev(sc->sc_dev, "%s: can't load RX mbuf\n",
+		    device_xname(sc->sc_dev));
 
 		return (error);
 	}
@@ -2520,7 +2569,7 @@
 		rxd = &sc->alc_cdata.alc_rxdesc[rx_cons];
 		mp = rxd->rx_m;
 		/* Add a new receive buffer to the ring. */
-		if (alc_newbuf(sc, rxd, false) != 0) {
+		if (alc_newbuf(sc, rxd) != 0) {
 			ifp->if_iqdrops++;
 			/* Reuse Rx buffers. */
 			if (sc->alc_cdata.alc_rxhead != NULL)
@@ -2599,14 +2648,15 @@
 {
 	struct alc_softc *sc = xsc;
 	struct mii_data *mii = &sc->sc_miibus;
-	int s;
 
-	s = splnet();
+	ALC_LOCK(sc);
+
 	mii_tick(mii);
 	alc_stats_update(sc);
-	splx(s);
 
 	callout_schedule(&sc->sc_tick_ch, hz);
+
+	ALC_UNLOCK(sc);
 }
 
 static void
@@ -2736,12 +2786,17 @@
 static int
 alc_init(struct ifnet *ifp)
 {
+	struct alc_softc *sc = ifp->if_softc;
+
+	ALC_LOCK(sc);
+	int err = alc_init_locked(ifp);
+	ALC_UNLOCK(sc);
 
-	return alc_init_backend(ifp, true);
+	return err;
 }
 
 static int
-alc_init_backend(struct ifnet *ifp, bool init)
+alc_init_locked(struct ifnet *ifp)
 {
 	struct alc_softc *sc = ifp->if_softc;
 	struct mii_data *mii;
@@ -2750,20 +2805,22 @@
 	uint32_t reg, rxf_hi, rxf_lo;
 	int error;
 
+	ALC_LOCK_ASSERT(sc);
+
 	/*
 	 * Cancel any pending I/O.
 	 */
-	alc_stop(ifp, 0);
+	alc_stop_locked(ifp, 0);
 	/*
 	 * Reset the chip to a known state.
 	 */
 	alc_reset(sc);
 
 	/* Initialize Rx descriptors. */
-	error = alc_init_rx_ring(sc, init);
+	error = alc_init_rx_ring(sc);
 	if (error != 0) {
 		printf("%s: no memory for Rx buffers.\n", device_xname(sc->sc_dev));
-		alc_stop(ifp, 0);
+		alc_stop_locked(ifp, 0);
 		return (error);
 	}
 	alc_init_rr_ring(sc);
@@ -3130,11 +3187,22 @@
 alc_stop(struct ifnet *ifp, int disable)
 {
 	struct alc_softc *sc = ifp->if_softc;
+
+	ALC_LOCK(sc);
+	alc_stop_locked(ifp, disable);
+	ALC_UNLOCK(sc);
+}
+
+static void
+alc_stop_locked(struct ifnet *ifp, int disable)
+{
+	struct alc_softc *sc = ifp->if_softc;
 	struct alc_txdesc *txd;
 	struct alc_rxdesc *rxd;
 	uint32_t reg;
 	int i;
 
+	ALC_LOCK_ASSERT(sc);
 	callout_stop(&sc->sc_tick_ch);
 
 	/*
@@ -3308,7 +3376,7 @@
 }
 
 static int
-alc_init_rx_ring(struct alc_softc *sc, bool init)
+alc_init_rx_ring(struct alc_softc *sc)
 {
 	struct alc_ring_data *rd;
 	struct alc_rxdesc *rxd;
@@ -3321,7 +3389,7 @@
 		rxd = &sc->alc_cdata.alc_rxdesc[i];
 		rxd->rx_m = NULL;
 		rxd->rx_desc = &rd->alc_rx_ring[i];
-		if (alc_newbuf(sc, rxd, init) != 0)
+		if (alc_newbuf(sc, rxd) != 0)
 			return (ENOBUFS);
 	}
 
Index: if_alcreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_alcreg.h,v
retrieving revision 1.6
diff -u -r1.6 if_alcreg.h
--- if_alcreg.h	29 Dec 2016 19:22:51 -0000	1.6
+++ if_alcreg.h	19 Mar 2017 22:27:18 -0000
@@ -1484,6 +1484,7 @@
 	int			alc_int_rx_mod;
 	int			alc_int_tx_mod;
 	int			alc_buf_size;
+	kmutex_t		alc_mtx;
 };
 
 /* Register access macros. */
@@ -1514,4 +1515,8 @@
 /* For compatibility with FreeBSD */
 #define IFM_UNKNOWN		31
 
+#define ALC_LOCK(_sc) mutex_enter(&(_sc)->alc_mtx)
+#define ALC_UNLOCK(_sc) mutex_exit(&(_sc)->alc_mtx)
+#define ALC_LOCK_ASSERT(_sc) KASSERT(mutex_owned(&(_sc)->alc_mtx))
+
 #endif	/* _IF_ALCREG_H */
