1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-17 10:26:15 +00:00

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.
This commit is contained in:
Bill Paul 2004-07-07 17:46:30 +00:00
parent b2a75fdfdf
commit 06794990cb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=131750
4 changed files with 31 additions and 15 deletions

View File

@ -975,6 +975,8 @@ struct ndis_sc_element {
typedef struct ndis_sc_element ndis_sc_element;
#define NDIS_MAXSEG 32
#define NDIS_BUS_SPACE_SHARED_MAXADDR 0x3E7FFFFF
struct ndis_sc_list {
uint32_t nsl_frags;
uint32_t *nsl_rsvd;

View File

@ -1297,8 +1297,22 @@ ndis_alloc_sharedmem(adapter, len, cached, vaddr, paddr)
if (sh == NULL)
return;
/*
* When performing shared memory allocations, create a tag
* with a lowaddr limit that restricts physical memory mappings
* so that they all fall within the first 1GB of memory.
* At least one device/driver combination (Linksys Instant
* Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
* problems with performing DMA operations with physical
* that lie above the 1GB mark. I don't know if this is a
* hardware limitation or if the addresses are being truncated
* within the driver, but this seems to be the only way to
* make these cards work reliably in systems with more than
* 1GB of physical memory.
*/
error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL,
NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL,
&sh->ndis_stag);

View File

@ -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;
if (!(ifp->if_flags & IFF_UP))
return;
sc = ifp->if_softc;
if (!NDIS_INITIALIZED(sc))
return;
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

View File

@ -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)