[rtems-libbsd commit] Update to FreeBSD stable/12 2019-01-29

Sebastian Huber sebh at rtems.org
Tue Jan 29 10:10:48 UTC 2019


Module:    rtems-libbsd
Branch:    5-freebsd-12
Commit:    a5b385b26fb88ecb0408c684643adec481596dd8
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=a5b385b26fb88ecb0408c684643adec481596dd8

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Jan 29 10:57:36 2019 +0100

Update to FreeBSD stable/12 2019-01-29

Git mirror commit 7005c2e76a6bfb359bf2f1acb8382c0b7a01f4be.

---

 freebsd-org                               |   2 +-
 freebsd/lib/libc/net/gai_strerror.c       |  18 +--
 freebsd/sbin/ifconfig/ifieee80211.c       |   5 -
 freebsd/sys/arm/ti/ti_sdhci.c             |   2 +-
 freebsd/sys/dev/pci/pci.c                 |  26 +++-
 freebsd/sys/dev/sdhci/fsl_sdhci.c         |   2 +-
 freebsd/sys/dev/sdhci/sdhci.c             | 228 +++++++++++++++++++-----------
 freebsd/sys/dev/sdhci/sdhci.h             |  21 ++-
 freebsd/sys/dev/usb/wlan/if_run.c         |  82 +++++++----
 freebsd/sys/dev/usb/wlan/if_urtw.c        |  50 ++++---
 freebsd/sys/dev/usb/wlan/if_urtwvar.h     |   4 -
 freebsd/sys/kern/kern_intr.c              | 104 ++++++++++++--
 freebsd/sys/kern/kern_mtxpool.c           |   4 +-
 freebsd/sys/kern/subr_bus.c               |  58 ++++++++
 freebsd/sys/kern/subr_rman.c              |  15 ++
 freebsd/sys/net80211/ieee80211.c          |   4 +-
 freebsd/sys/net80211/ieee80211_crypto.c   |  11 +-
 freebsd/sys/net80211/ieee80211_freebsd.c  |  49 +++++++
 freebsd/sys/net80211/ieee80211_freebsd.h  |   6 +-
 freebsd/sys/net80211/ieee80211_ioctl.c    |  10 +-
 freebsd/sys/net80211/ieee80211_scan_sta.c |  65 ++++++---
 freebsd/sys/net80211/ieee80211_var.h      |  10 +-
 freebsd/sys/netinet/in.c                  |  21 ++-
 freebsd/sys/netinet/ip_output.c           |   3 +-
 freebsd/sys/netinet/sctp_constants.h      |   3 +
 freebsd/sys/netinet/sctp_usrreq.c         |   4 +
 freebsd/sys/netinet/tcp_output.c          |   3 +-
 freebsd/sys/netinet6/in6.c                |  21 ++-
 freebsd/sys/netpfil/pf/pf_table.c         |   5 +-
 freebsd/sys/sys/bus.h                     |   6 +
 freebsd/sys/sys/interrupt.h               |   4 +
 freebsd/sys/sys/rman.h                    |   2 +
 freebsd/sys/sys/rmlock.h                  |   1 -
 freebsd/sys/sys/rwlock.h                  |   1 -
 34 files changed, 630 insertions(+), 220 deletions(-)

diff --git a/freebsd-org b/freebsd-org
index 3a48f36..7005c2e 160000
--- a/freebsd-org
+++ b/freebsd-org
@@ -1 +1 @@
-Subproject commit 3a48f3689d65c5304cf706bbf2c5576daeb60a96
+Subproject commit 7005c2e76a6bfb359bf2f1acb8382c0b7a01f4be
diff --git a/freebsd/lib/libc/net/gai_strerror.c b/freebsd/lib/libc/net/gai_strerror.c
index b2b35d6..402b16f 100644
--- a/freebsd/lib/libc/net/gai_strerror.c
+++ b/freebsd/lib/libc/net/gai_strerror.c
@@ -47,19 +47,19 @@ __FBSDID("$FreeBSD$");
 #include "un-namespace.h"
 
 /* Entries EAI_ADDRFAMILY (1) and EAI_NODATA (7) are obsoleted, but left */
-/* for backward compatibility with userland code prior to 2553bis-02 */
+/* for backwards compatibility with userland code prior to RFC2553bis-02 */
 static const char *ai_errlist[] = {
 	"Success",					/* 0 */
-	"Address family for hostname not supported",	/* 1 */
-	"Temporary failure in name resolution",		/* EAI_AGAIN */
-	"Invalid value for ai_flags",			/* EAI_BADFLAGS */
+	"Address family for hostname not supported",	/* 1: Obsolete */
+	"Name could not be resolved at this time",	/* EAI_AGAIN */
+	"Flags parameter had an invalid value",		/* EAI_BADFLAGS */
 	"Non-recoverable failure in name resolution",	/* EAI_FAIL */
-	"ai_family not supported",			/* EAI_FAMILY */
+	"Address family not recognized",		/* EAI_FAMILY */
 	"Memory allocation failure", 			/* EAI_MEMORY */
-	"No address associated with hostname",		/* 7 */
-	"hostname nor servname provided, or not known",	/* EAI_NONAME */
-	"servname not supported for ai_socktype",	/* EAI_SERVICE */
-	"ai_socktype not supported", 			/* EAI_SOCKTYPE */
+	"No address associated with hostname",		/* 7: Obsolete*/
+	"Name does not resolve",			/* EAI_NONAME */
+	"Service was not recognized for socket type",	/* EAI_SERVICE */
+	"Intended socket type was not recognized",	/* EAI_SOCKTYPE */
 	"System error returned in errno", 		/* EAI_SYSTEM */
 	"Invalid value for hints",			/* EAI_BADHINTS */
 	"Resolved protocol is unknown",			/* EAI_PROTOCOL */
diff --git a/freebsd/sbin/ifconfig/ifieee80211.c b/freebsd/sbin/ifconfig/ifieee80211.c
index fa40795..dc7b88d 100644
--- a/freebsd/sbin/ifconfig/ifieee80211.c
+++ b/freebsd/sbin/ifconfig/ifieee80211.c
@@ -1539,9 +1539,6 @@ getmodeflags(const char *val)
 	return flags;
 }
 
-#define	IEEE80211_CHAN_HTA	(IEEE80211_CHAN_HT|IEEE80211_CHAN_5GHZ)
-#define	IEEE80211_CHAN_HTG	(IEEE80211_CHAN_HT|IEEE80211_CHAN_2GHZ)
-
 #define	_APPLY(_flags, _base, _param, _v) do {				\
     if (_flags & IEEE80211_CHAN_HT) {					\
 	    if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
@@ -1731,8 +1728,6 @@ DECL_CMD_FUNC(set80211maxretry, val, d)
 }
 #undef _APPLY_RATE
 #undef _APPLY
-#undef IEEE80211_CHAN_HTA
-#undef IEEE80211_CHAN_HTG
 
 static
 DECL_CMD_FUNC(set80211fragthreshold, val, d)
diff --git a/freebsd/sys/arm/ti/ti_sdhci.c b/freebsd/sys/arm/ti/ti_sdhci.c
index c5d29cb..6656ce2 100644
--- a/freebsd/sys/arm/ti/ti_sdhci.c
+++ b/freebsd/sys/arm/ti/ti_sdhci.c
@@ -757,7 +757,7 @@ static driver_t ti_sdhci_driver = {
 
 DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, NULL,
     NULL);
-MODULE_DEPEND(sdhci_ti, sdhci, 1, 1, 1);
+SDHCI_DEPEND(sdhci_ti);
 
 #ifndef MMCCAM
 MMC_DECLARE_BRIDGE(sdhci_ti);
diff --git a/freebsd/sys/dev/pci/pci.c b/freebsd/sys/dev/pci/pci.c
index 512e863..09d1ee4 100644
--- a/freebsd/sys/dev/pci/pci.c
+++ b/freebsd/sys/dev/pci/pci.c
@@ -4467,6 +4467,7 @@ int
 pci_suspend_child(device_t dev, device_t child)
 {
 	struct pci_devinfo *dinfo;
+	struct resource_list_entry *rle;
 	int error;
 
 	dinfo = device_get_ivars(child);
@@ -4483,8 +4484,20 @@ pci_suspend_child(device_t dev, device_t child)
 	if (error)
 		return (error);
 
-	if (pci_do_power_suspend)
+	if (pci_do_power_suspend) {
+		/*
+		 * Make sure this device's interrupt handler is not invoked
+		 * in the case the device uses a shared interrupt that can
+		 * be raised by some other device.
+		 * This is applicable only to regular (legacy) PCI interrupts
+		 * as MSI/MSI-X interrupts are never shared.
+		 */
+		rle = resource_list_find(&dinfo->resources,
+		    SYS_RES_IRQ, 0);
+		if (rle != NULL && rle->res != NULL)
+			(void)bus_suspend_intr(child, rle->res);
 		pci_set_power_child(dev, child, PCI_POWERSTATE_D3);
+	}
 
 	return (0);
 }
@@ -4493,6 +4506,7 @@ int
 pci_resume_child(device_t dev, device_t child)
 {
 	struct pci_devinfo *dinfo;
+	struct resource_list_entry *rle;
 
 	if (pci_do_power_resume)
 		pci_set_power_child(dev, child, PCI_POWERSTATE_D0);
@@ -4504,6 +4518,16 @@ pci_resume_child(device_t dev, device_t child)
 
 	bus_generic_resume_child(dev, child);
 
+	/*
+	 * Allow interrupts only after fully resuming the driver and hardware.
+	 */
+	if (pci_do_power_suspend) {
+		/* See pci_suspend_child for details. */
+		rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0);
+		if (rle != NULL && rle->res != NULL)
+			(void)bus_resume_intr(child, rle->res);
+	}
+
 	return (0);
 }
 
diff --git a/freebsd/sys/dev/sdhci/fsl_sdhci.c b/freebsd/sys/dev/sdhci/fsl_sdhci.c
index 84665b4..be3d1de 100644
--- a/freebsd/sys/dev/sdhci/fsl_sdhci.c
+++ b/freebsd/sys/dev/sdhci/fsl_sdhci.c
@@ -1016,7 +1016,7 @@ static driver_t fsl_sdhci_driver = {
 
 DRIVER_MODULE(sdhci_fsl, simplebus, fsl_sdhci_driver, fsl_sdhci_devclass,
     NULL, NULL);
-MODULE_DEPEND(sdhci_fsl, sdhci, 1, 1, 1);
+SDHCI_DEPEND(sdhci_fsl);
 
 #ifndef MMCCAM
 MMC_DECLARE_BRIDGE(sdhci_fsl);
diff --git a/freebsd/sys/dev/sdhci/sdhci.c b/freebsd/sys/dev/sdhci/sdhci.c
index 0bb9edc..b9a8a38 100644
--- a/freebsd/sys/dev/sdhci/sdhci.c
+++ b/freebsd/sys/dev/sdhci/sdhci.c
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/conf.h>
 #include <sys/kernel.h>
 #include <sys/kobj.h>
+#include <sys/libkern.h>
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
@@ -110,19 +111,20 @@ static void sdhci_retune(void *arg);
 static void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock);
 static void sdhci_set_power(struct sdhci_slot *slot, u_char power);
 static void sdhci_set_transfer_mode(struct sdhci_slot *slot,
-   struct mmc_data *data);
+   const struct mmc_data *data);
 static void sdhci_start(struct sdhci_slot *slot);
 static void sdhci_timeout(void *arg);
 static void sdhci_start_command(struct sdhci_slot *slot,
    struct mmc_command *cmd);
-static void sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data);
+static void sdhci_start_data(struct sdhci_slot *slot,
+   const struct mmc_data *data);
 static void sdhci_write_block_pio(struct sdhci_slot *slot);
 static void sdhci_transfer_pio(struct sdhci_slot *slot);
 
 #ifdef MMCCAM
 /* CAM-related */
 static void sdhci_cam_action(struct cam_sim *sim, union ccb *ccb);
-static int sdhci_cam_get_possible_host_clock(struct sdhci_slot *slot,
+static int sdhci_cam_get_possible_host_clock(const struct sdhci_slot *slot,
     int proposed_clock);
 static void sdhci_cam_handle_mmcio(struct cam_sim *sim, union ccb *ccb);
 static void sdhci_cam_poll(struct cam_sim *sim);
@@ -132,12 +134,14 @@ static int sdhci_cam_update_ios(struct sdhci_slot *slot);
 #endif
 
 /* helper routines */
+static int sdhci_dma_alloc(struct sdhci_slot *slot);
+static void sdhci_dma_free(struct sdhci_slot *slot);
 static void sdhci_dumpregs(struct sdhci_slot *slot);
 static void sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs,
     int error);
-static int slot_printf(struct sdhci_slot *slot, const char * fmt, ...)
+static int slot_printf(const struct sdhci_slot *slot, const char * fmt, ...)
     __printflike(2, 3);
-static uint32_t sdhci_tuning_intmask(struct sdhci_slot *slot);
+static uint32_t sdhci_tuning_intmask(const struct sdhci_slot *slot);
 
 #define	SDHCI_LOCK(_slot)		mtx_lock(&(_slot)->mtx)
 #define	SDHCI_UNLOCK(_slot)		mtx_unlock(&(_slot)->mtx)
@@ -181,7 +185,7 @@ sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 }
 
 static int
-slot_printf(struct sdhci_slot *slot, const char * fmt, ...)
+slot_printf(const struct sdhci_slot *slot, const char * fmt, ...)
 {
 	va_list ap;
 	int retval;
@@ -292,7 +296,7 @@ sdhci_reset(struct sdhci_slot *slot, uint8_t mask)
 }
 
 static uint32_t
-sdhci_tuning_intmask(struct sdhci_slot *slot)
+sdhci_tuning_intmask(const struct sdhci_slot *slot)
 {
 	uint32_t intmask;
 
@@ -739,55 +743,94 @@ sdhci_card_poll(void *arg)
 	    sdhci_card_poll, slot);
 }
 
-int
-sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
+static int
+sdhci_dma_alloc(struct sdhci_slot *slot)
 {
-	kobjop_desc_t kobj_desc;
-	kobj_method_t *kobj_method;
-	uint32_t caps, caps2, freq, host_caps;
 	int err;
 
-	SDHCI_LOCK_INIT(slot);
-
-	slot->num = num;
-	slot->bus = dev;
+	if (!(slot->quirks & SDHCI_QUIRK_BROKEN_SDMA_BOUNDARY)) {
+		if (MAXPHYS <= 1024 * 4)
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_4K;
+		else if (MAXPHYS <= 1024 * 8)
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_8K;
+		else if (MAXPHYS <= 1024 * 16)
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_16K;
+		else if (MAXPHYS <= 1024 * 32)
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_32K;
+		else if (MAXPHYS <= 1024 * 64)
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_64K;
+		else if (MAXPHYS <= 1024 * 128)
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_128K;
+		else if (MAXPHYS <= 1024 * 256)
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_256K;
+		else
+			slot->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_512K;
+	}
+	slot->sdma_bbufsz = SDHCI_SDMA_BNDRY_TO_BBUFSZ(slot->sdma_boundary);
 
-	/* Allocate DMA tag. */
-	err = bus_dma_tag_create(bus_get_dma_tag(dev),
-	    DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT,
-	    BUS_SPACE_MAXADDR, NULL, NULL,
-	    DMA_BLOCK_SIZE, 1, DMA_BLOCK_SIZE,
-	    BUS_DMA_ALLOCNOW, NULL, NULL,
-	    &slot->dmatag);
+	/*
+	 * Allocate the DMA tag for an SDMA bounce buffer.
+	 * Note that the SDHCI specification doesn't state any alignment
+	 * constraint for the SDMA system address.  However, controllers
+	 * typically ignore the SDMA boundary bits in SDHCI_DMA_ADDRESS when
+	 * forming the actual address of data, requiring the SDMA buffer to
+	 * be aligned to the SDMA boundary.
+	 */
+	err = bus_dma_tag_create(bus_get_dma_tag(slot->bus), slot->sdma_bbufsz,
+	    0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    slot->sdma_bbufsz, 1, slot->sdma_bbufsz, BUS_DMA_ALLOCNOW,
+	    NULL, NULL, &slot->dmatag);
 	if (err != 0) {
-		device_printf(dev, "Can't create DMA tag\n");
-		SDHCI_LOCK_DESTROY(slot);
+		slot_printf(slot, "Can't create DMA tag for SDMA\n");
 		return (err);
 	}
-	/* Allocate DMA memory. */
+	/* Allocate DMA memory for the SDMA bounce buffer. */
 	err = bus_dmamem_alloc(slot->dmatag, (void **)&slot->dmamem,
 	    BUS_DMA_NOWAIT, &slot->dmamap);
 	if (err != 0) {
-		device_printf(dev, "Can't alloc DMA memory\n");
+		slot_printf(slot, "Can't alloc DMA memory for SDMA\n");
 		bus_dma_tag_destroy(slot->dmatag);
-		SDHCI_LOCK_DESTROY(slot);
 		return (err);
 	}
-	/* Map the memory. */
+	/* Map the memory of the SDMA bounce buffer. */
 	err = bus_dmamap_load(slot->dmatag, slot->dmamap,
-	    (void *)slot->dmamem, DMA_BLOCK_SIZE,
-	    sdhci_getaddr, &slot->paddr, 0);
+	    (void *)slot->dmamem, slot->sdma_bbufsz, sdhci_getaddr,
+	    &slot->paddr, 0);
 	if (err != 0 || slot->paddr == 0) {
-		device_printf(dev, "Can't load DMA memory\n");
+		slot_printf(slot, "Can't load DMA memory for SDMA\n");
 		bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap);
 		bus_dma_tag_destroy(slot->dmatag);
-		SDHCI_LOCK_DESTROY(slot);
 		if (err)
 			return (err);
 		else
 			return (EFAULT);
 	}
 
+	return (0);
+}
+
+static void
+sdhci_dma_free(struct sdhci_slot *slot)
+{
+
+	bus_dmamap_unload(slot->dmatag, slot->dmamap);
+	bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap);
+	bus_dma_tag_destroy(slot->dmatag);
+}
+
+int
+sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
+{
+	kobjop_desc_t kobj_desc;
+	kobj_method_t *kobj_method;
+	uint32_t caps, caps2, freq, host_caps;
+	int err;
+
+	SDHCI_LOCK_INIT(slot);
+
+	slot->num = num;
+	slot->bus = dev;
+
 	slot->version = (RD2(slot, SDHCI_HOST_VERSION)
 		>> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK;
 	if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS) {
@@ -803,12 +846,8 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
 	if (slot->version >= SDHCI_SPEC_300) {
 		if ((caps & SDHCI_SLOTTYPE_MASK) != SDHCI_SLOTTYPE_REMOVABLE &&
 		    (caps & SDHCI_SLOTTYPE_MASK) != SDHCI_SLOTTYPE_EMBEDDED) {
-			device_printf(dev,
+			slot_printf(slot,
 			    "Driver doesn't support shared bus slots\n");
-			bus_dmamap_unload(slot->dmatag, slot->dmamap);
-			bus_dmamem_free(slot->dmatag, slot->dmamem,
-			    slot->dmamap);
-			bus_dma_tag_destroy(slot->dmatag);
 			SDHCI_LOCK_DESTROY(slot);
 			return (ENXIO);
 		} else if ((caps & SDHCI_SLOTTYPE_MASK) ==
@@ -832,7 +871,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
 	 */
 	if (slot->max_clk == 0) {
 		slot->max_clk = SDHCI_DEFAULT_MAX_FREQ * 1000000;
-		device_printf(dev, "Hardware doesn't specify base clock "
+		slot_printf(slot, "Hardware doesn't specify base clock "
 		    "frequency, using %dMHz as default.\n",
 		    SDHCI_DEFAULT_MAX_FREQ);
 	}
@@ -853,7 +892,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
 	 * max timeout, but still mention it.
 	 */
 	if (slot->timeout_clk == 0) {
-		device_printf(dev, "Hardware doesn't specify timeout clock "
+		slot_printf(slot, "Hardware doesn't specify timeout clock "
 		    "frequency, setting BROKEN_TIMEOUT quirk.\n");
 		slot->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 	}
@@ -869,7 +908,7 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
 	if ((caps & SDHCI_CAN_VDD_180) && (slot->opt & SDHCI_SLOT_EMBEDDED))
 	    slot->host.host_ocr |= MMC_OCR_LOW_VOLTAGE;
 	if (slot->host.host_ocr == 0) {
-		device_printf(dev, "Hardware doesn't report any "
+		slot_printf(slot, "Hardware doesn't report any "
 		    "support voltages.\n");
 	}
 
@@ -955,7 +994,7 @@ no_tuning:
 			slot->retune_count = (caps2 & SDHCI_RETUNE_CNT_MASK) >>
 			    SDHCI_RETUNE_CNT_SHIFT;
 			if (slot->retune_count > 0xb) {
-				device_printf(dev, "Unknown re-tuning count "
+				slot_printf(slot, "Unknown re-tuning count "
 				    "%x, using 1 sec\n", slot->retune_count);
 				slot->retune_count = 1;
 			} else if (slot->retune_count != 0)
@@ -1014,6 +1053,19 @@ no_tuning:
 	if (slot->opt & SDHCI_PLATFORM_TRANSFER)
 		slot->opt &= ~SDHCI_HAVE_DMA;
 
+	if (slot->opt & SDHCI_HAVE_DMA) {
+		err = sdhci_dma_alloc(slot);
+		if (err != 0) {
+			if (slot->opt & SDHCI_TUNING_SUPPORTED) {
+				free(slot->tune_req, M_DEVBUF);
+				free(slot->tune_cmd, M_DEVBUF);
+				free(slot->tune_data, M_DEVBUF);
+			}
+			SDHCI_LOCK_DESTROY(slot);
+			return (err);
+		}
+	}
+
 	if (bootverbose || sdhci_debug) {
 		slot_printf(slot,
 		    "%uMHz%s %s VDD:%s%s%s VCCQ: 3.3V%s%s DRV: B%s%s%s %s %s\n",
@@ -1111,9 +1163,8 @@ sdhci_cleanup_slot(struct sdhci_slot *slot)
 	SDHCI_LOCK(slot);
 	sdhci_reset(slot, SDHCI_RESET_ALL);
 	SDHCI_UNLOCK(slot);
-	bus_dmamap_unload(slot->dmatag, slot->dmamap);
-	bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap);
-	bus_dma_tag_destroy(slot->dmatag);
+	if (slot->opt & SDHCI_HAVE_DMA)
+		sdhci_dma_free(slot);
 	if (slot->opt & SDHCI_TUNING_SUPPORTED) {
 		free(slot->tune_req, M_DEVBUF);
 		free(slot->tune_cmd, M_DEVBUF);
@@ -1177,7 +1228,7 @@ sdhci_generic_get_card_present(device_t brdev __unused, struct sdhci_slot *slot)
 void
 sdhci_generic_set_uhs_timing(device_t brdev __unused, struct sdhci_slot *slot)
 {
-	struct mmc_ios *ios;
+	const struct mmc_ios *ios;
 	uint16_t hostctrl2;
 
 	if (slot->version < SDHCI_SPEC_300)
@@ -1310,7 +1361,7 @@ int
 sdhci_generic_tune(device_t brdev __unused, device_t reqdev, bool hs400)
 {
 	struct sdhci_slot *slot = device_get_ivars(reqdev);
-	struct mmc_ios *ios = &slot->host.ios;
+	const struct mmc_ios *ios = &slot->host.ios;
 	struct mmc_command *tune_cmd;
 	struct mmc_data *tune_data;
 	uint32_t opcode;
@@ -1579,7 +1630,7 @@ sdhci_timeout(void *arg)
 }
 
 static void
-sdhci_set_transfer_mode(struct sdhci_slot *slot, struct mmc_data *data)
+sdhci_set_transfer_mode(struct sdhci_slot *slot, const struct mmc_data *data)
 {
 	uint16_t mode;
 
@@ -1781,9 +1832,9 @@ sdhci_finish_command(struct sdhci_slot *slot)
 }
 
 static void
-sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data)
+sdhci_start_data(struct sdhci_slot *slot, const struct mmc_data *data)
 {
-	uint32_t target_timeout, current_timeout;
+	uint32_t blkcnt, blksz, current_timeout, sdma_bbufsz, target_timeout;
 	uint8_t div;
 
 	if (data == NULL && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) {
@@ -1819,7 +1870,7 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data)
 	/* Use DMA if possible. */
 	if ((slot->opt & SDHCI_HAVE_DMA))
 		slot->flags |= SDHCI_USE_DMA;
-	/* If data is small, broken DMA may return zeroes instead of data, */
+	/* If data is small, broken DMA may return zeroes instead of data. */
 	if ((slot->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) &&
 	    (data->len <= 512))
 		slot->flags &= ~SDHCI_USE_DMA;
@@ -1829,20 +1880,22 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data)
 		slot->flags &= ~SDHCI_USE_DMA;
 	/* Load DMA buffer. */
 	if (slot->flags & SDHCI_USE_DMA) {
+		sdma_bbufsz = slot->sdma_bbufsz;
 		if (data->flags & MMC_DATA_READ)
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_PREREAD);
 		else {
-			memcpy(slot->dmamem, data->data,
-			    (data->len < DMA_BLOCK_SIZE) ?
-			    data->len : DMA_BLOCK_SIZE);
+			memcpy(slot->dmamem, data->data, ulmin(data->len,
+			    sdma_bbufsz));
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_PREWRITE);
 		}
 		WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr);
-		/* Interrupt aggregation: Mask border interrupt
-		 * for the last page and unmask else. */
-		if (data->len == DMA_BLOCK_SIZE)
+		/*
+		 * Interrupt aggregation: Mask border interrupt for the last
+		 * bounce buffer and unmask otherwise.
+		 */
+		if (data->len == sdma_bbufsz)
 			slot->intmask &= ~SDHCI_INT_DMA_END;
 		else
 			slot->intmask |= SDHCI_INT_DMA_END;
@@ -1850,16 +1903,15 @@ sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data)
 	}
 	/* Current data offset for both PIO and DMA. */
 	slot->offset = 0;
-	/* Set block size and request IRQ on 4K border. */
-	WR2(slot, SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(DMA_BOUNDARY,
-	    (data->len < 512) ? data->len : 512));
+	/* Set block size and request border interrupts on the SDMA boundary. */
+	blksz = SDHCI_MAKE_BLKSZ(slot->sdma_boundary, ulmin(data->len, 512));
+	WR2(slot, SDHCI_BLOCK_SIZE, blksz);
 	/* Set block count. */
-	WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512);
-
+	blkcnt = howmany(data->len, 512);
+	WR2(slot, SDHCI_BLOCK_COUNT, blkcnt);
 	if (__predict_false(sdhci_debug > 1))
-		slot_printf(slot, "Block size: %02x, count %lu\n",
-		    (unsigned int)SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512) ? data->len : 512),
-		    (unsigned long)(data->len + 511) / 512);
+		slot_printf(slot, "Blk size: 0x%08x | Blk cnt:  0x%08x\n",
+		    blksz, blkcnt);
 }
 
 void
@@ -1883,7 +1935,7 @@ sdhci_finish_data(struct sdhci_slot *slot)
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_POSTREAD);
 			memcpy((u_char*)data->data + slot->offset, slot->dmamem,
-			    (left < DMA_BLOCK_SIZE) ? left : DMA_BLOCK_SIZE);
+			    ulmin(left, slot->sdma_bbufsz));
 		} else
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_POSTWRITE);
@@ -1907,15 +1959,14 @@ sdhci_finish_data(struct sdhci_slot *slot)
 static void
 sdhci_start(struct sdhci_slot *slot)
 {
-        union ccb *ccb;
+	union ccb *ccb;
+	struct ccb_mmcio *mmcio;
 
 	ccb = slot->ccb;
 	if (ccb == NULL)
 		return;
 
-        struct ccb_mmcio *mmcio;
 	mmcio = &ccb->mmcio;
-
 	if (!(slot->flags & CMD_STARTED)) {
 		slot->flags |= CMD_STARTED;
 		sdhci_start_command(slot, &mmcio->cmd);
@@ -1947,7 +1998,7 @@ sdhci_start(struct sdhci_slot *slot)
 static void
 sdhci_start(struct sdhci_slot *slot)
 {
-	struct mmc_request *req;
+	const struct mmc_request *req;
 
 	req = slot->req;
 	if (req == NULL)
@@ -2076,6 +2127,7 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask)
 {
 	struct mmc_data *data;
 	size_t left;
+	uint32_t sdma_bbufsz;
 
 	if (!slot->curcmd) {
 		slot_printf(slot, "Got data interrupt 0x%08x, but "
@@ -2130,6 +2182,7 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask)
 	/* Handle DMA border. */
 	if (intmask & SDHCI_INT_DMA_END) {
 		data = slot->curcmd->data;
+		sdma_bbufsz = slot->sdma_bbufsz;
 
 		/* Unload DMA buffer ... */
 		left = data->len - slot->offset;
@@ -2137,26 +2190,28 @@ sdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask)
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_POSTREAD);
 			memcpy((u_char*)data->data + slot->offset, slot->dmamem,
-			    (left < DMA_BLOCK_SIZE) ? left : DMA_BLOCK_SIZE);
+			    ulmin(left, sdma_bbufsz));
 		} else {
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_POSTWRITE);
 		}
 		/* ... and reload it again. */
-		slot->offset += DMA_BLOCK_SIZE;
+		slot->offset += sdma_bbufsz;
 		left = data->len - slot->offset;
 		if (data->flags & MMC_DATA_READ) {
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_PREREAD);
 		} else {
 			memcpy(slot->dmamem, (u_char*)data->data + slot->offset,
-			    (left < DMA_BLOCK_SIZE)? left : DMA_BLOCK_SIZE);
+			    ulmin(left, sdma_bbufsz));
 			bus_dmamap_sync(slot->dmatag, slot->dmamap,
 			    BUS_DMASYNC_PREWRITE);
 		}
-		/* Interrupt aggregation: Mask border interrupt
-		 * for the last page. */
-		if (left == DMA_BLOCK_SIZE) {
+		/*
+		 * Interrupt aggregation: Mask border interrupt for the last
+		 * bounce buffer.
+		 */
+		if (left == sdma_bbufsz) {
 			slot->intmask &= ~SDHCI_INT_DMA_END;
 			WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
 		}
@@ -2279,7 +2334,7 @@ int
 sdhci_generic_read_ivar(device_t bus, device_t child, int which,
     uintptr_t *result)
 {
-	struct sdhci_slot *slot = device_get_ivars(child);
+	const struct sdhci_slot *slot = device_get_ivars(child);
 
 	switch (which) {
 	default:
@@ -2442,6 +2497,7 @@ sdhci_generic_write_ivar(device_t bus, device_t child, int which,
 void
 sdhci_start_slot(struct sdhci_slot *slot)
 {
+
         if ((slot->devq = cam_simq_alloc(1)) == NULL) {
                 goto fail;
         }
@@ -2601,7 +2657,8 @@ sdhci_cam_poll(struct cam_sim *sim)
 }
 
 static int
-sdhci_cam_get_possible_host_clock(struct sdhci_slot *slot, int proposed_clock)
+sdhci_cam_get_possible_host_clock(const struct sdhci_slot *slot,
+    int proposed_clock)
 {
 	int max_clock, clock, i;
 
@@ -2628,15 +2685,14 @@ sdhci_cam_get_possible_host_clock(struct sdhci_slot *slot, int proposed_clock)
 	return clock;
 }
 
-int
+static int
 sdhci_cam_settran_settings(struct sdhci_slot *slot, union ccb *ccb)
 {
 	struct mmc_ios *ios;
-	struct mmc_ios *new_ios;
-	struct ccb_trans_settings_mmc *cts;
+	const struct mmc_ios *new_ios;
+	const struct ccb_trans_settings_mmc *cts;
 
 	ios = &slot->host.ios;
-
 	cts = &ccb->cts.proto_specific.mmc;
 	new_ios = &cts->ios;
 
@@ -2674,7 +2730,7 @@ sdhci_cam_settran_settings(struct sdhci_slot *slot, union ccb *ccb)
 	return (sdhci_cam_update_ios(slot));
 }
 
-int
+static int
 sdhci_cam_update_ios(struct sdhci_slot *slot)
 {
 	struct mmc_ios *ios = &slot->host.ios;
@@ -2716,10 +2772,10 @@ sdhci_cam_update_ios(struct sdhci_slot *slot)
 	return (0);
 }
 
-int
+static int
 sdhci_cam_request(struct sdhci_slot *slot, union ccb *ccb)
 {
-	struct ccb_mmcio *mmcio;
+	const struct ccb_mmcio *mmcio;
 
 	mmcio = &ccb->mmcio;
 
@@ -2754,4 +2810,4 @@ sdhci_cam_request(struct sdhci_slot *slot, union ccb *ccb)
 }
 #endif /* MMCCAM */
 
-MODULE_VERSION(sdhci, 1);
+MODULE_VERSION(sdhci, SDHCI_VERSION);
diff --git a/freebsd/sys/dev/sdhci/sdhci.h b/freebsd/sys/dev/sdhci/sdhci.h
index a22e023..4c4c274 100644
--- a/freebsd/sys/dev/sdhci/sdhci.h
+++ b/freebsd/sys/dev/sdhci/sdhci.h
@@ -32,8 +32,8 @@
 
 #include <rtems/bsd/local/opt_mmccam.h>
 
-#define	DMA_BLOCK_SIZE	4096
-#define	DMA_BOUNDARY	0	/* DMA reload every 4K */
+/* Macro for sizing the SDMA bounce buffer on the SDMA buffer boundary. */
+#define	SDHCI_SDMA_BNDRY_TO_BBUFSZ(bndry)	(4096 * (1 << bndry))
 
 /* Controller doesn't honor resets unless we touch the clock register */
 #define	SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1 << 0)
@@ -95,6 +95,8 @@
 #define	SDHCI_QUIRK_BROKEN_AUTO_STOP			(1 << 28)
 /* Controller supports eMMC HS400 mode if SDHCI_CAN_SDR104 is set. */
 #define	SDHCI_QUIRK_MMC_HS400_IF_CAN_SDR104		(1 << 29)
+/* SDMA boundary in SDHCI_BLOCK_SIZE broken - use front-end supplied value. */
+#define	SDHCI_QUIRK_BROKEN_SDMA_BOUNDARY		(1 << 30)
 
 /*
  * Controller registers
@@ -102,6 +104,14 @@
 #define	SDHCI_DMA_ADDRESS	0x00
 
 #define	SDHCI_BLOCK_SIZE	0x04
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_4K	0x00
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_8K	0x01
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_16K	0x02
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_32K	0x03
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_64K	0x04
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_128K	0x05
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_256K	0x06
+#define	 SDHCI_BLKSZ_SDMA_BNDRY_512K	0x07
 #define	 SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
 
 #define	SDHCI_BLOCK_COUNT	0x06
@@ -362,6 +372,8 @@ struct sdhci_slot {
 	bus_dmamap_t	dmamap;
 	u_char		*dmamem;
 	bus_addr_t	paddr;		/* DMA buffer address */
+	uint32_t	sdma_bbufsz;	/* SDMA bounce buffer size */
+	uint8_t		sdma_boundary;	/* SDMA boundary */
 	struct task	card_task;	/* Card presence check task */
 	struct timeout_task
 			card_delayed_task;/* Card insert delayed task */
@@ -434,4 +446,9 @@ bool sdhci_generic_get_card_present(device_t brdev, struct sdhci_slot *slot);
 void sdhci_generic_set_uhs_timing(device_t brdev, struct sdhci_slot *slot);
 void sdhci_handle_card_present(struct sdhci_slot *slot, bool is_present);
 
+#define	SDHCI_VERSION	2
+
+#define	SDHCI_DEPEND(name)						\
+    MODULE_DEPEND(name, sdhci, SDHCI_VERSION, SDHCI_VERSION, SDHCI_VERSION);
+
 #endif	/* __SDHCI_H__ */
diff --git a/freebsd/sys/dev/usb/wlan/if_run.c b/freebsd/sys/dev/usb/wlan/if_run.c
index 3bd247e..0feb201 100644
--- a/freebsd/sys/dev/usb/wlan/if_run.c
+++ b/freebsd/sys/dev/usb/wlan/if_run.c
@@ -2826,69 +2826,80 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
 	uint8_t ant, rssi;
 	int8_t nf;
 
-	rxwi = mtod(m, struct rt2860_rxwi *);
-	len = le16toh(rxwi->len) & 0xfff;
 	rxwisize = sizeof(struct rt2860_rxwi);
 	if (sc->mac_ver == 0x5592)
 		rxwisize += sizeof(uint64_t);
 	else if (sc->mac_ver == 0x3593)
 		rxwisize += sizeof(uint32_t);
-	if (__predict_false(len > dmalen)) {
-		m_freem(m);
-		counter_u64_add(ic->ic_ierrors, 1);
+
+	if (__predict_false(dmalen <
+	    rxwisize + sizeof(struct ieee80211_frame_ack))) {
+		RUN_DPRINTF(sc, RUN_DEBUG_RECV,
+		    "payload is too short: dma length %u < %zu\n",
+		    dmalen, rxwisize + sizeof(struct ieee80211_frame_ack));
+		goto fail;
+	}
+
+	rxwi = mtod(m, struct rt2860_rxwi *);
+	len = le16toh(rxwi->len) & 0xfff;
+
+	if (__predict_false(len > dmalen - rxwisize)) {
 		RUN_DPRINTF(sc, RUN_DEBUG_RECV,
 		    "bad RXWI length %u > %u\n", len, dmalen);
-		return;
+		goto fail;
 	}
+
 	/* Rx descriptor is located at the end */
 	rxd = (struct rt2870_rxd *)(mtod(m, caddr_t) + dmalen);
 	flags = le32toh(rxd->flags);
 
 	if (__predict_false(flags & (RT2860_RX_CRCERR | RT2860_RX_ICVERR))) {
-		m_freem(m);
-		counter_u64_add(ic->ic_ierrors, 1);
 		RUN_DPRINTF(sc, RUN_DEBUG_RECV, "%s error.\n",
 		    (flags & RT2860_RX_CRCERR)?"CRC":"ICV");
-		return;
+		goto fail;
+	}
+
+	if (flags & RT2860_RX_L2PAD) {
+		/*
+		 * XXX OpenBSD removes padding between header
+		 * and payload here...
+		 */
+		RUN_DPRINTF(sc, RUN_DEBUG_RECV,
+		    "received RT2860_RX_L2PAD frame\n");
+		len += 2;
 	}
 
 	m->m_data += rxwisize;
-	m->m_pkthdr.len = m->m_len -= rxwisize;
+	m->m_pkthdr.len = m->m_len = len;
 
 	wh = mtod(m, struct ieee80211_frame *);
 
+	/* XXX wrong for monitor mode */
 	if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
 		wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
 		m->m_flags |= M_WEP;
 	}
 
-	if (flags & RT2860_RX_L2PAD) {
-		RUN_DPRINTF(sc, RUN_DEBUG_RECV,
-		    "received RT2860_RX_L2PAD frame\n");
-		len += 2;
-	}
-
-	ni = ieee80211_find_rxnode(ic,
-	    mtod(m, struct ieee80211_frame_min *));
+	if (len >= sizeof(struct ieee80211_frame_min)) {
+		ni = ieee80211_find_rxnode(ic,
+		    mtod(m, struct ieee80211_frame_min *));
+	} else
+		ni = NULL;
 
 	if (__predict_false(flags & RT2860_RX_MICERR)) {
 		/* report MIC failures to net80211 for TKIP */
 		if (ni != NULL)
 			ieee80211_notify_michael_failure(ni->ni_vap, wh,
 			    rxwi->keyidx);
-		m_freem(m);
-		counter_u64_add(ic->ic_ierrors, 1);
 		RUN_DPRINTF(sc, RUN_DEBUG_RECV,
 		    "MIC error. Someone is lying.\n");
-		return;
+		goto fail;
 	}
 
 	ant = run_maxrssi_chain(sc, rxwi);
 	rssi = rxwi->rssi[ant];
 	nf = run_rssi2dbm(sc, rssi, ant);
 
-	m->m_pkthdr.len = m->m_len = len;
-
 	if (__predict_false(ieee80211_radiotap_active(ic))) {
 		struct run_rx_radiotap_header *tap = &sc->sc_rxtap;
 		uint16_t phy;
@@ -2936,6 +2947,12 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen)
 	} else {
 		(void)ieee80211_input_all(ic, m, rssi, nf);
 	}
+
+	return;
+
+fail:
+	m_freem(m);
+	counter_u64_add(ic->ic_ierrors, 1);
 }
 
 static void
@@ -2945,7 +2962,7 @@ run_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct mbuf *m = NULL;
 	struct mbuf *m0;
-	uint32_t dmalen;
+	uint32_t dmalen, mbuf_len;
 	uint16_t rxwisize;
 	int xferlen;
 
@@ -3051,6 +3068,14 @@ tr_setup:
 			break;
 		}
 
+		mbuf_len = dmalen + sizeof(struct rt2870_rxd);
+		if (__predict_false(mbuf_len > MCLBYTES)) {
+			RUN_DPRINTF(sc, RUN_DEBUG_RECV_DESC | RUN_DEBUG_USB,
+			    "payload is too big: mbuf_len %u\n", mbuf_len);
+			counter_u64_add(ic->ic_ierrors, 1);
+			break;
+		}
+
 		/* copy aggregated frames to another mbuf */
 		m0 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
 		if (__predict_false(m0 == NULL)) {
@@ -3060,14 +3085,13 @@ tr_setup:
 			break;
 		}
 		m_copydata(m, 4 /* skip 32-bit DMA-len header */,
-		    dmalen + sizeof(struct rt2870_rxd), mtod(m0, caddr_t));
-		m0->m_pkthdr.len = m0->m_len =
-		    dmalen + sizeof(struct rt2870_rxd);
+		    mbuf_len, mtod(m0, caddr_t));
+		m0->m_pkthdr.len = m0->m_len = mbuf_len;
 		run_rx_frame(sc, m0, dmalen);
 
 		/* update data ptr */
-		m->m_data += dmalen + 8;
-		m->m_pkthdr.len = m->m_len -= dmalen + 8;
+		m->m_data += mbuf_len + 4;
+		m->m_pkthdr.len = m->m_len -= mbuf_len + 4;
 	}
 
 	/* make sure we free the source buffer, if any */
diff --git a/freebsd/sys/dev/usb/wlan/if_urtw.c b/freebsd/sys/dev/usb/wlan/if_urtw.c
index 309375f..a47fc0e 100644
--- a/freebsd/sys/dev/usb/wlan/if_urtw.c
+++ b/freebsd/sys/dev/usb/wlan/if_urtw.c
@@ -3935,21 +3935,18 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p,
 
 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
 
-	if (actlen < (int)URTW_MIN_RXBUFSZ) {
-		counter_u64_add(ic->ic_ierrors, 1);
-		return (NULL);
-	}
-
 	if (sc->sc_flags & URTW_RTL8187B) {
 		struct urtw_8187b_rxhdr *rx;
 
+		if (actlen < sizeof(*rx) + IEEE80211_ACK_LEN)
+			goto fail;
+
 		rx = (struct urtw_8187b_rxhdr *)(data->buf +
 		    (actlen - (sizeof(struct urtw_8187b_rxhdr))));
 		flen = le32toh(rx->flag) & 0xfff;
-		if (flen > actlen) {
-			counter_u64_add(ic->ic_ierrors, 1);
-			return (NULL);
-		}
+		if (flen > actlen - sizeof(*rx))
+			goto fail;
+
 		rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf;
 		/* XXX correct? */
 		rssi = rx->rssi & URTW_RX_RSSI_MASK;
@@ -3957,13 +3954,14 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p,
 	} else {
 		struct urtw_8187l_rxhdr *rx;
 
+		if (actlen < sizeof(*rx) + IEEE80211_ACK_LEN)
+			goto fail;
+
 		rx = (struct urtw_8187l_rxhdr *)(data->buf +
 		    (actlen - (sizeof(struct urtw_8187l_rxhdr))));
 		flen = le32toh(rx->flag) & 0xfff;
-		if (flen > actlen) {
-			counter_u64_add(ic->ic_ierrors, 1);
-			return (NULL);
-		}
+		if (flen > actlen - sizeof(*rx))
+			goto fail;
 
 		rate = (le32toh(rx->flag) >> URTW_RX_FLAG_RXRATE_SHIFT) & 0xf;
 		/* XXX correct? */
@@ -3971,11 +3969,12 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p,
 		noise = rx->noise;
 	}
 
+	if (flen < IEEE80211_ACK_LEN)
+		goto fail;
+
 	mnew = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
-	if (mnew == NULL) {
-		counter_u64_add(ic->ic_ierrors, 1);
-		return (NULL);
-	}
+	if (mnew == NULL)
+		goto fail;
 
 	m = data->m;
 	data->m = mnew;
@@ -3994,13 +3993,17 @@ urtw_rxeof(struct usb_xfer *xfer, struct urtw_data *data, int *rssi_p,
 	}
 
 	wh = mtod(m, struct ieee80211_frame *);
-	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA)
+	if (IEEE80211_IS_DATA(wh))
 		sc->sc_currate = (rate > 0) ? rate : sc->sc_currate;
 
 	*rssi_p = rssi;
 	*nf_p = noise;		/* XXX correct? */
 
 	return (m);
+
+fail:
+	counter_u64_add(ic->ic_ierrors, 1);
+	return (NULL);
 }
 
 static void
@@ -4008,7 +4011,6 @@ urtw_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct urtw_softc *sc = usbd_xfer_softc(xfer);
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
 	struct mbuf *m = NULL;
 	struct urtw_data *data;
@@ -4046,9 +4048,13 @@ setup:
 		 */
 		URTW_UNLOCK(sc);
 		if (m != NULL) {
-			wh = mtod(m, struct ieee80211_frame *);
-			ni = ieee80211_find_rxnode(ic,
-			    (struct ieee80211_frame_min *)wh);
+			if (m->m_pkthdr.len >=
+			    sizeof(struct ieee80211_frame_min)) {
+				ni = ieee80211_find_rxnode(ic,
+				    mtod(m, struct ieee80211_frame_min *));
+			} else
+				ni = NULL;
+
 			if (ni != NULL) {
 				(void) ieee80211_input(ni, m, rssi, nf);
 				/* node is no longer needed */
diff --git a/freebsd/sys/dev/usb/wlan/if_urtwvar.h b/freebsd/sys/dev/usb/wlan/if_urtwvar.h
index 08ffc8f..1b5e2cd 100644
--- a/freebsd/sys/dev/usb/wlan/if_urtwvar.h
+++ b/freebsd/sys/dev/usb/wlan/if_urtwvar.h
@@ -47,10 +47,6 @@ struct urtw_data {
 };
 typedef STAILQ_HEAD(, urtw_data) urtw_datahead;
 
-/* XXX not correct..  */
-#define	URTW_MIN_RXBUFSZ						\
-	(sizeof(struct ieee80211_frame_min))
-
 #define URTW_RX_DATA_LIST_COUNT		4
 #define URTW_TX_DATA_LIST_COUNT		16
 #define URTW_RX_MAXSIZE			0x9c4
diff --git a/freebsd/sys/kern/kern_intr.c b/freebsd/sys/kern/kern_intr.c
index 20117ea..9c647eb 100644
--- a/freebsd/sys/kern/kern_intr.c
+++ b/freebsd/sys/kern/kern_intr.c
@@ -756,6 +756,28 @@ intr_event_barrier(struct intr_event *ie)
 	atomic_thread_fence_acq();
 }
 
+static void
+intr_handler_barrier(struct intr_handler *handler)
+{
+	struct intr_event *ie;
+
+	ie = handler->ih_event;
+	mtx_assert(&ie->ie_lock, MA_OWNED);
+	KASSERT((handler->ih_flags & IH_DEAD) == 0,
+	    ("update for a removed handler"));
+
+	if (ie->ie_thread == NULL) {
+		intr_event_barrier(ie);
+		return;
+	}
+	if ((handler->ih_flags & IH_CHANGED) == 0) {
+		handler->ih_flags |= IH_CHANGED;
+		intr_event_schedule_thread(ie);
+	}
+	while ((handler->ih_flags & IH_CHANGED) != 0)
+		msleep(handler, &ie->ie_lock, 0, "ih_barr", 0);
+}
+
 /*
  * Sleep until an ithread finishes executing an interrupt handler.
  *
@@ -880,6 +902,49 @@ intr_event_remove_handler(void *cookie)
 }
 #endif /* __rtems__ */
 
+int
+intr_event_suspend_handler(void *cookie)
+{
+	struct intr_handler *handler = (struct intr_handler *)cookie;
+	struct intr_event *ie;
+
+	if (handler == NULL)
+		return (EINVAL);
+	ie = handler->ih_event;
+	KASSERT(ie != NULL,
+	    ("interrupt handler \"%s\" has a NULL interrupt event",
+	    handler->ih_name));
+	mtx_lock(&ie->ie_lock);
+	handler->ih_flags |= IH_SUSP;
+	intr_handler_barrier(handler);
+	mtx_unlock(&ie->ie_lock);
+	return (0);
+}
+
+int
+intr_event_resume_handler(void *cookie)
+{
+	struct intr_handler *handler = (struct intr_handler *)cookie;
+	struct intr_event *ie;
+
+	if (handler == NULL)
+		return (EINVAL);
+	ie = handler->ih_event;
+	KASSERT(ie != NULL,
+	    ("interrupt handler \"%s\" has a NULL interrupt event",
+	    handler->ih_name));
+
+	/*
+	 * intr_handler_barrier() acts not only as a barrier,
+	 * it also allows to check for any pending interrupts.
+	 */
+	mtx_lock(&ie->ie_lock);
+	handler->ih_flags &= ~IH_SUSP;
+	intr_handler_barrier(handler);
+	mtx_unlock(&ie->ie_lock);
+	return (0);
+}
+
 static int
 intr_event_schedule_thread(struct intr_event *ie)
 {
@@ -1068,10 +1133,21 @@ intr_event_execute_handlers(struct proc *p, struct intr_event *ie)
 		 */
 		ihp = ih;
 
+		if ((ih->ih_flags & IH_CHANGED) != 0) {
+			mtx_lock(&ie->ie_lock);
+			ih->ih_flags &= ~IH_CHANGED;
+			wakeup(ih);
+			mtx_unlock(&ie->ie_lock);
+		}
+
 		/* Skip filter only handlers */
 		if (ih->ih_handler == NULL)
 			continue;
 
+		/* Skip suspended handlers */
+		if ((ih->ih_flags & IH_SUSP) != 0)
+			continue;
+
 		/*
 		 * For software interrupt threads, we only execute
 		 * handlers that have their need flag set.  Hardware
@@ -1255,8 +1331,9 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame)
 	struct intr_handler *ih;
 	struct trapframe *oldframe;
 	struct thread *td;
-	int ret, thread;
 	int phase;
+	int ret;
+	bool filter, thread;
 
 	td = curthread;
 
@@ -1275,7 +1352,8 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame)
 	 * a trapframe as its argument.
 	 */
 	td->td_intr_nesting_level++;
-	thread = 0;
+	filter = false;
+	thread = false;
 	ret = 0;
 	critical_enter();
 	oldframe = td->td_intr_frame;
@@ -1291,8 +1369,10 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame)
 	atomic_thread_fence_seq_cst();
 
 	CK_SLIST_FOREACH(ih, &ie->ie_handlers, ih_next) {
+		if ((ih->ih_flags & IH_SUSP) != 0)
+			continue;
 		if (ih->ih_filter == NULL) {
-			thread = 1;
+			thread = true;
 			continue;
 		}
 		CTR4(KTR_INTR, "%s: exec %p(%p) for %s", __func__,
@@ -1307,24 +1387,25 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame)
 		    (ret & ~(FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) == 0),
 		    ("%s: incorrect return value %#x from %s", __func__, ret,
 		    ih->ih_name));
+		filter = filter || ret == FILTER_HANDLED;
 
-		/* 
+		/*
 		 * Wrapper handler special handling:
 		 *
-		 * in some particular cases (like pccard and pccbb), 
+		 * in some particular cases (like pccard and pccbb),
 		 * the _real_ device handler is wrapped in a couple of
 		 * functions - a filter wrapper and an ithread wrapper.
-		 * In this case (and just in this case), the filter wrapper 
+		 * In this case (and just in this case), the filter wrapper
 		 * could ask the system to schedule the ithread and mask
 		 * the interrupt source if the wrapped handler is composed
 		 * of just an ithread handler.
 		 *
-		 * TODO: write a generic wrapper to avoid people rolling 
-		 * their own
+		 * TODO: write a generic wrapper to avoid people rolling
+		 * their own.
 		 */
 		if (!thread) {
 			if (ret == FILTER_SCHEDULE_THREAD)
-				thread = 1;
+				thread = true;
 		}
 	}
 	atomic_add_rel_int(&ie->ie_active[phase], -1);
@@ -1348,6 +1429,11 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame)
 	}
 	critical_exit();
 	td->td_intr_nesting_level--;
+#ifdef notyet
+	/* The interrupt is not aknowledged by any filter and has no ithread. */
+	if (!thread && !filter)
+		return (EINVAL);
+#endif
 	return (0);
 }
 
diff --git a/freebsd/sys/kern/kern_mtxpool.c b/freebsd/sys/kern/kern_mtxpool.c
index 7f6c4dc..bc47d82 100644
--- a/freebsd/sys/kern/kern_mtxpool.c
+++ b/freebsd/sys/kern/kern_mtxpool.c
@@ -64,14 +64,14 @@ static MALLOC_DEFINE(M_MTXPOOL, "mtx_pool", "mutex pool");
 
 /* Pool sizes must be a power of two */
 #ifndef MTX_POOL_SLEEP_SIZE
-#define MTX_POOL_SLEEP_SIZE		128
+#define MTX_POOL_SLEEP_SIZE		1024
 #endif
 
 struct mtxpool_header {
 	int		mtxpool_size;
 	int		mtxpool_mask;
 	int		mtxpool_shift;
-	int		mtxpool_next;
+	int		mtxpool_next __aligned(CACHE_LINE_SIZE);
 };
 
 struct mtx_pool {
diff --git a/freebsd/sys/kern/subr_bus.c b/freebsd/sys/kern/subr_bus.c
index 391b2ed..29fdfe3 100644
--- a/freebsd/sys/kern/subr_bus.c
+++ b/freebsd/sys/kern/subr_bus.c
@@ -4101,6 +4101,36 @@ bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq,
 }
 
 /**
+ * @brief Helper function for implementing BUS_SUSPEND_INTR().
+ *
+ * This simple implementation of BUS_SUSPEND_INTR() simply calls the
+ * BUS_SUSPEND_INTR() method of the parent of @p dev.
+ */
+int
+bus_generic_suspend_intr(device_t dev, device_t child, struct resource *irq)
+{
+	/* Propagate up the bus hierarchy until someone handles it. */
+	if (dev->parent)
+		return (BUS_SUSPEND_INTR(dev->parent, child, irq));
+	return (EINVAL);
+}
+
+/**
+ * @brief Helper function for implementing BUS_RESUME_INTR().
+ *
+ * This simple implementation of BUS_RESUME_INTR() simply calls the
+ * BUS_RESUME_INTR() method of the parent of @p dev.
+ */
+int
+bus_generic_resume_intr(device_t dev, device_t child, struct resource *irq)
+{
+	/* Propagate up the bus hierarchy until someone handles it. */
+	if (dev->parent)
+		return (BUS_RESUME_INTR(dev->parent, child, irq));
+	return (EINVAL);
+}
+
+/**
  * @brief Helper function for implementing BUS_ADJUST_RESOURCE().
  *
  * This simple implementation of BUS_ADJUST_RESOURCE() simply calls the
@@ -4668,6 +4698,34 @@ bus_teardown_intr(device_t dev, struct resource *r, void *cookie)
 }
 
 /**
+ * @brief Wrapper function for BUS_SUSPEND_INTR().
+ *
+ * This function simply calls the BUS_SUSPEND_INTR() method of the
+ * parent of @p dev.
+ */
+int
+bus_suspend_intr(device_t dev, struct resource *r)
+{
+	if (dev->parent == NULL)
+		return (EINVAL);
+	return (BUS_SUSPEND_INTR(dev->parent, dev, r));
+}
+
+/**
+ * @brief Wrapper function for BUS_RESUME_INTR().
+ *
+ * This function simply calls the BUS_RESUME_INTR() method of the
+ * parent of @p dev.
+ */
+int
+bus_resume_intr(device_t dev, struct resource *r)
+{
+	if (dev->parent == NULL)
+		return (EINVAL);
+	return (BUS_RESUME_INTR(dev->parent, dev, r));
+}
+
+/**
  * @brief Wrapper function for BUS_BIND_INTR().
  *
  * This function simply calls the BUS_BIND_INTR() method of the
diff --git a/freebsd/sys/kern/subr_rman.c b/freebsd/sys/kern/subr_rman.c
index 75f22dd..e307df4 100644
--- a/freebsd/sys/kern/subr_rman.c
+++ b/freebsd/sys/kern/subr_rman.c
@@ -96,6 +96,7 @@ struct resource_i {
 	rman_res_t	r_end;		/* index of the last entry (inclusive) */
 	u_int	r_flags;
 	void	*r_virtual;	/* virtual address of this resource */
+	void	*r_irq_cookie;	/* interrupt cookie for this (interrupt) resource */
 	device_t r_dev;	/* device which has allocated this resource */
 	struct rman *r_rm;	/* resource manager from whence this came */
 	int	r_rid;		/* optional rid for this resource. */
@@ -871,6 +872,20 @@ rman_get_virtual(struct resource *r)
 }
 
 void
+rman_set_irq_cookie(struct resource *r, void *c)
+{
+
+	r->__r_i->r_irq_cookie = c;
+}
+
+void *
+rman_get_irq_cookie(struct resource *r)
+{
+
+	return (r->__r_i->r_irq_cookie);
+}
+
+void
 rman_set_bustag(struct resource *r, bus_space_tag_t t)
 {
 
diff --git a/freebsd/sys/net80211/ieee80211.c b/freebsd/sys/net80211/ieee80211.c
index a81b534..74aeeb8 100644
--- a/freebsd/sys/net80211/ieee80211.c
+++ b/freebsd/sys/net80211/ieee80211.c
@@ -407,8 +407,10 @@ ieee80211_ifdetach(struct ieee80211com *ic)
 	 * The VAP is responsible for setting and clearing
 	 * the VIMAGE context.
 	 */
-	while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
+	while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) {
+		ieee80211_com_vdetach(vap);
 		ieee80211_vap_destroy(vap);
+	}
 	ieee80211_waitfor_parent(ic);
 
 	ieee80211_sysctl_detach(ic);
diff --git a/freebsd/sys/net80211/ieee80211_crypto.c b/freebsd/sys/net80211/ieee80211_crypto.c
index 2e28538..264e3f1 100644
--- a/freebsd/sys/net80211/ieee80211_crypto.c
+++ b/freebsd/sys/net80211/ieee80211_crypto.c
@@ -664,14 +664,15 @@ ieee80211_crypto_decap(struct ieee80211_node *ni, struct mbuf *m, int hdrlen,
 		k = &ni->ni_ucastkey;
 
 	/*
-	 * Insure crypto header is contiguous for all decap work.
+	 * Insure crypto header is contiguous and long enough for all
+	 * decap work.
 	 */
 	cip = k->wk_cipher;
-	if (m->m_len < hdrlen + cip->ic_header &&
-	    (m = m_pullup(m, hdrlen + cip->ic_header)) == NULL) {
+	if (m->m_len < hdrlen + cip->ic_header) {
 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
-		    "unable to pullup %s header", cip->ic_name);
-		vap->iv_stats.is_rx_wepfail++;	/* XXX */
+		    "frame is too short (%d < %u) for crypto decap",
+		    cip->ic_name, m->m_len, hdrlen + cip->ic_header);
+		vap->iv_stats.is_rx_tooshort++;
 		*key = NULL;
 		return (0);
 	}
diff --git a/freebsd/sys/net80211/ieee80211_freebsd.c b/freebsd/sys/net80211/ieee80211_freebsd.c
index 00430f7..57e2f23 100644
--- a/freebsd/sys/net80211/ieee80211_freebsd.c
+++ b/freebsd/sys/net80211/ieee80211_freebsd.c
@@ -309,6 +309,55 @@ ieee80211_sysctl_vdetach(struct ieee80211vap *vap)
 	}
 }
 
+#define	MS(_v, _f)	(((_v) & _f##_M) >> _f##_S)
+int
+ieee80211_com_vincref(struct ieee80211vap *vap)
+{
+	uint32_t ostate;
+
+	ostate = atomic_fetchadd_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
+
+	if (ostate & IEEE80211_COM_DETACHED) {
+		atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
+		return (ENETDOWN);
+	}
+
+	if (MS(ostate, IEEE80211_COM_REF) == IEEE80211_COM_REF_MAX) {
+		atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
+		return (EOVERFLOW);
+	}
+
+	return (0);
+}
+
+void
+ieee80211_com_vdecref(struct ieee80211vap *vap)
+{
+	uint32_t ostate;
+
+	ostate = atomic_fetchadd_32(&vap->iv_com_state, -IEEE80211_COM_REF_ADD);
+
+	KASSERT(MS(ostate, IEEE80211_COM_REF) != 0,
+	    ("com reference counter underflow"));
+
+	(void) ostate;
+}
+
+void
+ieee80211_com_vdetach(struct ieee80211vap *vap)
+{
+	int sleep_time;
+
+	sleep_time = msecs_to_ticks(250);
+	if (sleep_time == 0)
+		sleep_time = 1;
+
+	atomic_set_32(&vap->iv_com_state, IEEE80211_COM_DETACHED);
+	while (MS(atomic_load_32(&vap->iv_com_state), IEEE80211_COM_REF) != 0)
+		pause("comref", sleep_time);
+}
+#undef	MS
+
 int
 ieee80211_node_dectestref(struct ieee80211_node *ni)
 {
diff --git a/freebsd/sys/net80211/ieee80211_freebsd.h b/freebsd/sys/net80211/ieee80211_freebsd.h
index 8395eb0..a70de10 100644
--- a/freebsd/sys/net80211/ieee80211_freebsd.h
+++ b/freebsd/sys/net80211/ieee80211_freebsd.h
@@ -224,6 +224,11 @@ typedef struct mtx ieee80211_rt_lock_t;
  */
 #include <machine/atomic.h>
 
+struct ieee80211vap;
+int	ieee80211_com_vincref(struct ieee80211vap *);
+void	ieee80211_com_vdecref(struct ieee80211vap *);
+void	ieee80211_com_vdetach(struct ieee80211vap *);
+
 #define ieee80211_node_initref(_ni) \
 	do { ((_ni)->ni_refcnt = 1); } while (0)
 #define ieee80211_node_incref(_ni) \
@@ -235,7 +240,6 @@ int	ieee80211_node_dectestref(struct ieee80211_node *ni);
 #define	ieee80211_node_refcnt(_ni)	(_ni)->ni_refcnt
 
 struct ifqueue;
-struct ieee80211vap;
 void	ieee80211_drain_ifq(struct ifqueue *);
 void	ieee80211_flush_ifq(struct ifqueue *, struct ieee80211vap *);
 
diff --git a/freebsd/sys/net80211/ieee80211_ioctl.c b/freebsd/sys/net80211/ieee80211_ioctl.c
index 02d993b..fb8357b 100644
--- a/freebsd/sys/net80211/ieee80211_ioctl.c
+++ b/freebsd/sys/net80211/ieee80211_ioctl.c
@@ -3482,10 +3482,14 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
 	struct ieee80211vap *vap = ifp->if_softc;
 	struct ieee80211com *ic = vap->iv_ic;
-	int error = 0, wait = 0;
+	int error = 0, wait = 0, ic_used;
 	struct ifreq *ifr;
 	struct ifaddr *ifa;			/* XXX */
 
+	ic_used = (cmd != SIOCSIFMTU && cmd != SIOCG80211STATS);
+	if (ic_used && (error = ieee80211_com_vincref(vap)) != 0)
+		return (error);
+
 	switch (cmd) {
 	case SIOCSIFFLAGS:
 		IEEE80211_LOCK(ic);
@@ -3622,5 +3626,9 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 		error = ether_ioctl(ifp, cmd, data);
 		break;
 	}
+
+	if (ic_used)
+		ieee80211_com_vdecref(vap);
+
 	return (error);
 }
diff --git a/freebsd/sys/net80211/ieee80211_scan_sta.c b/freebsd/sys/net80211/ieee80211_scan_sta.c
index a7a1fc2..3ea313d 100644
--- a/freebsd/sys/net80211/ieee80211_scan_sta.c
+++ b/freebsd/sys/net80211/ieee80211_scan_sta.c
@@ -474,6 +474,8 @@ static const u_int chanflags[IEEE80211_MODE_MAX] = {
 	/* check legacy */
 	[IEEE80211_MODE_11NA]	  = IEEE80211_CHAN_A,
 	[IEEE80211_MODE_11NG]	  = IEEE80211_CHAN_G,
+	[IEEE80211_MODE_VHT_5GHZ] = IEEE80211_CHAN_A,
+	[IEEE80211_MODE_VHT_2GHZ] = IEEE80211_CHAN_G,
 };
 
 static void
@@ -496,12 +498,15 @@ add_channels(struct ieee80211vap *vap,
 		if (c == NULL || isexcluded(vap, c))
 			continue;
 		if (mode == IEEE80211_MODE_AUTO) {
+			KASSERT(IEEE80211_IS_CHAN_B(c),
+			    ("%s: wrong channel for 'auto' mode %u / %u\n",
+			    __func__, c->ic_freq, c->ic_flags));
+
 			/*
 			 * XXX special-case 11b/g channels so we select
 			 *     the g channel if both are present.
 			 */
-			if (IEEE80211_IS_CHAN_B(c) &&
-			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
+			if ((cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
 				c = cg;
 		}
 		ss->ss_chans[ss->ss_last++] = c;
@@ -620,32 +625,48 @@ makescanlist(struct ieee80211_scan_state *ss, struct ieee80211vap *vap,
 	 */
 	for (scan = table; scan->list != NULL; scan++) {
 		mode = scan->mode;
-		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
+
+		switch (mode) {
+		case IEEE80211_MODE_11B:
+			if (vap->iv_des_mode == IEEE80211_MODE_11B)
+				break;
+
 			/*
-			 * If a desired mode was specified, scan only 
-			 * channels that satisfy that constraint.
+			 * The scan table marks 2.4Ghz channels as b
+			 * so if the desired mode is 11g / 11ng / 11acg,
+			 * then use the 11b channel list but upgrade the mode.
+			 *
+			 * NB: 11b -> AUTO lets add_channels upgrade an
+			 * 11b channel to 11g if available.
 			 */
-			if (vap->iv_des_mode != mode) {
-				/*
-				 * The scan table marks 2.4Ghz channels as b
-				 * so if the desired mode is 11g, then use
-				 * the 11b channel list but upgrade the mode.
-				 */
-				if (vap->iv_des_mode == IEEE80211_MODE_11G) {
-					if (mode == IEEE80211_MODE_11G) /* Skip the G check */
-						continue;
-					else if (mode == IEEE80211_MODE_11B)
-						mode = IEEE80211_MODE_11G;	/* upgrade */
-				}
+			if (vap->iv_des_mode == IEEE80211_MODE_AUTO ||
+			    vap->iv_des_mode == IEEE80211_MODE_11G ||
+			    vap->iv_des_mode == IEEE80211_MODE_11NG ||
+			    vap->iv_des_mode == IEEE80211_MODE_VHT_2GHZ) {
+				mode = vap->iv_des_mode;
+				break;
 			}
-		} else {
+
+			continue;
+		case IEEE80211_MODE_11A:
+			/* Use 11a channel list for 11na / 11ac modes */
+			if (vap->iv_des_mode == IEEE80211_MODE_11NA ||
+			    vap->iv_des_mode == IEEE80211_MODE_VHT_5GHZ) {
+				mode = vap->iv_des_mode;
+				break;
+			}
+
+			/* FALLTHROUGH */
+		default:
 			/*
-			 * This lets add_channels upgrade an 11b channel
-			 * to 11g if available.
+			 * If a desired mode was specified, scan only
+			 * channels that satisfy that constraint.
 			 */
-			if (mode == IEEE80211_MODE_11B)
-				mode = IEEE80211_MODE_AUTO;
+			if (vap->iv_des_mode != IEEE80211_MODE_AUTO &&
+			    vap->iv_des_mode != mode)
+				continue;
 		}
+
 #ifdef IEEE80211_F_XR
 		/* XR does not operate on turbo channels */
 		if ((vap->iv_flags & IEEE80211_F_XR) &&
diff --git a/freebsd/sys/net80211/ieee80211_var.h b/freebsd/sys/net80211/ieee80211_var.h
index ee17c80..af42a24 100644
--- a/freebsd/sys/net80211/ieee80211_var.h
+++ b/freebsd/sys/net80211/ieee80211_var.h
@@ -562,7 +562,9 @@ struct ieee80211vap {
 				    const struct wmeParams *wme_params);
 	struct task		iv_wme_task;	/* deferred VAP WME update */
 
-	uint64_t		iv_spare[6];
+	uint64_t		iv_spare[5];
+	uint32_t		iv_com_state;	/* com usage / detached flag */
+	uint32_t		iv_spare1;
 };
 MALLOC_DECLARE(M_80211_VAP);
 
@@ -685,6 +687,12 @@ MALLOC_DECLARE(M_80211_VAP);
 #define	IEEE80211_VFHT_BITS \
 	"\20\1VHT\2VHT40\3VHT80\4VHT80P80\5VHT160"
 
+#define	IEEE80211_COM_DETACHED	0x00000001	/* ieee80211_ifdetach called */
+#define	IEEE80211_COM_REF_ADD	0x00000002	/* add / remove reference */
+#define	IEEE80211_COM_REF_M	0xfffffffe	/* reference counter bits */
+#define	IEEE80211_COM_REF_S	1
+#define	IEEE80211_COM_REF_MAX	(IEEE80211_COM_REF_M >> IEEE80211_COM_REF_S)
+
 int	ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3);
 void	ieee80211_ifattach(struct ieee80211com *);
 void	ieee80211_ifdetach(struct ieee80211com *);
diff --git a/freebsd/sys/netinet/in.c b/freebsd/sys/netinet/in.c
index db1ebda..ae32c8d 100644
--- a/freebsd/sys/netinet/in.c
+++ b/freebsd/sys/netinet/in.c
@@ -1382,15 +1382,13 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add
 	IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
 	KASSERT(l3addr->sa_family == AF_INET,
 	    ("sin_family %d", l3addr->sa_family));
-	lle = in_lltable_find_dst(llt, sin->sin_addr);
+	KASSERT((flags & (LLE_UNLOCKED | LLE_EXCLUSIVE)) !=
+	    (LLE_UNLOCKED | LLE_EXCLUSIVE),
+	    ("wrong lle request flags: %#x", flags));
 
+	lle = in_lltable_find_dst(llt, sin->sin_addr);
 	if (lle == NULL)
 		return (NULL);
-
-	KASSERT((flags & (LLE_UNLOCKED|LLE_EXCLUSIVE)) !=
-	    (LLE_UNLOCKED|LLE_EXCLUSIVE),("wrong lle request flags: 0x%X",
-	    flags));
-
 	if (flags & LLE_UNLOCKED)
 		return (lle);
 
@@ -1399,6 +1397,17 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add
 	else
 		LLE_RLOCK(lle);
 
+	/*
+	 * If the afdata lock is not held, the LLE may have been unlinked while
+	 * we were blocked on the LLE lock.  Check for this case.
+	 */
+	if (__predict_false((lle->la_flags & LLE_LINKED) == 0)) {
+		if (flags & LLE_EXCLUSIVE)
+			LLE_WUNLOCK(lle);
+		else
+			LLE_RUNLOCK(lle);
+		return (NULL);
+	}
 	return (lle);
 }
 
diff --git a/freebsd/sys/netinet/ip_output.c b/freebsd/sys/netinet/ip_output.c
index 477388d..bf83f31 100644
--- a/freebsd/sys/netinet/ip_output.c
+++ b/freebsd/sys/netinet/ip_output.c
@@ -1264,7 +1264,8 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt)
 			if (inp->inp_options) {
 				struct mbuf *options;
 
-				options = m_dup(inp->inp_options, M_NOWAIT);
+				options = m_copym(inp->inp_options, 0,
+				    M_COPYALL, M_NOWAIT);
 				INP_RUNLOCK(inp);
 				if (options != NULL) {
 					error = sooptcopyout(sopt,
diff --git a/freebsd/sys/netinet/sctp_constants.h b/freebsd/sys/netinet/sctp_constants.h
index d07381d..7ee7e31 100644
--- a/freebsd/sys/netinet/sctp_constants.h
+++ b/freebsd/sys/netinet/sctp_constants.h
@@ -983,6 +983,9 @@ __FBSDID("$FreeBSD$");
     ((((uint8_t *)&(a)->s_addr)[0] == 169) && \
      (((uint8_t *)&(a)->s_addr)[1] == 254))
 
+/* Maximum size of optval for IPPROTO_SCTP level socket options. */
+#define SCTP_SOCKET_OPTION_LIMIT (64 * 1024)
+
 
 #if defined(_KERNEL)
 #define SCTP_GETTIME_TIMEVAL(x) (getmicrouptime(x))
diff --git a/freebsd/sys/netinet/sctp_usrreq.c b/freebsd/sys/netinet/sctp_usrreq.c
index b519971..54362ed 100644
--- a/freebsd/sys/netinet/sctp_usrreq.c
+++ b/freebsd/sys/netinet/sctp_usrreq.c
@@ -6830,6 +6830,10 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt)
 		return (error);
 	}
 	optsize = sopt->sopt_valsize;
+	if (optsize > SCTP_SOCKET_OPTION_LIMIT) {
+		SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
+		return (ENOBUFS);
+	}
 	if (optsize) {
 		SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
 		if (optval == NULL) {
diff --git a/freebsd/sys/netinet/tcp_output.c b/freebsd/sys/netinet/tcp_output.c
index e19cf0d..200ae8a 100644
--- a/freebsd/sys/netinet/tcp_output.c
+++ b/freebsd/sys/netinet/tcp_output.c
@@ -658,7 +658,8 @@ after_sack_rexmit:
 		if (adv >= (int32_t)(2 * tp->t_maxseg) &&
 		    (adv >= (int32_t)(so->so_rcv.sb_hiwat / 4) ||
 		     recwin <= (so->so_rcv.sb_hiwat / 8) ||
-		     so->so_rcv.sb_hiwat <= 8 * tp->t_maxseg))
+		     so->so_rcv.sb_hiwat <= 8 * tp->t_maxseg ||
+		     adv >= TCP_MAXWIN << tp->rcv_scale))
 			goto send;
 		if (2 * adv >= (int32_t)so->so_rcv.sb_hiwat)
 			goto send;
diff --git a/freebsd/sys/netinet6/in6.c b/freebsd/sys/netinet6/in6.c
index ef59203..1331d2e 100644
--- a/freebsd/sys/netinet6/in6.c
+++ b/freebsd/sys/netinet6/in6.c
@@ -2319,16 +2319,13 @@ in6_lltable_lookup(struct lltable *llt, u_int flags,
 	IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
 	KASSERT(l3addr->sa_family == AF_INET6,
 	    ("sin_family %d", l3addr->sa_family));
+	KASSERT((flags & (LLE_UNLOCKED | LLE_EXCLUSIVE)) !=
+	    (LLE_UNLOCKED | LLE_EXCLUSIVE),
+	    ("wrong lle request flags: %#x", flags));
 
 	lle = in6_lltable_find_dst(llt, &sin6->sin6_addr);
-
 	if (lle == NULL)
 		return (NULL);
-
-	KASSERT((flags & (LLE_UNLOCKED|LLE_EXCLUSIVE)) !=
-	    (LLE_UNLOCKED|LLE_EXCLUSIVE),("wrong lle request flags: 0x%X",
-	    flags));
-
 	if (flags & LLE_UNLOCKED)
 		return (lle);
 
@@ -2336,6 +2333,18 @@ in6_lltable_lookup(struct lltable *llt, u_int flags,
 		LLE_WLOCK(lle);
 	else
 		LLE_RLOCK(lle);
+
+	/*
+	 * If the afdata lock is not held, the LLE may have been unlinked while
+	 * we were blocked on the LLE lock.  Check for this case.
+	 */
+	if (__predict_false((lle->la_flags & LLE_LINKED) == 0)) {
+		if (flags & LLE_EXCLUSIVE)
+			LLE_WUNLOCK(lle);
+		else
+			LLE_RUNLOCK(lle);
+		return (NULL);
+	}
 	return (lle);
 }
 
diff --git a/freebsd/sys/netpfil/pf/pf_table.c b/freebsd/sys/netpfil/pf/pf_table.c
index 3f15fb0..6f41898 100644
--- a/freebsd/sys/netpfil/pf/pf_table.c
+++ b/freebsd/sys/netpfil/pf/pf_table.c
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
 #include <net/vnet.h>
 #include <net/pfvar.h>
 
+#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
+
 #define	ACCEPT_FLAGS(flags, oklist)		\
 	do {					\
 		if ((flags & ~(oklist)) &	\
@@ -1994,7 +1996,8 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
 	}
 	if ((ke == NULL || ke->pfrke_not) != notrule) {
 		if (op_pass != PFR_OP_PASS)
-			printf("pfr_update_stats: assertion failed.\n");
+			DPFPRINTF(PF_DEBUG_URGENT,
+			    ("pfr_update_stats: assertion failed.\n"));
 		op_pass = PFR_OP_XPASS;
 	}
 	kt->pfrkt_packets[dir_out][op_pass]++;
diff --git a/freebsd/sys/sys/bus.h b/freebsd/sys/sys/bus.h
index 74a48f8..0159b82 100644
--- a/freebsd/sys/sys/bus.h
+++ b/freebsd/sys/sys/bus.h
@@ -485,6 +485,10 @@ int	bus_generic_suspend(device_t dev);
 int	bus_generic_suspend_child(device_t dev, device_t child);
 int	bus_generic_teardown_intr(device_t dev, device_t child,
 				  struct resource *irq, void *cookie);
+int	bus_generic_suspend_intr(device_t dev, device_t child,
+				  struct resource *irq);
+int	bus_generic_resume_intr(device_t dev, device_t child,
+				  struct resource *irq);
 int	bus_generic_unmap_resource(device_t dev, device_t child, int type,
 				   struct resource *r,
 				   struct resource_map *map);
@@ -535,6 +539,8 @@ int	bus_setup_intr(device_t dev, struct resource *r, int flags,
 		       driver_filter_t filter, driver_intr_t handler, 
 		       void *arg, void **cookiep);
 int	bus_teardown_intr(device_t dev, struct resource *r, void *cookie);
+int	bus_suspend_intr(device_t dev, struct resource *r);
+int	bus_resume_intr(device_t dev, struct resource *r);
 int	bus_bind_intr(device_t dev, struct resource *r, int cpu);
 int	bus_describe_intr(device_t dev, struct resource *irq, void *cookie,
 			  const char *fmt, ...) __printflike(4, 5);
diff --git a/freebsd/sys/sys/interrupt.h b/freebsd/sys/sys/interrupt.h
index 105bb96..5c63405 100644
--- a/freebsd/sys/sys/interrupt.h
+++ b/freebsd/sys/sys/interrupt.h
@@ -62,6 +62,8 @@ struct intr_handler {
 #define	IH_EXCLUSIVE	0x00000002	/* Exclusive interrupt. */
 #define	IH_ENTROPY	0x00000004	/* Device is a good entropy source. */
 #define	IH_DEAD		0x00000008	/* Handler should be removed. */
+#define	IH_SUSP		0x00000010	/* Device is powered down. */
+#define	IH_CHANGED	0x40000000	/* Handler state is changed. */
 #define	IH_MPSAFE	0x80000000	/* Handler does not need Giant. */
 
 /*
@@ -184,6 +186,8 @@ int	intr_event_describe_handler(struct intr_event *ie, void *cookie,
 int	intr_event_destroy(struct intr_event *ie);
 int	intr_event_handle(struct intr_event *ie, struct trapframe *frame);
 int	intr_event_remove_handler(void *cookie);
+int	intr_event_suspend_handler(void *cookie);
+int	intr_event_resume_handler(void *cookie);
 int	intr_getaffinity(int irq, int mode, void *mask);
 void	*intr_handler_source(void *cookie);
 int	intr_setaffinity(int irq, int mode, void *mask);
diff --git a/freebsd/sys/sys/rman.h b/freebsd/sys/sys/rman.h
index 9c2f465..e955cd5 100644
--- a/freebsd/sys/sys/rman.h
+++ b/freebsd/sys/sys/rman.h
@@ -131,6 +131,7 @@ bus_space_tag_t rman_get_bustag(struct resource *);
 rman_res_t	rman_get_end(struct resource *);
 device_t rman_get_device(struct resource *);
 u_int	rman_get_flags(struct resource *);
+void   *rman_get_irq_cookie(struct resource *);
 void	rman_get_mapping(struct resource *, struct resource_map *);
 int	rman_get_rid(struct resource *);
 rman_res_t	rman_get_size(struct resource *);
@@ -155,6 +156,7 @@ void	rman_set_bushandle(struct resource *_r, bus_space_handle_t _h);
 void	rman_set_bustag(struct resource *_r, bus_space_tag_t _t);
 void	rman_set_device(struct resource *_r, device_t _dev);
 void	rman_set_end(struct resource *_r, rman_res_t _end);
+void	rman_set_irq_cookie(struct resource *_r, void *_c);
 void	rman_set_mapping(struct resource *, struct resource_map *);
 void	rman_set_rid(struct resource *_r, int _rid);
 void	rman_set_start(struct resource *_r, rman_res_t _start);
diff --git a/freebsd/sys/sys/rmlock.h b/freebsd/sys/sys/rmlock.h
index 1dd2740..ca098b2 100644
--- a/freebsd/sys/sys/rmlock.h
+++ b/freebsd/sys/sys/rmlock.h
@@ -55,7 +55,6 @@ void	rm_init_flags(struct rmlock *rm, const char *name, int opts);
 void	rm_destroy(struct rmlock *rm);
 int	rm_wowned(const struct rmlock *rm);
 void	rm_sysinit(void *arg);
-void	rm_sysinit_flags(void *arg);
 
 void	_rm_wlock_debug(struct rmlock *rm, const char *file, int line);
 void	_rm_wunlock_debug(struct rmlock *rm, const char *file, int line);
diff --git a/freebsd/sys/sys/rwlock.h b/freebsd/sys/sys/rwlock.h
index 531f10d..594e1f6 100644
--- a/freebsd/sys/sys/rwlock.h
+++ b/freebsd/sys/sys/rwlock.h
@@ -136,7 +136,6 @@
 void	_rw_init_flags(volatile uintptr_t *c, const char *name, int opts);
 void	_rw_destroy(volatile uintptr_t *c);
 void	rw_sysinit(void *arg);
-void	rw_sysinit_flags(void *arg);
 int	_rw_wowned(const volatile uintptr_t *c);
 void	_rw_wlock_cookie(volatile uintptr_t *c, const char *file, int line);
 int	__rw_try_wlock_int(struct rwlock *rw LOCK_FILE_LINE_ARG_DEF);



More information about the vc mailing list