The NDIS (and DISPATH/DPC) rules are pretty well known, there isn’t a
lot of wheel to (re)invent.
What is variable: your hardware interface. The driver basically consists
of the hardware interface, NDIS interface and glue between them.
You want to decouple execution flows of these parts so that they won’t
block and hold each other.
If the hardware is cheap and simple (like USB 2.0, SDIO) would be
reasonable to serialize it: make a single thread servicing the data
pump, or set of DPC routines around the hardware, that need to be
serialized.
In the NDIS part, you’ll have send, control (OID) and packet return
paths running in parallel; they will feed data to the h/w interface part
(which runs asynchronously).
The h/w interface will decode received data (network and output of
OIDs). If it is data, indicate it up, if this is OID - complete it.
Keep in mind that NDIS API which indicate data up or complete requests
may immediately call you back to submit new request (yes, recursion!
This is where you need to decouple the paths).
It also depends on whether your driver is NDIS6 or NDIS5.
Synchronization rules there are different.
At the end the design will likely have several queues filled by various
inbound paths, and emptied by the h/w interface “engine”.
In any case you cannot run entirely at PASSIVE because NDIS entry points
can be called at dispatch. Delaying them to passive is a waste.
Most of hardware interfaces (even USB) also calls the callbacks at
dispatch. So spinlocks are natural choice. There is nothing to fear, you
need just learn
and get some experience.
If your hardware is very high-throwput (PCIe or like that), it should be
specially designed to cooperate with the host driver better. NDIS has
few special mechanisms for such devices (TCP offloads, RSS and others).
I don’t know why, but it “feels” very right for me to run control
path in PASSIVE and serialized.
> Perhaps that’s because I come from the world of embedded systems,
Yes, very likely. In many of these systems drivers are tasks,
interrupts are like events, so communication among drivers is like
communication among tasks. But Windows NT is different.
Good luck,
– pa
On 06-Aug-2011 22:17, xxxxx@gmail.com wrote:
Hi everybody, and thanks for your replies.
I spent some more time thinking of the problem (and the solutions), and I have some more questions and thoughts, if I may…
The first thought was that I’m probably trying to find a common solution for the entire driver, and that might not work. After all, handling the data path has different requirements than handling the control path.
So, I’d like to focus on handling the control path.
By this I mean the OIDs, and also the control data that goes to and form the air
(scanning, authentication, etc…).
Will serializing this path (where operations are usually serialized anyway?)
be acceptable?
Do you think that the “handle everything in PASSIVE mode” method I suggested in option 1 work here?
My concerns are mainly about performance:
- Spin locks are expensive (busy wait, flushing cache)
- Running in DISPATCH level for long time hurts performance
- It seems like MS (slowly but assuredly) directs developers to use DISPATCH
level, or even user-mode (e.g.: for Win8 logo, there are limitations on the
amount of time a driver may run in DISPATCH level), so I’d like to avoid
DISPATCH level as much as I can.
- In this way, data path will never lose CPU to control path (if there is CPU time for the driver).
I don’t know why, but it “feels” very right for me to run control path in PASSIVE and serialized.
Perhaps that’s because I come from the world of embedded systems, where the CPU
runs only the device’s apps, and that data is more important than control 
Sorry for being lengthy… it’s a sign for confusion:-)
Your thoughts and ideas are welcome.
Thanks,