summaryrefslogtreecommitdiff
path: root/sys/dev/gem
diff options
context:
space:
mode:
authorMarius Strobl <marius@FreeBSD.org>2005-10-05 22:08:17 +0000
committerMarius Strobl <marius@FreeBSD.org>2005-10-05 22:08:17 +0000
commit1a1b6619b554797f10433cc533122fdeab838363 (patch)
treee09ef87841eeccd266ef75b84619224c63640bb1 /sys/dev/gem
parent448a4a78707c2b2f531d54fcd7f759f212a9625d (diff)
Notes
Diffstat (limited to 'sys/dev/gem')
-rw-r--r--sys/dev/gem/if_gem.c134
-rw-r--r--sys/dev/gem/if_gem_pci.c16
-rw-r--r--sys/dev/gem/if_gemvar.h9
3 files changed, 112 insertions, 47 deletions
diff --git a/sys/dev/gem/if_gem.c b/sys/dev/gem/if_gem.c
index b6b4de9e38b4..84033e36fefc 100644
--- a/sys/dev/gem/if_gem.c
+++ b/sys/dev/gem/if_gem.c
@@ -50,7 +50,9 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -74,6 +76,7 @@ __FBSDID("$FreeBSD$");
#define TRIES 10000
static void gem_start(struct ifnet *);
+static void gem_start_locked(struct ifnet *);
static void gem_stop(struct ifnet *, int);
static int gem_ioctl(struct ifnet *, u_long, caddr_t);
static void gem_cddma_callback(void *, bus_dma_segment_t *, int, int);
@@ -82,6 +85,7 @@ static void gem_txdma_callback(void *, bus_dma_segment_t *, int,
static void gem_tick(void *);
static void gem_watchdog(struct ifnet *);
static void gem_init(void *);
+static void gem_init_locked(struct gem_softc *sc);
static void gem_init_regs(struct gem_softc *sc);
static int gem_ringsize(int sz);
static int gem_meminit(struct gem_softc *);
@@ -137,9 +141,17 @@ gem_attach(sc)
if (ifp == NULL)
return (ENOSPC);
+ callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0);
+#ifdef GEM_RINT_TIMEOUT
+ callout_init_mtx(&sc->sc_rx_ch, &sc->sc_mtx, 0);
+#endif
+
/* Make sure the chip is stopped. */
ifp->if_softc = sc;
+ GEM_LOCK(sc);
+ gem_stop(ifp, 0);
gem_reset(sc);
+ GEM_UNLOCK(sc);
error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, GEM_NSEGS,
@@ -165,7 +177,7 @@ gem_attach(sc)
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
sizeof(struct gem_control_data), 1,
sizeof(struct gem_control_data), BUS_DMA_ALLOCNOW,
- busdma_lock_mutex, &Giant, &sc->sc_cdmatag);
+ busdma_lock_mutex, &sc->sc_mtx, &sc->sc_cdmatag);
if (error)
goto fail_ttag;
@@ -256,8 +268,7 @@ gem_attach(sc)
if_initname(ifp, device_get_name(sc->sc_dev),
device_get_unit(sc->sc_dev));
ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
- IFF_NEEDSGIANT;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_start = gem_start;
ifp->if_ioctl = gem_ioctl;
ifp->if_watchdog = gem_watchdog;
@@ -321,11 +332,6 @@ gem_attach(sc)
"hook\n");
#endif
- callout_init(&sc->sc_tick_ch, 0);
-#ifdef GEM_RINT_TIMEOUT
- callout_init(&sc->sc_rx_ch, 0);
-#endif
-
/*
* Tell the upper layer(s) we support long frames.
*/
@@ -375,7 +381,13 @@ gem_detach(sc)
struct ifnet *ifp = sc->sc_ifp;
int i;
+ GEM_LOCK(sc);
gem_stop(ifp, 1);
+ GEM_UNLOCK(sc);
+ callout_drain(&sc->sc_tick_ch);
+#ifdef GEM_RINT_TIMEOUT
+ callout_drain(&sc->sc_rx_ch);
+#endif
ether_ifdetach(ifp);
if_free(ifp);
device_delete_child(sc->sc_dev, sc->sc_miibus);
@@ -407,7 +419,9 @@ gem_suspend(sc)
{
struct ifnet *ifp = sc->sc_ifp;
+ GEM_LOCK(sc);
gem_stop(ifp, 0);
+ GEM_UNLOCK(sc);
}
void
@@ -416,13 +430,15 @@ gem_resume(sc)
{
struct ifnet *ifp = sc->sc_ifp;
+ GEM_LOCK(sc);
/*
* On resume all registers have to be initialized again like
* after power-on.
*/
sc->sc_inited = 0;
if (ifp->if_flags & IFF_UP)
- gem_init(ifp);
+ gem_init_locked(sc);
+ GEM_UNLOCK(sc);
}
static void
@@ -523,11 +539,9 @@ gem_tick(arg)
void *arg;
{
struct gem_softc *sc = arg;
- int s;
- s = splnet();
+ GEM_LOCK_ASSERT(sc, MA_OWNED);
mii_tick(sc->sc_mii);
- splx(s);
callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc);
}
@@ -556,9 +570,7 @@ gem_reset(sc)
{
bus_space_tag_t t = sc->sc_bustag;
bus_space_handle_t h = sc->sc_h;
- int s;
- s = splnet();
#ifdef GEM_DEBUG
CTR1(KTR_GEM, "%s: gem_reset", device_get_name(sc->sc_dev));
#endif
@@ -569,7 +581,6 @@ gem_reset(sc)
bus_space_write_4(t, h, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX);
if (!gem_bitwait(sc, GEM_RESET, GEM_RESET_RX | GEM_RESET_TX, 0))
device_printf(sc->sc_dev, "cannot reset device\n");
- splx(s);
}
@@ -613,6 +624,9 @@ gem_stop(ifp, disable)
#endif
callout_stop(&sc->sc_tick_ch);
+#ifdef GEM_RINT_TIMEOUT
+ callout_stop(&sc->sc_rx_ch);
+#endif
/* XXX - Should we reset these instead? */
gem_disable_tx(sc);
@@ -846,22 +860,31 @@ gem_ringsize(sz)
return (v);
}
+static void
+gem_init(xsc)
+ void *xsc;
+{
+ struct gem_softc *sc = (struct gem_softc *)xsc;
+
+ GEM_LOCK(sc);
+ gem_init_locked(sc);
+ GEM_UNLOCK(sc);
+}
+
/*
* Initialization of interface; set up initialization block
* and transmit/receive descriptor rings.
*/
static void
-gem_init(xsc)
- void *xsc;
+gem_init_locked(sc)
+ struct gem_softc *sc;
{
- struct gem_softc *sc = (struct gem_softc *)xsc;
struct ifnet *ifp = sc->sc_ifp;
bus_space_tag_t t = sc->sc_bustag;
bus_space_handle_t h = sc->sc_h;
- int s;
u_int32_t v;
- s = splnet();
+ GEM_LOCK_ASSERT(sc, MA_OWNED);
#ifdef GEM_DEBUG
CTR1(KTR_GEM, "%s: gem_init: calling stop", device_get_name(sc->sc_dev));
@@ -964,7 +987,6 @@ gem_init(xsc)
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_timer = 0;
sc->sc_ifflags = ifp->if_flags;
- splx(s);
}
static int
@@ -1115,6 +1137,17 @@ gem_start(ifp)
struct ifnet *ifp;
{
struct gem_softc *sc = (struct gem_softc *)ifp->if_softc;
+
+ GEM_LOCK(sc);
+ gem_start_locked(ifp);
+ GEM_UNLOCK(sc);
+}
+
+static void
+gem_start_locked(ifp)
+ struct ifnet *ifp;
+{
+ struct gem_softc *sc = (struct gem_softc *)ifp->if_softc;
struct mbuf *m0 = NULL;
int firsttx, ntx = 0, ofree, txmfail;
@@ -1318,9 +1351,9 @@ gem_tint(sc)
if (sc->sc_txfree == GEM_NTXDESC - 1)
sc->sc_txwin = 0;
- /* Freed some descriptors, so reset IFF_OACTIVE and restart. */
+ /* Freed some descriptors, so reset IFF_DRV_OACTIVE and restart. */
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- gem_start(ifp);
+ gem_start_locked(ifp);
if (STAILQ_EMPTY(&sc->sc_txdirtyq))
ifp->if_timer = 0;
@@ -1337,8 +1370,10 @@ static void
gem_rint_timeout(arg)
void *arg;
{
+ struct gem_softc *sc = (struct gem_softc *)arg;
- gem_rint((struct gem_softc *)arg);
+ GEM_LOCK_ASSERT(sc, MA_OWNED);
+ gem_rint(sc);
}
#endif
@@ -1441,7 +1476,9 @@ gem_rint(sc)
m->m_pkthdr.len = m->m_len = len - ETHER_CRC_LEN;
/* Pass it on. */
+ GEM_UNLOCK(sc);
(*ifp->if_input)(ifp, m);
+ GEM_LOCK(sc);
}
if (progress) {
@@ -1538,6 +1575,7 @@ gem_intr(v)
bus_space_handle_t seb = sc->sc_h;
u_int32_t status;
+ GEM_LOCK(sc);
status = bus_space_read_4(t, seb, GEM_STATUS);
#ifdef GEM_DEBUG
CTR3(KTR_GEM, "%s: gem_intr: cplt %x, status %x",
@@ -1561,7 +1599,7 @@ gem_intr(v)
device_printf(sc->sc_dev, "MAC tx fault, status %x\n",
txstat);
if (txstat & (GEM_MAC_TX_UNDERRUN | GEM_MAC_TX_PKT_TOO_LONG))
- gem_init(sc);
+ gem_init_locked(sc);
}
if (status & GEM_INTR_RX_MAC) {
int rxstat = bus_space_read_4(t, seb, GEM_MAC_RX_STATUS);
@@ -1570,11 +1608,12 @@ gem_intr(v)
* due to a silicon bug so handle them silently.
*/
if (rxstat & GEM_MAC_RX_OVERFLOW)
- gem_init(sc);
+ gem_init_locked(sc);
else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT))
device_printf(sc->sc_dev, "MAC rx fault, status %x\n",
rxstat);
}
+ GEM_UNLOCK(sc);
}
@@ -1584,6 +1623,7 @@ gem_watchdog(ifp)
{
struct gem_softc *sc = ifp->if_softc;
+ GEM_LOCK(sc);
#ifdef GEM_DEBUG
CTR3(KTR_GEM, "gem_watchdog: GEM_RX_CONFIG %x GEM_MAC_RX_STATUS %x "
"GEM_MAC_RX_CONFIG %x",
@@ -1601,7 +1641,8 @@ gem_watchdog(ifp)
++ifp->if_oerrors;
/* Try to get more packets going. */
- gem_init(ifp);
+ gem_init_locked(sc);
+ GEM_UNLOCK(sc);
}
/*
@@ -1725,13 +1766,14 @@ gem_mii_statchg(dev)
{
struct gem_softc *sc = device_get_softc(dev);
#ifdef GEM_DEBUG
- int instance = IFM_INST(sc->sc_mii->mii_media.ifm_cur->ifm_media);
+ int instance;
#endif
bus_space_tag_t t = sc->sc_bustag;
bus_space_handle_t mac = sc->sc_h;
u_int32_t v;
#ifdef GEM_DEBUG
+ instance = IFM_INST(sc->sc_mii->mii_media.ifm_cur->ifm_media);
if (sc->sc_debug)
printf("gem_mii_statchg: status change: phy = %d\n",
sc->sc_phys[instance]);
@@ -1778,10 +1820,14 @@ gem_mediachange(ifp)
struct ifnet *ifp;
{
struct gem_softc *sc = ifp->if_softc;
+ int error;
/* XXX Add support for serial media. */
- return (mii_mediachg(sc->sc_mii));
+ GEM_LOCK(sc);
+ error = mii_mediachg(sc->sc_mii);
+ GEM_UNLOCK(sc);
+ return (error);
}
void
@@ -1791,12 +1837,16 @@ gem_mediastatus(ifp, ifmr)
{
struct gem_softc *sc = ifp->if_softc;
- if ((ifp->if_flags & IFF_UP) == 0)
+ GEM_LOCK(sc);
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ GEM_UNLOCK(sc);
return;
+ }
mii_pollstat(sc->sc_mii);
ifmr->ifm_active = sc->sc_mii->mii_media_active;
ifmr->ifm_status = sc->sc_mii->mii_media_status;
+ GEM_UNLOCK(sc);
}
/*
@@ -1810,45 +1860,43 @@ gem_ioctl(ifp, cmd, data)
{
struct gem_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
- int s, error = 0;
+ int error = 0;
switch (cmd) {
- case SIOCSIFADDR:
- case SIOCGIFADDR:
- case SIOCSIFMTU:
- error = ether_ioctl(ifp, cmd, data);
- break;
case SIOCSIFFLAGS:
+ GEM_LOCK(sc);
if (ifp->if_flags & IFF_UP) {
if ((sc->sc_ifflags ^ ifp->if_flags) == IFF_PROMISC)
gem_setladrf(sc);
else
- gem_init(sc);
+ gem_init_locked(sc);
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
gem_stop(ifp, 0);
}
sc->sc_ifflags = ifp->if_flags;
- error = 0;
+ GEM_UNLOCK(sc);
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
+ GEM_LOCK(sc);
gem_setladrf(sc);
- error = 0;
+ GEM_UNLOCK(sc);
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, cmd);
break;
default:
- error = ENOTTY;
+ error = ether_ioctl(ifp, cmd, data);
break;
}
/* Try to get things going again */
+ GEM_LOCK(sc);
if (ifp->if_flags & IFF_UP)
- gem_start(ifp);
- splx(s);
+ gem_start_locked(ifp);
+ GEM_UNLOCK(sc);
return (error);
}
@@ -1868,6 +1916,8 @@ gem_setladrf(sc)
u_int32_t v;
int i;
+ GEM_LOCK_ASSERT(sc, MA_OWNED);
+
/* Get current RX configuration */
v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG);
diff --git a/sys/dev/gem/if_gem_pci.c b/sys/dev/gem/if_gem_pci.c
index 5347ee9fb0d5..bca56fe0e7d5 100644
--- a/sys/dev/gem/if_gem_pci.c
+++ b/sys/dev/gem/if_gem_pci.c
@@ -40,7 +40,9 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/resource.h>
#include <sys/socket.h>
@@ -175,12 +177,14 @@ gem_pci_attach(dev)
sc->sc_dev = dev;
sc->sc_pci = 1; /* XXX */
+ GEM_LOCK_INIT(sc, device_get_nameunit(dev));
+
gsc->gsc_srid = PCI_GEM_BASEADDR;
gsc->gsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&gsc->gsc_srid, RF_ACTIVE);
if (gsc->gsc_sres == NULL) {
device_printf(dev, "failed to allocate bus space resource\n");
- return (ENXIO);
+ goto fail_mtx;
}
gsc->gsc_irid = 0;
@@ -205,8 +209,8 @@ gem_pci_attach(dev)
goto fail_ires;
}
- if (bus_setup_intr(dev, gsc->gsc_ires, INTR_TYPE_NET, gem_intr, sc,
- &gsc->gsc_ih) != 0) {
+ if (bus_setup_intr(dev, gsc->gsc_ires, INTR_TYPE_NET | INTR_MPSAFE,
+ gem_intr, sc, &gsc->gsc_ih) != 0) {
device_printf(dev, "failed to set up interrupt\n");
gem_detach(sc);
goto fail_ires;
@@ -217,6 +221,8 @@ fail_ires:
bus_release_resource(dev, SYS_RES_IRQ, gsc->gsc_irid, gsc->gsc_ires);
fail_sres:
bus_release_resource(dev, SYS_RES_MEMORY, gsc->gsc_srid, gsc->gsc_sres);
+fail_mtx:
+ GEM_LOCK_DESTROY(sc);
return (ENXIO);
}
@@ -227,11 +233,11 @@ gem_pci_detach(dev)
struct gem_pci_softc *gsc = device_get_softc(dev);
struct gem_softc *sc = &gsc->gsc_gem;
- gem_detach(sc);
-
bus_teardown_intr(dev, gsc->gsc_ires, gsc->gsc_ih);
+ gem_detach(sc);
bus_release_resource(dev, SYS_RES_IRQ, gsc->gsc_irid, gsc->gsc_ires);
bus_release_resource(dev, SYS_RES_MEMORY, gsc->gsc_srid, gsc->gsc_sres);
+ GEM_LOCK_DESTROY(sc);
return (0);
}
diff --git a/sys/dev/gem/if_gemvar.h b/sys/dev/gem/if_gemvar.h
index ed3eb7a2099f..abfe327e566b 100644
--- a/sys/dev/gem/if_gemvar.h
+++ b/sys/dev/gem/if_gemvar.h
@@ -188,6 +188,8 @@ struct gem_softc {
int sc_inited;
int sc_debug;
int sc_ifflags;
+
+ struct mtx sc_mtx;
};
#define GEM_DMA_READ(sc, v) (((sc)->sc_pci) ? le64toh(v) : be64toh(v))
@@ -214,6 +216,13 @@ do { \
& GEM_RD_BUFSIZE) | GEM_RD_OWN); \
} while (0)
+#define GEM_LOCK_INIT(_sc, _name) \
+ mtx_init(&(_sc)->sc_mtx, _name, MTX_NETWORK_LOCK, MTX_DEF)
+#define GEM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define GEM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define GEM_LOCK_ASSERT(_sc, _what) mtx_assert(&(_sc)->sc_mtx, (_what))
+#define GEM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx)
+
#ifdef _KERNEL
extern devclass_t gem_devclass;