summaryrefslogtreecommitdiffstats
path: root/sys/dev/if_ndis/if_ndis.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/if_ndis/if_ndis.c')
-rw-r--r--sys/dev/if_ndis/if_ndis.c110
1 files changed, 98 insertions, 12 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
index 5ec5dc8..417612e 100644
--- a/sys/dev/if_ndis/if_ndis.c
+++ b/sys/dev/if_ndis/if_ndis.c
@@ -120,12 +120,14 @@ static funcptr ndis_linksts_done_wrap;
static funcptr ndis_ticktask_wrap;
static funcptr ndis_starttask_wrap;
static funcptr ndis_resettask_wrap;
+static funcptr ndis_inputtask_wrap;
static void ndis_tick (void *);
static void ndis_ticktask (device_object *, void *);
static void ndis_start (struct ifnet *);
static void ndis_starttask (device_object *, void *);
static void ndis_resettask (device_object *, void *);
+static void ndis_inputtask (device_object *, void *);
static int ndis_ioctl (struct ifnet *, u_long, caddr_t);
static int ndis_wi_ioctl_get (struct ifnet *, u_long, caddr_t);
static int ndis_wi_ioctl_set (struct ifnet *, u_long, caddr_t);
@@ -199,6 +201,8 @@ ndisdrv_modevent(mod, cmd, arg)
2, WINDRV_WRAP_STDCALL);
windrv_wrap((funcptr)ndis_resettask, &ndis_resettask_wrap,
2, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)ndis_inputtask, &ndis_inputtask_wrap,
+ 2, WINDRV_WRAP_STDCALL);
break;
case MOD_UNLOAD:
ndisdrv_loaded--;
@@ -217,6 +221,7 @@ ndisdrv_modevent(mod, cmd, arg)
windrv_unwrap(ndis_ticktask_wrap);
windrv_unwrap(ndis_starttask_wrap);
windrv_unwrap(ndis_resettask_wrap);
+ windrv_unwrap(ndis_inputtask_wrap);
break;
default:
error = EINVAL;
@@ -488,6 +493,7 @@ ndis_attach(dev)
ifp->if_softc = sc;
KeInitializeSpinLock(&sc->ndis_spinlock);
+ KeInitializeSpinLock(&sc->ndis_rxlock);
InitializeListHead(&sc->ndis_shlist);
if (sc->ndis_iftype == PCMCIABus) {
@@ -571,6 +577,14 @@ ndis_attach(dev)
goto fail;
}
+ /*
+ * If this is a deserialized miniport, we don't have
+ * to honor the OID_GEN_MAXIMUM_SEND_PACKETS result.
+ */
+
+ if (!NDIS_SERIALIZED(sc->ndis_block))
+ sc->ndis_maxpkts = NDIS_TXPKTS;
+
/* Enforce some sanity, just in case. */
if (sc->ndis_maxpkts == 0)
@@ -582,7 +596,7 @@ ndis_attach(dev)
/* Allocate a pool of ndis_packets for TX encapsulation. */
NdisAllocatePacketPool(&i, &sc->ndis_txpool,
- sc->ndis_maxpkts, PROTOCOL_RESERVED_SIZE_IN_PACKET);
+ NDIS_TXPKTS, PROTOCOL_RESERVED_SIZE_IN_PACKET);
if (i != NDIS_STATUS_SUCCESS) {
sc->ndis_txpool = NULL;
@@ -616,6 +630,14 @@ ndis_attach(dev)
/* Check for task offload support. */
ndis_probe_offload(sc);
+#if __FreeBSD_version < 502109
+ /*
+ * An NDIS device was detected. Inform the world.
+ */
+ device_printf(dev, "%s address: %6D\n",
+ sc->ndis_80211 ? "802.11" : "Ethernet", eaddr, ":");
+#endif
+
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
@@ -888,6 +910,7 @@ got_crypto:
sc->ndis_tickitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
sc->ndis_startitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
sc->ndis_resetitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
+ sc->ndis_inputitem = IoAllocateWorkItem(sc->ndis_block->nmb_deviceobj);
KeInitializeDpc(&sc->ndis_rxdpc, ndis_rxeof_xfr_wrap, sc->ndis_block);
@@ -941,6 +964,8 @@ ndis_detach(dev)
IoFreeWorkItem(sc->ndis_startitem);
if (sc->ndis_resetitem != NULL)
IoFreeWorkItem(sc->ndis_resetitem);
+ if (sc->ndis_inputitem != NULL)
+ IoFreeWorkItem(sc->ndis_inputitem);
bus_generic_detach(dev);
@@ -1037,6 +1062,9 @@ ndis_resume(dev)
/*
* The following bunch of routines are here to support drivers that
* use the NdisMEthIndicateReceive()/MiniportTransferData() mechanism.
+ * The NdisMEthIndicateReceive() handler runs at DISPATCH_LEVEL for
+ * serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
+ * miniports.
*/
static void
@@ -1103,14 +1131,19 @@ ndis_rxeof_eth(adapter, ctx, addr, hdr, hdrlen, lookahead, lookaheadlen, pktlen)
KeAcquireSpinLock(&block->nmb_lock, &irql);
- InsertTailList((&block->nmb_packetlist),
- ((list_entry *)&p->u.np_clrsvd.np_miniport_rsvd));
+ InsertTailList((&block->nmb_packetlist), (&p->np_list));
KeReleaseSpinLock(&block->nmb_lock, irql);
return;
}
+/*
+ * NdisMEthIndicateReceiveComplete() handler, runs at DISPATCH_LEVEL
+ * for serialized miniports, or IRQL <= DISPATCH_LEVEL for deserialized
+ * miniports.
+ */
+
static void
ndis_rxeof_done(adapter)
ndis_handle adapter;
@@ -1130,7 +1163,7 @@ ndis_rxeof_done(adapter)
}
/*
- * Runs at DISPATCH_LEVEL.
+ * MiniportTransferData() handler, runs at DISPATCH_LEVEL.
*/
static void
ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
@@ -1157,8 +1190,8 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
l = block->nmb_packetlist.nle_flink;
while(!IsListEmpty(&block->nmb_packetlist)) {
l = RemoveHeadList((&block->nmb_packetlist));
- p = CONTAINING_RECORD(l, ndis_packet,
- u.np_clrsvd.np_miniport_rsvd);
+ p = CONTAINING_RECORD(l, ndis_packet, np_list);
+ InitializeListHead((&p->np_list));
priv = (ndis_ethpriv *)&p->np_protocolreserved;
m = p->np_m0;
@@ -1185,8 +1218,12 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
if (status == NDIS_STATUS_SUCCESS) {
IoFreeMdl(p->np_private.npp_head);
NdisFreePacket(p);
- ifp->if_ipackets++;
- (*ifp->if_input)(ifp, m);
+ KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
+ _IF_ENQUEUE(&sc->ndis_rxqueue, m);
+ KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
+ IoQueueWorkItem(sc->ndis_inputitem,
+ (io_workitem_func)ndis_inputtask_wrap,
+ WORKQUEUE_CRITICAL, ifp);
}
if (status == NDIS_STATUS_FAILURE)
@@ -1201,6 +1238,9 @@ ndis_rxeof_xfr(dpc, adapter, sysarg1, sysarg2)
return;
}
+/*
+ * NdisMTransferDataComplete() handler, runs at DISPATCH_LEVEL.
+ */
static void
ndis_rxeof_xfr_done(adapter, packet, status, len)
ndis_handle adapter;
@@ -1228,8 +1268,13 @@ ndis_rxeof_xfr_done(adapter, packet, status, len)
m->m_len = m->m_pkthdr.len;
m->m_pkthdr.rcvif = ifp;
- ifp->if_ipackets++;
- (*ifp->if_input)(ifp, m);
+ KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
+ _IF_ENQUEUE(&sc->ndis_rxqueue, m);
+ KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
+ IoQueueWorkItem(sc->ndis_inputitem,
+ (io_workitem_func)ndis_inputtask_wrap,
+ WORKQUEUE_CRITICAL, ifp);
+
return;
}
/*
@@ -1311,7 +1356,6 @@ ndis_rxeof(adapter, packets, pktcnt)
}
m0 = m;
m0->m_pkthdr.rcvif = ifp;
- ifp->if_ipackets++;
/* Deal with checksum offload. */
@@ -1333,7 +1377,12 @@ ndis_rxeof(adapter, packets, pktcnt)
}
}
- (*ifp->if_input)(ifp, m0);
+ KeAcquireSpinLockAtDpcLevel(&sc->ndis_rxlock);
+ _IF_ENQUEUE(&sc->ndis_rxqueue, m);
+ KeReleaseSpinLockFromDpcLevel(&sc->ndis_rxlock);
+ IoQueueWorkItem(sc->ndis_inputitem,
+ (io_workitem_func)ndis_inputtask_wrap,
+ WORKQUEUE_CRITICAL, ifp);
}
}
@@ -1341,6 +1390,43 @@ ndis_rxeof(adapter, packets, pktcnt)
}
/*
+ * This routine is run at PASSIVE_LEVEL. We use this routine to pass
+ * packets into the stack in order to avoid calling (*ifp->if_input)()
+ * with any locks held (at DISPATCH_LEVEL, we'll be holding the
+ * 'dispatch level' per-cpu sleep lock).
+ */
+
+static void
+ndis_inputtask(dobj, arg)
+ device_object *dobj;
+ void *arg;
+{
+ ndis_miniport_block *block;
+ struct ifnet *ifp;
+ struct ndis_softc *sc;
+ struct mbuf *m;
+ uint8_t irql;
+
+ ifp = arg;
+ sc = ifp->if_softc;
+ block = dobj->do_devext;
+
+ KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
+ while(1) {
+ _IF_DEQUEUE(&sc->ndis_rxqueue, m);
+ if (m == NULL)
+ break;
+ KeReleaseSpinLock(&sc->ndis_rxlock, irql);
+ ifp->if_ipackets++;
+ (*ifp->if_input)(ifp, m);
+ KeAcquireSpinLock(&sc->ndis_rxlock, &irql);
+ }
+ KeReleaseSpinLock(&sc->ndis_rxlock, irql);
+
+ return;
+}
+
+/*
* A frame was downloaded to the chip. It's safe for us to clean up
* the list buffers.
*/
OpenPOWER on IntegriCloud