From 966185d79734c20244e08234d5257f633ca9ec0c Mon Sep 17 00:00:00 2001 From: wpaul Date: Wed, 7 Jul 2004 17:46:30 +0000 Subject: Fix two problems: - In subr_ndis.c:ndis_allocate_sharemem(), create the busdma tags used for shared memory allocations with a lowaddr of 0x3E7FFFFF. This forces the buffers to be mapped to physical/bus addresses within the first 1GB of physical memory. It seems that at least one card (Linksys Instant Wireless PCI V2.7) depends on this behavior. I don't know if this is a hardware restriction, or if the NDIS driver for this card is truncating the addresses itself, but using physical/bus addresses beyong the 1GB limit causes initialization failures. - Create am NDIS_INITIALIZED() macro in if_ndisvar.h and use it in if_ndis.c to test whether the device has been initialized rather than checking for the presence of the IFF_UP flag in if_flags. While debugging the previous problem, I noticed that bringing up the device would always produce failures from ndis_setmulti(). It turns out that the following steps now occur during device initialization: - IFF_UP flag is set in if_flags - ifp->if_ioctl() called with SIOCSIFADDR (which we don't handle) - ifp->if_ioctl() called with SIOCADDMULTI - ifp->if_ioctl() called with SIOCADDMULTI (again) - ifp->if_ioctl() called with SIOCADDMULTI (yet again) - ifp->if_ioctl() called with SIOCSIFFLAGS Setting the receive filter and multicast filters can only be done when the underlying NDIS driver has been initialized, which is done by ifp->if_init(). However, we don't call ifp->if_init() until ifp->if_ioctl() is called with SIOCSIFFLAGS and IFF_UP has been set. It appears that now, the network stack tries to add multicast addresses to interface's filter before those steps occur. Normally, ndis_setmulti() would trap this condition by checking for the IFF_UP flag, but the network code has in fact set this flag already, so ndis_setmulti() is fooled into thinking the interface has been initialized when it really hasn't. It turns out this is usually harmless because the ifp->if_init() routine (in this case ndis_init()) will set up the multicast filter when it initializes the hardware anyway, and the underlying routines (ndis_get_info()/ndis_set_info()) know that the driver/NIC haven't been initialized yet, but you end up spurious error messages on the console all the time. Something tells me this new behavior isn't really correct. I think the intention was to fix it so that ifp->if_init() is only called once when we ifconfig an interface up, but the end result seems a little bogus: the change of the IFF_UP flag should be propagated down to the driver before calling any other ioctl() that might actually require the hardware to be up and running. --- sys/dev/if_ndis/if_ndis.c | 23 +++++++++++------------ sys/dev/if_ndis/if_ndisvar.h | 3 ++- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'sys/dev/if_ndis') diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index d68d765..60b6096 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -139,7 +139,7 @@ ndis_setmulti(sc) ifp = &sc->arpcom.ac_if; - if (!(ifp->if_flags & IFF_UP)) + if (!NDIS_INITIALIZED(sc)) return; if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { @@ -214,7 +214,7 @@ ndis_set_offload(sc) ifp = &sc->arpcom.ac_if; - if (!(ifp->if_flags & IFF_UP)) + if (!NDIS_INITIALIZED(sc)) return(EINVAL); /* See if there's anything to set. */ @@ -766,7 +766,7 @@ ndis_suspend(dev) ifp = &sc->arpcom.ac_if; #ifdef notdef - if (ifp->if_flags & IFF_UP) + if (NDIS_INITIALIZED(sc)) ndis_stop(sc); #endif @@ -783,7 +783,7 @@ ndis_resume(dev) sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; - if (ifp->if_flags & IFF_UP) + if (NDIS_INITIALIZED(sc)) ndis_init(sc); return(0); @@ -957,7 +957,7 @@ ndis_linksts_done(adapter) ifp = block->nmb_ifp; sc = ifp->if_softc; - if (!(ifp->if_flags & IFF_UP)) + if (!NDIS_INITIALIZED(sc)) return; switch (block->nmb_getstat) { @@ -1364,7 +1364,7 @@ ndis_ifmedia_upd(ifp) sc = ifp->if_softc; - if (ifp->if_flags & IFF_UP) + if (NDIS_INITIALIZED(sc)) ndis_init(sc); return(0); @@ -1385,12 +1385,11 @@ ndis_ifmedia_sts(ifp, ifmr) ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; + sc = ifp->if_softc; - if (!(ifp->if_flags & IFF_UP)) + if (!NDIS_INITIALIZED(sc)) return; - sc = ifp->if_softc; - len = sizeof(linkstate); error = ndis_get_info(sc, OID_GEN_MEDIA_CONNECT_STATUS, (void *)&linkstate, &len); @@ -1435,7 +1434,7 @@ ndis_setstate_80211(sc) ic = &sc->ic; ifp = &sc->ic.ic_ac.ac_if; - if (!(ifp->if_flags & IFF_UP)) + if (!NDIS_INITIALIZED(sc)) return; /* Set network infrastructure mode. */ @@ -1734,7 +1733,7 @@ ndis_getstate_80211(sc) ic = &sc->ic; ifp = &sc->ic.ic_ac.ac_if; - if (!(ifp->if_flags & IFF_UP)) + if (!NDIS_INITIALIZED(sc)) return; if (sc->ndis_link) @@ -1926,7 +1925,7 @@ ndis_ioctl(ifp, command, data) break; case SIOCGIFGENERIC: case SIOCSIFGENERIC: - if (sc->ndis_80211 && ifp->if_flags & IFF_UP) { + if (sc->ndis_80211 && NDIS_INITIALIZED(sc)) { if (command == SIOCGIFGENERIC) error = ndis_wi_ioctl_get(ifp, command, data); else diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h index 88a6361..4560e34 100644 --- a/sys/dev/if_ndis/if_ndisvar.h +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -62,6 +62,8 @@ struct ndis_cfglist { TAILQ_HEAD(nch, ndis_cfglist); +#define NDIS_INITIALIZED(sc) (sc->ndis_block.nmb_miniportadapterctx != NULL) + #define NDIS_INC(x) \ (x)->ndis_txidx = ((x)->ndis_txidx + 1) % (x)->ndis_maxpkts @@ -131,4 +133,3 @@ struct ndis_softc { #define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx) #define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx) - -- cgit v1.1