summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2004-07-07 17:46:30 +0000
committerwpaul <wpaul@FreeBSD.org>2004-07-07 17:46:30 +0000
commit966185d79734c20244e08234d5257f633ca9ec0c (patch)
treea4599e326560d3819670b9185061088a7574b600 /sys/compat
parent2d2e93d885384c000c60e399a24d2e4bb9cae3fa (diff)
downloadFreeBSD-src-966185d79734c20244e08234d5257f633ca9ec0c.zip
FreeBSD-src-966185d79734c20244e08234d5257f633ca9ec0c.tar.gz
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.
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/ndis/ndis_var.h2
-rw-r--r--sys/compat/ndis/subr_ndis.c16
2 files changed, 17 insertions, 1 deletions
diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h
index f2c3566..2c015a9 100644
--- a/sys/compat/ndis/ndis_var.h
+++ b/sys/compat/ndis/ndis_var.h
@@ -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;
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c
index 30def31..243c9dc 100644
--- a/sys/compat/ndis/subr_ndis.c
+++ b/sys/compat/ndis/subr_ndis.c
@@ -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);
OpenPOWER on IntegriCloud