Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 05 Sep 2005 13:07:43 +0100
From:      Gavin Atkinson <gavin.atkinson@ury.york.ac.uk>
To:        John Baldwin <jhb@freebsd.org>
Cc:        current@freebsd.org
Subject:   Re: [PATCH] Locking fixes for tl(4)
Message-ID:  <1125922064.75892.20.camel@buffy.york.ac.uk>
In-Reply-To: <20050904235509.J31032@ury.york.ac.uk>
References:  <200508311636.49278.jhb@FreeBSD.org> <20050904234626.H31032@ury.york.ac.uk> <20050904235509.J31032@ury.york.ac.uk>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
On Mon, 2005-09-05 at 00:01 +0100, Gavin Atkinson wrote:
> On Sun, 4 Sep 2005, Gavin Atkinson wrote:
> > On Wed, 31 Aug 2005, John Baldwin wrote:
> >
> >> Patch fixes locking for tl(4) and marks it MPSAFE.  Please test, thanks!
> >> 
> >> http://www.FreeBSD.org/~jhb/patches/tl_locking.patch
> >
> > Doesn't work, I'm afraid.  Panic on attach:
> 
> ... because tl_hardreset() is called before sc->tl_ifp is allocated.  I'm 
> recompiling now, having moved the if_alloc and related code to before the 
> first hardreset() call.

The attached patch has survived pan average amount of network activity
overnight.  It's basically your original patch, but with a slight
rearrangement in tl_attach() to move the if_alloc() call earlier.

Gavin

[-- Attachment #2 --]
Index: src/sys/pci/if_tl.c
===================================================================
RCS file: /usr/cvs/src/sys/pci/if_tl.c,v
retrieving revision 1.101
diff -u -r1.101 if_tl.c
--- src/sys/pci/if_tl.c	9 Aug 2005 10:20:02 -0000	1.101
+++ src/sys/pci/if_tl.c	5 Sep 2005 07:52:03 -0000
@@ -276,8 +276,10 @@
 
 static void tl_intr(void *);
 static void tl_start(struct ifnet *);
+static void tl_start_locked(struct ifnet *);
 static int tl_ioctl(struct ifnet *, u_long, caddr_t);
 static void tl_init(void *);
+static void tl_init_locked(struct tl_softc *);
 static void tl_stop(struct tl_softc *);
 static void tl_watchdog(struct ifnet *);
 static void tl_shutdown(device_t);
@@ -650,7 +652,8 @@
 	int			i, ack;
 	int			minten = 0;
 
-	TL_LOCK(sc);
+	if (sc->tl_ifp->if_input != NULL)
+		TL_LOCK_ASSERT(sc);
 
 	tl_mii_sync(sc);
 
@@ -730,8 +733,6 @@
 		tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN);
 	}
 
-	TL_UNLOCK(sc);
-
 	if (ack)
 		return(1);
 	return(0);
@@ -745,7 +746,8 @@
 {
 	int			minten;
 
-	TL_LOCK(sc);
+	if (sc->tl_ifp->if_input != NULL)
+		TL_LOCK_ASSERT(sc);
 
 	tl_mii_sync(sc);
 
@@ -789,8 +791,6 @@
 	if (minten)
 		tl_dio_setbit(sc, TL_NETSIO, TL_SIO_MINTEN);
 
-	TL_UNLOCK(sc);
-
 	return(0);
 }
 
@@ -840,7 +840,8 @@
 	struct mii_data		*mii;
 
 	sc = device_get_softc(dev);
-	TL_LOCK(sc);
+	if (sc->tl_ifp->if_input != NULL)
+		TL_LOCK_ASSERT(sc);
 	mii = device_get_softc(sc->tl_miibus);
 
 	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
@@ -848,7 +849,6 @@
 	} else {
 		tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_DUPLEX);
 	}
-	TL_UNLOCK(sc);
 
 	return;
 }
@@ -1138,7 +1138,7 @@
 	}
 
 	mtx_init(&sc->tl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
-	    MTX_DEF | MTX_RECURSE);
+	    MTX_DEF);
 
 	/*
 	 * Map control/status registers.
@@ -1223,6 +1223,13 @@
 	if (t->tl_vid == OLICOM_VENDORID)
 		sc->tl_eeaddr = TL_EEPROM_EADDR_OC;
 
+	ifp = sc->tl_ifp = if_alloc(IFT_ETHER);
+	if (ifp == NULL) {
+		device_printf(dev, "can not if_alloc()\n");
+		error = ENOSPC;
+		goto fail;
+	}
+
 	/* Reset the adapter. */
 	tl_softreset(sc, 1);
 	tl_hardreset(dev);
@@ -1234,6 +1241,7 @@
 	if (tl_read_eeprom(sc, eaddr, sc->tl_eeaddr, ETHER_ADDR_LEN)) {
 		device_printf(dev, "failed to read station address\n");
 		error = ENXIO;
+		if_free(ifp);
 		goto fail;
 	}
 
@@ -1259,23 +1267,16 @@
                 }
         }
 
-	ifp = sc->tl_ifp = if_alloc(IFT_ETHER);
-	if (ifp == NULL) {
-		device_printf(dev, "can not if_alloc()\n");
-		error = ENOSPC;
-		goto fail;
-	}
 	ifp->if_softc = sc;
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
-	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
-	    IFF_NEEDSGIANT;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = tl_ioctl;
 	ifp->if_start = tl_start;
 	ifp->if_watchdog = tl_watchdog;
 	ifp->if_init = tl_init;
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_snd.ifq_maxlen = TL_TX_LIST_CNT - 1;
-	callout_handle_init(&sc->tl_stat_ch);
+	callout_init_mtx(&sc->tl_stat_callout, &sc->tl_mtx, 0);
 
 	/* Reset the adapter again. */
 	tl_softreset(sc, 1);
@@ -1310,7 +1311,7 @@
 	ether_ifattach(ifp, eaddr);
 
 	/* Hook interrupt last to avoid having to lock softc */
-	error = bus_setup_intr(dev, sc->tl_irq, INTR_TYPE_NET,
+	error = bus_setup_intr(dev, sc->tl_irq, INTR_TYPE_NET | INTR_MPSAFE,
 	    tl_intr, sc, &sc->tl_intrhand);
 
 	if (error) {
@@ -1343,12 +1344,14 @@
 
 	sc = device_get_softc(dev);
 	KASSERT(mtx_initialized(&sc->tl_mtx), ("tl mutex not initialized"));
-	TL_LOCK(sc);
 	ifp = sc->tl_ifp;
 
 	/* These should only be active if attach succeeded */
 	if (device_is_attached(dev)) {
+		TL_LOCK(sc);
 		tl_stop(sc);
+		TL_UNLOCK(sc);
+		callout_drain(&sc->tl_stat_callout);
 		ether_ifdetach(ifp);
 		if_free(ifp);
 	}
@@ -1368,7 +1371,6 @@
 	if (sc->tl_res)
 		bus_release_resource(dev, TL_RES, TL_RID, sc->tl_res);
 
-	TL_UNLOCK(sc);
 	mtx_destroy(&sc->tl_mtx);
 
 	return(0);
@@ -1444,16 +1446,10 @@
 {
 	struct mbuf		*m_new = NULL;
 
-	MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+	m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
 	if (m_new == NULL)
 		return(ENOBUFS);
 
-	MCLGET(m_new, M_DONTWAIT);
-	if (!(m_new->m_flags & M_EXT)) {
-		m_freem(m_new);
-		return(ENOBUFS);
-	}
-
 #ifdef __alpha__
 	m_new->m_data += 2;
 #endif
@@ -1691,7 +1687,7 @@
 
 	tl_softreset(sc, 1);
 	tl_stop(sc);
-	tl_init(sc);
+	tl_init_locked(sc);
 	CMD_SET(sc, TL_CMD_INTSON);
 
 	return(0);
@@ -1784,7 +1780,7 @@
 	}
 
 	if (ifp->if_snd.ifq_head != NULL)
-		tl_start(ifp);
+		tl_start_locked(ifp);
 
 	TL_UNLOCK(sc);
 
@@ -1804,7 +1800,7 @@
 	bzero((char *)&tl_stats, sizeof(struct tl_stats));
 
 	sc = xsc;
-	TL_LOCK(sc);
+	TL_LOCK_ASSERT(sc);
 	ifp = sc->tl_ifp;
 
 	p = (u_int32_t *)&tl_stats;
@@ -1838,15 +1834,13 @@
 		}
 	}
 
-	sc->tl_stat_ch = timeout(tl_stats_update, sc, hz);
+	callout_reset(&sc->tl_stat_callout, hz, tl_stats_update, sc);
 
 	if (!sc->tl_bitrate) {
 		mii = device_get_softc(sc->tl_miibus);
 		mii_tick(mii);
 	}
 
-	TL_UNLOCK(sc);
-
 	return;
 }
 
@@ -1957,12 +1951,24 @@
 	struct ifnet		*ifp;
 {
 	struct tl_softc		*sc;
+
+	sc = ifp->if_softc;
+	TL_LOCK(sc);
+	tl_start_locked(ifp);
+	TL_UNLOCK(sc);
+}
+
+static void
+tl_start_locked(ifp)
+	struct ifnet		*ifp;
+{
+	struct tl_softc		*sc;
 	struct mbuf		*m_head = NULL;
 	u_int32_t		cmd;
 	struct tl_chain		*prev = NULL, *cur_tx = NULL, *start_tx;
 
 	sc = ifp->if_softc;
-	TL_LOCK(sc);
+	TL_LOCK_ASSERT(sc);
 
 	/*
 	 * Check for an available queue slot. If there are none,
@@ -1970,7 +1976,6 @@
 	 */
 	if (sc->tl_cdata.tl_tx_free == NULL) {
 		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
-		TL_UNLOCK(sc);
 		return;
 	}
 
@@ -2007,10 +2012,8 @@
 	/*
 	 * If there are no packets queued, bail.
 	 */
-	if (cur_tx == NULL) {
-		TL_UNLOCK(sc);
+	if (cur_tx == NULL)
 		return;
-	}
 
 	/*
 	 * That's all we can stands, we can't stands no more.
@@ -2040,7 +2043,6 @@
 	 * Set a timeout in case the chip goes out to lunch.
 	 */
 	ifp->if_timer = 5;
-	TL_UNLOCK(sc);
 
 	return;
 }
@@ -2050,10 +2052,20 @@
 	void			*xsc;
 {
 	struct tl_softc		*sc = xsc;
+
+	TL_LOCK(sc);
+	tl_init_locked(sc);
+	TL_UNLOCK(sc);
+}
+
+static void
+tl_init_locked(sc)
+	struct tl_softc		*sc;
+{
 	struct ifnet		*ifp = sc->tl_ifp;
 	struct mii_data		*mii;
 
-	TL_LOCK(sc);
+	TL_LOCK_ASSERT(sc);
 
 	ifp = sc->tl_ifp;
 
@@ -2098,7 +2110,6 @@
 		if_printf(ifp,
 		    "initialization failed: no memory for rx buffers\n");
 		tl_stop(sc);
-		TL_UNLOCK(sc);
 		return;
 	}
 
@@ -2128,8 +2139,7 @@
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
 	/* Start the stats update counter */
-	sc->tl_stat_ch = timeout(tl_stats_update, sc, hz);
-	TL_UNLOCK(sc);
+	callout_reset(&sc->tl_stat_callout, hz, tl_stats_update, sc);
 
 	return;
 }
@@ -2146,12 +2156,14 @@
 
 	sc = ifp->if_softc;
 
+	TL_LOCK(sc);
 	if (sc->tl_bitrate)
 		tl_setmode(sc, sc->ifmedia.ifm_media);
 	else {
 		mii = device_get_softc(sc->tl_miibus);
 		mii_mediachg(mii);
 	}
+	TL_UNLOCK(sc);
 
 	return(0);
 }
@@ -2169,6 +2181,7 @@
 
 	sc = ifp->if_softc;
 
+	TL_LOCK(sc);
 	ifmr->ifm_active = IFM_ETHER;
 
 	if (sc->tl_bitrate) {
@@ -2187,6 +2200,7 @@
 		ifmr->ifm_active = mii->mii_media_active;
 		ifmr->ifm_status = mii->mii_media_status;
 	}
+	TL_UNLOCK(sc);
 
 	return;
 }
@@ -2199,12 +2213,11 @@
 {
 	struct tl_softc		*sc = ifp->if_softc;
 	struct ifreq		*ifr = (struct ifreq *) data;
-	int			s, error = 0;
-
-	s = splimp();
+	int			error = 0;
 
 	switch(command) {
 	case SIOCSIFFLAGS:
+		TL_LOCK(sc);
 		if (ifp->if_flags & IFF_UP) {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
 			    ifp->if_flags & IFF_PROMISC &&
@@ -2217,18 +2230,21 @@
 				tl_dio_clrbit(sc, TL_NETCMD, TL_CMD_CAF);
 				tl_setmulti(sc);
 			} else
-				tl_init(sc);
+				tl_init_locked(sc);
 		} else {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 				tl_stop(sc);
 			}
 		}
 		sc->tl_if_flags = ifp->if_flags;
+		TL_UNLOCK(sc);
 		error = 0;
 		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
+		TL_LOCK(sc);
 		tl_setmulti(sc);
+		TL_UNLOCK(sc);
 		error = 0;
 		break;
 	case SIOCSIFMEDIA:
@@ -2247,8 +2263,6 @@
 		break;
 	}
 
-	(void)splx(s);
-
 	return(error);
 }
 
@@ -2262,10 +2276,12 @@
 
 	if_printf(ifp, "device timeout\n");
 
+	TL_LOCK(sc);
 	ifp->if_oerrors++;
 
 	tl_softreset(sc, 1);
-	tl_init(sc);
+	tl_init_locked(sc);
+	TL_UNLOCK(sc);
 
 	return;
 }
@@ -2281,12 +2297,12 @@
 	register int		i;
 	struct ifnet		*ifp;
 
-	TL_LOCK(sc);
+	TL_LOCK_ASSERT(sc);
 
 	ifp = sc->tl_ifp;
 
 	/* Stop the stats updater. */
-	untimeout(tl_stats_update, sc, sc->tl_stat_ch);
+	callout_stop(&sc->tl_stat_callout);
 
 	/* Stop the transmitter */
 	CMD_CLR(sc, TL_CMD_RT);
@@ -2333,7 +2349,6 @@
 		sizeof(sc->tl_ldata->tl_tx_list));
 
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
-	TL_UNLOCK(sc);
 
 	return;
 }
@@ -2350,7 +2365,9 @@
 
 	sc = device_get_softc(dev);
 
+	TL_LOCK(sc);
 	tl_stop(sc);
+	TL_UNLOCK(sc);
 
 	return;
 }
Index: src/sys/pci/if_tlreg.h
===================================================================
RCS file: /usr/cvs/src/sys/pci/if_tlreg.h,v
retrieving revision 1.21
diff -u -r1.21 if_tlreg.h
--- src/sys/pci/if_tlreg.h	10 Jun 2005 16:49:23 -0000	1.21
+++ src/sys/pci/if_tlreg.h	5 Sep 2005 07:52:03 -0000
@@ -124,7 +124,7 @@
 	u_int8_t		tl_txeoc;
 	u_int8_t		tl_bitrate;
 	int			tl_if_flags;
-	struct callout_handle	tl_stat_ch;
+	struct callout		tl_stat_callout;
 	struct mtx		tl_mtx;
 };
 

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1125922064.75892.20.camel>