From a5b385b26fb88ecb0408c684643adec481596dd8 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 29 Jan 2019 10:57:36 +0100 Subject: 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 3a48f368..7005c2e7 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 b2b35d69..402b16f6 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 fa407957..dc7b88d1 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 c5d29cb6..6656ce20 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 512e8636..09d1ee42 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 84665b41..be3d1de3 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 0bb9edc7..b9a8a38d 100644 --- a/freebsd/sys/dev/sdhci/sdhci.c +++ b/freebsd/sys/dev/sdhci/sdhci.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 a22e0235..4c4c2745 100644 --- a/freebsd/sys/dev/sdhci/sdhci.h +++ b/freebsd/sys/dev/sdhci/sdhci.h @@ -32,8 +32,8 @@ #include -#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 3bd247e3..0feb201f 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 309375f0..a47fc0e1 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 08ffc8f3..1b5e2cd1 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 20117eac..9c647eb6 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 7f6c4dce..bc47d826 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 391b2ed6..29fdfe34 100644 --- a/freebsd/sys/kern/subr_bus.c +++ b/freebsd/sys/kern/subr_bus.c @@ -4100,6 +4100,36 @@ bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq, return (EINVAL); } +/** + * @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(). * @@ -4667,6 +4697,34 @@ bus_teardown_intr(device_t dev, struct resource *r, void *cookie) return (BUS_TEARDOWN_INTR(dev->parent, dev, r, 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(). * diff --git a/freebsd/sys/kern/subr_rman.c b/freebsd/sys/kern/subr_rman.c index 75f22dd5..e307df46 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. */ @@ -870,6 +871,20 @@ rman_get_virtual(struct resource *r) return (r->__r_i->r_virtual); } +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 a81b5343..74aeeb80 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 2e28538c..264e3f17 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 00430f77..57e2f23f 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 8395eb00..a70de108 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 +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 02d993b5..fb8357bd 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 a7a1fc29..3ea313d5 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 ee17c806..af42a249 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 db1ebda0..ae32c8d9 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 477388d7..bf83f31b 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 d07381d5..7ee7e311 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 b519971c..54362ed5 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 e19cf0d5..200ae8ad 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 ef59203e..1331d2e5 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 3f15fb0e..6f418985 100644 --- a/freebsd/sys/netpfil/pf/pf_table.c +++ b/freebsd/sys/netpfil/pf/pf_table.c @@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$"); #include #include +#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 74a48f81..0159b829 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 105bb968..5c634054 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 9c2f4653..e955cd58 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 1dd2740c..ca098b2d 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 531f10d2..594e1f6c 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); -- cgit v1.2.3