summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2003-12-14 21:31:32 +0000
committerwpaul <wpaul@FreeBSD.org>2003-12-14 21:31:32 +0000
commit953349a8b8ddfbf5397e22c1bb8a24b53c4e2790 (patch)
tree51a3bccb96f6842e2ec3221ffb7482f6c5c8d952
parenta2e08c3ed417496ce19a6b839cc5f4ce96f123ad (diff)
downloadFreeBSD-src-953349a8b8ddfbf5397e22c1bb8a24b53c4e2790.zip
FreeBSD-src-953349a8b8ddfbf5397e22c1bb8a24b53c4e2790.tar.gz
Rework mbuf<->ndis_packet/ndis_packet<->mbuf translation a little to
make it more robust. This should fix problems with crashes under heavy traffic loads that have been reported. Also add a 'query done' callback handler to satisfy the e100bex.sys sample Intel driver.
-rw-r--r--sys/compat/ndis/kern_ndis.c65
-rw-r--r--sys/compat/ndis/ndis_var.h9
-rw-r--r--sys/dev/if_ndis/if_ndis.c41
-rw-r--r--sys/dev/if_ndis/if_ndisvar.h1
4 files changed, 65 insertions, 51 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index 3aca08f..5214a1f 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -76,6 +76,7 @@ __stdcall static void ndis_status_func(ndis_handle, ndis_status,
void *, uint32_t);
__stdcall static void ndis_statusdone_func(ndis_handle);
__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
+__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
/*
@@ -122,6 +123,15 @@ ndis_setdone_func(adapter, status)
}
__stdcall static void
+ndis_getdone_func(adapter, status)
+ ndis_handle adapter;
+ ndis_status status;
+{
+ printf ("Query done... %x\n", status);
+ return;
+}
+
+__stdcall static void
ndis_resetdone_func(adapter, status, addressingreset)
ndis_handle adapter;
ndis_status status;
@@ -309,11 +319,24 @@ ndis_return_packet(packet, arg)
{
struct ndis_softc *sc;
ndis_handle adapter;
+ ndis_packet *p;
__stdcall ndis_return_handler returnfunc;
+ uint32_t t;
if (arg == NULL || packet == NULL)
return;
+ p = packet;
+
+ /* Decrement refcount. */
+ p->np_private.npp_count--;
+
+ /* Release packet when refcount hits zero, otherwise return. */
+ if (p->np_private.npp_count)
+ return;
+ t = *(uint32_t *)&p->u.np_clrsvd.np_miniport_rsvd[0];
+if (t == 0)
+printf ("returning %p %x\n", p, t);
sc = arg;
returnfunc = sc->ndis_chars.nmc_return_packet_func;
adapter = sc->ndis_block.nmb_miniportadapterctx;
@@ -439,6 +462,7 @@ ndis_ptom(m0, p)
priv = &p->np_private;
buf = priv->npp_head;
+ priv->npp_count = 0;
for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
if (buf == priv->npp_head)
@@ -450,25 +474,15 @@ ndis_ptom(m0, p)
*m0 = NULL;
return(ENOBUFS);
}
-
- /*
- * Note: there's some hackery going on here. We want
- * to mate the mbufs to the buffers in the NDIS packet,
- * but we don't mark the mbufs with the M_EXT flag to
- * indicate external storage. This is because we don't
- * want anything special done to free the buffers.
- * Depending on the circumstances, the caller may want
- * the entire packet to be released, buffers and all,
- * by calling ndis_return_packet(), or ndis_free_packet().
- * We leave it up to the caller to do the MEXTADD() to
- * set up the free mechanism in the first mbuf of the
- * chain.
- */
if (buf->nb_bytecount > buf->nb_size)
m->m_len = buf->nb_size;
else
m->m_len = buf->nb_bytecount;
m->m_data = buf->nb_mappedsystemva;
+ MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
+ p->np_rsvd[0], 0, EXT_NDIS);
+ m->m_ext.ext_buf = (void *)p; /* XXX */
+ priv->npp_count++;
totlen += m->m_len;
if (m->m_flags & MT_HEADER)
*m0 = m;
@@ -524,7 +538,6 @@ ndis_mtop(m0, p)
for (m = m0; m != NULL; m = m->m_next) {
if (m->m_len == NULL)
continue;
-
buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO);
if (buf == NULL) {
ndis_free_packet(*p);
@@ -651,20 +664,11 @@ ndis_init_dma(arg)
if (sc->ndis_tmaps == NULL)
return(ENOMEM);
- sc->ndis_mbufs = malloc(sizeof(struct mbuf) * sc->ndis_maxpkts,
- M_DEVBUF, M_NOWAIT|M_ZERO);
-
- if (sc->ndis_mbufs == NULL) {
- free(sc->ndis_tmaps, M_DEVBUF);
- return(ENOMEM);
- }
-
for (i = 0; i < sc->ndis_maxpkts; i++) {
error = bus_dmamap_create(sc->ndis_ttag, 0,
&sc->ndis_tmaps[i]);
if (error) {
free(sc->ndis_tmaps, M_DEVBUF);
- free(sc->ndis_mbufs, M_DEVBUF);
return(ENODEV);
}
}
@@ -677,18 +681,24 @@ ndis_destroy_dma(arg)
void *arg;
{
struct ndis_softc *sc;
+ struct mbuf *m;
+ ndis_packet *p = NULL;
int i;
sc = arg;
for (i = 0; i < sc->ndis_maxpkts; i++) {
- if (sc->ndis_mbufs[i] != NULL)
- m_freem(sc->ndis_mbufs[i]);
+ if (sc->ndis_txarray[i] != NULL) {
+ p = sc->ndis_txarray[i];
+ m = (struct mbuf *)p->np_rsvd[1];
+ if (m != NULL)
+ m_freem(m);
+ ndis_free_packet(sc->ndis_txarray[i]);
+ }
bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
}
free(sc->ndis_tmaps, M_DEVBUF);
- free(sc->ndis_mbufs, M_DEVBUF);
bus_dma_tag_destroy(sc->ndis_ttag);
@@ -1041,6 +1051,7 @@ ndis_load_driver(img, arg)
block->nmb_signature = (void *)0xcafebabe;
block->nmb_setdone_func = ndis_setdone_func;
+ block->nmb_querydone_func = ndis_getdone_func;
block->nmb_status_func = ndis_status_func;
block->nmb_statusdone_func = ndis_statusdone_func;
block->nmb_resetdone_func = ndis_resetdone_func;
diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h
index 78bcfd2..df6d3ce 100644
--- a/sys/compat/ndis/ndis_var.h
+++ b/sys/compat/ndis/ndis_var.h
@@ -814,14 +814,16 @@ typedef struct ndis_packet_oob ndis_packet_oob;
struct ndis_packet {
ndis_packet_private np_private;
union {
+ /* For connectionless miniports. */
struct {
uint8_t np_miniport_rsvd[2 * sizeof(void *)];
uint8_t np_wrapper_rsvd[2 * sizeof(void *)];
- } np_rsvd;
+ } np_clrsvd;
+ /* For de-serialized miniports */
struct {
uint8_t np_miniport_rsvdex[3 * sizeof(void *)];
uint8_t np_wrapper_rsvdex[sizeof(void *)];
- } np_rsvdrx;
+ } np_dsrsvd;
struct {
uint8_t np_mac_rsvd[4 * sizeof(void *)];
} np_macrsvd;
@@ -840,6 +842,9 @@ struct ndis_packet {
typedef struct ndis_packet ndis_packet;
+/* mbuf ext type for NDIS */
+#define EXT_NDIS 0x999
+
struct ndis_filterdbs {
union {
void *nf_ethdb;
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
index 7a6b56a..c96d918 100644
--- a/sys/dev/if_ndis/if_ndis.c
+++ b/sys/dev/if_ndis/if_ndis.c
@@ -354,11 +354,6 @@ ndis_attach(dev)
}
sc->ndis_txpending = sc->ndis_maxpkts;
- sc->ndis_mbufs = malloc(sizeof(struct mbuf) * sc->ndis_maxpkts,
- M_DEVBUF, M_NOWAIT);
-
- if (sc->ndis_mbufs == NULL)
- goto fail;
sc->ndis_oidcnt = 0;
/* Get supported oid list. */
@@ -489,13 +484,12 @@ ndis_rxeof(adapter, packets, pktcnt)
for (i = 0; i < pktcnt; i++) {
p = packets[i];
+ /* Stash the softc here so ptom can use it. */
+ p->np_rsvd[0] = (uint32_t *)sc;
if (ndis_ptom(&m0, p)) {
printf ("ndis%d: ptom failed\n", sc->ndis_unit);
ndis_return_packet(sc, p);
} else {
- MEXTADD(m0, m0->m_data, m0->m_pkthdr.len,
- ndis_return_packet, sc, 0, EXT_NET_DRV);
- m0->m_ext.ext_buf = (void *)p; /* XXX */
m0->m_pkthdr.rcvif = ifp;
ifp->if_ipackets++;
(*ifp->if_input)(ifp, m0);
@@ -520,23 +514,24 @@ ndis_txeof(adapter, packet, status)
ndis_miniport_block *block;
struct ifnet *ifp;
int idx;
+ struct mbuf *m;
block = (ndis_miniport_block *)adapter;
sc = (struct ndis_softc *)block->nmb_ifp;
ifp = block->nmb_ifp;
- if (packet->np_rsvd[1] != NULL) {
- idx = (int)packet->np_rsvd[1];
- ifp->if_opackets++;
- if (sc->ndis_mbufs[idx] != NULL) {
- m_freem(sc->ndis_mbufs[idx]);
- sc->ndis_mbufs[idx] = NULL;
- }
- if (sc->ndis_sc)
- bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
- }
+ if (packet->np_rsvd[1] == NULL)
+ panic("NDIS driver corrupted reserved packet fields");
+
+ m = (struct mbuf *)packet->np_rsvd[1];
+ idx = (int)packet->np_rsvd[0];
+ ifp->if_opackets++;
+ m_freem(m);
+ if (sc->ndis_sc)
+ bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
ndis_free_packet(packet);
+ sc->ndis_txarray[idx] = NULL;
sc->ndis_txpending++;
ifp->if_timer = 0;
@@ -667,6 +662,7 @@ ndis_start(ifp)
NDIS_LOCK(sc);
sc->ndis_txarray[sc->ndis_txidx] = NULL;
+
if (ndis_mtop(m, &sc->ndis_txarray[sc->ndis_txidx])) {
NDIS_UNLOCK(sc);
IF_PREPEND(&ifp->if_snd, m);
@@ -678,9 +674,9 @@ ndis_start(ifp)
* so we can free it later.
*/
- sc->ndis_mbufs[sc->ndis_txidx] = m;
- (sc->ndis_txarray[sc->ndis_txidx])->np_rsvd[1] =
+ (sc->ndis_txarray[sc->ndis_txidx])->np_rsvd[0] =
(uint32_t *)sc->ndis_txidx;
+ (sc->ndis_txarray[sc->ndis_txidx])->np_rsvd[1] = (uint32_t *)m;
/*
* Do scatter/gather processing, if driver requested it.
@@ -781,6 +777,9 @@ ndis_init(xsc)
if (error)
printf ("set filter failed: %d\n", error);
+ sc->ndis_txidx = 0;
+ sc->ndis_txpending = sc->ndis_maxpkts;
+
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
@@ -955,7 +954,7 @@ ndis_shutdown(dev)
struct ndis_softc *sc;
sc = device_get_softc(dev);
-/* ndis_shutdown_nic(sc); */
+ ndis_shutdown_nic(sc);
return;
}
diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h
index 7a76217..bc3b902 100644
--- a/sys/dev/if_ndis/if_ndisvar.h
+++ b/sys/dev/if_ndis/if_ndisvar.h
@@ -111,7 +111,6 @@ struct ndis_softc {
bus_dma_tag_t ndis_ttag;
bus_dmamap_t *ndis_mmaps;
bus_dmamap_t *ndis_tmaps;
- struct mbuf **ndis_mbufs;
int ndis_mmapcnt;
};
OpenPOWER on IntegriCloud