freebsd-nq/sys/dev/if_ndis/if_ndisvar.h
Bill Paul 2b94c69d1d Continue my efforts to imitate Windows as closely as possible by
attempting to duplicate Windows spinlocks. Windows spinlocks differ
from FreeBSD spinlocks in the way they block preemption. FreeBSD
spinlocks use critical_enter(), which masks off _all_ interrupts.
This prevents any other threads from being scheduled, but it also
prevents ISRs from running. In Windows, preemption is achieved by
raising the processor IRQL to DISPATCH_LEVEL, which prevents other
threads from preempting you, but does _not_ prevent device ISRs
from running. (This is essentially what Solaris calls dispatcher
locks.) The Windows spinlock itself (kspin_lock) is just an integer
value which is atomically set when you acquire the lock and atomically
cleared when you release it.

FreeBSD doesn't have IRQ levels, so we have to cheat a little by
using thread priorities: normal thread priority is PASSIVE_LEVEL,
lowest interrupt thread priority is DISPATCH_LEVEL, highest thread
priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is
HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL
matter to us. The immediate benefit of all this is that I no
longer have to rely on a mutex pool.

Now, I'm sure many people will be seized by the urge to criticize
me for doing an end run around our own spinlock implementation, but
it makes more sense to do it this way. Well, it does to me anyway.

Overview of the changes:

- Properly implement hal_lock(), hal_unlock(), hal_irql(),
  hal_raise_irql() and hal_lower_irql() so that they more closely
  resemble their Windows counterparts. The IRQL is determined by
  thread priority.

- Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do
  in Windows, which is to atomically set/clear the lock value. These
  routines are designed to be called from DISPATCH_LEVEL, and are
  actually half of the work involved in acquiring/releasing spinlocks.

- Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers
  that allow us to call a _fastcall function in spite of the fact
  that our version of gcc doesn't support __attribute__((__fastcall__))
  yet. The macros take 1, 2 or 3 arguments, respectively. We need
  to call hal_lock(), hal_unlock() etc... ourselves, but can't really
  invoke the function directly. I could have just made the underlying
  functions native routines and put _fastcall wrappers around them for
  the benefit of Windows binaries, but that would create needless bloat.

- Remove ndis_mtxpool and all references to it. We don't need it
  anymore.

- Re-implement the NdisSpinLock routines so that they use hal_lock()
  and friends like they do in Windows.

- Use the new spinlock methods for handling lookaside lists and
  linked list updates in place of the mutex locks that were there
  before.

- Remove mutex locking from ndis_isr() and ndis_intrhand() since they're
  already called with ndis_intrmtx held in if_ndis.c.

- Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif.
  It turns out there are some drivers which stupidly free the memory
  in which their spinlocks reside before calling ndis_destroy_lock()
  on them (touch-after-free bug). The ADMtek wireless driver
  is guilty of this faux pas. (Why this doesn't clobber Windows I
  have no idea.)

- Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into
  real functions instead of aliasing them to NdisAcaquireSpinLock()
  and NdisReleaseSpinLock(). The Dpr routines use
  KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(),
  which acquires the lock without twiddling the IRQL.

- In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some
  drivers may call the status/status done callbacks as the result of
  setting an OID: ndis_80211_getstate() gets OIDs, which means we
  might cause the driver to recursively access some of its internal
  structures unexpectedly. The ndis_ticktask() routine will call
  ndis_80211_getstate() for us eventually anyway.

- Fix the channel setting code a little in ndis_80211_setstate(),
  and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft
  spec says you're not supposed to twiddle the channel in BSS mode;
  I may need to enforce this later.) This fixes the problems I was
  having with the ADMtek adm8211 driver: we were setting the channel
  to a non-standard default, which would cause it to fail to associate
  in BSS mode.

- Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when
  calling certain miniport routines, per the Microsoft documentation.

I think that's everything. Hopefully, other than fixing the ADMtek
driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00

133 lines
4.0 KiB
C

/*
* Copyright (c) 2003
* Bill Paul <wpaul@windriver.com>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#define NDIS_DEFAULT_NODENAME "FreeBSD NDIS node"
#define NDIS_NODENAME_LEN 32
struct ndis_pci_type {
uint16_t ndis_vid;
uint16_t ndis_did;
uint32_t ndis_subsys;
char *ndis_name;
};
struct ndis_pccard_type {
const char *ndis_vid;
const char *ndis_did;
char *ndis_name;
};
struct ndis_shmem {
bus_dma_tag_t ndis_stag;
bus_dmamap_t ndis_smap;
void *ndis_saddr;
struct ndis_shmem *ndis_next;
};
struct ndis_cfglist {
ndis_cfg ndis_cfg;
TAILQ_ENTRY(ndis_cfglist) link;
};
TAILQ_HEAD(nch, ndis_cfglist);
#define NDIS_INC(x) \
(x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts
#define arpcom ic.ic_ac
struct ndis_softc {
struct ieee80211com ic; /* interface info */
#ifdef notdef
struct ieee80211com arpcom; /* interface info */
#endif
struct ifmedia ifmedia; /* media info */
u_long ndis_hwassist;
uint32_t ndis_v4tx;
uint32_t ndis_v4rx;
bus_space_handle_t ndis_bhandle;
bus_space_tag_t ndis_btag;
void *ndis_intrhand;
struct resource *ndis_irq;
struct resource *ndis_res;
struct resource *ndis_res_io;
int ndis_io_rid;
struct resource *ndis_res_mem;
int ndis_mem_rid;
struct resource *ndis_res_altmem;
int ndis_altmem_rid;
struct resource *ndis_res_am; /* attribute mem (pccard) */
struct resource *ndis_res_cm; /* common mem (pccard) */
int ndis_rescnt;
struct mtx ndis_mtx;
struct mtx ndis_intrmtx;
device_t ndis_dev;
int ndis_unit;
ndis_miniport_block ndis_block;
ndis_miniport_characteristics ndis_chars;
interface_type ndis_type;
struct callout_handle ndis_stat_ch;
int ndis_maxpkts;
ndis_oid *ndis_oids;
int ndis_oidcnt;
int ndis_txidx;
int ndis_txpending;
ndis_packet **ndis_txarray;
int ndis_sc;
ndis_cfg *ndis_regvals;
struct nch ndis_cfglist_head;
int ndis_80211;
int ndis_link;
uint32_t ndis_filter;
int ndis_if_flags;
int ndis_skip;
struct sysctl_ctx_list ndis_ctx;
struct sysctl_oid *ndis_tree;
int ndis_devidx;
interface_type ndis_iftype;
bus_dma_tag_t ndis_parent_tag;
struct ndis_shmem *ndis_shlist;
bus_dma_tag_t ndis_mtag;
bus_dma_tag_t ndis_ttag;
bus_dmamap_t *ndis_mmaps;
bus_dmamap_t *ndis_tmaps;
int ndis_mmapcnt;
};
#define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx)
#define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx)