diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-08-09 13:04:41 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-09-21 10:29:37 +0200 |
commit | e4a8065910cd6b2e7e0448cc6431ca2906322389 (patch) | |
tree | 73492991cfa40f994c20d761d476e6bc16304536 /freebsd/sys | |
parent | Update to FreeBSD head 2017-08-01 (diff) | |
download | rtems-libbsd-e4a8065910cd6b2e7e0448cc6431ca2906322389.tar.bz2 |
Update to FreeBSD head 2017-10-01
Git mirror commit b2f0376b45428f13151d229c5ae9d4d8f74acbd1.
Update #3472.
Diffstat (limited to 'freebsd/sys')
146 files changed, 2440 insertions, 1332 deletions
diff --git a/freebsd/sys/arm/ti/am335x/am335x_prcm.c b/freebsd/sys/arm/ti/am335x/am335x_prcm.c index a05647d5..bc61c9f8 100644 --- a/freebsd/sys/arm/ti/am335x/am335x_prcm.c +++ b/freebsd/sys/arm/ti/am335x/am335x_prcm.c @@ -469,8 +469,8 @@ static driver_t am335x_prcm_driver = { static devclass_t am335x_prcm_devclass; -DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, - am335x_prcm_devclass, 0, 0); +EARLY_DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, + am335x_prcm_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_EARLY); MODULE_VERSION(am335x_prcm, 1); MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1); diff --git a/freebsd/sys/arm/ti/ti_cpuid.h b/freebsd/sys/arm/ti/ti_cpuid.h index 213714b3..7a3fcd5e 100644 --- a/freebsd/sys/arm/ti/ti_cpuid.h +++ b/freebsd/sys/arm/ti/ti_cpuid.h @@ -99,4 +99,10 @@ static __inline int ti_chip(void) uint32_t ti_revision(void); +static __inline bool ti_soc_is_supported(void) +{ + + return (_ti_chip != -1); +} + #endif /* _TI_CPUID_H_ */ diff --git a/freebsd/sys/arm/ti/ti_scm.c b/freebsd/sys/arm/ti/ti_scm.c index 2e54262e..96b284c9 100644 --- a/freebsd/sys/arm/ti/ti_scm.c +++ b/freebsd/sys/arm/ti/ti_scm.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include <dev/fdt/fdt_pinctrl.h> #include "ti_scm.h" +#include "ti_cpuid.h" static struct resource_spec ti_scm_res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */ @@ -88,6 +89,10 @@ static struct ti_scm_softc *ti_scm_sc; static int ti_scm_probe(device_t dev) { + + if (!ti_soc_is_supported()) + return (ENXIO); + if (!ofw_bus_status_okay(dev)) return (ENXIO); diff --git a/freebsd/sys/arm/ti/ti_sdhci.c b/freebsd/sys/arm/ti/ti_sdhci.c index 76e4b750..58d178a0 100644 --- a/freebsd/sys/arm/ti/ti_sdhci.c +++ b/freebsd/sys/arm/ti/ti_sdhci.c @@ -685,11 +685,7 @@ ti_sdhci_attach(device_t dev) bus_generic_probe(dev); bus_generic_attach(dev); -#ifdef MMCCAM - sdhci_cam_start_slot(&sc->slot); -#else sdhci_start_slot(&sc->slot); -#endif return (0); fail: diff --git a/freebsd/sys/cam/cam_ccb.h b/freebsd/sys/cam/cam_ccb.h index 92d76d6a..97560848 100644 --- a/freebsd/sys/cam/cam_ccb.h +++ b/freebsd/sys/cam/cam_ccb.h @@ -379,8 +379,7 @@ struct ccb_getdev { u_int8_t serial_num[252]; u_int8_t inq_flags; u_int8_t serial_num_len; - const struct nvme_controller_data *nvme_cdata; - const struct nvme_namespace_data *nvme_data; + void *padding[2]; }; /* Device Statistics CCB */ @@ -644,7 +643,7 @@ struct ccb_pathinq_settings_sas { }; struct ccb_pathinq_settings_nvme { - uint16_t nsid; /* Namespace ID for this path */ + uint32_t nsid; /* Namespace ID for this path */ }; #define PATHINQ_SETTINGS_SIZE 128 @@ -850,7 +849,8 @@ struct ccb_nvmeio { struct nvme_completion cpl; /* NVME completion, per NVME standard */ uint8_t *data_ptr; /* Ptr to the data buf/SG list */ uint32_t dxfer_len; /* Data transfer length */ - uint32_t resid; /* Transfer residual length: 2's comp unused ?*/ + uint16_t sglist_cnt; /* Number of SG list entries */ + uint16_t unused; /* padding for removed uint32_t */ }; /* @@ -1289,6 +1289,8 @@ struct ccb_dev_advinfo { #define CDAI_TYPE_PHYS_PATH 3 #define CDAI_TYPE_RCAPLONG 4 #define CDAI_TYPE_EXT_INQ 5 +#define CDAI_TYPE_NVME_CNTRL 6 /* NVMe Identify Controller data */ +#define CDAI_TYPE_NVME_NS 7 /* NVMe Identify Namespace data */ off_t bufsiz; /* IN: Size of external buffer */ #define CAM_SCSI_DEVID_MAXLEN 65536 /* length in buffer is an uint16_t */ off_t provsiz; /* OUT: Size required/used */ diff --git a/freebsd/sys/cam/mmc/mmc.h b/freebsd/sys/cam/mmc/mmc.h index 9fae837e..2e31f029 100644 --- a/freebsd/sys/cam/mmc/mmc.h +++ b/freebsd/sys/cam/mmc/mmc.h @@ -87,6 +87,7 @@ struct mmc_params { #define CARD_FEATURE_SDIO 0x1 << 2 #define CARD_FEATURE_SD20 0x1 << 3 #define CARD_FEATURE_MMC 0x1 << 4 +#define CARD_FEATURE_18V 0x1 << 5 uint8_t sdio_func_count; } __packed; diff --git a/freebsd/sys/cam/mmc/mmc_sdio.h b/freebsd/sys/cam/mmc/mmc_sdio.h deleted file mode 100644 index 6d22ffc0..00000000 --- a/freebsd/sys/cam/mmc/mmc_sdio.h +++ /dev/null @@ -1,64 +0,0 @@ -/*- - * Copyright (c) 2014 Ilya Bakulin. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Portions of this software may have been developed with reference to - * the SD Simplified Specification. The following disclaimer may apply: - * - * The following conditions apply to the release of the simplified - * specification ("Simplified Specification") by the SD Card Association and - * the SD Group. The Simplified Specification is a subset of the complete SD - * Specification which is owned by the SD Card Association and the SD - * Group. This Simplified Specification is provided on a non-confidential - * basis subject to the disclaimers below. Any implementation of the - * Simplified Specification may require a license from the SD Card - * Association, SD Group, SD-3C LLC or other third parties. - * - * Disclaimers: - * - * The information contained in the Simplified Specification is presented only - * as a standard specification for SD Cards and SD Host/Ancillary products and - * is provided "AS-IS" without any representations or warranties of any - * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD - * Card Association for any damages, any infringements of patents or other - * right of the SD Group, SD-3C LLC, the SD Card Association or any third - * parties, which may result from its use. No license is granted by - * implication, estoppel or otherwise under any patent or other rights of the - * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing - * herein shall be construed as an obligation by the SD Group, the SD-3C LLC - * or the SD Card Association to disclose or distribute any technical - * information, know-how or other confidential information to any third party. - * - * $FreeBSD$ - */ - -/* - * Various SDIO-related stuff - */ - -#ifndef CAM_MMC_SDIO_H -#define CAM_MMC_SDIO_H - -void sdio_print_stupid_message(struct cam_periph *periph); -void sdio_fill_mmcio_rw_direct(union ccb *ccb, uint8_t f, uint8_t wr, uint32_t adr, uint8_t *data); -uint8_t sdio_parse_mmcio_rw_direct(union ccb *ccb, uint8_t *data); -#endif diff --git a/freebsd/sys/cam/nvme/nvme_all.h b/freebsd/sys/cam/nvme/nvme_all.h index 3cff74d3..b52b7a78 100644 --- a/freebsd/sys/cam/nvme/nvme_all.h +++ b/freebsd/sys/cam/nvme/nvme_all.h @@ -44,5 +44,7 @@ int nvme_identify_match(caddr_t identbuffer, caddr_t table_entry); void nvme_print_ident(const struct nvme_controller_data *, const struct nvme_namespace_data *); const char *nvme_op_string(const struct nvme_command *); const char *nvme_cmd_string(const struct nvme_command *, char *, size_t); +const void *nvme_get_identify_cntrl(struct cam_periph *); +const void *nvme_get_identify_ns(struct cam_periph *); #endif /* CAM_NVME_NVME_ALL_H */ diff --git a/freebsd/sys/cam/scsi/scsi_all.c b/freebsd/sys/cam/scsi/scsi_all.c index 85e95cb6..c13f5516 100644 --- a/freebsd/sys/cam/scsi/scsi_all.c +++ b/freebsd/sys/cam/scsi/scsi_all.c @@ -471,10 +471,6 @@ static struct op_table_entry scsi_op_codes[] = { { 0x86, ALL & ~(L | R | F), "ACCESS CONTROL IN" }, /* 87 OO OO OOOOOOO ACCESS CONTROL OUT */ { 0x87, ALL & ~(L | R | F), "ACCESS CONTROL OUT" }, - /* - * XXX READ(16)/WRITE(16) were not listed for CD/DVE in op-num.txt - * but we had it since r1.40. Do we really want them? - */ /* 88 MM O O O READ(16) */ { 0x88, D | T | W | O | B, "READ(16)" }, /* 89 O COMPARE AND WRITE*/ @@ -5105,8 +5101,8 @@ scsi_sense_sbuf(struct cam_device *device, struct ccb_scsiio *csio, * errors on finicky architectures. We don't * ensure that the sense data is pointer aligned. */ - bcopy(&csio->sense_data, &sense, - sizeof(struct scsi_sense_data *)); + bcopy((struct scsi_sense_data **)&csio->sense_data, + &sense, sizeof(struct scsi_sense_data *)); } } else { /* @@ -5230,8 +5226,8 @@ scsi_extract_sense_ccb(union ccb *ccb, return (0); if (ccb->ccb_h.flags & CAM_SENSE_PTR) - bcopy(&ccb->csio.sense_data, &sense_data, - sizeof(struct scsi_sense_data *)); + bcopy((struct scsi_sense_data **)&ccb->csio.sense_data, + &sense_data, sizeof(struct scsi_sense_data *)); else sense_data = &ccb->csio.sense_data; scsi_extract_sense_len(sense_data, diff --git a/freebsd/sys/dev/e1000/if_em.c b/freebsd/sys/dev/e1000/if_em.c index f5a0b94e..dba6ef0a 100644 --- a/freebsd/sys/dev/e1000/if_em.c +++ b/freebsd/sys/dev/e1000/if_em.c @@ -341,6 +341,8 @@ MODULE_DEPEND(em, pci, 1, 1, 1); MODULE_DEPEND(em, ether, 1, 1, 1); MODULE_DEPEND(em, iflib, 1, 1, 1); +IFLIB_PNP_INFO(pci, em, em_vendor_info_array); + static driver_t igb_driver = { "igb", igb_methods, sizeof(struct adapter), }; @@ -352,6 +354,7 @@ MODULE_DEPEND(igb, pci, 1, 1, 1); MODULE_DEPEND(igb, ether, 1, 1, 1); MODULE_DEPEND(igb, iflib, 1, 1, 1); +IFLIB_PNP_INFO(pci, igb, igb_vendor_info_array); static device_method_t em_if_methods[] = { DEVMETHOD(ifdi_attach_pre, em_if_attach_pre), @@ -485,7 +488,7 @@ static struct if_shared_ctx em_sctx_init = { .isc_vendor_info = em_vendor_info_array, .isc_driver_version = em_driver_version, .isc_driver = &em_if_driver, - .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP, + .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP | IFLIB_NEED_ZERO_CSUM, .isc_nrxd_min = {EM_MIN_RXD}, .isc_ntxd_min = {EM_MIN_TXD}, @@ -513,12 +516,12 @@ static struct if_shared_ctx igb_sctx_init = { .isc_vendor_info = igb_vendor_info_array, .isc_driver_version = em_driver_version, .isc_driver = &em_if_driver, - .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP, + .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_TSO_INIT_IP | IFLIB_NEED_ZERO_CSUM, .isc_nrxd_min = {EM_MIN_RXD}, .isc_ntxd_min = {EM_MIN_TXD}, - .isc_nrxd_max = {EM_MAX_RXD}, - .isc_ntxd_max = {EM_MAX_TXD}, + .isc_nrxd_max = {IGB_MAX_RXD}, + .isc_ntxd_max = {IGB_MAX_TXD}, .isc_nrxd_default = {EM_DEFAULT_RXD}, .isc_ntxd_default = {EM_DEFAULT_TXD}, }; @@ -536,22 +539,26 @@ static int em_get_regs(SYSCTL_HANDLER_ARGS) { struct adapter *adapter = (struct adapter *)arg1; struct e1000_hw *hw = &adapter->hw; - struct sbuf *sb; - u32 *regs_buff = (u32 *)malloc(sizeof(u32) * IGB_REGS_LEN, M_DEVBUF, M_NOWAIT); + u32 *regs_buff; int rc; + regs_buff = malloc(sizeof(u32) * IGB_REGS_LEN, M_DEVBUF, M_WAITOK); memset(regs_buff, 0, IGB_REGS_LEN * sizeof(u32)); rc = sysctl_wire_old_buffer(req, 0); MPASS(rc == 0); - if (rc != 0) + if (rc != 0) { + free(regs_buff, M_DEVBUF); return (rc); + } sb = sbuf_new_for_sysctl(NULL, NULL, 32*400, req); MPASS(sb != NULL); - if (sb == NULL) + if (sb == NULL) { + free(regs_buff, M_DEVBUF); return (ENOMEM); + } /* General Registers */ regs_buff[0] = E1000_READ_REG(hw, E1000_CTRL); @@ -607,6 +614,8 @@ static int em_get_regs(SYSCTL_HANDLER_ARGS) sbuf_printf(sb, "\tTDFHS\t %08x\n", regs_buff[20]); sbuf_printf(sb, "\tTDFPC\t %08x\n\n", regs_buff[21]); + free(regs_buff, M_DEVBUF); + #ifdef DUMP_DESCS { if_softc_ctx_t scctx = adapter->shared; @@ -3641,34 +3650,13 @@ em_enable_wakeup(if_ctx_t ctx) struct adapter *adapter = iflib_get_softc(ctx); device_t dev = iflib_get_dev(ctx); if_t ifp = iflib_get_ifp(ctx); - u32 pmc, ctrl, ctrl_ext, rctl, wuc; + int error = 0; + u32 pmc, ctrl, ctrl_ext, rctl; u16 status; - if ((pci_find_cap(dev, PCIY_PMG, &pmc) != 0)) + if (pci_find_cap(dev, PCIY_PMG, &pmc) != 0) return; - /* Advertise the wakeup capability */ - ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); - ctrl |= (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN3); - E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); - wuc = E1000_READ_REG(&adapter->hw, E1000_WUC); - wuc |= (E1000_WUC_PME_EN | E1000_WUC_APME); - E1000_WRITE_REG(&adapter->hw, E1000_WUC, wuc); - - if ((adapter->hw.mac.type == e1000_ich8lan) || - (adapter->hw.mac.type == e1000_pchlan) || - (adapter->hw.mac.type == e1000_ich9lan) || - (adapter->hw.mac.type == e1000_ich10lan)) - e1000_suspend_workarounds_ich8lan(&adapter->hw); - - /* Keep the laser running on Fiber adapters */ - if (adapter->hw.phy.media_type == e1000_media_type_fiber || - adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { - ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_SDP3_DATA; - E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, ctrl_ext); - } - /* * Determine type of Wakeup: note that wol * is set with all bits on by default. @@ -3687,10 +3675,34 @@ em_enable_wakeup(if_ctx_t ctx) E1000_WRITE_REG(&adapter->hw, E1000_RCTL, rctl); } + if (!(adapter->wol & (E1000_WUFC_EX | E1000_WUFC_MAG | E1000_WUFC_MC))) + goto pme; + + /* Advertise the wakeup capability */ + ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL); + ctrl |= (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN3); + E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl); + + /* Keep the laser running on Fiber adapters */ + if (adapter->hw.phy.media_type == e1000_media_type_fiber || + adapter->hw.phy.media_type == e1000_media_type_internal_serdes) { + ctrl_ext = E1000_READ_REG(&adapter->hw, E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP3_DATA; + E1000_WRITE_REG(&adapter->hw, E1000_CTRL_EXT, ctrl_ext); + } + + if ((adapter->hw.mac.type == e1000_ich8lan) || + (adapter->hw.mac.type == e1000_pchlan) || + (adapter->hw.mac.type == e1000_ich9lan) || + (adapter->hw.mac.type == e1000_ich10lan)) + e1000_suspend_workarounds_ich8lan(&adapter->hw); + if ( adapter->hw.mac.type >= e1000_pchlan) { - if (em_enable_phy_wakeup(adapter)) - return; + error = em_enable_phy_wakeup(adapter); + if (error) + goto pme; } else { + /* Enable wakeup by the MAC */ E1000_WRITE_REG(&adapter->hw, E1000_WUC, E1000_WUC_PME_EN); E1000_WRITE_REG(&adapter->hw, E1000_WUFC, adapter->wol); } @@ -3698,10 +3710,10 @@ em_enable_wakeup(if_ctx_t ctx) if (adapter->hw.phy.type == e1000_phy_igp_3) e1000_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); - /* Request PME */ +pme: status = pci_read_config(dev, pmc + PCIR_POWER_STATUS, 2); status &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); - if (if_getcapenable(ifp) & IFCAP_WOL) + if (!error && (if_getcapenable(ifp) & IFCAP_WOL)) status |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; pci_write_config(dev, pmc + PCIR_POWER_STATUS, status, 2); diff --git a/freebsd/sys/dev/e1000/if_em.h b/freebsd/sys/dev/e1000/if_em.h index 67d97e17..b7599291 100644 --- a/freebsd/sys/dev/e1000/if_em.h +++ b/freebsd/sys/dev/e1000/if_em.h @@ -96,10 +96,10 @@ /* Tunables */ /* - * EM_TXD: Maximum number of Transmit Descriptors + * EM_MAX_TXD: Maximum number of Transmit Descriptors * Valid Range: 80-256 for 82542 and 82543-based adapters * 80-4096 for others - * Default Value: 256 + * Default Value: 1024 * This value is the number of transmit descriptors allocated by the driver. * Increasing this value allows the driver to queue more transmits. Each * descriptor is 16 bytes. @@ -111,12 +111,13 @@ #define EM_MAX_TXD 4096 #define EM_DEFAULT_TXD 1024 #define EM_DEFAULT_MULTI_TXD 4096 +#define IGB_MAX_TXD 4096 /* - * EM_RXD - Maximum number of receive Descriptors + * EM_MAX_RXD - Maximum number of receive Descriptors * Valid Range: 80-256 for 82542 and 82543-based adapters * 80-4096 for others - * Default Value: 256 + * Default Value: 1024 * This value is the number of receive descriptors allocated by the driver. * Increasing this value allows the driver to buffer more incoming packets. * Each descriptor is 16 bytes. A receive buffer is also allocated for each @@ -129,6 +130,7 @@ #define EM_MAX_RXD 4096 #define EM_DEFAULT_RXD 1024 #define EM_DEFAULT_MULTI_RXD 4096 +#define IGB_MAX_RXD 4096 /* * EM_TIDV - Transmit Interrupt Delay Value @@ -555,26 +557,6 @@ typedef struct _em_vendor_info_t { void em_dump_rs(struct adapter *); -#define EM_CORE_LOCK_INIT(_sc, _name) \ - mtx_init(&(_sc)->core_mtx, _name, "EM Core Lock", MTX_DEF) -#define EM_TX_LOCK_INIT(_sc, _name) \ - mtx_init(&(_sc)->tx_mtx, _name, "EM TX Lock", MTX_DEF) -#define EM_RX_LOCK_INIT(_sc, _name) \ - mtx_init(&(_sc)->rx_mtx, _name, "EM RX Lock", MTX_DEF) -#define EM_CORE_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->core_mtx) -#define EM_TX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->tx_mtx) -#define EM_RX_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_mtx) -#define EM_CORE_LOCK(_sc) mtx_lock(&(_sc)->core_mtx) -#define EM_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_mtx) -#define EM_TX_TRYLOCK(_sc) mtx_trylock(&(_sc)->tx_mtx) -#define EM_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_mtx) -#define EM_CORE_UNLOCK(_sc) mtx_unlock(&(_sc)->core_mtx) -#define EM_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_mtx) -#define EM_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_mtx) -#define EM_CORE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->core_mtx, MA_OWNED) -#define EM_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_mtx, MA_OWNED) -#define EM_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_mtx, MA_OWNED) - #define EM_RSSRK_SIZE 4 #define EM_RSSRK_VAL(key, i) (key[(i) * EM_RSSRK_SIZE] | \ key[(i) * EM_RSSRK_SIZE + 1] << 8 | \ diff --git a/freebsd/sys/dev/fdt/fdt_common.c b/freebsd/sys/dev/fdt/fdt_common.c index b149695c..c8c777f1 100644 --- a/freebsd/sys/dev/fdt/fdt_common.c +++ b/freebsd/sys/dev/fdt/fdt_common.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #define FDT_TYPE_LEN 64 #define FDT_REG_CELLS 4 +#define FDT_RANGES_SIZE 48 SYSCTL_NODE(_hw, OID_AUTO, fdt, CTLFLAG_RD, 0, "Flattened Device Tree"); @@ -151,7 +152,7 @@ fdt_get_range_by_busaddr(phandle_t node, u_long addr, u_long *base, int fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size) { - pcell_t ranges[6], *rangesptr; + pcell_t ranges[FDT_RANGES_SIZE], *rangesptr; pcell_t addr_cells, size_cells, par_addr_cells; u_long par_bus_addr, pbase, psize; int err, len, tuple_size, tuples; diff --git a/freebsd/sys/dev/mmc/bridge.h b/freebsd/sys/dev/mmc/bridge.h index 53e61b48..b7d95ffc 100644 --- a/freebsd/sys/dev/mmc/bridge.h +++ b/freebsd/sys/dev/mmc/bridge.h @@ -65,12 +65,10 @@ * linux/mmc/host.h file. * * A mmc bridge is a chipset that can have one or more mmc and/or sd - * cards attached to it. mmc cards are attached on a bus topology, - * while sd and sdio cards are attached using a star topology (meaning - * in practice each sd card has its own, independent slot). Each - * mmcbr is assumed to be derived from the mmcbr. This is done to - * allow for easier addition of bridges (as each bridge does not need - * to be added to the mmcbus file). + * cards attached to it. mmc devices are attached on a bus topology, + * while sd and sdio cards usually are attached using a star topology + * (meaning in practice each sd card has its own, independent slot). + * Since SDHCI v3.00, buses for esd and esdio are possible, though. * * Attached to the mmc bridge is an mmcbus. The mmcbus is described * in dev/mmc/mmcbus_if.m. @@ -182,7 +180,7 @@ struct mmc_host { extern driver_t mmc_driver; extern devclass_t mmc_devclass; -#define MMC_VERSION 4 +#define MMC_VERSION 5 #define MMC_DECLARE_BRIDGE(name) \ DRIVER_MODULE(mmc, name, mmc_driver, mmc_devclass, NULL, NULL); \ diff --git a/freebsd/sys/dev/mmc/mmc.c b/freebsd/sys/dev/mmc/mmc.c index 74e26332..77934e86 100644 --- a/freebsd/sys/dev/mmc/mmc.c +++ b/freebsd/sys/dev/mmc/mmc.c @@ -106,12 +106,34 @@ struct mmc_ivars { uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ uint32_t cmd6_time; /* Generic switch timeout [us] */ + uint32_t quirks; /* Quirks as per mmc_quirk->quirks */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ char card_sn_string[16];/* Formatted serial # for disk->d_ident */ }; #define CMD_RETRIES 3 +static const struct mmc_quirk mmc_quirks[] = { + /* + * For some SanDisk iNAND devices, the CMD38 argument needs to be + * provided in EXT_CSD[113]. + */ + { 0x2, 0x100, "SEM02G", MMC_QUIRK_INAND_CMD38 }, + { 0x2, 0x100, "SEM04G", MMC_QUIRK_INAND_CMD38 }, + { 0x2, 0x100, "SEM08G", MMC_QUIRK_INAND_CMD38 }, + { 0x2, 0x100, "SEM16G", MMC_QUIRK_INAND_CMD38 }, + { 0x2, 0x100, "SEM32G", MMC_QUIRK_INAND_CMD38 }, + + /* + * Disable TRIM for Kingston eMMCs where a firmware bug can lead to + * unrecoverable data corruption. + */ + { 0x70, MMC_QUIRK_OID_ANY, "V10008", MMC_QUIRK_BROKEN_TRIM }, + { 0x70, MMC_QUIRK_OID_ANY, "V10016", MMC_QUIRK_BROKEN_TRIM }, + + { 0x0, 0x0, NULL, 0x0 } +}; + static SYSCTL_NODE(_hw, OID_AUTO, mmc, CTLFLAG_RD, NULL, "mmc driver"); static int mmc_debug; @@ -1123,7 +1145,7 @@ mmc_format_card_id_string(struct mmc_ivars *ivar) /* * Format a card ID string for use by the mmcsd driver, it's what * appears between the <> in the following: - * mmcsd0: 968MB <SD SD01G 8.0 SN 2686905 Mfg 08/2008 by 3 TN> at mmc0 + * mmcsd0: 968MB <SD SD01G 8.0 SN 2686905 MFG 08/2008 by 3 TN> at mmc0 * 22.5MHz/4bit/128-block * * Also format just the card serial number, which the mmcsd driver will @@ -1561,6 +1583,7 @@ mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) break; } } + device_printf(dev, " quirks: %b\n", ivar->quirks, MMC_QUIRKS_FMT); device_printf(dev, " bus: %ubit, %uMHz (%s timing)\n", (ivar->bus_width == bus_width_1 ? 1 : (ivar->bus_width == bus_width_4 ? 4 : 8)), @@ -1577,6 +1600,7 @@ mmc_discover_cards(struct mmc_softc *sc) u_char switch_res[64]; uint32_t raw_cid[4]; struct mmc_ivars *ivar = NULL; + const struct mmc_quirk *quirk; device_t child; int err, host_caps, i, newcard; uint32_t resp, sec_count, status; @@ -1884,6 +1908,18 @@ mmc_discover_cards(struct mmc_softc *sc) ivar->raw_ext_csd[EXT_CSD_REV] >= 5); child_common: + for (quirk = &mmc_quirks[0]; quirk->mid != 0x0; quirk++) { + if ((quirk->mid == MMC_QUIRK_MID_ANY || + quirk->mid == ivar->cid.mid) && + (quirk->oid == MMC_QUIRK_OID_ANY || + quirk->oid == ivar->cid.oid) && + strncmp(quirk->pnm, ivar->cid.pnm, + sizeof(ivar->cid.pnm)) == 0) { + ivar->quirks = quirk->quirks; + break; + } + } + /* * Some cards that report maximum I/O block sizes greater * than 512 require the block length to be set to 512, even @@ -2485,6 +2521,12 @@ mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) case MMC_IVAR_MAX_DATA: *result = mmcbr_get_max_data(bus); break; + case MMC_IVAR_CMD6_TIMEOUT: + *result = ivar->cmd6_time; + break; + case MMC_IVAR_QUIRKS: + *result = ivar->quirks; + break; case MMC_IVAR_CARD_ID_STRING: *(char **)result = ivar->card_id_string; break; diff --git a/freebsd/sys/dev/mmc/mmc_subr.c b/freebsd/sys/dev/mmc/mmc_subr.c index 006354ba..76a14028 100644 --- a/freebsd/sys/dev/mmc/mmc_subr.c +++ b/freebsd/sys/dev/mmc/mmc_subr.c @@ -74,7 +74,7 @@ __FBSDID("$FreeBSD$"); #define LOG_PPS 5 /* Log no more than 5 errors per second. */ int -mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd, +mmc_wait_for_cmd(device_t busdev, device_t dev, struct mmc_command *cmd, int retries) { struct mmc_request mreq; @@ -89,14 +89,14 @@ mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd, if (cmd->data != NULL) cmd->data->mrq = &mreq; mreq.cmd = cmd; - if (MMCBUS_WAIT_FOR_REQUEST(brdev, reqdev, &mreq) != 0) + if (MMCBUS_WAIT_FOR_REQUEST(busdev, dev, &mreq) != 0) err = MMC_ERR_FAILED; else err = cmd->error; } while (err != MMC_ERR_NONE && retries-- > 0); - if (err != MMC_ERR_NONE && brdev == reqdev) { - sc = device_get_softc(brdev); + if (err != MMC_ERR_NONE && busdev == dev) { + sc = device_get_softc(busdev); if (sc->squelched == 0 && ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { device_printf(sc->dev, "CMD%d failed, RESULT: %d\n", @@ -108,14 +108,14 @@ mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd, } int -mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca, +mmc_wait_for_app_cmd(device_t busdev, device_t dev, uint16_t rca, struct mmc_command *cmd, int retries) { struct mmc_command appcmd; struct mmc_softc *sc; int err; - sc = device_get_softc(brdev); + sc = device_get_softc(busdev); /* Squelch error reporting at lower levels, we report below. */ sc->squelched++; @@ -124,14 +124,14 @@ mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca, appcmd.opcode = MMC_APP_CMD; appcmd.arg = (uint32_t)rca << 16; appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - if (mmc_wait_for_cmd(brdev, reqdev, &appcmd, 0) != 0) + if (mmc_wait_for_cmd(busdev, dev, &appcmd, 0) != 0) err = MMC_ERR_FAILED; else err = appcmd.error; if (err == MMC_ERR_NONE) { if (!(appcmd.resp[0] & R1_APP_CMD)) err = MMC_ERR_FAILED; - else if (mmc_wait_for_cmd(brdev, reqdev, cmd, 0) != 0) + else if (mmc_wait_for_cmd(busdev, dev, cmd, 0) != 0) err = MMC_ERR_FAILED; else err = cmd->error; @@ -139,7 +139,7 @@ mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca, } while (err != MMC_ERR_NONE && retries-- > 0); sc->squelched--; - if (err != MMC_ERR_NONE && brdev == reqdev) { + if (err != MMC_ERR_NONE && busdev == dev) { if (sc->squelched == 0 && ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) { device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n", @@ -151,7 +151,7 @@ mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca, } int -mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set, +mmc_switch(device_t busdev, device_t dev, uint16_t rca, uint8_t set, uint8_t index, uint8_t value, u_int timeout, bool status) { struct mmc_command cmd; @@ -160,7 +160,7 @@ mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set, KASSERT(timeout != 0, ("%s: no timeout", __func__)); - sc = device_get_softc(brdev); + sc = device_get_softc(busdev); memset(&cmd, 0, sizeof(cmd)); cmd.opcode = MMC_SWITCH_FUNC; @@ -171,8 +171,8 @@ mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set, * exceeds the maximum host timeout, use a R1 instead of a R1B * response in order to keep the hardware from timing out. */ - if (mmcbr_get_caps(brdev) & MMC_CAP_WAIT_WHILE_BUSY && - timeout > mmcbr_get_max_busy_timeout(brdev)) + if (mmcbr_get_caps(busdev) & MMC_CAP_WAIT_WHILE_BUSY && + timeout > mmcbr_get_max_busy_timeout(busdev)) cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; else cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; @@ -182,17 +182,17 @@ mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set, * than to a tuning command that may have snuck in between. */ sc->retune_paused++; - err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES); if (err != MMC_ERR_NONE || status == false) goto out; - err = mmc_switch_status(brdev, reqdev, rca, timeout); + err = mmc_switch_status(busdev, dev, rca, timeout); out: sc->retune_paused--; return (err); } int -mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout) +mmc_switch_status(device_t busdev, device_t dev, uint16_t rca, u_int timeout) { struct timeval cur, end; int err; @@ -207,7 +207,7 @@ mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout) */ end.tv_sec = end.tv_usec = 0; for (;;) { - err = mmc_send_status(brdev, reqdev, rca, &status); + err = mmc_send_status(busdev, dev, rca, &status); if (err != MMC_ERR_NONE) break; if (R1_CURRENT_STATE(status) == R1_STATE_TRAN) @@ -228,7 +228,7 @@ mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout) } int -mmc_send_ext_csd(device_t brdev, device_t reqdev, uint8_t *rawextcsd) +mmc_send_ext_csd(device_t busdev, device_t dev, uint8_t *rawextcsd) { struct mmc_command cmd; struct mmc_data data; @@ -246,12 +246,12 @@ mmc_send_ext_csd(device_t brdev, device_t reqdev, uint8_t *rawextcsd) data.len = MMC_EXTCSD_SIZE; data.flags = MMC_DATA_READ; - err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES); return (err); } int -mmc_send_status(device_t brdev, device_t reqdev, uint16_t rca, uint32_t *status) +mmc_send_status(device_t busdev, device_t dev, uint16_t rca, uint32_t *status) { struct mmc_command cmd; int err; @@ -260,7 +260,7 @@ mmc_send_status(device_t brdev, device_t reqdev, uint16_t rca, uint32_t *status) cmd.opcode = MMC_SEND_STATUS; cmd.arg = (uint32_t)rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES); + err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES); *status = cmd.resp[0]; return (err); } diff --git a/freebsd/sys/dev/mmc/mmc_subr.h b/freebsd/sys/dev/mmc/mmc_subr.h index 6e300d2f..33ea6760 100644 --- a/freebsd/sys/dev/mmc/mmc_subr.h +++ b/freebsd/sys/dev/mmc/mmc_subr.h @@ -57,16 +57,16 @@ struct mmc_command; -int mmc_send_ext_csd(device_t brdev, device_t reqdev, uint8_t *rawextcsd); -int mmc_send_status(device_t brdev, device_t reqdev, uint16_t rca, +int mmc_send_ext_csd(device_t busdev, device_t dev, uint8_t *rawextcsd); +int mmc_send_status(device_t busdev, device_t dev, uint16_t rca, uint32_t *status); -int mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set, +int mmc_switch(device_t busdev, device_t dev, uint16_t rca, uint8_t set, uint8_t index, uint8_t value, u_int timeout, bool send_status); -int mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, +int mmc_switch_status(device_t busdev, device_t dev, uint16_t rca, u_int timeout); -int mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca, +int mmc_wait_for_app_cmd(device_t busdev, device_t dev, uint16_t rca, struct mmc_command *cmd, int retries); -int mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd, +int mmc_wait_for_cmd(device_t busdev, device_t dev, struct mmc_command *cmd, int retries); #endif /* DEV_MMC_SUBR_H */ diff --git a/freebsd/sys/dev/mmc/mmcreg.h b/freebsd/sys/dev/mmc/mmcreg.h index 80f433c1..8120b69f 100644 --- a/freebsd/sys/dev/mmc/mmcreg.h +++ b/freebsd/sys/dev/mmc/mmcreg.h @@ -276,6 +276,13 @@ struct mmc_request { #define MMC_ERASE_GROUP_END 36 /* 37 -- reserved old command */ #define MMC_ERASE 38 +#define MMC_ERASE_ERASE 0x00000000 +#define MMC_ERASE_TRIM 0x00000001 +#define MMC_ERASE_FULE 0x00000002 +#define MMC_ERASE_DISCARD 0x00000003 +#define MMC_ERASE_SECURE_ERASE 0x80000000 +#define MMC_ERASE_SECURE_TRIM1 0x80000001 +#define MMC_ERASE_SECURE_TRIM2 0x80008000 /* Class 9: I/O mode commands */ #define MMC_FAST_IO 39 @@ -383,6 +390,7 @@ struct mmc_request { #define EXT_CSD_ERASE_TO_MULT 223 /* RO */ #define EXT_CSD_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_SIZE_MULT 226 /* RO */ +#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ #define EXT_CSD_PWR_CL_200_195 236 /* RO */ #define EXT_CSD_PWR_CL_200_360 237 /* RO */ #define EXT_CSD_PWR_CL_52_195_DDR 238 /* RO */ @@ -467,6 +475,22 @@ struct mmc_request { #define EXT_CSD_STROBE_SUPPORT_EN 0x01 +#define EXT_CSD_SEC_FEATURE_SUPPORT_ER_EN 0x01 +#define EXT_CSD_SEC_FEATURE_SUPPORT_BD_BLK_EN 0x04 +#define EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN 0x10 +#define EXT_CSD_SEC_FEATURE_SUPPORT_SANITIZE 0x40 + +/* + * Vendor specific EXT_CSD fields + */ +/* SanDisk iNAND */ +#define EXT_CSD_INAND_CMD38 113 +#define EXT_CSD_INAND_CMD38_ERASE 0x00 +#define EXT_CSD_INAND_CMD38_TRIM 0x01 +#define EXT_CSD_INAND_CMD38_SECURE_ERASE 0x80 +#define EXT_CSD_INAND_CMD38_SECURE_TRIM1 0x81 +#define EXT_CSD_INAND_CMD38_SECURE_TRIM2 0x82 + #define MMC_TYPE_HS_26_MAX 26000000 #define MMC_TYPE_HS_52_MAX 52000000 #define MMC_TYPE_DDR52_MAX 52000000 @@ -608,8 +632,7 @@ struct mmc_cid { uint8_t fwrev; }; -struct mmc_csd -{ +struct mmc_csd { uint8_t csd_structure; uint8_t spec_vers; uint16_t ccc; @@ -635,16 +658,14 @@ struct mmc_csd wp_grp_enable:1; }; -struct mmc_scr -{ +struct mmc_scr { unsigned char sda_vsn; unsigned char bus_widths; #define SD_SCR_BUS_WIDTH_1 (1 << 0) #define SD_SCR_BUS_WIDTH_4 (1 << 2) }; -struct mmc_sd_status -{ +struct mmc_sd_status { uint8_t bus_width; uint8_t secured_mode; uint16_t card_type; @@ -657,6 +678,19 @@ struct mmc_sd_status uint8_t erase_offset; }; +struct mmc_quirk { + uint32_t mid; +#define MMC_QUIRK_MID_ANY ((uint32_t)-1) + uint16_t oid; +#define MMC_QUIRK_OID_ANY ((uint16_t)-1) + const char *pnm; + uint32_t quirks; +#define MMC_QUIRK_INAND_CMD38 0x0001 +#define MMC_QUIRK_BROKEN_TRIM 0x0002 +}; + +#define MMC_QUIRKS_FMT "\020" "\001INAND_CMD38" "\002BROKEN_TRIM" + /* * Various MMC/SD constants */ diff --git a/freebsd/sys/dev/mmc/mmcsd.c b/freebsd/sys/dev/mmc/mmcsd.c index 195feae2..45bd9c50 100644 --- a/freebsd/sys/dev/mmc/mmcsd.c +++ b/freebsd/sys/dev/mmc/mmcsd.c @@ -128,7 +128,7 @@ struct mmcsd_part { struct mmcsd_softc { device_t dev; - device_t mmcbr; + device_t mmcbus; struct mmcsd_part *part[MMC_PART_MAX]; enum mmc_card_mode mode; u_int max_data; /* Maximum data size [blocks] */ @@ -137,6 +137,10 @@ struct mmcsd_softc { uint8_t part_curr; /* Partition currently switched to */ uint8_t ext_csd[MMC_EXTCSD_SIZE]; uint16_t rca; + uint32_t flags; +#define MMCSD_INAND_CMD38 0x0001 +#define MMCSD_USE_TRIM 0x0002 + uint32_t cmd6_time; /* Generic switch timeout [us] */ uint32_t part_time; /* Partition switch timeout [us] */ off_t enh_base; /* Enhanced user data area slice base ... */ off_t enh_size; /* ... and size [bytes] */ @@ -147,6 +151,9 @@ struct mmcsd_softc { #ifndef __rtems__ static const char *errmsg[] = +#else /* __rtems__ */ +static const char * const errmsg[] = +#endif /* __rtems__ */ { "None", "Timeout", @@ -156,7 +163,6 @@ static const char *errmsg[] = "Invalid", "NO MEMORY" }; -#endif /* __rtems__ */ #define LOG_PPS 5 /* Log no more than 5 errors per second. */ @@ -183,11 +189,12 @@ static int mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td); static void mmcsd_add_part(struct mmcsd_softc *sc, u_int type, - const char *name, u_int cnt, off_t media_size, off_t erase_size, bool ro); + const char *name, u_int cnt, off_t media_size, bool ro); static int mmcsd_bus_bit_width(device_t dev); #ifndef __rtems__ static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp); #endif /* __rtems__ */ +static const char *mmcsd_errmsg(int e); static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag); static int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, @@ -440,20 +447,21 @@ error: static int mmcsd_attach(device_t dev) { - device_t mmcbr; + device_t mmcbus; struct mmcsd_softc *sc; const uint8_t *ext_csd; off_t erase_size, sector_size, size, wp_size; uintmax_t bytes; int err, i; + uint32_t quirks; uint8_t rev; bool comp, ro; char unit[2]; sc = device_get_softc(dev); sc->dev = dev; - sc->mmcbr = mmcbr = device_get_parent(dev); - sc->mode = mmcbr_get_mode(mmcbr); + sc->mmcbus = mmcbus = device_get_parent(dev); + sc->mode = mmcbr_get_mode(mmcbus); /* * Note that in principle with an SDHCI-like re-tuning implementation, * the maximum data size can change at runtime due to a device removal/ @@ -464,20 +472,47 @@ mmcsd_attach(device_t dev) * place either. */ sc->max_data = mmc_get_max_data(dev); - sc->erase_sector = mmc_get_erase_sector(dev); sc->high_cap = mmc_get_high_cap(dev); sc->rca = mmc_get_rca(dev); + sc->cmd6_time = mmc_get_cmd6_timeout(dev); + quirks = mmc_get_quirks(dev); /* Only MMC >= 4.x devices support EXT_CSD. */ if (mmc_get_spec_vers(dev) >= 4) { - MMCBUS_ACQUIRE_BUS(mmcbr, dev); - err = mmc_send_ext_csd(mmcbr, dev, sc->ext_csd); - MMCBUS_RELEASE_BUS(mmcbr, dev); - if (err != MMC_ERR_NONE) - bzero(sc->ext_csd, sizeof(sc->ext_csd)); + MMCBUS_ACQUIRE_BUS(mmcbus, dev); + err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd); + MMCBUS_RELEASE_BUS(mmcbus, dev); + if (err != MMC_ERR_NONE) { + device_printf(dev, "Error reading EXT_CSD %s\n", + mmcsd_errmsg(err)); + return (ENXIO); + } } ext_csd = sc->ext_csd; + if ((quirks & MMC_QUIRK_INAND_CMD38) != 0) { + if (mmc_get_spec_vers(dev) < 4) { + device_printf(dev, + "MMC_QUIRK_INAND_CMD38 set but no EXT_CSD\n"); + return (EINVAL); + } + sc->flags |= MMCSD_INAND_CMD38; + } + + /* + * EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN denotes support for both + * insecure and secure TRIM. + */ + if ((ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & + EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN) != 0 && + (quirks & MMC_QUIRK_BROKEN_TRIM) == 0) { + if (bootverbose) + device_printf(dev, "taking advantage of TRIM\n"); + sc->flags |= MMCSD_USE_TRIM; + sc->erase_sector = 1; + } else + sc->erase_sector = mmc_get_erase_sector(dev); + /* * Enhanced user data area and general purpose partitions are only * supported in revision 1.4 (EXT_CSD_REV == 4) and later, the RPMB @@ -531,8 +566,7 @@ mmcsd_attach(device_t dev) */ ro = mmc_get_read_only(dev); mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_DEFAULT, "mmcsd", - device_get_unit(dev), mmc_get_media_size(dev) * sector_size, - sc->erase_sector * sector_size, ro); + device_get_unit(dev), mmc_get_media_size(dev) * sector_size, ro); if (mmc_get_spec_vers(dev) < 3) return (0); @@ -555,13 +589,13 @@ mmcsd_attach(device_t dev) /* Add boot partitions, which are of a fixed multiple of 128 KB. */ size = ext_csd[EXT_CSD_BOOT_SIZE_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; - if (size > 0 && (mmcbr_get_caps(mmcbr) & MMC_CAP_BOOT_NOACC) == 0) { + if (size > 0 && (mmcbr_get_caps(mmcbus) & MMC_CAP_BOOT_NOACC) == 0) { mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT0, - MMCSD_FMT_BOOT, 0, size, MMC_BOOT_RPMB_BLOCK_SIZE, + MMCSD_FMT_BOOT, 0, size, ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK) != 0)); mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_BOOT1, - MMCSD_FMT_BOOT, 1, size, MMC_BOOT_RPMB_BLOCK_SIZE, + MMCSD_FMT_BOOT, 1, size, ro | ((ext_csd[EXT_CSD_BOOT_WP_STATUS] & EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK) != 0)); } @@ -570,7 +604,7 @@ mmcsd_attach(device_t dev) size = ext_csd[EXT_CSD_RPMB_MULT] * MMC_BOOT_RPMB_BLOCK_SIZE; if (rev >= 5 && size > 0) mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_RPMB, - MMCSD_FMT_RPMB, 0, size, MMC_BOOT_RPMB_BLOCK_SIZE, ro); + MMCSD_FMT_RPMB, 0, size, ro); if (rev <= 3 || comp == FALSE) return (0); @@ -590,8 +624,7 @@ mmcsd_attach(device_t dev) if (size == 0) continue; mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_GP0 + i, - MMCSD_FMT_GP, i, size * erase_size * wp_size, - erase_size, ro); + MMCSD_FMT_GP, i, size * erase_size * wp_size, ro); } } return (0); @@ -644,10 +677,10 @@ static struct cdevsw mmcsd_rpmb_cdevsw = { static void mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, - off_t media_size, off_t erase_size, bool ro) + off_t media_size, bool ro) { struct make_dev_args args; - device_t dev, mmcbr; + device_t dev, mmcbus; const char *ext; const uint8_t *ext_csd; struct mmcsd_part *part; @@ -662,7 +695,7 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, char unit[2]; dev = sc->dev; - mmcbr = sc->mmcbr; + mmcbus = sc->mmcbus; part = sc->part[type] = malloc(sizeof(*part), M_DEVBUF, M_WAITOK | M_ZERO); part->sc = sc; @@ -710,10 +743,10 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, d->d_sectorsize = mmc_get_sector_size(dev); d->d_maxsize = sc->max_data * d->d_sectorsize; d->d_mediasize = media_size; - d->d_stripesize = erase_size; + d->d_stripesize = sc->erase_sector * d->d_sectorsize; d->d_unit = cnt; d->d_flags = DISKFLAG_CANDELETE; - d->d_delmaxsize = erase_size; + d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize; strlcpy(d->d_ident, mmc_get_card_sn_string(dev), sizeof(d->d_ident)); strlcpy(d->d_descr, mmc_get_card_id_string(dev), @@ -735,10 +768,10 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, bytes = mmcsd_pretty_size(media_size, unit); if (type == EXT_CSD_PART_CONFIG_ACC_DEFAULT) { - speed = mmcbr_get_clock(mmcbr); + speed = mmcbr_get_clock(mmcbus); printf("%s%d: %ju%sB <%s>%s at %s %d.%01dMHz/%dbit/%d-block\n", part->name, cnt, bytes, unit, mmc_get_card_id_string(dev), - ro ? " (read-only)" : "", device_get_nameunit(mmcbr), + ro ? " (read-only)" : "", device_get_nameunit(mmcbus), speed / 1000000, (speed / 100000) % 10, mmcsd_bus_bit_width(dev), sc->max_data); } else if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) { @@ -1053,7 +1086,7 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) struct mmc_command cmd; struct mmc_data data; struct mmcsd_softc *sc; - device_t dev, mmcbr; + device_t dev, mmcbus; void *dp; u_long len; int err, retries; @@ -1136,9 +1169,9 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) } } dev = sc->dev; - mmcbr = sc->mmcbr; - MMCBUS_ACQUIRE_BUS(mmcbr, dev); - err = mmcsd_switch_part(mmcbr, dev, rca, part->type); + mmcbus = sc->mmcbus; + MMCBUS_ACQUIRE_BUS(mmcbus, dev); + err = mmcsd_switch_part(mmcbus, dev, rca, part->type); if (err != MMC_ERR_NONE) goto release; if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { @@ -1148,9 +1181,9 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) goto switch_back; } if (mic->is_acmd != 0) - (void)mmc_wait_for_app_cmd(mmcbr, dev, rca, &cmd, 0); + (void)mmc_wait_for_app_cmd(mmcbus, dev, rca, &cmd, 0); else - (void)mmc_wait_for_cmd(mmcbr, dev, &cmd, 0); + (void)mmc_wait_for_cmd(mmcbus, dev, &cmd, 0); if (part->type == EXT_CSD_PART_CONFIG_ACC_RPMB) { /* * If the request went to the RPMB partition, try to ensure @@ -1158,7 +1191,7 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) */ retries = MMCSD_CMD_RETRIES; do { - err = mmc_send_status(mmcbr, dev, rca, &status); + err = mmc_send_status(mmcbus, dev, rca, &status); if (err != MMC_ERR_NONE) break; if (R1_STATUS(status) == 0 && @@ -1169,7 +1202,7 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) switch_back: /* ... and always switch back to the default partition. */ - err = mmcsd_switch_part(mmcbr, dev, rca, + err = mmcsd_switch_part(mmcbus, dev, rca, EXT_CSD_PART_CONFIG_ACC_DEFAULT); if (err != MMC_ERR_NONE) goto release; @@ -1180,11 +1213,11 @@ switch_back: * so retrieve EXT_CSD again. */ if (cmd.opcode == MMC_SWITCH_FUNC) { - err = mmc_send_ext_csd(mmcbr, dev, sc->ext_csd); + err = mmc_send_ext_csd(mmcbus, dev, sc->ext_csd); if (err != MMC_ERR_NONE) goto release; } - MMCBUS_RELEASE_BUS(mmcbr, dev); + MMCBUS_RELEASE_BUS(mmcbus, dev); if (cmd.error != MMC_ERR_NONE) { switch (cmd.error) { case MMC_ERR_TIMEOUT: @@ -1214,7 +1247,7 @@ switch_back: goto out; release: - MMCBUS_RELEASE_BUS(mmcbr, dev); + MMCBUS_RELEASE_BUS(mmcbus, dev); err = EIO; out: @@ -1262,7 +1295,7 @@ mmcsd_set_blockcount(struct mmcsd_softc *sc, u_int count, bool reliable) if (reliable) cmd.arg |= 1 << 31; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - MMCBUS_WAIT_FOR_REQUEST(sc->mmcbr, sc->dev, &req); + MMCBUS_WAIT_FOR_REQUEST(sc->mmcbus, sc->dev, &req); return (cmd.error); } @@ -1289,7 +1322,7 @@ mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part) * anew. */ if (part == EXT_CSD_PART_CONFIG_ACC_RPMB) - MMCBUS_RETUNE_PAUSE(sc->mmcbr, sc->dev, true); + MMCBUS_RETUNE_PAUSE(sc->mmcbus, sc->dev, true); if (sc->part_curr == part) return (MMC_ERR_NONE); @@ -1301,18 +1334,17 @@ mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part) EXT_CSD_PART_CONFIG, value, sc->part_time, true); if (err != MMC_ERR_NONE) { if (part == EXT_CSD_PART_CONFIG_ACC_RPMB) - MMCBUS_RETUNE_UNPAUSE(sc->mmcbr, sc->dev); + MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev); return (err); } sc->ext_csd[EXT_CSD_PART_CONFIG] = value; if (sc->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB) - MMCBUS_RETUNE_UNPAUSE(sc->mmcbr, sc->dev); + MMCBUS_RETUNE_UNPAUSE(sc->mmcbus, sc->dev); sc->part_curr = part; return (MMC_ERR_NONE); } -#ifndef __rtems__ static const char * mmcsd_errmsg(int e) { @@ -1322,6 +1354,7 @@ mmcsd_errmsg(int e) return (errmsg[e]); } +#ifndef __rtems__ static daddr_t mmcsd_rw(struct mmcsd_part *part, struct bio *bp) { @@ -1331,13 +1364,13 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp) struct mmc_request req; struct mmc_data data; struct mmcsd_softc *sc; - device_t dev, mmcbr; + device_t dev, mmcbus; u_int numblocks, sz; char *vaddr; sc = part->sc; dev = sc->dev; - mmcbr = sc->mmcbr; + mmcbus = sc->mmcbus; block = bp->bio_pblkno; sz = part->disk->d_sectorsize; @@ -1382,7 +1415,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp) stop.mrq = &req; req.stop = &stop; } - MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req); + MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) @@ -1403,32 +1436,56 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp) struct mmc_command cmd; struct mmc_request req; struct mmcsd_softc *sc; - device_t dev, mmcbr; + device_t dev, mmcbus; u_int erase_sector, sz; + int err; + bool use_trim; sc = part->sc; dev = sc->dev; - mmcbr = sc->mmcbr; + mmcbus = sc->mmcbus; block = bp->bio_pblkno; sz = part->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); - /* Coalesce with part remaining from previous request. */ - if (block > part->eblock && block <= part->eend) - block = part->eblock; - if (end >= part->eblock && end < part->eend) - end = part->eend; - /* Safe round to the erase sector boundaries. */ - erase_sector = sc->erase_sector; - start = block + erase_sector - 1; /* Round up. */ - start -= start % erase_sector; - stop = end; /* Round down. */ - stop -= end % erase_sector; - /* We can't erase an area smaller than a sector, store it for later. */ - if (start >= stop) { - part->eblock = block; - part->eend = end; - return (end); + use_trim = sc->flags & MMCSD_USE_TRIM; + if (use_trim == true) { + start = block; + stop = end; + } else { + /* Coalesce with the remainder of the previous request. */ + if (block > part->eblock && block <= part->eend) + block = part->eblock; + if (end >= part->eblock && end < part->eend) + end = part->eend; + /* Safely round to the erase sector boundaries. */ + erase_sector = sc->erase_sector; + start = block + erase_sector - 1; /* Round up. */ + start -= start % erase_sector; + stop = end; /* Round down. */ + stop -= end % erase_sector; + /* + * We can't erase an area smaller than an erase sector, so + * store it for later. + */ + if (start >= stop) { + part->eblock = block; + part->eend = end; + return (end); + } + } + + if ((sc->flags & MMCSD_INAND_CMD38) != 0) { + err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_INAND_CMD38, use_trim == true ? + EXT_CSD_INAND_CMD38_TRIM : EXT_CSD_INAND_CMD38_ERASE, + sc->cmd6_time, true); + if (err != MMC_ERR_NONE) { + device_printf(dev, + "Setting iNAND erase command failed %s\n", + mmcsd_errmsg(err)); + return (block); + } } /* @@ -1436,7 +1493,7 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp) * commands. Note that these latter don't use the data lines, so * re-tuning shouldn't actually become necessary during erase. */ - MMCBUS_RETUNE_PAUSE(mmcbr, dev, false); + MMCBUS_RETUNE_PAUSE(mmcbus, dev, false); /* Set erase start position. */ memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); @@ -1450,10 +1507,10 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp) if (sc->high_cap == 0) cmd.arg <<= 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req); + MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { - device_printf(dev, "Setting erase start position failed %d\n", - req.cmd->error); + device_printf(dev, "Setting erase start position failed %s\n", + mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } @@ -1470,10 +1527,10 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp) cmd.arg <<= 9; cmd.arg--; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req); + MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { - device_printf(dev, "Setting erase stop position failed %d\n", - req.cmd->error); + device_printf(dev, "Setting erase stop position failed %s\n", + mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } @@ -1482,27 +1539,28 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp) memset(&cmd, 0, sizeof(cmd)); req.cmd = &cmd; cmd.opcode = MMC_ERASE; - cmd.arg = 0; + cmd.arg = use_trim == true ? MMC_ERASE_TRIM : MMC_ERASE_ERASE; cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req); + MMCBUS_WAIT_FOR_REQUEST(mmcbus, dev, &req); if (req.cmd->error != MMC_ERR_NONE) { - device_printf(dev, "erase err3: %d\n", req.cmd->error); - device_printf(dev, "Issuing erase command failed %d\n", - req.cmd->error); + device_printf(dev, "Issuing erase command failed %s\n", + mmcsd_errmsg(req.cmd->error)); block = bp->bio_pblkno; goto unpause; } - /* Store one of remaining parts for the next call. */ - if (bp->bio_pblkno >= part->eblock || block == start) { - part->eblock = stop; /* Predict next forward. */ - part->eend = end; - } else { - part->eblock = block; /* Predict next backward. */ - part->eend = start; + if (use_trim == false) { + /* Store one of the remaining parts for the next call. */ + if (bp->bio_pblkno >= part->eblock || block == start) { + part->eblock = stop; /* Predict next forward. */ + part->eend = end; + } else { + part->eblock = block; /* Predict next backward. */ + part->eend = start; + } } block = end; unpause: - MMCBUS_RETUNE_UNPAUSE(mmcbr, dev); + MMCBUS_RETUNE_UNPAUSE(mmcbus, dev); return (block); } @@ -1515,7 +1573,7 @@ mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, struct disk *disk; struct mmcsd_softc *sc; struct mmcsd_part *part; - device_t dev, mmcbr; + device_t dev, mmcbus; int err; /* length zero is special and really means flush buffers to media */ @@ -1526,7 +1584,7 @@ mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, part = disk->d_drv1; sc = part->sc; dev = sc->dev; - mmcbr = sc->mmcbr; + mmcbus = sc->mmcbus; g_reset_bio(&bp); bp.bio_disk = disk; @@ -1535,16 +1593,16 @@ mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, bp.bio_data = virtual; bp.bio_cmd = BIO_WRITE; end = bp.bio_pblkno + bp.bio_bcount / disk->d_sectorsize; - MMCBUS_ACQUIRE_BUS(mmcbr, dev); - err = mmcsd_switch_part(mmcbr, dev, sc->rca, part->type); + MMCBUS_ACQUIRE_BUS(mmcbus, dev); + err = mmcsd_switch_part(mmcbus, dev, sc->rca, part->type); if (err != MMC_ERR_NONE) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) device_printf(dev, "Partition switch error\n"); - MMCBUS_RELEASE_BUS(mmcbr, dev); + MMCBUS_RELEASE_BUS(mmcbus, dev); return (EIO); } block = mmcsd_rw(part, &bp); - MMCBUS_RELEASE_BUS(mmcbr, dev); + MMCBUS_RELEASE_BUS(mmcbus, dev); return ((end < block) ? EIO : 0); } @@ -1555,13 +1613,13 @@ mmcsd_task(void *arg) struct mmcsd_part *part; struct mmcsd_softc *sc; struct bio *bp; - device_t dev, mmcbr; + device_t dev, mmcbus; int err, sz; part = arg; sc = part->sc; dev = sc->dev; - mmcbr = sc->mmcbr; + mmcbus = sc->mmcbus; while (1) { MMCSD_DISK_LOCK(part); @@ -1581,11 +1639,11 @@ mmcsd_task(void *arg) biodone(bp); continue; } - MMCBUS_ACQUIRE_BUS(mmcbr, dev); + MMCBUS_ACQUIRE_BUS(mmcbus, dev); sz = part->disk->d_sectorsize; block = bp->bio_pblkno; end = bp->bio_pblkno + (bp->bio_bcount / sz); - err = mmcsd_switch_part(mmcbr, dev, sc->rca, part->type); + err = mmcsd_switch_part(mmcbus, dev, sc->rca, part->type); if (err != MMC_ERR_NONE) { if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) @@ -1601,7 +1659,7 @@ mmcsd_task(void *arg) block = mmcsd_delete(part, bp); } release: - MMCBUS_RELEASE_BUS(mmcbr, dev); + MMCBUS_RELEASE_BUS(mmcbus, dev); if (block < end) { bp->bio_error = EIO; bp->bio_resid = (end - block) * sz; diff --git a/freebsd/sys/dev/mmc/mmcvar.h b/freebsd/sys/dev/mmc/mmcvar.h index 9f62b112..d0f4e330 100644 --- a/freebsd/sys/dev/mmc/mmcvar.h +++ b/freebsd/sys/dev/mmc/mmcvar.h @@ -68,6 +68,8 @@ enum mmc_device_ivars { MMC_IVAR_BUS_WIDTH, MMC_IVAR_ERASE_SECTOR, MMC_IVAR_MAX_DATA, + MMC_IVAR_CMD6_TIMEOUT, + MMC_IVAR_QUIRKS, MMC_IVAR_CARD_ID_STRING, MMC_IVAR_CARD_SN_STRING, }; @@ -90,6 +92,8 @@ MMC_ACCESSOR(card_type, CARD_TYPE, int) MMC_ACCESSOR(bus_width, BUS_WIDTH, int) MMC_ACCESSOR(erase_sector, ERASE_SECTOR, int) MMC_ACCESSOR(max_data, MAX_DATA, int) +MMC_ACCESSOR(cmd6_timeout, CMD6_TIMEOUT, u_int) +MMC_ACCESSOR(quirks, QUIRKS, u_int) MMC_ACCESSOR(card_id_string, CARD_ID_STRING, const char *) MMC_ACCESSOR(card_sn_string, CARD_SN_STRING, const char *) diff --git a/freebsd/sys/dev/nvme/nvme.h b/freebsd/sys/dev/nvme/nvme.h index aa640b37..d4fc131e 100644 --- a/freebsd/sys/dev/nvme/nvme.h +++ b/freebsd/sys/dev/nvme/nvme.h @@ -69,6 +69,8 @@ union cap_lo_register { } bits __packed; } __packed; +_Static_assert(sizeof(union cap_lo_register) == 4, "bad size for cap_lo_register"); + union cap_hi_register { uint32_t raw; struct { @@ -93,6 +95,8 @@ union cap_hi_register { } bits __packed; } __packed; +_Static_assert(sizeof(union cap_hi_register) == 4, "bad size of cap_hi_register"); + union cc_register { uint32_t raw; struct { @@ -123,6 +127,8 @@ union cc_register { } bits __packed; } __packed; +_Static_assert(sizeof(union cc_register) == 4, "bad size for cc_register"); + enum shn_value { NVME_SHN_NORMAL = 0x1, NVME_SHN_ABRUPT = 0x2, @@ -144,6 +150,8 @@ union csts_register { } bits __packed; } __packed; +_Static_assert(sizeof(union csts_register) == 4, "bad size for csts_register"); + enum shst_value { NVME_SHST_NORMAL = 0x0, NVME_SHST_OCCURRING = 0x1, @@ -165,6 +173,8 @@ union aqa_register { } bits __packed; } __packed; +_Static_assert(sizeof(union aqa_register) == 4, "bad size for aqa_resgister"); + struct nvme_registers { /** controller capabilities */ @@ -198,6 +208,8 @@ struct nvme_registers } doorbell[1] __packed; } __packed; +_Static_assert(sizeof(struct nvme_registers) == 0x1008, "bad size for nvme_registers"); + struct nvme_command { /* dword 0 */ @@ -231,6 +243,8 @@ struct nvme_command uint32_t cdw15; /* command-specific */ } __packed; +_Static_assert(sizeof(struct nvme_command) == 16 * 4, "bad size for nvme_command"); + struct nvme_status { uint16_t p : 1; /* phase tag */ @@ -241,6 +255,8 @@ struct nvme_status { uint16_t dnr : 1; /* do not retry */ } __packed; +_Static_assert(sizeof(struct nvme_status) == 2, "bad size for nvme_status"); + struct nvme_completion { /* dword 0 */ @@ -258,6 +274,8 @@ struct nvme_completion { struct nvme_status status; } __packed; +_Static_assert(sizeof(struct nvme_completion) == 4 * 4, "bad size for nvme_completion"); + struct nvme_dsm_range { uint32_t attributes; @@ -265,6 +283,8 @@ struct nvme_dsm_range { uint64_t starting_lba; } __packed; +_Static_assert(sizeof(struct nvme_dsm_range) == 16, "bad size for nvme_dsm_ranage"); + /* status code types */ enum nvme_status_code_type { NVME_SCT_GENERIC = 0x0, @@ -377,7 +397,14 @@ enum nvme_feature { NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09, NVME_FEAT_WRITE_ATOMICITY = 0x0A, NVME_FEAT_ASYNC_EVENT_CONFIGURATION = 0x0B, - /* 0x0C-0x7F - reserved */ + NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C, + NVME_FEAT_HOST_MEMORY_BUFFER = 0x0D, + NVME_FEAT_TIMESTAMP = 0x0E, + NVME_FEAT_KEEP_ALIVE_TIMER = 0x0F, + NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT = 0x10, + NVME_FEAT_NON_OP_POWER_STATE_CONFIG = 0x11, + /* 0x12-0x77 - reserved */ + /* 0x78-0x7f - NVMe Management Interface */ NVME_FEAT_SOFTWARE_PROGRESS_MARKER = 0x80, /* 0x81-0xBF - command set specific (reserved) */ /* 0xC0-0xFF - vendor specific */ @@ -423,6 +450,8 @@ struct nvme_power_state { uint8_t ps_rsvd10[9]; } __packed; +_Static_assert(sizeof(struct nvme_power_state) == 32, "bad size for nvme_power_state"); + #define NVME_SERIAL_NUMBER_LENGTH 20 #define NVME_MODEL_NUMBER_LENGTH 40 #define NVME_FIRMWARE_REVISION_LENGTH 8 @@ -461,7 +490,27 @@ struct nvme_controller_data { /** Controller ID */ uint16_t ctrlr_id; - uint8_t reserved1[176]; + /** Version */ + uint32_t ver; + + /** RTD3 Resume Latency */ + uint32_t rtd3r; + + /** RTD3 Enter Latency */ + uint32_t rtd3e; + + /** Optional Asynchronous Events Supported */ + uint32_t oaes; /* bitfield really */ + + /** Controller Attributes */ + uint32_t ctratt; /* bitfield really */ + + uint8_t reserved1[12]; + + /** FRU Globally Unique Identifier */ + uint8_t fguid[16]; + + uint8_t reserved2[128]; /* bytes 256-511: admin command set attributes */ @@ -521,7 +570,28 @@ struct nvme_controller_data { uint8_t avscc_rsvd : 7; } __packed avscc; - uint8_t reserved2[15]; + /** Autonomous Power State Transition Attributes */ + struct { + /* Autonmous Power State Transitions supported */ + uint8_t apst_supp : 1; + + uint8_t apsta_rsvd : 7; + } __packed apsta; + + /** Warning Composite Temperature Threshold */ + uint16_t wctemp; + + /** Critical Composite Temperature Threshold */ + uint16_t cctemp; + + /** Maximum Time for Firmware Activation */ + uint16_t mtfa; + + /** Host Memory Buffer Preferred Size */ + uint32_t hmpre; + + /** Host Memory Buffer Minimum Size */ + uint32_t hmmin; /** Name space capabilities */ struct { @@ -530,7 +600,34 @@ struct nvme_controller_data { uint8_t unvmcap[16]; } __packed untncap; - uint8_t reserved3[200]; + /** Replay Protected Memory Block Support */ + uint32_t rpmbs; /* Really a bitfield */ + + /** Extended Device Self-test Time */ + uint16_t edstt; + + /** Device Self-test Options */ + uint8_t dsto; /* Really a bitfield */ + + /** Firmware Update Granularity */ + uint8_t fwug; + + /** Keep Alive Support */ + uint16_t kas; + + /** Host Controlled Thermal Management Attributes */ + uint16_t hctma; /* Really a bitfield */ + + /** Minimum Thermal Management Temperature */ + uint16_t mntmt; + + /** Maximum Thermal Management Temperature */ + uint16_t mxtmt; + + /** Sanitize Capabilities */ + uint32_t sanicap; /* Really a bitfield */ + + uint8_t reserved3[180]; /* bytes 512-703: nvm command set attributes */ /** submission queue entry size */ @@ -545,7 +642,8 @@ struct nvme_controller_data { uint8_t max : 4; } __packed cqes; - uint8_t reserved4[2]; + /** Maximum Outstanding Commands */ + uint16_t maxcmd; /** number of namespaces */ uint32_t nn; @@ -583,6 +681,8 @@ struct nvme_controller_data { uint8_t vs[1024]; } __packed __aligned(4); +_Static_assert(sizeof(struct nvme_controller_data) == 4096, "bad size for nvme_controller_data"); + struct nvme_namespace_data { /** namespace size */ @@ -673,6 +773,8 @@ struct nvme_namespace_data { uint8_t vendor_specific[3712]; } __packed __aligned(4); +_Static_assert(sizeof(struct nvme_namespace_data) == 4096, "bad size for nvme_namepsace_data"); + enum nvme_log_page { /* 0x00 - reserved */ @@ -715,6 +817,8 @@ struct nvme_error_information_entry { uint8_t reserved[35]; } __packed __aligned(4); +_Static_assert(sizeof(struct nvme_error_information_entry) == 64, "bad size for nvme_error_information_entry"); + union nvme_critical_warning_state { uint8_t raw; @@ -729,6 +833,8 @@ union nvme_critical_warning_state { } __packed bits; } __packed; +_Static_assert(sizeof(union nvme_critical_warning_state) == 1, "bad size for nvme_critical_warning_state"); + struct nvme_health_information_page { union nvme_critical_warning_state critical_warning; @@ -765,6 +871,8 @@ struct nvme_health_information_page { uint8_t reserved2[296]; } __packed __aligned(4); +_Static_assert(sizeof(struct nvme_health_information_page) == 512, "bad size for nvme_health_information_page"); + struct nvme_firmware_page { struct { @@ -777,6 +885,8 @@ struct nvme_firmware_page { uint8_t reserved2[448]; } __packed __aligned(4); +_Static_assert(sizeof(struct nvme_firmware_page) == 512, "bad size for nvme_firmware_page"); + struct intel_log_temp_stats { uint64_t current; @@ -790,6 +900,8 @@ struct intel_log_temp_stats uint64_t est_offset; } __packed __aligned(4); +_Static_assert(sizeof(struct intel_log_temp_stats) == 13 * 8, "bad size for intel_log_temp_stats"); + #define NVME_TEST_MAX_THREADS 128 struct nvme_io_test { @@ -958,7 +1070,7 @@ int nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp, /* Command building helper functions -- shared with CAM */ static inline -void nvme_ns_flush_cmd(struct nvme_command *cmd, uint16_t nsid) +void nvme_ns_flush_cmd(struct nvme_command *cmd, uint32_t nsid) { cmd->opc = NVME_OPC_FLUSH; @@ -966,7 +1078,7 @@ void nvme_ns_flush_cmd(struct nvme_command *cmd, uint16_t nsid) } static inline -void nvme_ns_rw_cmd(struct nvme_command *cmd, uint32_t rwcmd, uint16_t nsid, +void nvme_ns_rw_cmd(struct nvme_command *cmd, uint32_t rwcmd, uint32_t nsid, uint64_t lba, uint32_t count) { cmd->opc = rwcmd; @@ -980,21 +1092,21 @@ void nvme_ns_rw_cmd(struct nvme_command *cmd, uint32_t rwcmd, uint16_t nsid, } static inline -void nvme_ns_write_cmd(struct nvme_command *cmd, uint16_t nsid, +void nvme_ns_write_cmd(struct nvme_command *cmd, uint32_t nsid, uint64_t lba, uint32_t count) { nvme_ns_rw_cmd(cmd, NVME_OPC_WRITE, nsid, lba, count); } static inline -void nvme_ns_read_cmd(struct nvme_command *cmd, uint16_t nsid, +void nvme_ns_read_cmd(struct nvme_command *cmd, uint32_t nsid, uint64_t lba, uint32_t count) { nvme_ns_rw_cmd(cmd, NVME_OPC_READ, nsid, lba, count); } static inline -void nvme_ns_trim_cmd(struct nvme_command *cmd, uint16_t nsid, +void nvme_ns_trim_cmd(struct nvme_command *cmd, uint32_t nsid, uint32_t num_ranges) { cmd->opc = NVME_OPC_DATASET_MANAGEMENT; @@ -1003,6 +1115,8 @@ void nvme_ns_trim_cmd(struct nvme_command *cmd, uint16_t nsid, cmd->cdw11 = NVME_DSM_ATTR_DEALLOCATE; } +extern int nvme_use_nvd; + #endif /* _KERNEL */ #endif /* __NVME_H__ */ diff --git a/freebsd/sys/dev/ofw/ofw_bus_subr.c b/freebsd/sys/dev/ofw/ofw_bus_subr.c index cc30578d..418304a0 100644 --- a/freebsd/sys/dev/ofw/ofw_bus_subr.c +++ b/freebsd/sys/dev/ofw/ofw_bus_subr.c @@ -722,22 +722,14 @@ phandle_t ofw_bus_find_compatible(phandle_t node, const char *onecompat) { phandle_t child, ret; - void *compat; - int len; /* * Traverse all children of 'start' node, and find first with * matching 'compatible' property. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { - len = OF_getprop_alloc(child, "compatible", 1, &compat); - if (len >= 0) { - ret = ofw_bus_node_is_compatible_int(compat, len, - onecompat); - free(compat, M_OFWPROP); - if (ret != 0) - return (child); - } + if (ofw_bus_node_is_compatible(child, onecompat) != 0) + return (child); ret = ofw_bus_find_compatible(child, onecompat); if (ret != 0) diff --git a/freebsd/sys/dev/ofw/ofw_fdt.c b/freebsd/sys/dev/ofw/ofw_fdt.c index 766be90f..282c3667 100644 --- a/freebsd/sys/dev/ofw/ofw_fdt.c +++ b/freebsd/sys/dev/ofw/ofw_fdt.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <dev/fdt/fdt_common.h> #include <dev/ofw/ofwvar.h> #include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_bus_subr.h> #include <rtems/bsd/local/ofw_if.h> @@ -388,7 +389,11 @@ ofw_fdt_setprop(ofw_t ofw, phandle_t package, const char *propname, if (offset < 0) return (-1); - return (fdt_setprop_inplace(fdtp, offset, propname, buf, len)); + if (fdt_setprop_inplace(fdtp, offset, propname, buf, len) != 0) + /* Try to add property, when setting value inplace failed */ + return (fdt_setprop(fdtp, offset, propname, buf, len)); + + return (0); } /* Convert a device specifier to a fully qualified pathname. */ @@ -459,7 +464,15 @@ ofw_fdt_fixup(ofw_t ofw) for (i = 0; fdt_fixup_table[i].model != NULL; i++) { if (strncmp(model, fdt_fixup_table[i].model, FDT_MODEL_LEN) != 0) - continue; + /* + * Sometimes it's convenient to provide one + * fixup entry that refers to many boards. + * To handle this case, simply check if model + * is compatible parameter + */ + if(!ofw_bus_node_is_compatible(root, + fdt_fixup_table[i].model)) + continue; if (fdt_fixup_table[i].handler != NULL) (*fdt_fixup_table[i].handler)(root); diff --git a/freebsd/sys/dev/pci/pci.c b/freebsd/sys/dev/pci/pci.c index be4c626f..69497d2c 100644 --- a/freebsd/sys/dev/pci/pci.c +++ b/freebsd/sys/dev/pci/pci.c @@ -2906,13 +2906,21 @@ pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp, * Determine the BAR's length by writing all 1's. The bottom * log_2(size) bits of the BAR will stick as 0 when we read * the value back. + * + * NB: according to the PCI Local Bus Specification, rev. 3.0: + * "Software writes 0FFFFFFFFh to both registers, reads them back, + * and combines the result into a 64-bit value." (section 6.2.5.1) + * + * Writes to both registers must be performed before attempting to + * read back the size value. */ + testval = 0; pci_write_config(dev, reg, 0xffffffff, 4); - testval = pci_read_config(dev, reg, 4); if (ln2range == 64) { pci_write_config(dev, reg + 4, 0xffffffff, 4); testval |= (pci_addr_t)pci_read_config(dev, reg + 4, 4) << 32; } + testval |= pci_read_config(dev, reg, 4); /* * Restore the original value of the BAR. We may have reprogrammed diff --git a/freebsd/sys/dev/rtwn/if_rtwn_ridx.h b/freebsd/sys/dev/rtwn/if_rtwn_ridx.h index eef43898..76f87aab 100644 --- a/freebsd/sys/dev/rtwn/if_rtwn_ridx.h +++ b/freebsd/sys/dev/rtwn/if_rtwn_ridx.h @@ -36,7 +36,7 @@ #define RTWN_RIDX_OFDM36 9 #define RTWN_RIDX_OFDM48 10 #define RTWN_RIDX_OFDM54 11 -#define RTWN_RIDX_MCS(i) (12 + (i)) +#define RTWN_RIDX_HT_MCS(i) (12 + (i)) #define RTWN_RIDX_COUNT 28 #define RTWN_RIDX_UNKNOWN (uint8_t)-1 @@ -82,10 +82,10 @@ rtwn_ctl_mcsrate(const struct ieee80211_rate_table *rt, uint8_t ridx) uint8_t cix, rate; /* Check if we are using MCS rate. */ - KASSERT(ridx >= RTWN_RIDX_MCS(0) && ridx != RTWN_RIDX_UNKNOWN, + KASSERT(ridx >= RTWN_RIDX_HT_MCS(0) && ridx != RTWN_RIDX_UNKNOWN, ("bad mcs rate index %d", ridx)); - rate = (ridx - RTWN_RIDX_MCS(0)) | IEEE80211_RATE_MCS; + rate = (ridx - RTWN_RIDX_HT_MCS(0)) | IEEE80211_RATE_MCS; cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex; KASSERT(cix != (uint8_t)-1, ("rate %d (%d) has no info", rate, ridx)); return rt->info[cix].dot11Rate; diff --git a/freebsd/sys/dev/rtwn/if_rtwn_rx.c b/freebsd/sys/dev/rtwn/if_rtwn_rx.c index 7b3f1c2e..fb260596 100644 --- a/freebsd/sys/dev/rtwn/if_rtwn_rx.c +++ b/freebsd/sys/dev/rtwn/if_rtwn_rx.c @@ -90,7 +90,7 @@ rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs, if ((rs_ht->rs_rates[i] & 0x7f) > 0xf) continue; /* 11n rates start at index 12 */ - ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf); + ridx = RTWN_RIDX_HT_MCS((rs_ht->rs_rates[i]) & 0xf); rates |= (1 << ridx); /* Guard against the rate table being oddly ordered */ diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e.h b/freebsd/sys/dev/rtwn/rtl8188e/r88e.h index 1c03ddd3..3a3c0865 100644 --- a/freebsd/sys/dev/rtwn/rtl8188e/r88e.h +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e.h @@ -49,7 +49,7 @@ uint8_t r88e_temp_read(struct rtwn_softc *); /* r88e_chan.c */ void r88e_get_txpower(struct rtwn_softc *, int, - struct ieee80211_channel *, uint16_t[]); + struct ieee80211_channel *, uint8_t[]); void r88e_set_bw20(struct rtwn_softc *, uint8_t); void r88e_set_gain(struct rtwn_softc *, uint8_t); diff --git a/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c index 903398a4..530df320 100644 --- a/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c +++ b/freebsd/sys/dev/rtwn/rtl8188e/r88e_chan.c @@ -87,7 +87,7 @@ r88e_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) void r88e_get_txpower(struct rtwn_softc *sc, int chain, - struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) + struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) { struct r92c_softc *rs = sc->sc_priv; const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; @@ -103,7 +103,7 @@ r88e_get_txpower(struct rtwn_softc *sc, int chain, /* XXX net80211 regulatory */ - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); memset(power, 0, max_mcs * sizeof(power[0])); @@ -123,7 +123,7 @@ r88e_get_txpower(struct rtwn_softc *sc, int chain, power[ridx] = ofdmpow; bw20pow = htpow + rt->bw20_tx_pwr_diff; - for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + for (ridx = RTWN_RIDX_HT_MCS(0); ridx <= max_mcs; ridx++) power[ridx] = bw20pow; /* Apply max limit. */ diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c.h index 5ac666d0..d8f7afc8 100644 --- a/freebsd/sys/dev/rtwn/rtl8192c/r92c.h +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c.h @@ -55,7 +55,9 @@ uint8_t r92c_temp_read(struct rtwn_softc *); /* r92c_chan.c */ void r92c_get_txpower(struct rtwn_softc *, int, - struct ieee80211_channel *, uint16_t[]); + struct ieee80211_channel *, uint8_t[]); +void r92c_write_txpower(struct rtwn_softc *, int, + uint8_t power[]); void r92c_set_bw20(struct rtwn_softc *, uint8_t); void r92c_set_chan(struct rtwn_softc *, struct ieee80211_channel *); void r92c_set_gain(struct rtwn_softc *, uint8_t); diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c index c5d72f87..2e50daf1 100644 --- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_chan.c @@ -84,7 +84,7 @@ r92c_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) /* XXX recheck */ void r92c_get_txpower(struct rtwn_softc *sc, int chain, - struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) + struct ieee80211_channel *c, uint8_t power[RTWN_RIDX_COUNT]) { struct r92c_softc *rs = sc->sc_priv; struct rtwn_r92c_txpwr *rt = rs->rs_txpwr; @@ -101,7 +101,7 @@ r92c_get_txpower(struct rtwn_softc *sc, int chain, /* XXX net80211 regulatory */ - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); memset(power, 0, max_mcs * sizeof(power[0])); @@ -148,7 +148,7 @@ r92c_get_txpower(struct rtwn_softc *sc, int chain, diff = rt->ht20_tx_pwr_diff[chain][group]; htpow += diff; /* HT40->HT20 correction. */ } - for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + for (ridx = RTWN_RIDX_HT_MCS(0); ridx <= max_mcs; ridx++) power[ridx] += htpow; /* Apply max limit. */ @@ -158,9 +158,9 @@ r92c_get_txpower(struct rtwn_softc *sc, int chain, } } -static void +void r92c_write_txpower(struct rtwn_softc *sc, int chain, - uint16_t power[RTWN_RIDX_COUNT]) + uint8_t power[RTWN_RIDX_COUNT]) { uint32_t reg; @@ -197,33 +197,33 @@ r92c_write_txpower(struct rtwn_softc *sc, int chain, SM(R92C_TXAGC_RATE54, power[RTWN_RIDX_OFDM54])); /* Write per-MCS Tx power. */ rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), - SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_MCS(0)]) | - SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_MCS(1)]) | - SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_MCS(2)]) | - SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_MCS(3)])); + SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_HT_MCS(0)]) | + SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_HT_MCS(1)]) | + SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_HT_MCS(2)]) | + SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_HT_MCS(3)])); rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), - SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_MCS(4)]) | - SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_MCS(5)]) | - SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_MCS(6)]) | - SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_MCS(7)])); + SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_HT_MCS(4)]) | + SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_HT_MCS(5)]) | + SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_HT_MCS(6)]) | + SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_HT_MCS(7)])); if (sc->ntxchains >= 2) { rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), - SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_MCS(8)]) | - SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_MCS(9)]) | - SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | - SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_HT_MCS(8)]) | + SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_HT_MCS(9)]) | + SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_HT_MCS(10)]) | + SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_HT_MCS(11)])); rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), - SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | - SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | - SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | - SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_HT_MCS(12)]) | + SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_HT_MCS(13)]) | + SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_HT_MCS(14)]) | + SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_HT_MCS(15)])); } } static void r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) { - uint16_t power[RTWN_RIDX_COUNT]; + uint8_t power[RTWN_RIDX_COUNT]; int i; for (i = 0; i < sc->ntxchains; i++) { @@ -233,7 +233,7 @@ r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) if (sc->sc_debug & RTWN_DEBUG_TXPWR) { int max_mcs, ridx; - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); /* Dump per-rate Tx power values. */ printf("Tx power for chain %d:\n", i); diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c index ab8b4989..e6c09eb2 100644 --- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_fw.c @@ -200,7 +200,7 @@ r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates, #endif /* Set rates mask for unicast frames. */ - if (maxrate >= RTWN_RIDX_MCS(0)) + if (maxrate >= RTWN_RIDX_HT_MCS(0)) mode = R92C_RAID_11GN; else if (maxrate >= RTWN_RIDX_OFDM6) mode = R92C_RAID_11BG; diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h index 13c38fb2..80f05828 100644 --- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_priv.h @@ -333,7 +333,7 @@ static const struct rtwn_rf_prog rtl8192c_rf[] = { struct rtwn_r92c_txagc { - uint8_t pwr[R92C_GROUP_2G][28]; /* RTWN_RIDX_MCS(15) + 1 */ + uint8_t pwr[R92C_GROUP_2G][28]; /* RTWN_RIDX_HT_MCS(15) + 1 */ }; /* diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c index b877fb88..80d2859c 100644 --- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_rx.c @@ -119,7 +119,7 @@ r92c_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, rxs->c_pktflags |= IEEE80211_RX_F_AMPDU; else if (rxdw1 & R92C_RXDW1_AMPDU_MORE) rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE; - if ((rxdw3 & R92C_RXDW3_SPLCP) && rate >= RTWN_RIDX_MCS(0)) + if ((rxdw3 & R92C_RXDW3_SPLCP) && rate >= RTWN_RIDX_HT_MCS(0)) rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI; if (rxdw3 & R92C_RXDW3_HT40) @@ -129,13 +129,13 @@ r92c_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, if (RTWN_RATE_IS_CCK(rate)) rxs->c_phytype = IEEE80211_RX_FP_11B; - else if (rate < RTWN_RIDX_MCS(0)) + else if (rate < RTWN_RIDX_HT_MCS(0)) rxs->c_phytype = IEEE80211_RX_FP_11G; else rxs->c_phytype = IEEE80211_RX_FP_11NG; /* Map HW rate index to 802.11 rate. */ - if (rate < RTWN_RIDX_MCS(0)) { + if (rate < RTWN_RIDX_HT_MCS(0)) { rxs->c_rate = ridx2rate[rate]; if (RTWN_RATE_IS_CCK(rate)) rxs->c_pktflags |= IEEE80211_RX_F_CCK; diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c index c2a6eab0..5c80af90 100644 --- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_tx.c @@ -101,7 +101,7 @@ r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { - if (ridx >= RTWN_RIDX_MCS(0)) + if (ridx >= RTWN_RIDX_HT_MCS(0)) rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); else rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); @@ -287,7 +287,7 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); prot = IEEE80211_PROT_NONE; - if (ridx >= RTWN_RIDX_MCS(0)) { + if (ridx >= RTWN_RIDX_HT_MCS(0)) { r92c_tx_set_ht40(sc, txd, ni); r92c_tx_set_sgi(sc, txd, ni); prot = ic->ic_htprotmode; diff --git a/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h b/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h index c48318d9..79592449 100644 --- a/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h +++ b/freebsd/sys/dev/rtwn/rtl8192c/r92c_var.h @@ -53,7 +53,7 @@ struct r92c_softc { void (*rs_set_bw20)(struct rtwn_softc *, uint8_t); void (*rs_get_txpower)(struct rtwn_softc *, int, - struct ieee80211_channel *, uint16_t[]); + struct ieee80211_channel *, uint8_t[]); void (*rs_set_gain)(struct rtwn_softc *, uint8_t); void (*rs_tx_enable_ampdu)(void *, int); void (*rs_tx_setup_hwseq)(void *); diff --git a/freebsd/sys/dev/rtwn/rtl8192e/r92e_chan.c b/freebsd/sys/dev/rtwn/rtl8192e/r92e_chan.c index 130ac5ca..0046b9f0 100644 --- a/freebsd/sys/dev/rtwn/rtl8192e/r92e_chan.c +++ b/freebsd/sys/dev/rtwn/rtl8192e/r92e_chan.c @@ -59,6 +59,8 @@ __FBSDID("$FreeBSD$"); #include <dev/rtwn/if_rtwn_ridx.h> #include <dev/rtwn/if_rtwn_rx.h> +#include <dev/rtwn/rtl8192c/r92c.h> + #include <dev/rtwn/rtl8192e/r92e.h> #include <dev/rtwn/rtl8192e/r92e_reg.h> #include <dev/rtwn/rtl8192e/r92e_var.h> @@ -102,7 +104,7 @@ r92e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, return; } - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); /* XXX regulatory */ /* XXX net80211 regulatory */ @@ -124,7 +126,7 @@ r92e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, else pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i]; - min_mcs = RTWN_RIDX_MCS(i * 8); + min_mcs = RTWN_RIDX_HT_MCS(i * 8); for (ridx = min_mcs; ridx <= max_mcs; ridx++) power[ridx] += pwr_diff; @@ -146,69 +148,6 @@ r92e_get_txpower(struct rtwn_softc *sc, int chain, struct ieee80211_channel *c, #endif } - -static void -r92e_write_txpower(struct rtwn_softc *sc, int chain, - uint8_t power[RTWN_RIDX_COUNT]) -{ - uint32_t reg; - - /* Write per-CCK rate Tx power. */ - if (chain == 0) { - reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); - reg = RW(reg, R92C_TXAGC_A_CCK1, power[RTWN_RIDX_CCK1]); - rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); - reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); - reg = RW(reg, R92C_TXAGC_A_CCK2, power[RTWN_RIDX_CCK2]); - reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK55]); - reg = RW(reg, R92C_TXAGC_A_CCK11, power[RTWN_RIDX_CCK11]); - rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); - } else { - reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); - reg = RW(reg, R92C_TXAGC_B_CCK1, power[RTWN_RIDX_CCK1]); - reg = RW(reg, R92C_TXAGC_B_CCK2, power[RTWN_RIDX_CCK2]); - reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK55]); - rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); - reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); - reg = RW(reg, R92C_TXAGC_B_CCK11, power[RTWN_RIDX_CCK11]); - rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); - } - /* Write per-OFDM rate Tx power. */ - rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), - SM(R92C_TXAGC_RATE06, power[RTWN_RIDX_OFDM6]) | - SM(R92C_TXAGC_RATE09, power[RTWN_RIDX_OFDM9]) | - SM(R92C_TXAGC_RATE12, power[RTWN_RIDX_OFDM12]) | - SM(R92C_TXAGC_RATE18, power[RTWN_RIDX_OFDM18])); - rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), - SM(R92C_TXAGC_RATE24, power[RTWN_RIDX_OFDM24]) | - SM(R92C_TXAGC_RATE36, power[RTWN_RIDX_OFDM36]) | - SM(R92C_TXAGC_RATE48, power[RTWN_RIDX_OFDM48]) | - SM(R92C_TXAGC_RATE54, power[RTWN_RIDX_OFDM54])); - /* Write per-MCS Tx power. */ - rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), - SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_MCS(0)]) | - SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_MCS(1)]) | - SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_MCS(2)]) | - SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_MCS(3)])); - rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), - SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_MCS(4)]) | - SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_MCS(5)]) | - SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_MCS(6)]) | - SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_MCS(7)])); - if (sc->ntxchains >= 2) { - rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), - SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_MCS(8)]) | - SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_MCS(9)]) | - SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | - SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); - rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), - SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | - SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | - SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | - SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); - } -} - static void r92e_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) { @@ -220,7 +159,7 @@ r92e_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) /* Compute per-rate Tx power values. */ r92e_get_txpower(sc, i, c, power); /* Write per-rate Tx power values to hardware. */ - r92e_write_txpower(sc, i, power); + r92c_write_txpower(sc, i, power); } } diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c index 27a71bd9..1f18bf56 100644 --- a/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_chan.c @@ -91,26 +91,26 @@ r12a_write_txpower(struct rtwn_softc *sc, int chain, SM(R12A_TXAGC_OFDM54, power[RTWN_RIDX_OFDM54])); /* Write per-MCS Tx power. */ rtwn_bb_write(sc, R12A_TXAGC_MCS3_0(chain), - SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_MCS(0)]) | - SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_MCS(1)]) | - SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_MCS(2)]) | - SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_MCS(3)])); + SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_HT_MCS(0)]) | + SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_HT_MCS(1)]) | + SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_HT_MCS(2)]) | + SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_HT_MCS(3)])); rtwn_bb_write(sc, R12A_TXAGC_MCS7_4(chain), - SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_MCS(4)]) | - SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_MCS(5)]) | - SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_MCS(6)]) | - SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_MCS(7)])); + SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_HT_MCS(4)]) | + SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_HT_MCS(5)]) | + SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_HT_MCS(6)]) | + SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_HT_MCS(7)])); if (sc->ntxchains >= 2) { rtwn_bb_write(sc, R12A_TXAGC_MCS11_8(chain), - SM(R12A_TXAGC_MCS8, power[RTWN_RIDX_MCS(8)]) | - SM(R12A_TXAGC_MCS9, power[RTWN_RIDX_MCS(9)]) | - SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | - SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + SM(R12A_TXAGC_MCS8, power[RTWN_RIDX_HT_MCS(8)]) | + SM(R12A_TXAGC_MCS9, power[RTWN_RIDX_HT_MCS(9)]) | + SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_HT_MCS(10)]) | + SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_HT_MCS(11)])); rtwn_bb_write(sc, R12A_TXAGC_MCS15_12(chain), - SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | - SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | - SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | - SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_HT_MCS(12)]) | + SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_HT_MCS(13)]) | + SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_HT_MCS(14)]) | + SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_HT_MCS(15)])); } /* TODO: VHT rates */ @@ -178,7 +178,7 @@ r12a_get_txpower(struct rtwn_softc *sc, int chain, } /* TODO: VHT rates. */ - max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + max_mcs = RTWN_RIDX_HT_MCS(sc->ntxchains * 8 - 1); /* XXX regulatory */ /* XXX net80211 regulatory */ @@ -207,7 +207,7 @@ r12a_get_txpower(struct rtwn_softc *sc, int chain, else pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i]; - min_mcs = RTWN_RIDX_MCS(i * 8); + min_mcs = RTWN_RIDX_HT_MCS(i * 8); for (ridx = min_mcs; ridx <= max_mcs; ridx++) power[ridx] += pwr_diff; } @@ -233,7 +233,7 @@ r12a_get_txpower(struct rtwn_softc *sc, int chain, else pwr_diff = rs->bw20_tx_pwr_diff_5g[chain][i]; - min_mcs = RTWN_RIDX_MCS(i * 8); + min_mcs = RTWN_RIDX_HT_MCS(i * 8); for (ridx = min_mcs; ridx <= max_mcs; ridx++) power[ridx] += pwr_diff; } diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c index dd90d7e9..c2dc4c3a 100644 --- a/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_rx.c @@ -264,7 +264,7 @@ r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, rxs->c_pktflags |= IEEE80211_RX_F_AMPDU_MORE; } - if ((rxdw4 & R12A_RXDW4_SPLCP) && rate >= RTWN_RIDX_MCS(0)) + if ((rxdw4 & R12A_RXDW4_SPLCP) && rate >= RTWN_RIDX_HT_MCS(0)) rxs->c_pktflags |= IEEE80211_RX_F_SHORTGI; switch (MS(rxdw4, R12A_RXDW4_BW)) { @@ -290,7 +290,7 @@ r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, /* XXX check with RTL8812AU */ is5ghz = (physt->cfosho[2] != 0x01); - if (rate < RTWN_RIDX_MCS(0)) { + if (rate < RTWN_RIDX_HT_MCS(0)) { if (is5ghz) rxs->c_phytype = IEEE80211_RX_FP_11A; else @@ -304,7 +304,7 @@ r12a_get_rx_stats(struct rtwn_softc *sc, struct ieee80211_rx_stats *rxs, } /* Map HW rate index to 802.11 rate. */ - if (rate < RTWN_RIDX_MCS(0)) { + if (rate < RTWN_RIDX_HT_MCS(0)) { rxs->c_rate = ridx2rate[rate]; if (RTWN_RATE_IS_CCK(rate)) rxs->c_pktflags |= IEEE80211_RX_F_CCK; diff --git a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c index 895f71e4..77e9e423 100644 --- a/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c +++ b/freebsd/sys/dev/rtwn/rtl8812a/r12a_tx.c @@ -109,7 +109,7 @@ r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd, if (mode == IEEE80211_PROT_CTSONLY || mode == IEEE80211_PROT_RTSCTS) { - if (ridx >= RTWN_RIDX_MCS(0)) + if (ridx >= RTWN_RIDX_HT_MCS(0)) rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); else rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); @@ -294,7 +294,7 @@ r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); prot = IEEE80211_PROT_NONE; - if (ridx >= RTWN_RIDX_MCS(0)) { + if (ridx >= RTWN_RIDX_HT_MCS(0)) { r12a_tx_set_ht40(sc, txd, ni); r12a_tx_set_sgi(sc, txd, ni); r12a_tx_set_ldpc(sc, txd, ni); diff --git a/freebsd/sys/dev/sdhci/sdhci.c b/freebsd/sys/dev/sdhci/sdhci.c index f1616a6e..8d1fed8f 100644 --- a/freebsd/sys/dev/sdhci/sdhci.c +++ b/freebsd/sys/dev/sdhci/sdhci.c @@ -1053,12 +1053,14 @@ no_tuning: return (0); } +#ifndef MMCCAM void sdhci_start_slot(struct sdhci_slot *slot) { sdhci_card_task(slot, 0); } +#endif int sdhci_cleanup_slot(struct sdhci_slot *slot) @@ -2398,7 +2400,7 @@ sdhci_generic_write_ivar(device_t bus, device_t child, int which, #ifdef MMCCAM void -sdhci_cam_start_slot(struct sdhci_slot *slot) +sdhci_start_slot(struct sdhci_slot *slot) { if ((slot->devq = cam_simq_alloc(1)) == NULL) { goto fail; diff --git a/freebsd/sys/dev/sdhci/sdhci.h b/freebsd/sys/dev/sdhci/sdhci.h index 73aa84b6..ba66415f 100644 --- a/freebsd/sys/dev/sdhci/sdhci.h +++ b/freebsd/sys/dev/sdhci/sdhci.h @@ -430,9 +430,4 @@ 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); -#ifdef MMCCAM -/* CAM-related */ -void sdhci_cam_start_slot(struct sdhci_slot *slot); -#endif - #endif /* __SDHCI_H__ */ diff --git a/freebsd/sys/dev/smc/if_smc.c b/freebsd/sys/dev/smc/if_smc.c index a018e09e..fd1a0960 100644 --- a/freebsd/sys/dev/smc/if_smc.c +++ b/freebsd/sys/dev/smc/if_smc.c @@ -784,7 +784,7 @@ smc_task_rx(void *context, int pending) } #ifdef DEVICE_POLLING -static void +static int smc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct smc_softc *sc; @@ -794,12 +794,13 @@ smc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) SMC_LOCK(sc); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { SMC_UNLOCK(sc); - return; + return (0); } SMC_UNLOCK(sc); if (cmd == POLL_AND_CHECK_STATUS) taskqueue_enqueue(sc->smc_tq, &sc->smc_intr); + return (0); } #endif diff --git a/freebsd/sys/dev/usb/net/if_ure.c b/freebsd/sys/dev/usb/net/if_ure.c index 27e3ecca..89ce723b 100644 --- a/freebsd/sys/dev/usb/net/if_ure.c +++ b/freebsd/sys/dev/usb/net/if_ure.c @@ -69,6 +69,7 @@ SYSCTL_INT(_hw_usb_ure, OID_AUTO, debug, CTLFLAG_RWTUN, &ure_debug, 0, */ static const STRUCT_USB_HOST_ID ure_devs[] = { #define URE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } + URE_DEV(LENOVO, RTL8153, 0), URE_DEV(REALTEK, RTL8152, URE_FLAG_8152), URE_DEV(REALTEK, RTL8153, 0), #undef URE_DEV diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.c b/freebsd/sys/dev/usb/quirk/usb_quirk.c index a5fac1b3..3ea3f3c6 100644 --- a/freebsd/sys/dev/usb/quirk/usb_quirk.c +++ b/freebsd/sys/dev/usb/quirk/usb_quirk.c @@ -236,6 +236,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { UQ_MSC_FORCE_PROTO_RBC), USB_QUIRK(INSYSTEM, STORAGE_V2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI, UQ_MSC_FORCE_PROTO_RBC), + USB_QUIRK(INTENSO, MEMORY_BOX, 0x0000, 0xffff, UQ_MSC_NO_INQUIRY), USB_QUIRK(IODATA, IU_CD2, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI), USB_QUIRK(IODATA, DVR_UEH8, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, @@ -335,7 +336,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_IGNORE_RESIDUE, UQ_MSC_NO_START_STOP), USB_QUIRK(PROLIFIC, PL2506, 0x0000, 0xffff, - UQ_MSC_NO_SYNC_CACHE), + UQ_MSC_NO_SYNC_CACHE, UQ_MSC_NO_PREVENT_ALLOW), USB_QUIRK_VP(USB_VENDOR_SAMSUNG_TECHWIN, USB_PRODUCT_SAMSUNG_TECHWIN_DIGIMAX_410, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_INQUIRY), @@ -509,6 +510,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(ROLAND, SD20, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), USB_QUIRK(ROLAND, SD80, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), USB_QUIRK(ROLAND, UA700, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), + USB_QUIRK(ROLAND, PCR300, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS), USB_QUIRK(EGO, M4U, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), USB_QUIRK(LOGILINK, U2M, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI), USB_QUIRK(MEDELI, DD305, 0x0000, 0xffff, UQ_SINGLE_CMD_MIDI, UQ_MATCH_VENDOR_ONLY), @@ -608,6 +610,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = { [UQ_SINGLE_CMD_MIDI] = "UQ_SINGLE_CMD_MIDI", [UQ_MSC_DYMO_EJECT] = "UQ_MSC_DYMO_EJECT", [UQ_AU_SET_SPDIF_CM6206] = "UQ_AU_SET_SPDIF_CM6206", + [UQ_WMT_IGNORE] = "UQ_WMT_IGNORE", }; /*------------------------------------------------------------------------* diff --git a/freebsd/sys/dev/usb/quirk/usb_quirk.h b/freebsd/sys/dev/usb/quirk/usb_quirk.h index f7e490ce..bb9fe190 100644 --- a/freebsd/sys/dev/usb/quirk/usb_quirk.h +++ b/freebsd/sys/dev/usb/quirk/usb_quirk.h @@ -110,6 +110,7 @@ enum { UQ_SINGLE_CMD_MIDI, /* at most one command per USB packet */ UQ_MSC_DYMO_EJECT, /* ejects Dymo MSC device */ UQ_AU_SET_SPDIF_CM6206, /* enable S/PDIF audio output */ + UQ_WMT_IGNORE, /* device should be ignored by wmt driver */ USB_QUIRK_MAX }; diff --git a/freebsd/sys/dev/usb/usb_hid.c b/freebsd/sys/dev/usb/usb_hid.c index 56e31a6e..5019aa1a 100644 --- a/freebsd/sys/dev/usb/usb_hid.c +++ b/freebsd/sys/dev/usb/usb_hid.c @@ -851,6 +851,80 @@ usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx, } /*------------------------------------------------------------------------* + * calculate HID item resolution. unit/mm for distances, unit/rad for angles + *------------------------------------------------------------------------*/ +int32_t +hid_item_resolution(struct hid_item *hi) +{ + /* + * hid unit scaling table according to HID Usage Table Review + * Request 39 Tbl 17 http://www.usb.org/developers/hidpage/HUTRR39b.pdf + */ + static const int64_t scale[0x10][2] = { + [0x00] = { 1, 1 }, + [0x01] = { 1, 10 }, + [0x02] = { 1, 100 }, + [0x03] = { 1, 1000 }, + [0x04] = { 1, 10000 }, + [0x05] = { 1, 100000 }, + [0x06] = { 1, 1000000 }, + [0x07] = { 1, 10000000 }, + [0x08] = { 100000000, 1 }, + [0x09] = { 10000000, 1 }, + [0x0A] = { 1000000, 1 }, + [0x0B] = { 100000, 1 }, + [0x0C] = { 10000, 1 }, + [0x0D] = { 1000, 1 }, + [0x0E] = { 100, 1 }, + [0x0F] = { 10, 1 }, + }; + int64_t logical_size; + int64_t physical_size; + int64_t multiplier; + int64_t divisor; + int64_t resolution; + + switch (hi->unit) { + case HUM_CENTIMETER: + multiplier = 1; + divisor = 10; + break; + case HUM_INCH: + multiplier = 10; + divisor = 254; + break; + case HUM_RADIAN: + multiplier = 1; + divisor = 1; + break; + case HUM_DEGREE: + multiplier = 573; + divisor = 10; + break; + default: + return (0); + } + + if ((hi->logical_maximum <= hi->logical_minimum) || + (hi->physical_maximum <= hi->physical_minimum) || + (hi->unit_exponent < 0) || (hi->unit_exponent >= nitems(scale))) + return (0); + + logical_size = (int64_t)hi->logical_maximum - + (int64_t)hi->logical_minimum; + physical_size = (int64_t)hi->physical_maximum - + (int64_t)hi->physical_minimum; + /* Round to ceiling */ + resolution = logical_size * multiplier * scale[hi->unit_exponent][0] / + (physical_size * divisor * scale[hi->unit_exponent][1]); + + if (resolution > INT32_MAX) + return (0); + + return (resolution); +} + +/*------------------------------------------------------------------------* * hid_is_mouse * * This function will decide if a USB descriptor belongs to a USB mouse. diff --git a/freebsd/sys/dev/usb/usb_hub.c b/freebsd/sys/dev/usb/usb_hub.c index e70be43b..0eaeeb60 100644 --- a/freebsd/sys/dev/usb/usb_hub.c +++ b/freebsd/sys/dev/usb/usb_hub.c @@ -102,7 +102,9 @@ SYSCTL_INT(_hw_usb, OID_AUTO, power_timeout, CTLFLAG_RWTUN, #if USB_HAVE_DISABLE_ENUM static int usb_disable_enumeration = 0; SYSCTL_INT(_hw_usb, OID_AUTO, disable_enumeration, CTLFLAG_RWTUN, - &usb_disable_enumeration, 0, "Set to disable all USB device enumeration."); + &usb_disable_enumeration, 0, "Set to disable all USB device enumeration. " + "This can secure against USB devices turning evil, " + "for example a USB memory stick becoming a USB keyboard."); static int usb_disable_port_power = 0; SYSCTL_INT(_hw_usb, OID_AUTO, disable_port_power, CTLFLAG_RWTUN, diff --git a/freebsd/sys/dev/usb/usbhid.h b/freebsd/sys/dev/usb/usbhid.h index 28dfede2..31aa7ea4 100644 --- a/freebsd/sys/dev/usb/usbhid.h +++ b/freebsd/sys/dev/usb/usbhid.h @@ -134,6 +134,12 @@ struct usb_hid_descriptor { /* Usages Digitizers */ #define HUD_UNDEFINED 0x0000 +#define HUD_DIGITIZER 0x0001 +#define HUD_PEN 0x0002 +#define HUD_TOUCHSCREEN 0x0004 +#define HUD_TOUCHPAD 0x0005 +#define HUD_CONFIG 0x000e +#define HUD_FINGER 0x0022 #define HUD_TIP_PRESSURE 0x0030 #define HUD_BARREL_PRESSURE 0x0031 #define HUD_IN_RANGE 0x0032 @@ -157,6 +163,16 @@ struct usb_hid_descriptor { #define HUD_BARREL_SWITCH 0x0044 #define HUD_ERASER 0x0045 #define HUD_TABLET_PICK 0x0046 +#define HUD_CONFIDENCE 0x0047 +#define HUD_WIDTH 0x0048 +#define HUD_HEIGHT 0x0049 +#define HUD_CONTACTID 0x0051 +#define HUD_INPUT_MODE 0x0052 +#define HUD_DEVICE_INDEX 0x0053 +#define HUD_CONTACTCOUNT 0x0054 +#define HUD_CONTACT_MAX 0x0055 +#define HUD_SCAN_TIME 0x0056 +#define HUD_BUTTON_TYPE 0x0059 /* Usages, Consumer */ #define HUC_AC_PAN 0x0238 @@ -178,6 +194,12 @@ struct usb_hid_descriptor { #define HIO_VOLATILE 0x080 #define HIO_BUFBYTES 0x100 +/* Units of Measure */ +#define HUM_CENTIMETER 0x11 +#define HUM_RADIAN 0x12 +#define HUM_INCH 0x13 +#define HUM_DEGREE 0x14 + #ifdef _KERNEL struct usb_config_descriptor; @@ -244,6 +266,7 @@ struct usb_hid_descriptor *hid_get_descriptor_from_usb( usb_error_t usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx, void **descp, uint16_t *sizep, struct malloc_type *mem, uint8_t iface_index); +int32_t hid_item_resolution(struct hid_item *hi); int hid_is_mouse(const void *d_ptr, uint16_t d_len); int hid_is_keyboard(const void *d_ptr, uint16_t d_len); #endif /* _KERNEL */ diff --git a/freebsd/sys/dev/usb/wlan/if_uath.c b/freebsd/sys/dev/usb/wlan/if_uath.c index c3435d57..c4ebe5ed 100644 --- a/freebsd/sys/dev/usb/wlan/if_uath.c +++ b/freebsd/sys/dev/usb/wlan/if_uath.c @@ -2203,17 +2203,19 @@ uath_sysctl_node(struct uath_softc *sc) #undef UATH_SYSCTL_STAT_ADD32 +CTASSERT(sizeof(u_int) >= sizeof(uint32_t)); + static void uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) { struct uath_cmd_hdr *hdr; - int dlen; + uint32_t dlen; hdr = (struct uath_cmd_hdr *)cmd->buf; /* NB: msgid is passed thru w/o byte swapping */ #ifdef UATH_DEBUG if (sc->sc_debug & UATH_DEBUG_CMDS) { - int len = be32toh(hdr->len); + uint32_t len = be32toh(hdr->len); printf("%s: %s [ix %u] len %u status %u\n", __func__, uath_codename(be32toh(hdr->code)), hdr->msgid, len, be32toh(hdr->magic)); @@ -2229,15 +2231,9 @@ uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) switch (hdr->code & 0xff) { /* reply to a read command */ default: - dlen = hdr->len - sizeof(*hdr); - if (dlen < 0) { - device_printf(sc->sc_dev, - "Invalid header length %d\n", dlen); - return; - } DPRINTF(sc, UATH_DEBUG_RX_PROC | UATH_DEBUG_RECV_ALL, - "%s: code %d data len %u\n", - __func__, hdr->code & 0xff, dlen); + "%s: code %d hdr len %u\n", + __func__, hdr->code & 0xff, hdr->len); /* * The first response from the target after the * HOST_AVAILABLE has an invalid msgid so we must @@ -2247,8 +2243,8 @@ uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) uint32_t *rp = (uint32_t *)(hdr+1); u_int olen; - if (!(sizeof(*hdr) <= hdr->len && - hdr->len < UATH_MAX_CMDSZ)) { + if (sizeof(*hdr) > hdr->len || + hdr->len >= UATH_MAX_CMDSZ) { device_printf(sc->sc_dev, "%s: invalid WDC msg length %u; " "msg ignored\n", __func__, hdr->len); @@ -2260,7 +2256,8 @@ uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) * number of bytes--unless it's 0 in which * case a single 32-bit word should be present. */ - if (dlen >= (int)sizeof(uint32_t)) { + dlen = hdr->len - sizeof(*hdr); + if (dlen >= sizeof(uint32_t)) { olen = be32toh(rp[0]); dlen -= sizeof(uint32_t); if (olen == 0) { @@ -2280,7 +2277,7 @@ uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) cmd->olen); olen = cmd->olen; } - if (olen > (u_int)dlen) { + if (olen > dlen) { /* XXX complain, shouldn't happen */ device_printf(sc->sc_dev, "%s: cmd 0x%x olen %u dlen %u\n", @@ -2302,8 +2299,10 @@ uath_cmdeof(struct uath_softc *sc, struct uath_cmd *cmd) return; } dlen = hdr->len - sizeof(*hdr); - if (dlen != (int)sizeof(uint32_t)) { - /* XXX something wrong */ + if (dlen != sizeof(uint32_t)) { + device_printf(sc->sc_dev, + "%s: dlen (%u) != %zu!\n", + __func__, dlen, sizeof(uint32_t)); return; } /* XXX have submitter do this */ @@ -2332,6 +2331,7 @@ uath_intr_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct uath_softc *sc = usbd_xfer_softc(xfer); struct uath_cmd *cmd; + struct uath_cmd_hdr *hdr; struct usb_page_cache *pc; int actlen; @@ -2349,10 +2349,25 @@ uath_intr_rx_callback(struct usb_xfer *xfer, usb_error_t error) STAILQ_INSERT_TAIL(&sc->sc_cmd_inactive, cmd, next); UATH_STAT_INC(sc, st_cmd_inactive); - KASSERT(actlen >= (int)sizeof(struct uath_cmd_hdr), - ("short xfer error")); + if (actlen < sizeof(struct uath_cmd_hdr)) { + device_printf(sc->sc_dev, + "%s: short xfer error (actlen %d)\n", + __func__, actlen); + goto setup; + } + pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_out(pc, 0, cmd->buf, actlen); + + hdr = (struct uath_cmd_hdr *)cmd->buf; + hdr->len = be32toh(hdr->len); + if (hdr->len > (uint32_t)actlen) { + device_printf(sc->sc_dev, + "%s: truncated xfer (len %u, actlen %d)\n", + __func__, hdr->len, actlen); + goto setup; + } + uath_cmdeof(sc, cmd); case USB_ST_SETUP: setup: @@ -2453,6 +2468,8 @@ uath_update_rxstat(struct uath_softc *sc, uint32_t status) } } +CTASSERT(UATH_MIN_RXBUFSZ >= sizeof(struct uath_chunk)); + static struct mbuf * uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, struct uath_rx_desc **pdesc) @@ -2475,13 +2492,24 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, } chunk = (struct uath_chunk *)data->buf; - if (chunk->seqnum == 0 && chunk->flags == 0 && chunk->length == 0) { + chunklen = be16toh(chunk->length); + if (chunk->seqnum == 0 && chunk->flags == 0 && chunklen == 0) { device_printf(sc->sc_dev, "%s: strange response\n", __func__); counter_u64_add(ic->ic_ierrors, 1); UATH_RESET_INTRX(sc); return (NULL); } + if (chunklen > actlen) { + device_printf(sc->sc_dev, + "%s: invalid chunk length (len %u > actlen %d)\n", + __func__, chunklen, actlen); + counter_u64_add(ic->ic_ierrors, 1); + /* XXX cleanup? */ + UATH_RESET_INTRX(sc); + return (NULL); + } + if (chunk->seqnum != sc->sc_intrx_nextnum) { DPRINTF(sc, UATH_DEBUG_XMIT, "invalid seqnum %d, expected %d\n", chunk->seqnum, sc->sc_intrx_nextnum); @@ -2498,9 +2526,19 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, chunk->flags & UATH_CFLAGS_RXMSG) UATH_STAT_INC(sc, st_multichunk); - chunklen = be16toh(chunk->length); - if (chunk->flags & UATH_CFLAGS_FINAL) + if (chunk->flags & UATH_CFLAGS_FINAL) { + if (chunklen < sizeof(struct uath_rx_desc)) { + device_printf(sc->sc_dev, + "%s: invalid chunk length %d\n", + __func__, chunklen); + counter_u64_add(ic->ic_ierrors, 1); + if (sc->sc_intrx_head != NULL) + m_freem(sc->sc_intrx_head); + UATH_RESET_INTRX(sc); + return (NULL); + } chunklen -= sizeof(struct uath_rx_desc); + } if (chunklen > 0 && (!(chunk->flags & UATH_CFLAGS_FINAL) || !(chunk->seqnum == 0))) { @@ -2561,6 +2599,19 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, (struct uath_rx_desc *)(((uint8_t *)chunk) + sizeof(struct uath_chunk) + be16toh(chunk->length) - sizeof(struct uath_rx_desc)); + if ((uint8_t *)chunk + actlen - sizeof(struct uath_rx_desc) < + (uint8_t *)desc) { + device_printf(sc->sc_dev, + "%s: wrong Rx descriptor pointer " + "(desc %p chunk %p actlen %d)\n", + __func__, desc, chunk, actlen); + counter_u64_add(ic->ic_ierrors, 1); + if (sc->sc_intrx_head != NULL) + m_freem(sc->sc_intrx_head); + UATH_RESET_INTRX(sc); + return (NULL); + } + *pdesc = desc; DPRINTF(sc, UATH_DEBUG_RECV | UATH_DEBUG_RECV_ALL, @@ -2588,8 +2639,33 @@ uath_data_rxeof(struct usb_xfer *xfer, struct uath_data *data, /* finalize mbuf */ if (sc->sc_intrx_head == NULL) { - m->m_pkthdr.len = m->m_len = - be32toh(desc->framelen) - UATH_RX_DUMMYSIZE; + uint32_t framelen; + + if (be32toh(desc->framelen) < UATH_RX_DUMMYSIZE) { + device_printf(sc->sc_dev, + "%s: framelen too small (%u)\n", + __func__, be32toh(desc->framelen)); + counter_u64_add(ic->ic_ierrors, 1); + if (sc->sc_intrx_head != NULL) + m_freem(sc->sc_intrx_head); + UATH_RESET_INTRX(sc); + return (NULL); + } + + framelen = be32toh(desc->framelen) - UATH_RX_DUMMYSIZE; + if (framelen > actlen - sizeof(struct uath_chunk) || + framelen < sizeof(struct ieee80211_frame_ack)) { + device_printf(sc->sc_dev, + "%s: wrong frame length (%u, actlen %d)!\n", + __func__, framelen, actlen); + counter_u64_add(ic->ic_ierrors, 1); + if (sc->sc_intrx_head != NULL) + m_freem(sc->sc_intrx_head); + UATH_RESET_INTRX(sc); + return (NULL); + } + + m->m_pkthdr.len = m->m_len = framelen; m->m_data += sizeof(struct uath_chunk); } else { mp = sc->sc_intrx_head; diff --git a/freebsd/sys/fs/devfs/devfs_vnops.c b/freebsd/sys/fs/devfs/devfs_vnops.c index 85c0af86..fcf69a1a 100644 --- a/freebsd/sys/fs/devfs/devfs_vnops.c +++ b/freebsd/sys/fs/devfs/devfs_vnops.c @@ -1193,6 +1193,24 @@ devfs_pathconf(struct vop_pathconf_args *ap) { switch (ap->a_name) { + case _PC_MAX_CANON: + if (ap->a_vp->v_vflag & VV_ISTTY) { + *ap->a_retval = MAX_CANON; + return (0); + } + return (EINVAL); + case _PC_MAX_INPUT: + if (ap->a_vp->v_vflag & VV_ISTTY) { + *ap->a_retval = MAX_INPUT; + return (0); + } + return (EINVAL); + case _PC_VDISABLE: + if (ap->a_vp->v_vflag & VV_ISTTY) { + *ap->a_retval = _POSIX_VDISABLE; + return (0); + } + return (EINVAL); case _PC_MAC_PRESENT: #ifdef MAC /* diff --git a/freebsd/sys/i386/include/machine/cpufunc.h b/freebsd/sys/i386/include/machine/cpufunc.h index 923d28ea..a311cd1d 100644 --- a/freebsd/sys/i386/include/machine/cpufunc.h +++ b/freebsd/sys/i386/include/machine/cpufunc.h @@ -62,7 +62,7 @@ breakpoint(void) } #endif -static __inline u_int +static __inline __pure2 u_int bsfl(u_int mask) { u_int result; @@ -71,7 +71,7 @@ bsfl(u_int mask) return (result); } -static __inline u_int +static __inline __pure2 u_int bsrl(u_int mask) { u_int result; @@ -172,7 +172,7 @@ sfence(void) #ifndef __rtems__ #define HAVE_INLINE_FFS -static __inline int +static __inline __pure2 int ffs(int mask) { /* @@ -186,7 +186,7 @@ ffs(int mask) #define HAVE_INLINE_FFSL -static __inline int +static __inline __pure2 int ffsl(long mask) { return (ffs((int)mask)); @@ -196,7 +196,7 @@ ffsl(long mask) #endif /* __rtems__ */ #ifndef __rtems__ -static __inline int +static __inline __pure2 int fls(int mask) { return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); @@ -205,7 +205,7 @@ fls(int mask) #define HAVE_INLINE_FLSL -static __inline int +static __inline __pure2 int flsl(long mask) { return (fls((int)mask)); diff --git a/freebsd/sys/i386/include/machine/intr_machdep.h b/freebsd/sys/i386/include/machine/intr_machdep.h index a8dd4564..5892d07c 100644 --- a/freebsd/sys/i386/include/machine/intr_machdep.h +++ b/freebsd/sys/i386/include/machine/intr_machdep.h @@ -130,6 +130,7 @@ struct intsrc { u_long *is_straycount; u_int is_index; u_int is_handlers; + u_int is_cpu; }; struct trapframe; diff --git a/freebsd/sys/i386/include/machine/md_var.h b/freebsd/sys/i386/include/machine/md_var.h index c93d70c8..2ca8c856 100644 --- a/freebsd/sys/i386/include/machine/md_var.h +++ b/freebsd/sys/i386/include/machine/md_var.h @@ -59,7 +59,6 @@ void doreti_popl_es(void) __asm(__STRING(doreti_popl_es)); void doreti_popl_es_fault(void) __asm(__STRING(doreti_popl_es_fault)); void doreti_popl_fs(void) __asm(__STRING(doreti_popl_fs)); void doreti_popl_fs_fault(void) __asm(__STRING(doreti_popl_fs_fault)); -void finishidentcpu(void); void fill_based_sd(struct segment_descriptor *sdp, uint32_t base); void i686_pagezero(void *addr); void sse2_pagezero(void *addr); diff --git a/freebsd/sys/kern/kern_sysctl.c b/freebsd/sys/kern/kern_sysctl.c index 90b15444..e99a8bd6 100644 --- a/freebsd/sys/kern/kern_sysctl.c +++ b/freebsd/sys/kern/kern_sysctl.c @@ -90,7 +90,7 @@ static MALLOC_DEFINE(M_SYSCTLTMP, "sysctltmp", "sysctl temp output buffer"); * sysctl requests larger than a single page via an exclusive lock. */ static struct rmlock sysctllock; -static struct sx sysctlmemlock; +static struct sx __exclusive_cache_line sysctlmemlock; #define SYSCTL_WLOCK() rm_wlock(&sysctllock) #define SYSCTL_WUNLOCK() rm_wunlock(&sysctllock) @@ -327,6 +327,91 @@ sysctl_load_tunable_by_oid_locked(struct sysctl_oid *oidp) } #endif /* __rtems__ */ +static int +sbuf_printf_drain(void *arg __unused, const char *data, int len) +{ + + return (printf("%.*s", len, data)); +} + +/* + * Locate the path to a given oid. Returns the length of the resulting path, + * or -1 if the oid was not found. nodes must have room for CTL_MAXNAME + * elements and be NULL initialized. + */ +static int +sysctl_search_oid(struct sysctl_oid **nodes, struct sysctl_oid *needle) +{ + int indx; + + SYSCTL_ASSERT_LOCKED(); + indx = 0; + while (indx < CTL_MAXNAME && indx >= 0) { + if (nodes[indx] == NULL && indx == 0) + nodes[indx] = SLIST_FIRST(&sysctl__children); + else if (nodes[indx] == NULL) + nodes[indx] = SLIST_FIRST(&nodes[indx - 1]->oid_children); + else + nodes[indx] = SLIST_NEXT(nodes[indx], oid_link); + + if (nodes[indx] == needle) + return (indx + 1); + + if (nodes[indx] == NULL) { + indx--; + continue; + } + + if ((nodes[indx]->oid_kind & CTLTYPE) == CTLTYPE_NODE) { + indx++; + continue; + } + } + return (-1); +} + +static void +sysctl_warn_reuse(const char *func, struct sysctl_oid *leaf) +{ + struct sysctl_oid *nodes[CTL_MAXNAME]; + char buf[128]; + struct sbuf sb; + int rc, i; + + (void)sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN | SBUF_INCLUDENUL); + sbuf_set_drain(&sb, sbuf_printf_drain, NULL); + + sbuf_printf(&sb, "%s: can't re-use a leaf (", __func__); + + memset(nodes, 0, sizeof(nodes)); + rc = sysctl_search_oid(nodes, leaf); + if (rc > 0) { + for (i = 0; i < rc; i++) + sbuf_printf(&sb, "%s%.*s", nodes[i]->oid_name, + i != (rc - 1), "."); + } else { + sbuf_printf(&sb, "%s", leaf->oid_name); + } + sbuf_printf(&sb, ")!\n"); + + (void)sbuf_finish(&sb); +} + +#ifdef SYSCTL_DEBUG +static int +sysctl_reuse_test(SYSCTL_HANDLER_ARGS) +{ + struct rm_priotracker tracker; + + SYSCTL_RLOCK(&tracker); + sysctl_warn_reuse(__func__, oidp); + SYSCTL_RUNLOCK(&tracker); + return (0); +} +SYSCTL_PROC(_sysctl, 0, reuse_test, CTLTYPE_STRING|CTLFLAG_RD|CTLFLAG_MPSAFE, + 0, 0, sysctl_reuse_test, "-", ""); +#endif + void sysctl_register_oid(struct sysctl_oid *oidp) { @@ -347,7 +432,7 @@ sysctl_register_oid(struct sysctl_oid *oidp) p->oid_refcnt++; return; } else { - printf("can't re-use a leaf (%s)!\n", p->oid_name); + sysctl_warn_reuse(__func__, p); return; } } @@ -721,8 +806,8 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent, SYSCTL_WUNLOCK(); return (oidp); } else { + sysctl_warn_reuse(__func__, oidp); SYSCTL_WUNLOCK(); - printf("can't re-use a leaf (%s)!\n", name); return (NULL); } } @@ -2005,16 +2090,9 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, } } req.validlen = req.oldlen; - - if (old) { - if (!useracc(old, req.oldlen, VM_PROT_WRITE)) - return (EFAULT); - req.oldptr= old; - } + req.oldptr = old; if (new != NULL) { - if (!useracc(new, newlen, VM_PROT_READ)) - return (EFAULT); req.newlen = newlen; req.newptr = new; } diff --git a/freebsd/sys/kern/subr_blist.c b/freebsd/sys/kern/subr_blist.c index c8e32c5b..7f232e93 100644 --- a/freebsd/sys/kern/subr_blist.c +++ b/freebsd/sys/kern/subr_blist.c @@ -34,14 +34,17 @@ * try to interpret the meaning of a 'block' other than to return * SWAPBLK_NONE on an allocation failure. * - * A radix tree is used to maintain the bitmap. Two radix constants are - * involved: One for the bitmaps contained in the leaf nodes (typically - * 64), and one for the meta nodes (typically 16). Both meta and leaf - * nodes have a hint field. This field gives us a hint as to the largest - * free contiguous range of blocks under the node. It may contain a - * value that is too high, but will never contain a value that is too - * low. When the radix tree is searched, allocation failures in subtrees - * update the hint. + * A radix tree controls access to pieces of the bitmap, and includes + * auxiliary information at each interior node about the availabilty of + * contiguous free blocks in the subtree rooted at that node. Two radix + * constants are involved: one for the size of the bitmaps contained in the + * leaf nodes (BLIST_BMAP_RADIX), and one for the number of descendents of + * each of the meta (interior) nodes (BLIST_META_RADIX). Each subtree is + * associated with a range of blocks. The root of any subtree stores a + * hint field that defines an upper bound on the size of the largest + * allocation that can begin in the associated block range. A hint is an + * upper bound on a potential allocation, but not necessarily a tight upper + * bound. * * The radix tree also implements two collapsed states for meta nodes: * the ALL-ALLOCATED state and the ALL-FREE state. If a meta node is @@ -92,6 +95,7 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/blist.h> #include <sys/malloc.h> +#include <sys/sbuf.h> #include <sys/proc.h> #include <sys/mutex.h> @@ -103,6 +107,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/malloc.h> +#include <sys/sbuf.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -112,6 +117,7 @@ __FBSDID("$FreeBSD$"); #define bitcount64(x) __bitcount64((uint64_t)(x)) #define malloc(a,b,c) calloc(a, 1) #define free(a,b) free(a) +static __inline int imax(int a, int b) { return (a > b ? a : b); } #include <sys/blist.h> @@ -122,29 +128,84 @@ void panic(const char *ctl, ...); /* * static support functions */ -static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count, - daddr_t cursor); -static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, - daddr_t radix, daddr_t skip, daddr_t cursor); +static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count); +static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t cursor, daddr_t count, + u_daddr_t radix); static void blst_leaf_free(blmeta_t *scan, daddr_t relblk, int count); static void blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, - daddr_t radix, daddr_t skip, daddr_t blk); + u_daddr_t radix); static void blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, - daddr_t skip, blist_t dest, daddr_t count); + blist_t dest, daddr_t count); static daddr_t blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count); static daddr_t blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, - daddr_t radix, daddr_t skip, daddr_t blk); -static daddr_t blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t skip, - daddr_t count); + u_daddr_t radix); +static daddr_t blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t count); #ifndef _KERNEL static void blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, - daddr_t skip, int tab); + int tab); #endif #ifdef _KERNEL static MALLOC_DEFINE(M_SWAP, "SWAP", "Swap space"); #endif +_Static_assert(BLIST_BMAP_RADIX % BLIST_META_RADIX == 0, + "radix divisibility error"); +#define BLIST_BMAP_MASK (BLIST_BMAP_RADIX - 1) +#define BLIST_META_MASK (BLIST_META_RADIX - 1) + +/* + * For a subtree that can represent the state of up to 'radix' blocks, the + * number of leaf nodes of the subtree is L=radix/BLIST_BMAP_RADIX. If 'm' + * is short for BLIST_META_RADIX, then for a tree of height h with L=m**h + * leaf nodes, the total number of tree nodes is 1 + m + m**2 + ... + m**h, + * or, equivalently, (m**(h+1)-1)/(m-1). This quantity is called 'skip' + * in the 'meta' functions that process subtrees. Since integer division + * discards remainders, we can express this computation as + * skip = (m * m**h) / (m - 1) + * skip = (m * (radix / BLIST_BMAP_RADIX)) / (m - 1) + * and since m divides BLIST_BMAP_RADIX, we can simplify further to + * skip = (radix / (BLIST_BMAP_RADIX / m)) / (m - 1) + * skip = radix / ((BLIST_BMAP_RADIX / m) * (m - 1)) + * so that simple integer division by a constant can safely be used for the + * calculation. + */ +static inline daddr_t +radix_to_skip(daddr_t radix) +{ + + return (radix / + ((BLIST_BMAP_RADIX / BLIST_META_RADIX) * BLIST_META_MASK)); +} + +/* + * Use binary search, or a faster method, to find the 1 bit in a u_daddr_t. + * Assumes that the argument has only one bit set. + */ +static inline int +bitpos(u_daddr_t mask) +{ + int hi, lo, mid; + + switch (sizeof(mask)) { +#ifdef HAVE_INLINE_FFSLL + case sizeof(long long): + return (ffsll(mask) - 1); +#endif + default: + lo = 0; + hi = BLIST_BMAP_RADIX; + while (lo + 1 < hi) { + mid = (lo + hi) >> 1; + if ((mask >> mid) != 0) + lo = mid; + else + hi = mid; + } + return (lo); + } +} + /* * blist_create() - create a blist capable of handling up to the specified * number of blocks @@ -159,18 +220,16 @@ blist_t blist_create(daddr_t blocks, int flags) { blist_t bl; - daddr_t nodes, radix, skip; + daddr_t nodes, radix; /* - * Calculate radix and skip field used for scanning. + * Calculate the radix field used for scanning. */ radix = BLIST_BMAP_RADIX; - skip = 0; while (radix < blocks) { radix *= BLIST_META_RADIX; - skip = (skip + 1) * BLIST_META_RADIX; } - nodes = 1 + blst_radix_init(NULL, radix, skip, blocks); + nodes = 1 + blst_radix_init(NULL, radix, blocks); bl = malloc(sizeof(struct blist), M_SWAP, flags); if (bl == NULL) @@ -178,14 +237,13 @@ blist_create(daddr_t blocks, int flags) bl->bl_blocks = blocks; bl->bl_radix = radix; - bl->bl_skip = skip; bl->bl_cursor = 0; bl->bl_root = malloc(nodes * sizeof(blmeta_t), M_SWAP, flags); if (bl->bl_root == NULL) { free(bl, M_SWAP); return (NULL); } - blst_radix_init(bl->bl_root, radix, skip, blocks); + blst_radix_init(bl->bl_root, radix, blocks); #if defined(BLIST_DEBUG) printf( @@ -226,10 +284,12 @@ blist_alloc(blist_t bl, daddr_t count) * reduce the hint, stopping further iterations. */ while (count <= bl->bl_root->bm_bighint) { - blk = blst_meta_alloc(bl->bl_root, 0, count, bl->bl_radix, - bl->bl_skip, bl->bl_cursor); + blk = blst_meta_alloc(bl->bl_root, bl->bl_cursor, count, + bl->bl_radix); if (blk != SWAPBLK_NONE) { bl->bl_cursor = blk + count; + if (bl->bl_cursor == bl->bl_blocks) + bl->bl_cursor = 0; return (blk); } else if (bl->bl_cursor != 0) bl->bl_cursor = 0; @@ -259,7 +319,7 @@ void blist_free(blist_t bl, daddr_t blkno, daddr_t count) { - blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix, bl->bl_skip, 0); + blst_meta_free(bl->bl_root, blkno, count, bl->bl_radix); } /* @@ -272,8 +332,7 @@ daddr_t blist_fill(blist_t bl, daddr_t blkno, daddr_t count) { - return (blst_meta_fill(bl->bl_root, blkno, count, bl->bl_radix, - bl->bl_skip, 0)); + return (blst_meta_fill(bl->bl_root, blkno, count, bl->bl_radix)); } /* @@ -292,7 +351,7 @@ blist_resize(blist_t *pbl, daddr_t count, int freenew, int flags) *pbl = newbl; if (count > save->bl_blocks) count = save->bl_blocks; - blst_copy(save->bl_root, 0, save->bl_radix, save->bl_skip, newbl, count); + blst_copy(save->bl_root, 0, save->bl_radix, newbl, count); /* * If resizing upwards, should we free the new space or not? @@ -311,13 +370,199 @@ blist_resize(blist_t *pbl, daddr_t count, int freenew, int flags) void blist_print(blist_t bl) { - printf("BLIST {\n"); - blst_radix_print(bl->bl_root, 0, bl->bl_radix, bl->bl_skip, 4); + printf("BLIST cursor = %08jx {\n", (uintmax_t)bl->bl_cursor); + blst_radix_print(bl->bl_root, 0, bl->bl_radix, 4); printf("}\n"); } #endif +static const u_daddr_t fib[] = { + 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, + 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, + 514229, 832040, 1346269, 2178309, 3524578, +}; + +/* + * Use 'gap' to describe a maximal range of unallocated blocks/bits. + */ +struct gap_stats { + daddr_t start; /* current gap start, or SWAPBLK_NONE */ + daddr_t num; /* number of gaps observed */ + daddr_t max; /* largest gap size */ + daddr_t avg; /* average gap size */ + daddr_t err; /* sum - num * avg */ + daddr_t histo[nitems(fib)]; /* # gaps in each size range */ + int max_bucket; /* last histo elt with nonzero val */ +}; + +/* + * gap_stats_counting() - is the state 'counting 1 bits'? + * or 'skipping 0 bits'? + */ +static inline bool +gap_stats_counting(const struct gap_stats *stats) +{ + + return (stats->start != SWAPBLK_NONE); +} + +/* + * init_gap_stats() - initialize stats on gap sizes + */ +static inline void +init_gap_stats(struct gap_stats *stats) +{ + + bzero(stats, sizeof(*stats)); + stats->start = SWAPBLK_NONE; +} + +/* + * update_gap_stats() - update stats on gap sizes + */ +static void +update_gap_stats(struct gap_stats *stats, daddr_t posn) +{ + daddr_t size; + int hi, lo, mid; + + if (!gap_stats_counting(stats)) { + stats->start = posn; + return; + } + size = posn - stats->start; + stats->start = SWAPBLK_NONE; + if (size > stats->max) + stats->max = size; + + /* + * Find the fibonacci range that contains size, + * expecting to find it in an early range. + */ + lo = 0; + hi = 1; + while (hi < nitems(fib) && fib[hi] <= size) { + lo = hi; + hi *= 2; + } + if (hi >= nitems(fib)) + hi = nitems(fib); + while (lo + 1 != hi) { + mid = (lo + hi) >> 1; + if (fib[mid] <= size) + lo = mid; + else + hi = mid; + } + stats->histo[lo]++; + if (lo > stats->max_bucket) + stats->max_bucket = lo; + stats->err += size - stats->avg; + stats->num++; + stats->avg += stats->err / stats->num; + stats->err %= stats->num; +} + +/* + * dump_gap_stats() - print stats on gap sizes + */ +static inline void +dump_gap_stats(const struct gap_stats *stats, struct sbuf *s) +{ + int i; + + sbuf_printf(s, "number of maximal free ranges: %jd\n", + (intmax_t)stats->num); + sbuf_printf(s, "largest free range: %jd\n", (intmax_t)stats->max); + sbuf_printf(s, "average maximal free range size: %jd\n", + (intmax_t)stats->avg); + sbuf_printf(s, "number of maximal free ranges of different sizes:\n"); + sbuf_printf(s, " count | size range\n"); + sbuf_printf(s, " ----- | ----------\n"); + for (i = 0; i < stats->max_bucket; i++) { + if (stats->histo[i] != 0) { + sbuf_printf(s, "%20jd | ", + (intmax_t)stats->histo[i]); + if (fib[i] != fib[i + 1] - 1) + sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i], + (intmax_t)fib[i + 1] - 1); + else + sbuf_printf(s, "%jd\n", (intmax_t)fib[i]); + } + } + sbuf_printf(s, "%20jd | ", (intmax_t)stats->histo[i]); + if (stats->histo[i] > 1) + sbuf_printf(s, "%jd to %jd\n", (intmax_t)fib[i], + (intmax_t)stats->max); + else + sbuf_printf(s, "%jd\n", (intmax_t)stats->max); +} + +/* + * blist_stats() - dump radix tree stats + */ +void +blist_stats(blist_t bl, struct sbuf *s) +{ + struct gap_stats gstats; + struct gap_stats *stats = &gstats; + daddr_t i, nodes, radix; + u_daddr_t bit, diff, mask; + + init_gap_stats(stats); + nodes = 0; + i = bl->bl_radix; + while (i < bl->bl_radix + bl->bl_blocks) { + /* + * Find max size subtree starting at i. + */ + radix = BLIST_BMAP_RADIX; + while (((i / radix) & BLIST_META_MASK) == 0) + radix *= BLIST_META_RADIX; + + /* + * Check for skippable subtrees starting at i. + */ + while (radix > BLIST_BMAP_RADIX) { + if (bl->bl_root[nodes].u.bmu_avail == 0) { + if (gap_stats_counting(stats)) + update_gap_stats(stats, i); + break; + } + if (bl->bl_root[nodes].u.bmu_avail == radix) { + if (!gap_stats_counting(stats)) + update_gap_stats(stats, i); + break; + } + + /* + * Skip subtree root. + */ + nodes++; + radix /= BLIST_META_RADIX; + } + if (radix == BLIST_BMAP_RADIX) { + /* + * Scan leaf. + */ + mask = bl->bl_root[nodes].u.bmu_bitmap; + diff = mask ^ (mask << 1); + if (gap_stats_counting(stats)) + diff ^= 1; + while (diff != 0) { + bit = diff & -diff; + update_gap_stats(stats, i + bitpos(bit)); + diff ^= bit; + } + } + nodes += radix_to_skip(radix); + i += radix; + } + update_gap_stats(stats, i); + dump_gap_stats(stats, s); +} + /************************************************************************ * ALLOCATION SUPPORT FUNCTIONS * ************************************************************************ @@ -333,36 +578,19 @@ blist_print(blist_t bl) * * This is the core of the allocator and is optimized for the * BLIST_BMAP_RADIX block allocation case. Otherwise, execution - * time is proportional to log2(count) + log2(BLIST_BMAP_RADIX). + * time is proportional to log2(count) + bitpos time. */ static daddr_t -blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count, daddr_t cursor) +blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count) { u_daddr_t mask; - int count1, hi, lo, mid, num_shifts, range1, range_ext; + int count1, hi, lo, num_shifts, range1, range_ext; - if (count == BLIST_BMAP_RADIX) { - /* - * Optimize allocation of BLIST_BMAP_RADIX bits. If this wasn't - * a special case, then forming the final value of 'mask' below - * would require special handling to avoid an invalid left shift - * when count equals the number of bits in mask. - */ - if (~scan->u.bmu_bitmap != 0) { - scan->bm_bighint = BLIST_BMAP_RADIX - 1; - return (SWAPBLK_NONE); - } - if (cursor != blk) - return (SWAPBLK_NONE); - scan->u.bmu_bitmap = 0; - scan->bm_bighint = 0; - return (blk); - } range1 = 0; count1 = count - 1; num_shifts = fls(count1); mask = scan->u.bmu_bitmap; - while (mask != 0 && num_shifts > 0) { + while ((-mask & ~mask) != 0 && num_shifts > 0) { /* * If bit i is set in mask, then bits in [i, i+range1] are set * in scan->u.bmu_bitmap. The value of range1 is equal to @@ -370,52 +598,95 @@ blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count, daddr_t cursor) * while preserving these invariants. The updates to mask leave * fewer bits set, but each bit that remains set represents a * longer string of consecutive bits set in scan->u.bmu_bitmap. + * If more updates to mask cannot clear more bits, because mask + * is partitioned with all 0 bits preceding all 1 bits, the loop + * terminates immediately. */ num_shifts--; range_ext = range1 + ((count1 >> num_shifts) & 1); - mask &= mask >> range_ext; + /* + * mask is a signed quantity for the shift because when it is + * shifted right, the sign bit should copied; when the last + * block of the leaf is free, pretend, for a while, that all the + * blocks that follow it are also free. + */ + mask &= (daddr_t)mask >> range_ext; range1 += range_ext; } if (mask == 0) { /* * Update bighint. There is no allocation bigger than range1 - * available in this leaf. + * starting in this leaf. */ scan->bm_bighint = range1; return (SWAPBLK_NONE); } - /* - * Discard any candidates that appear before the cursor. - */ - lo = cursor - blk; - mask &= ~(u_daddr_t)0 << lo; - + /* Discard any candidates that appear before blk. */ + mask &= (u_daddr_t)-1 << (blk & BLIST_BMAP_MASK); if (mask == 0) return (SWAPBLK_NONE); /* * The least significant set bit in mask marks the start of the first * available range of sufficient size. Clear all the bits but that one, - * and then perform a binary search to find its position. + * and then find its position. */ mask &= -mask; - hi = BLIST_BMAP_RADIX - count1; - while (lo + 1 < hi) { - mid = (lo + hi) >> 1; - if ((mask >> mid) != 0) - lo = mid; - else - hi = mid; + lo = bitpos(mask); + + hi = lo + count; + if (hi > BLIST_BMAP_RADIX) { + /* + * An allocation within this leaf is impossible, so a successful + * allocation depends on the next leaf providing some of the blocks. + */ + if (((blk / BLIST_BMAP_RADIX + 1) & BLIST_META_MASK) == 0) { + /* + * The next leaf has a different meta-node parent, so it + * is not necessarily initialized. Update bighint, + * comparing the range found at the end of mask to the + * largest earlier range that could have been made to + * vanish in the initial processing of mask. + */ + scan->bm_bighint = imax(BLIST_BMAP_RADIX - lo, range1); + return (SWAPBLK_NONE); + } + hi -= BLIST_BMAP_RADIX; + if (((scan[1].u.bmu_bitmap + 1) & ~((u_daddr_t)-1 << hi)) != 0) { + /* + * The next leaf doesn't have enough free blocks at the + * beginning to complete the spanning allocation. The + * hint cannot be updated, because the same allocation + * request could be satisfied later, by this leaf, if + * the state of the next leaf changes, and without any + * changes to this leaf. + */ + return (SWAPBLK_NONE); + } + /* Clear the first 'hi' bits in the next leaf, allocating them. */ + scan[1].u.bmu_bitmap &= (u_daddr_t)-1 << hi; + hi = BLIST_BMAP_RADIX; } - /* - * Set in mask exactly the bits being allocated, and clear them from - * the set of available bits. - */ - mask = (mask << count) - mask; + /* Set the bits of mask at position 'lo' and higher. */ + mask = -mask; + if (hi == BLIST_BMAP_RADIX) { + /* + * Update bighint. There is no allocation bigger than range1 + * available in this leaf after this allocation completes. + */ + scan->bm_bighint = range1; + } else { + /* Clear the bits of mask at position 'hi' and higher. */ + mask &= (u_daddr_t)-1 >> (BLIST_BMAP_RADIX - hi); + /* If this allocation uses all the bits, clear the hint. */ + if (mask == scan->u.bmu_bitmap) + scan->bm_bighint = 0; + } + /* Clear the allocated bits from this leaf. */ scan->u.bmu_bitmap &= ~mask; - return (blk + lo); + return ((blk & ~BLIST_BMAP_MASK) + lo); } /* @@ -427,15 +698,14 @@ blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count, daddr_t cursor) * and we have a few optimizations strewn in as well. */ static daddr_t -blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, daddr_t radix, - daddr_t skip, daddr_t cursor) +blst_meta_alloc(blmeta_t *scan, daddr_t cursor, daddr_t count, u_daddr_t radix) { - daddr_t i, next_skip, r; + daddr_t blk, i, next_skip, r, skip; int child; bool scan_from_start; if (radix == BLIST_BMAP_RADIX) - return (blst_leaf_alloc(scan, blk, count, cursor)); + return (blst_leaf_alloc(scan, cursor, count)); if (scan->u.bmu_avail < count) { /* * The meta node's hint must be too large if the allocation @@ -445,6 +715,8 @@ blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, daddr_t radix, scan->bm_bighint = scan->u.bmu_avail; return (SWAPBLK_NONE); } + blk = cursor & -radix; + skip = radix_to_skip(radix); next_skip = skip / BLIST_META_RADIX; /* @@ -458,7 +730,7 @@ blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, daddr_t radix, * Reinitialize each of the meta node's children. An ALL-FREE * meta node cannot have a terminator in any subtree. */ - for (i = 1; i <= skip; i += next_skip) { + for (i = 1; i < skip; i += next_skip) { if (next_skip == 1) scan[i].u.bmu_bitmap = (u_daddr_t)-1; else @@ -479,13 +751,13 @@ blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, daddr_t radix, scan_from_start = cursor == blk; child = (cursor - blk) / radix; blk += child * radix; - for (i = 1 + child * next_skip; i <= skip; i += next_skip) { + for (i = 1 + child * next_skip; i < skip; i += next_skip) { if (count <= scan[i].bm_bighint) { /* - * The allocation might fit in the i'th subtree. + * The allocation might fit beginning in the i'th subtree. */ - r = blst_meta_alloc(&scan[i], blk, count, radix, - next_skip - 1, cursor > blk ? cursor : blk); + r = blst_meta_alloc(&scan[i], + cursor > blk ? cursor : blk, count, radix); if (r != SWAPBLK_NONE) { scan->u.bmu_avail -= count; return (r); @@ -515,22 +787,20 @@ blst_meta_alloc(blmeta_t *scan, daddr_t blk, daddr_t count, daddr_t radix, static void blst_leaf_free(blmeta_t *scan, daddr_t blk, int count) { + u_daddr_t mask; + int n; + /* * free some data in this bitmap - * - * e.g. - * 0000111111111110000 + * mask=0000111111111110000 * \_________/\__/ - * v n + * count n */ - int n = blk & (BLIST_BMAP_RADIX - 1); - u_daddr_t mask; - + n = blk & BLIST_BMAP_MASK; mask = ((u_daddr_t)-1 << n) & ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - count - n)); - if (scan->u.bmu_bitmap & mask) - panic("blst_radix_free: freeing free block"); + panic("freeing free block"); scan->u.bmu_bitmap |= mask; /* @@ -553,16 +823,16 @@ blst_leaf_free(blmeta_t *scan, daddr_t blk, int count) * range). */ static void -blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, daddr_t radix, - daddr_t skip, daddr_t blk) +blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, u_daddr_t radix) { - daddr_t i, next_skip, v; + daddr_t blk, i, next_skip, skip, v; int child; if (scan->bm_bighint == (daddr_t)-1) panic("freeing invalid range"); if (radix == BLIST_BMAP_RADIX) return (blst_leaf_free(scan, freeBlk, count)); + skip = radix_to_skip(radix); next_skip = skip / BLIST_META_RADIX; if (scan->u.bmu_avail == 0) { @@ -574,7 +844,7 @@ blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, daddr_t radix, scan->bm_bighint = count; if (count != radix) { - for (i = 1; i <= skip; i += next_skip) { + for (i = 1; i < skip; i += next_skip) { if (scan[i].bm_bighint == (daddr_t)-1) break; scan[i].bm_bighint = 0; @@ -606,16 +876,17 @@ blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, daddr_t radix, * Break the free down into its components */ + blk = freeBlk & -radix; radix /= BLIST_META_RADIX; child = (freeBlk - blk) / radix; blk += child * radix; i = 1 + child * next_skip; - while (i <= skip && blk < freeBlk + count) { + while (i < skip && blk < freeBlk + count) { v = blk + radix - freeBlk; if (v > count) v = count; - blst_meta_free(&scan[i], freeBlk, v, radix, next_skip - 1, blk); + blst_meta_free(&scan[i], freeBlk, v, radix); if (scan->bm_bighint < scan[i].bm_bighint) scan->bm_bighint = scan[i].bm_bighint; count -= v; @@ -632,10 +903,10 @@ blst_meta_free(blmeta_t *scan, daddr_t freeBlk, daddr_t count, daddr_t radix, * tree. The space may not already be free in the destination. */ static void -blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip, - blist_t dest, daddr_t count) +blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, blist_t dest, + daddr_t count) { - daddr_t i, next_skip; + daddr_t i, next_skip, skip; /* * Leaf node @@ -679,21 +950,20 @@ blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip, } - radix /= BLIST_META_RADIX; + skip = radix_to_skip(radix); next_skip = skip / BLIST_META_RADIX; + radix /= BLIST_META_RADIX; - for (i = 1; count && i <= skip; i += next_skip) { + for (i = 1; count && i < skip; i += next_skip) { if (scan[i].bm_bighint == (daddr_t)-1) break; if (count >= radix) { - blst_copy(&scan[i], blk, radix, next_skip - 1, dest, - radix); + blst_copy(&scan[i], blk, radix, dest, radix); count -= radix; } else { if (count) { - blst_copy(&scan[i], blk, radix, next_skip - 1, - dest, count); + blst_copy(&scan[i], blk, radix, dest, count); } count = 0; } @@ -711,10 +981,11 @@ blst_copy(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip, static daddr_t blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count) { - int n = blk & (BLIST_BMAP_RADIX - 1); daddr_t nblks; u_daddr_t mask; + int n; + n = blk & BLIST_BMAP_MASK; mask = ((u_daddr_t)-1 << n) & ((u_daddr_t)-1 >> (BLIST_BMAP_RADIX - count - n)); @@ -734,10 +1005,9 @@ blst_leaf_fill(blmeta_t *scan, daddr_t blk, int count) * number of blocks allocated by the call. */ static daddr_t -blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, daddr_t radix, - daddr_t skip, daddr_t blk) +blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, u_daddr_t radix) { - daddr_t i, nblks, next_skip, v; + daddr_t blk, i, nblks, next_skip, skip, v; int child; if (scan->bm_bighint == (daddr_t)-1) @@ -760,7 +1030,9 @@ blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, daddr_t radix, scan->bm_bighint = 0; return (nblks); } + skip = radix_to_skip(radix); next_skip = skip / BLIST_META_RADIX; + blk = allocBlk & -radix; /* * An ALL-FREE meta node requires special handling before allocating @@ -773,7 +1045,7 @@ blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, daddr_t radix, * Reinitialize each of the meta node's children. An ALL-FREE * meta node cannot have a terminator in any subtree. */ - for (i = 1; i <= skip; i += next_skip) { + for (i = 1; i < skip; i += next_skip) { if (next_skip == 1) scan[i].u.bmu_bitmap = (u_daddr_t)-1; else @@ -788,12 +1060,11 @@ blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, daddr_t radix, child = (allocBlk - blk) / radix; blk += child * radix; i = 1 + child * next_skip; - while (i <= skip && blk < allocBlk + count) { + while (i < skip && blk < allocBlk + count) { v = blk + radix - allocBlk; if (v > count) v = count; - nblks += blst_meta_fill(&scan[i], allocBlk, v, radix, - next_skip - 1, blk); + nblks += blst_meta_fill(&scan[i], allocBlk, v, radix); count -= v; allocBlk += v; blk += radix; @@ -812,9 +1083,9 @@ blst_meta_fill(blmeta_t *scan, daddr_t allocBlk, daddr_t count, daddr_t radix, * RADIX values we use. */ static daddr_t -blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t skip, daddr_t count) +blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t count) { - daddr_t i, memindex, next_skip; + daddr_t i, memindex, next_skip, skip; memindex = 0; @@ -841,17 +1112,18 @@ blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t skip, daddr_t count) scan->u.bmu_avail = 0; } - radix /= BLIST_META_RADIX; + skip = radix_to_skip(radix); next_skip = skip / BLIST_META_RADIX; + radix /= BLIST_META_RADIX; - for (i = 1; i <= skip; i += next_skip) { + for (i = 1; i < skip; i += next_skip) { if (count >= radix) { /* * Allocate the entire object */ memindex = i + blst_radix_init(((scan) ? &scan[i] : NULL), radix, - next_skip - 1, radix); + radix); count -= radix; } else if (count > 0) { /* @@ -859,14 +1131,18 @@ blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t skip, daddr_t count) */ memindex = i + blst_radix_init(((scan) ? &scan[i] : NULL), radix, - next_skip - 1, count); + count); count = 0; } else { /* - * Add terminator and break out + * Add terminator and break out. Make terminator bitmap + * zero to avoid a spanning leaf allocation that + * includes the terminator. */ - if (scan) + if (scan) { scan[i].bm_bighint = (daddr_t)-1; + scan[i].u.bmu_bitmap = 0; + } break; } } @@ -878,10 +1154,9 @@ blst_radix_init(blmeta_t *scan, daddr_t radix, daddr_t skip, daddr_t count) #ifdef BLIST_DEBUG static void -blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip, - int tab) +blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, int tab) { - daddr_t i, next_skip; + daddr_t i, next_skip, skip; if (radix == BLIST_BMAP_RADIX) { printf( @@ -922,11 +1197,12 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip, (long long)scan->bm_bighint ); - radix /= BLIST_META_RADIX; + skip = radix_to_skip(radix); next_skip = skip / BLIST_META_RADIX; + radix /= BLIST_META_RADIX; tab += 4; - for (i = 1; i <= skip; i += next_skip) { + for (i = 1; i < skip; i += next_skip) { if (scan[i].bm_bighint == (daddr_t)-1) { printf( "%*.*s(%08llx,%lld): Terminator\n", @@ -935,7 +1211,7 @@ blst_radix_print(blmeta_t *scan, daddr_t blk, daddr_t radix, daddr_t skip, ); break; } - blst_radix_print(&scan[i], blk, radix, next_skip - 1, tab); + blst_radix_print(&scan[i], blk, radix, tab); blk += radix; } tab -= 4; @@ -956,6 +1232,7 @@ main(int ac, char **av) int size = 1024; int i; blist_t bl; + struct sbuf *s; for (i = 1; i < ac; ++i) { const char *ptr = av[i]; @@ -990,6 +1267,13 @@ main(int ac, char **av) case 'p': blist_print(bl); break; + case 's': + s = sbuf_new_auto(); + blist_stats(bl, s); + sbuf_finish(s); + printf("%s", sbuf_data(s)); + sbuf_delete(s); + break; case 'a': if (sscanf(buf + 1, "%lld", &count) == 1) { daddr_t blk = blist_alloc(bl, count); @@ -1017,6 +1301,7 @@ main(int ac, char **av) case 'h': puts( "p -print\n" + "s -stats\n" "a %d -allocate\n" "f %x %d -free\n" "l %x %d -fill\n" diff --git a/freebsd/sys/kern/subr_sbuf.c b/freebsd/sys/kern/subr_sbuf.c index 8dd11b07..951cb50c 100644 --- a/freebsd/sys/kern/subr_sbuf.c +++ b/freebsd/sys/kern/subr_sbuf.c @@ -75,6 +75,8 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) #define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION) #define SBUF_NULINCLUDED(s) ((s)->s_flags & SBUF_INCLUDENUL) +#define SBUF_ISDRAINTOEOR(s) ((s)->s_flags & SBUF_DRAINTOEOR) +#define SBUF_DODRAINTOEOR(s) (SBUF_ISSECTION(s) && SBUF_ISDRAINTOEOR(s)) /* * Set / clear flags @@ -310,6 +312,7 @@ sbuf_clear(struct sbuf *s) SBUF_CLEARFLAG(s, SBUF_FINISHED); s->s_error = 0; s->s_len = 0; + s->s_rec_off = 0; s->s_sect_len = 0; } @@ -364,14 +367,18 @@ sbuf_drain(struct sbuf *s) KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s)); KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s)); - len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len); - if (len < 0) { - s->s_error = -len; + if (SBUF_DODRAINTOEOR(s) && s->s_rec_off == 0) + return (s->s_error = EDEADLK); + len = s->s_drain_func(s->s_drain_arg, s->s_buf, + SBUF_DODRAINTOEOR(s) ? s->s_rec_off : s->s_len); + if (len <= 0) { + s->s_error = len ? -len : EDEADLK; return (s->s_error); } KASSERT(len > 0 && len <= s->s_len, ("Bad drain amount %d for sbuf %p", len, s)); s->s_len -= len; + s->s_rec_off -= len; /* * Fast path for the expected case where all the data was * drained. @@ -635,9 +642,9 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) break; /* Cannot print with the current available space. */ if (s->s_drain_func != NULL && s->s_len > 0) - error = sbuf_drain(s); - else - error = sbuf_extend(s, len - SBUF_FREESPACE(s)); + error = sbuf_drain(s); /* sbuf_drain() sets s_error. */ + else if (sbuf_extend(s, len - SBUF_FREESPACE(s)) != 0) + s->s_error = error = ENOMEM; } while (error == 0); /* @@ -654,8 +661,6 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) s->s_len += len; if (SBUF_ISSECTION(s)) s->s_sect_len += len; - if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) - s->s_error = ENOMEM; KASSERT(s->s_len < s->s_size, ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); @@ -837,6 +842,7 @@ sbuf_start_section(struct sbuf *s, ssize_t *old_lenp) ("s_sect_len != 0 when starting a section")); if (old_lenp != NULL) *old_lenp = -1; + s->s_rec_off = s->s_len; SBUF_SETFLAG(s, SBUF_INSECTION); } else { KASSERT(old_lenp != NULL, @@ -867,7 +873,7 @@ sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c) } len = s->s_sect_len; if (old_len == -1) { - s->s_sect_len = 0; + s->s_rec_off = s->s_sect_len = 0; SBUF_CLEARFLAG(s, SBUF_INSECTION); } else { s->s_sect_len += old_len; diff --git a/freebsd/sys/kern/sys_socket.c b/freebsd/sys/kern/sys_socket.c index 9dd458f1..b3c9c56d 100644 --- a/freebsd/sys/kern/sys_socket.c +++ b/freebsd/sys/kern/sys_socket.c @@ -976,11 +976,7 @@ sowakeup_aio(struct socket *so, struct sockbuf *sb) if (sb->sb_flags & SB_AIO_RUNNING) return; sb->sb_flags |= SB_AIO_RUNNING; - if (sb == &so->so_snd) - SOCK_LOCK(so); soref(so); - if (sb == &so->so_snd) - SOCK_UNLOCK(so); soaio_enqueue(&sb->sb_aiotask); } diff --git a/freebsd/sys/kern/uipc_sockbuf.c b/freebsd/sys/kern/uipc_sockbuf.c index 4b710a2c..4ec7187c 100644 --- a/freebsd/sys/kern/uipc_sockbuf.c +++ b/freebsd/sys/kern/uipc_sockbuf.c @@ -336,7 +336,7 @@ sowakeup(struct socket *so, struct sockbuf *sb) if (sb->sb_flags & SB_AIO) sowakeup_aio(so, sb); SOCKBUF_UNLOCK(sb); - if (ret == SU_ISCONNECTED && !(so->so_state & SS_ISDISCONNECTED)) + if (ret == SU_ISCONNECTED) soisconnected(so); if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) pgsigio(&so->so_sigio, SIGIO, 0); diff --git a/freebsd/sys/kern/uipc_socket.c b/freebsd/sys/kern/uipc_socket.c index 1773606d..5e4fda56 100644 --- a/freebsd/sys/kern/uipc_socket.c +++ b/freebsd/sys/kern/uipc_socket.c @@ -3744,24 +3744,41 @@ soisconnecting(struct socket *so) void soisconnected(struct socket *so) { - struct socket *head; - int ret; - /* - * XXXGL: this is the only place where we acquire socket locks - * in reverse order: first child, then listening socket. To - * avoid possible LOR, use try semantics. - */ -restart: SOCK_LOCK(so); - if ((head = so->so_listen) != NULL && - __predict_false(SOLISTEN_TRYLOCK(head) == 0)) { - SOCK_UNLOCK(so); - goto restart; - } so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); so->so_state |= SS_ISCONNECTED; - if (head != NULL && (so->so_qstate == SQ_INCOMP)) { + + if (so->so_qstate == SQ_INCOMP) { + struct socket *head = so->so_listen; + int ret; + + KASSERT(head, ("%s: so %p on incomp of NULL", __func__, so)); + /* + * Promoting a socket from incomplete queue to complete, we + * need to go through reverse order of locking. We first do + * trylock, and if that doesn't succeed, we go the hard way + * leaving a reference and rechecking consistency after proper + * locking. + */ + if (__predict_false(SOLISTEN_TRYLOCK(head) == 0)) { + soref(head); + SOCK_UNLOCK(so); + SOLISTEN_LOCK(head); + SOCK_LOCK(so); + if (__predict_false(head != so->so_listen)) { + /* + * The socket went off the listen queue, + * should be lost race to close(2) of sol. + * The socket is about to soabort(). + */ + SOCK_UNLOCK(so); + sorele(head); + return; + } + /* Not the last one, as so holds a ref. */ + refcount_release(&head->so_count); + } again: if ((so->so_options & SO_ACCEPTFILTER) == 0) { TAILQ_REMOVE(&head->sol_incomp, so, so_list); @@ -3790,8 +3807,6 @@ again: } return; } - if (head != NULL) - SOLISTEN_UNLOCK(head); SOCK_UNLOCK(so); wakeup(&so->so_timeo); sorwakeup(so); @@ -3825,13 +3840,14 @@ soisdisconnected(struct socket *so) so->so_state |= SS_ISDISCONNECTED; if (!SOLISTENING(so)) { + SOCK_UNLOCK(so); SOCKBUF_LOCK(&so->so_rcv); socantrcvmore_locked(so); SOCKBUF_LOCK(&so->so_snd); sbdrop_locked(&so->so_snd, sbused(&so->so_snd)); socantsendmore_locked(so); - } - SOCK_UNLOCK(so); + } else + SOCK_UNLOCK(so); wakeup(&so->so_timeo); } diff --git a/freebsd/sys/kern/uipc_usrreq.c b/freebsd/sys/kern/uipc_usrreq.c index 7237956a..702ba1e4 100644 --- a/freebsd/sys/kern/uipc_usrreq.c +++ b/freebsd/sys/kern/uipc_usrreq.c @@ -698,9 +698,9 @@ uipc_close(struct socket *so) { struct unpcb *unp, *unp2; #ifndef __rtems__ - struct vnode *vp; + struct vnode *vp = NULL; #else /* __rtems__ */ - IMFS_generic_t *vp; + IMFS_generic_t *vp = NULL; #endif /* __rtems__ */ unp = sotounpcb(so); @@ -1181,7 +1181,11 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, release: if (control != NULL) m_freem(control); - if (m != NULL) + /* + * In case of PRUS_NOTREADY, uipc_ready() is responsible + * for freeing memory. + */ + if (m != NULL && (flags & PRUS_NOTREADY) == 0) m_freem(m); return (error); } @@ -1196,7 +1200,12 @@ uipc_ready(struct socket *so, struct mbuf *m, int count) unp = sotounpcb(so); UNP_LINK_RLOCK(); - unp2 = unp->unp_conn; + if ((unp2 = unp->unp_conn) == NULL) { + UNP_LINK_RUNLOCK(); + for (int i = 0; i < count; i++) + m = m_free(m); + return (ECONNRESET); + } UNP_PCB_LOCK(unp2); so2 = unp2->unp_socket; diff --git a/freebsd/sys/libkern/crc32.c b/freebsd/sys/libkern/crc32.c index c987fb4d..f1f11e3b 100644 --- a/freebsd/sys/libkern/crc32.c +++ b/freebsd/sys/libkern/crc32.c @@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> + +#ifdef _KERNEL #include <sys/libkern.h> #include <sys/systm.h> @@ -59,6 +61,7 @@ __FBSDID("$FreeBSD$"); #if defined(__aarch64__) #include <machine/cpu.h> #endif +#endif /* _KERNEL */ const uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, @@ -761,6 +764,7 @@ calculate_crc32c(uint32_t crc32c, const unsigned char *buffer, unsigned int length) { +#ifdef _KERNEL #if defined(__amd64__) || defined(__i386__) if ((cpu_feature2 & CPUID2_SSE42) != 0) { return (sse42_crc32c(crc32c, buffer, length)); @@ -778,6 +782,7 @@ calculate_crc32c(uint32_t crc32c, return (armv8_crc32c(crc32c, buffer, length)); } else #endif +#endif /* _KERNEL */ if (length < 4) { return (singletable_crc32c(crc32c, buffer, length)); } else { diff --git a/freebsd/sys/mips/include/machine/cpufunc.h b/freebsd/sys/mips/include/machine/cpufunc.h index 5ebaf4cc..d4150edd 100644 --- a/freebsd/sys/mips/include/machine/cpufunc.h +++ b/freebsd/sys/mips/include/machine/cpufunc.h @@ -279,6 +279,15 @@ MIPS_RW32_COP0(entrylo1, MIPS_COP_0_TLB_LO1); MIPS_RW32_COP0(prid, MIPS_COP_0_PRID); /* XXX 64-bit? */ MIPS_RW32_COP0_SEL(ebase, MIPS_COP_0_PRID, 1); + +#if defined(CPU_MIPS24K) || defined(CPU_MIPS34K) || \ + defined(CPU_MIPS74K) || defined(CPU_MIPS1004K) || \ + defined(CPU_MIPS1074K) || defined(CPU_INTERAPTIV) || \ + defined(CPU_PROAPTIV) +/* MIPS32/64 r2 intctl */ +MIPS_RW32_COP0_SEL(intctl, MIPS_COP_0_INTCTL, 1); +#endif + #ifdef CPU_XBURST MIPS_RW32_COP0_SEL(xburst_mbox0, MIPS_COP_0_XBURST_MBOX, 0); MIPS_RW32_COP0_SEL(xburst_mbox1, MIPS_COP_0_XBURST_MBOX, 1); diff --git a/freebsd/sys/mips/include/machine/cpuregs.h b/freebsd/sys/mips/include/machine/cpuregs.h index b6f2433e..ca86a1c5 100644 --- a/freebsd/sys/mips/include/machine/cpuregs.h +++ b/freebsd/sys/mips/include/machine/cpuregs.h @@ -468,6 +468,7 @@ * 10 MIPS_COP_0_TLB_HI 3636 TLB entry high. * 11 MIPS_COP_0_COMPARE .333 Compare (against Count). * 12 MIPS_COP_0_STATUS 3333 Status register. + * 12/1 MIPS_COP_0_INTCTL ..33 Interrupt setup (MIPS32/64 r2). * 13 MIPS_COP_0_CAUSE 3333 Exception cause register. * 14 MIPS_COP_0_EXC_PC 3636 Exception PC. * 15 MIPS_COP_0_PRID 3333 Processor revision identifier. @@ -548,6 +549,7 @@ /* MIPS32/64 */ #define MIPS_COP_0_USERLOCAL _(4) /* sel 2 is userlevel register */ #define MIPS_COP_0_HWRENA _(7) +#define MIPS_COP_0_INTCTL _(12) #define MIPS_COP_0_DEBUG _(23) #define MIPS_COP_0_DEPC _(24) #define MIPS_COP_0_PERFCNT _(25) @@ -562,6 +564,16 @@ #define MIPS_MMU_FIXED 0x03 /* Standard fixed mapping */ /* + * IntCtl Register Fields + */ +#define MIPS_INTCTL_IPTI_MASK 0xE0000000 /* bits 31..29 timer intr # */ +#define MIPS_INTCTL_IPTI_SHIFT 29 +#define MIPS_INTCTL_IPPCI_MASK 0x1C000000 /* bits 26..29 perf counter intr # */ +#define MIPS_INTCTL_IPPCI_SHIFT 26 +#define MIPS_INTCTL_VS_MASK 0x000001F0 /* bits 5..9 vector spacing */ +#define MIPS_INTCTL_VS_SHIFT 4 + +/* * Config Register Fields * (See "MIPS Architecture for Programmers Volume III", MD00091, Table 9.39) */ diff --git a/freebsd/sys/net/bpf.c b/freebsd/sys/net/bpf.c index b0ecb039..cd8d34d7 100644 --- a/freebsd/sys/net/bpf.c +++ b/freebsd/sys/net/bpf.c @@ -113,6 +113,7 @@ struct bpf_if { struct rwlock bif_lock; /* interface lock */ LIST_HEAD(, bpf_d) bif_wlist; /* writer-only list */ int bif_flags; /* Interface flags */ + struct bpf_if **bif_bpf; /* Pointer to pointer to us */ }; CTASSERT(offsetof(struct bpf_if, bif_ext) == 0); @@ -2658,6 +2659,7 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) bp->bif_dlt = dlt; rw_init(&bp->bif_lock, "bpf interface lock"); KASSERT(*driverp == NULL, ("bpfattach2: driverp already initialized")); + bp->bif_bpf = driverp; *driverp = bp; BPF_LOCK(); @@ -2728,6 +2730,7 @@ bpfdetach(struct ifnet *ifp) */ BPFIF_WLOCK(bp); bp->bif_flags |= BPFIF_FLAG_DYING; + *bp->bif_bpf = NULL; BPFIF_WUNLOCK(bp); CTR4(KTR_NET, "%s: sheduling free for encap %d (%p) for if %p", @@ -2797,13 +2800,6 @@ bpf_ifdetach(void *arg __unused, struct ifnet *ifp) nmatched++; } BPF_UNLOCK(); - - /* - * Note that we cannot zero other pointers to - * custom DLTs possibly used by given interface. - */ - if (nmatched != 0) - ifp->if_bpf = NULL; } /* diff --git a/freebsd/sys/net/ieee8023ad_lacp.c b/freebsd/sys/net/ieee8023ad_lacp.c index fefe2a1f..d3fb457e 100644 --- a/freebsd/sys/net/ieee8023ad_lacp.c +++ b/freebsd/sys/net/ieee8023ad_lacp.c @@ -465,7 +465,11 @@ lacp_linkstate(struct lagg_port *lgp) uint16_t old_key; bzero((char *)&ifmr, sizeof(ifmr)); - error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); + error = (*ifp->if_ioctl)(ifp, SIOCGIFXMEDIA, (caddr_t)&ifmr); + if (error != 0) { + bzero((char *)&ifmr, sizeof(ifmr)); + error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); + } if (error != 0) return; diff --git a/freebsd/sys/net/if.c b/freebsd/sys/net/if.c index ecf9955a..00505706 100644 --- a/freebsd/sys/net/if.c +++ b/freebsd/sys/net/if.c @@ -2663,6 +2663,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) case SIOCGIFMEDIA: case SIOCGIFXMEDIA: case SIOCGIFGENERIC: + case SIOCGIFRSSKEY: + case SIOCGIFRSSHASH: if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); error = (*ifp->if_ioctl)(ifp, cmd, data); diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c index 5d258493..3499f3db 100644 --- a/freebsd/sys/net/if_bridge.c +++ b/freebsd/sys/net/if_bridge.c @@ -586,6 +586,7 @@ static moduledata_t bridge_mod = { }; DECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +MODULE_VERSION(if_bridge, 1); MODULE_DEPEND(if_bridge, bridgestp, 1, 1, 1); /* diff --git a/freebsd/sys/net/if_enc.c b/freebsd/sys/net/if_enc.c index 2a0b17d3..5fc53b5e 100644 --- a/freebsd/sys/net/if_enc.c +++ b/freebsd/sys/net/if_enc.c @@ -101,9 +101,15 @@ static void enc_remove_hhooks(struct enc_softc *); static const char encname[] = "enc"; +#define IPSEC_ENC_AFTER_PFIL 0x04 /* * Before and after are relative to when we are stripping the * outer IP header. + * + * AFTER_PFIL flag used only for bpf_mask_*. It enables BPF capturing + * after PFIL hook execution. It might be useful when PFIL hook does + * some changes to the packet, e.g. address translation. If PFIL hook + * consumes mbuf, nothing will be captured. */ static VNET_DEFINE(int, filter_mask_in) = IPSEC_ENC_BEFORE; static VNET_DEFINE(int, bpf_mask_in) = IPSEC_ENC_BEFORE; @@ -196,6 +202,30 @@ enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return (0); } +static void +enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav, + int32_t hhook_type, uint8_t enc, uint8_t af) +{ + struct enchdr hdr; + + if (hhook_type == HHOOK_TYPE_IPSEC_IN && + (enc & V_bpf_mask_in) == 0) + return; + else if (hhook_type == HHOOK_TYPE_IPSEC_OUT && + (enc & V_bpf_mask_out) == 0) + return; + if (bpf_peers_present(ifp->if_bpf) == 0) + return; + hdr.af = af; + hdr.spi = sav->spi; + hdr.flags = 0; + if (sav->alg_enc != SADB_EALG_NONE) + hdr.flags |= M_CONF; + if (sav->alg_auth != SADB_AALG_NONE) + hdr.flags |= M_AUTH; + bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m); +} + /* * One helper hook function is used by any hook points. * + from hhook_type we can determine the packet direction: @@ -208,7 +238,6 @@ static int enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, void *hdata, struct osd *hosd) { - struct enchdr hdr; struct ipsec_ctx_data *ctx; struct enc_softc *sc; struct ifnet *ifp, *rcvif; @@ -225,21 +254,7 @@ enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, if (ctx->af != hhook_id) return (EPFNOSUPPORT); - if (((hhook_type == HHOOK_TYPE_IPSEC_IN && - (ctx->enc & V_bpf_mask_in) != 0) || - (hhook_type == HHOOK_TYPE_IPSEC_OUT && - (ctx->enc & V_bpf_mask_out) != 0)) && - bpf_peers_present(ifp->if_bpf) != 0) { - hdr.af = ctx->af; - hdr.spi = ctx->sav->spi; - hdr.flags = 0; - if (ctx->sav->alg_enc != SADB_EALG_NONE) - hdr.flags |= M_CONF; - if (ctx->sav->alg_auth != SADB_AALG_NONE) - hdr.flags |= M_AUTH; - bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), *ctx->mp); - } - + enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, ctx->enc, ctx->af); switch (hhook_type) { case HHOOK_TYPE_IPSEC_IN: if (ctx->enc == IPSEC_ENC_BEFORE) { @@ -292,6 +307,8 @@ enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, return (EACCES); } (*ctx->mp)->m_pkthdr.rcvif = rcvif; + enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, + IPSEC_ENC_AFTER_PFIL, ctx->af); return (0); } diff --git a/freebsd/sys/net/if_var.h b/freebsd/sys/net/if_var.h index b8e5e5b8..c2de24a7 100644 --- a/freebsd/sys/net/if_var.h +++ b/freebsd/sys/net/if_var.h @@ -183,7 +183,8 @@ struct if_encap_req { struct m_snd_tag; #define IF_SND_TAG_TYPE_RATE_LIMIT 0 -#define IF_SND_TAG_TYPE_MAX 1 +#define IF_SND_TAG_TYPE_UNLIMITED 1 +#define IF_SND_TAG_TYPE_MAX 2 struct if_snd_tag_alloc_header { uint32_t type; /* send tag type, see IF_SND_TAG_XXX */ @@ -198,19 +199,26 @@ struct if_snd_tag_alloc_rate_limit { struct if_snd_tag_rate_limit_params { uint64_t max_rate; /* in bytes/s */ + uint32_t queue_level; /* 0 (empty) .. 65535 (full) */ +#define IF_SND_QUEUE_LEVEL_MIN 0 +#define IF_SND_QUEUE_LEVEL_MAX 65535 + uint32_t reserved; /* padding */ }; union if_snd_tag_alloc_params { struct if_snd_tag_alloc_header hdr; struct if_snd_tag_alloc_rate_limit rate_limit; + struct if_snd_tag_alloc_rate_limit unlimited; }; union if_snd_tag_modify_params { struct if_snd_tag_rate_limit_params rate_limit; + struct if_snd_tag_rate_limit_params unlimited; }; union if_snd_tag_query_params { struct if_snd_tag_rate_limit_params rate_limit; + struct if_snd_tag_rate_limit_params unlimited; }; typedef int (if_snd_tag_alloc_t)(struct ifnet *, union if_snd_tag_alloc_params *, diff --git a/freebsd/sys/net/if_vlan.c b/freebsd/sys/net/if_vlan.c index daba2606..872b07ad 100644 --- a/freebsd/sys/net/if_vlan.c +++ b/freebsd/sys/net/if_vlan.c @@ -3,6 +3,7 @@ /*- * Copyright 1998 Massachusetts Institute of Technology * Copyright 2012 ADARA Networks, Inc. + * Copyright 2017 Dell EMC Isilon * * Portions of this software were developed by Robert N. M. Watson under * contract to ADARA Networks, Inc. @@ -65,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/systm.h> #include <sys/sx.h> +#include <sys/taskqueue.h> #include <net/bpf.h> #include <net/ethernet.h> @@ -103,6 +105,53 @@ struct ifvlantrunk { int refcnt; }; +/* + * This macro provides a facility to iterate over every vlan on a trunk with + * the assumption that none will be added/removed during iteration. + */ +#ifdef VLAN_ARRAY +#define VLAN_FOREACH(_ifv, _trunk) \ + size_t _i; \ + for (_i = 0; _i < VLAN_ARRAY_SIZE; _i++) \ + if (((_ifv) = (_trunk)->vlans[_i]) != NULL) +#else /* VLAN_ARRAY */ +#define VLAN_FOREACH(_ifv, _trunk) \ + struct ifvlan *_next; \ + size_t _i; \ + for (_i = 0; _i < (1 << (_trunk)->hwidth); _i++) \ + LIST_FOREACH_SAFE((_ifv), &(_trunk)->hash[_i], ifv_list, _next) +#endif /* VLAN_ARRAY */ + +/* + * This macro provides a facility to iterate over every vlan on a trunk while + * also modifying the number of vlans on the trunk. The iteration continues + * until some condition is met or there are no more vlans on the trunk. + */ +#ifdef VLAN_ARRAY +/* The VLAN_ARRAY case is simple -- just a for loop using the condition. */ +#define VLAN_FOREACH_UNTIL_SAFE(_ifv, _trunk, _cond) \ + size_t _i; \ + for (_i = 0; !(_cond) && _i < VLAN_ARRAY_SIZE; _i++) \ + if (((_ifv) = (_trunk)->vlans[_i])) +#else /* VLAN_ARRAY */ +/* + * The hash table case is more complicated. We allow for the hash table to be + * modified (i.e. vlans removed) while we are iterating over it. To allow for + * this we must restart the iteration every time we "touch" something during + * the iteration, since removal will resize the hash table and invalidate our + * current position. If acting on the touched element causes the trunk to be + * emptied, then iteration also stops. + */ +#define VLAN_FOREACH_UNTIL_SAFE(_ifv, _trunk, _cond) \ + size_t _i; \ + bool _touch = false; \ + for (_i = 0; \ + !(_cond) && _i < (1 << (_trunk)->hwidth); \ + _i = (_touch && ((_trunk) != NULL) ? 0 : _i + 1), _touch = false) \ + if (((_ifv) = LIST_FIRST(&(_trunk)->hash[_i])) != NULL && \ + (_touch = true)) +#endif /* VLAN_ARRAY */ + struct vlan_mc_entry { struct sockaddr_dl mc_addr; SLIST_ENTRY(vlan_mc_entry) mc_entries; @@ -125,6 +174,7 @@ struct ifvlan { uint16_t ifvm_vid; /* VLAN ID */ uint8_t ifvm_pcp; /* Priority Code Point (PCP). */ } ifv_mib; + struct task lladdr_task; SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; #ifndef VLAN_ARRAY LIST_ENTRY(ifvlan) ifv_list; @@ -175,33 +225,92 @@ static eventhandler_tag ifdetach_tag; static eventhandler_tag iflladdr_tag; /* - * We have a global mutex, that is used to serialize configuration - * changes and isn't used in normal packet delivery. + * if_vlan uses two module-level locks to allow concurrent modification of vlan + * interfaces and (mostly) allow for vlans to be destroyed while they are being + * used for tx/rx. To accomplish this in a way that has acceptable performance + * and cooperation with other parts of the network stack there is a + * non-sleepable rmlock(9) and an sx(9). Both locks are exclusively acquired + * when destroying a vlan interface, i.e. when the if_vlantrunk field of struct + * ifnet is de-allocated and NULL'd. Thus a reader holding either lock has a + * guarantee that the struct ifvlantrunk references a valid vlan trunk. * - * We also have a per-trunk rmlock(9), that is locked shared on packet - * processing and exclusive when configuration is changed. + * The performance-sensitive paths that warrant using the rmlock(9) are + * vlan_transmit and vlan_input. Both have to check for the vlan interface's + * existence using if_vlantrunk, and being in the network tx/rx paths the use + * of an rmlock(9) gives a measureable improvement in performance. + * + * The reason for having an sx(9) is mostly because there are still areas that + * must be sleepable and also have safe concurrent access to a vlan interface. + * Since the sx(9) exists, it is used by default in most paths unless sleeping + * is not permitted, or if it is not clear whether sleeping is permitted. * + * Note that despite these protections, there is still an inherent race in the + * destruction of vlans since there's no guarantee that the ifnet hasn't been + * freed/reused when the tx/rx functions are called by the stack. This can only + * be fixed by addressing ifnet's lifetime issues. + */ +#define _VLAN_RM_ID ifv_rm_lock +#define _VLAN_SX_ID ifv_sx + +static struct rmlock _VLAN_RM_ID; +static struct sx _VLAN_SX_ID; + +#define VLAN_LOCKING_INIT() \ + rm_init(&_VLAN_RM_ID, "vlan_rm"); \ + sx_init(&_VLAN_SX_ID, "vlan_sx") + +#define VLAN_LOCKING_DESTROY() \ + rm_destroy(&_VLAN_RM_ID); \ + sx_destroy(&_VLAN_SX_ID) + +#define _VLAN_RM_TRACKER _vlan_rm_tracker +#define VLAN_RLOCK() rm_rlock(&_VLAN_RM_ID, \ + &_VLAN_RM_TRACKER) +#define VLAN_RUNLOCK() rm_runlock(&_VLAN_RM_ID, \ + &_VLAN_RM_TRACKER) +#define VLAN_WLOCK() rm_wlock(&_VLAN_RM_ID) +#define VLAN_WUNLOCK() rm_wunlock(&_VLAN_RM_ID) +#define VLAN_RLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_RLOCKED) +#define VLAN_WLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_WLOCKED) +#define VLAN_RWLOCK_ASSERT() rm_assert(&_VLAN_RM_ID, RA_LOCKED) +#define VLAN_LOCK_READER struct rm_priotracker _VLAN_RM_TRACKER + +#define VLAN_SLOCK() sx_slock(&_VLAN_SX_ID) +#define VLAN_SUNLOCK() sx_sunlock(&_VLAN_SX_ID) +#define VLAN_XLOCK() sx_xlock(&_VLAN_SX_ID) +#define VLAN_XUNLOCK() sx_xunlock(&_VLAN_SX_ID) +#define VLAN_SLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_SLOCKED) +#define VLAN_XLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_XLOCKED) +#define VLAN_SXLOCK_ASSERT() sx_assert(&_VLAN_SX_ID, SA_LOCKED) + + +/* + * We also have a per-trunk rmlock(9), that is locked shared on packet + * processing and exclusive when configuration is changed. Note: This should + * only be acquired while there is a shared lock on either of the global locks + * via VLAN_SLOCK or VLAN_RLOCK. Thus, an exclusive lock on the global locks + * makes a call to TRUNK_RLOCK/TRUNK_WLOCK technically superfluous. + */ +#define _TRUNK_RM_TRACKER _trunk_rm_tracker +#define TRUNK_LOCK_INIT(trunk) rm_init(&(trunk)->lock, vlanname) +#define TRUNK_LOCK_DESTROY(trunk) rm_destroy(&(trunk)->lock) +#define TRUNK_RLOCK(trunk) rm_rlock(&(trunk)->lock, \ + &_TRUNK_RM_TRACKER) +#define TRUNK_WLOCK(trunk) rm_wlock(&(trunk)->lock) +#define TRUNK_RUNLOCK(trunk) rm_runlock(&(trunk)->lock, \ + &_TRUNK_RM_TRACKER) +#define TRUNK_WUNLOCK(trunk) rm_wunlock(&(trunk)->lock) +#define TRUNK_RLOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_RLOCKED) +#define TRUNK_LOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_LOCKED) +#define TRUNK_WLOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_WLOCKED) +#define TRUNK_LOCK_READER struct rm_priotracker _TRUNK_RM_TRACKER + +/* * The VLAN_ARRAY substitutes the dynamic hash with a static array * with 4096 entries. In theory this can give a boost in processing, - * however on practice it does not. Probably this is because array + * however in practice it does not. Probably this is because the array * is too big to fit into CPU cache. */ -static struct sx ifv_lock; -#define VLAN_LOCK_INIT() sx_init(&ifv_lock, "vlan_global") -#define VLAN_LOCK_DESTROY() sx_destroy(&ifv_lock) -#define VLAN_LOCK_ASSERT() sx_assert(&ifv_lock, SA_LOCKED) -#define VLAN_LOCK() sx_xlock(&ifv_lock) -#define VLAN_UNLOCK() sx_xunlock(&ifv_lock) -#define TRUNK_LOCK_INIT(trunk) rm_init(&(trunk)->lock, vlanname) -#define TRUNK_LOCK_DESTROY(trunk) rm_destroy(&(trunk)->lock) -#define TRUNK_LOCK(trunk) rm_wlock(&(trunk)->lock) -#define TRUNK_UNLOCK(trunk) rm_wunlock(&(trunk)->lock) -#define TRUNK_LOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_WLOCKED) -#define TRUNK_RLOCK(trunk) rm_rlock(&(trunk)->lock, &tracker) -#define TRUNK_RUNLOCK(trunk) rm_runlock(&(trunk)->lock, &tracker) -#define TRUNK_LOCK_RASSERT(trunk) rm_assert(&(trunk)->lock, RA_RLOCKED) -#define TRUNK_LOCK_READER struct rm_priotracker tracker - #ifndef VLAN_ARRAY static void vlan_inithash(struct ifvlantrunk *trunk); static void vlan_freehash(struct ifvlantrunk *trunk); @@ -241,6 +350,8 @@ static int vlan_clone_destroy(struct if_clone *, struct ifnet *); static void vlan_ifdetach(void *arg, struct ifnet *ifp); static void vlan_iflladdr(void *arg, struct ifnet *ifp); +static void vlan_lladdr_fn(void *arg, int pending); + static struct if_clone *vlan_cloner; #ifdef VIMAGE @@ -295,7 +406,7 @@ vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv) int i, b; struct ifvlan *ifv2; - TRUNK_LOCK_ASSERT(trunk); + TRUNK_WLOCK_ASSERT(trunk); KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); b = 1 << trunk->hwidth; @@ -325,7 +436,7 @@ vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv) int i, b; struct ifvlan *ifv2; - TRUNK_LOCK_ASSERT(trunk); + TRUNK_WLOCK_ASSERT(trunk); KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); b = 1 << trunk->hwidth; @@ -353,7 +464,7 @@ vlan_growhash(struct ifvlantrunk *trunk, int howmuch) struct ifvlanhead *hash2; int hwidth2, i, j, n, n2; - TRUNK_LOCK_ASSERT(trunk); + TRUNK_WLOCK_ASSERT(trunk); KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); if (howmuch == 0) { @@ -399,7 +510,7 @@ vlan_gethash(struct ifvlantrunk *trunk, uint16_t vid) { struct ifvlan *ifv; - TRUNK_LOCK_RASSERT(trunk); + TRUNK_RLOCK_ASSERT(trunk); LIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)], ifv_list) if (ifv->ifv_vid == vid) @@ -469,12 +580,11 @@ vlan_inithash(struct ifvlantrunk *trunk) static void trunk_destroy(struct ifvlantrunk *trunk) { - VLAN_LOCK_ASSERT(); + VLAN_XLOCK_ASSERT(); + VLAN_WLOCK_ASSERT(); - TRUNK_LOCK(trunk); vlan_freehash(trunk); trunk->parent->if_vlantrunk = NULL; - TRUNK_UNLOCK(trunk); TRUNK_LOCK_DESTROY(trunk); if_rele(trunk->parent); free(trunk, M_VLAN); @@ -497,9 +607,15 @@ vlan_setmulti(struct ifnet *ifp) struct vlan_mc_entry *mc; int error; + /* + * XXX This stupidly needs the rmlock to avoid sleeping while holding + * the in6_multi_mtx (see in6_mc_join_locked). + */ + VLAN_RWLOCK_ASSERT(); + /* Find the parent. */ sc = ifp->if_softc; - TRUNK_LOCK_ASSERT(TRUNK(sc)); + TRUNK_WLOCK_ASSERT(TRUNK(sc)); ifp_p = PARENT(sc); CURVNET_SET_QUIET(ifp_p->if_vnet); @@ -546,36 +662,42 @@ static void vlan_iflladdr(void *arg __unused, struct ifnet *ifp) { struct ifvlan *ifv; -#ifndef VLAN_ARRAY - struct ifvlan *next; -#endif - int i; + struct ifnet *ifv_ifp; + struct ifvlantrunk *trunk; + struct sockaddr_dl *sdl; + VLAN_LOCK_READER; - /* - * Check if it's a trunk interface first of all - * to avoid needless locking. - */ - if (ifp->if_vlantrunk == NULL) + /* Need the rmlock since this is run on taskqueue_swi. */ + VLAN_RLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_RUNLOCK(); return; + } - VLAN_LOCK(); /* * OK, it's a trunk. Loop over and change all vlan's lladdrs on it. + * We need an exclusive lock here to prevent concurrent SIOCSIFLLADDR + * ioctl calls on the parent garbling the lladdr of the child vlan. */ -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if ((ifv = ifp->if_vlantrunk->vlans[i])) { -#else /* VLAN_ARRAY */ - for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++) - LIST_FOREACH_SAFE(ifv, &ifp->if_vlantrunk->hash[i], ifv_list, next) { -#endif /* VLAN_ARRAY */ - VLAN_UNLOCK(); - if_setlladdr(ifv->ifv_ifp, IF_LLADDR(ifp), - ifp->if_addrlen); - VLAN_LOCK(); - } - VLAN_UNLOCK(); - + TRUNK_WLOCK(trunk); + VLAN_FOREACH(ifv, trunk) { + /* + * Copy new new lladdr into the ifv_ifp, enqueue a task + * to actually call if_setlladdr. if_setlladdr needs to + * be deferred to a taskqueue because it will call into + * the if_vlan ioctl path and try to acquire the global + * lock. + */ + ifv_ifp = ifv->ifv_ifp; + bcopy(IF_LLADDR(ifp), IF_LLADDR(ifv_ifp), + ifp->if_addrlen); + sdl = (struct sockaddr_dl *)ifv_ifp->if_addr->ifa_addr; + sdl->sdl_alen = ifp->if_addrlen; + taskqueue_enqueue(taskqueue_thread, &ifv->lladdr_task); + } + TRUNK_WUNLOCK(trunk); + VLAN_RUNLOCK(); } /* @@ -589,46 +711,30 @@ static void vlan_ifdetach(void *arg __unused, struct ifnet *ifp) { struct ifvlan *ifv; - int i; - - /* - * Check if it's a trunk interface first of all - * to avoid needless locking. - */ - if (ifp->if_vlantrunk == NULL) - return; + struct ifvlantrunk *trunk; /* If the ifnet is just being renamed, don't do anything. */ if (ifp->if_flags & IFF_RENAMING) return; + VLAN_XLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_XUNLOCK(); + return; + } - VLAN_LOCK(); /* * OK, it's a trunk. Loop over and detach all vlan's on it. * Check trunk pointer after each vlan_unconfig() as it will * free it and set to NULL after the last vlan was detached. */ -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if ((ifv = ifp->if_vlantrunk->vlans[i])) { - vlan_unconfig_locked(ifv->ifv_ifp, 1); - if (ifp->if_vlantrunk == NULL) - break; - } -#else /* VLAN_ARRAY */ -restart: - for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++) - if ((ifv = LIST_FIRST(&ifp->if_vlantrunk->hash[i]))) { - vlan_unconfig_locked(ifv->ifv_ifp, 1); - if (ifp->if_vlantrunk) - goto restart; /* trunk->hwidth can change */ - else - break; - } -#endif /* VLAN_ARRAY */ + VLAN_FOREACH_UNTIL_SAFE(ifv, ifp->if_vlantrunk, + ifp->if_vlantrunk == NULL) + vlan_unconfig_locked(ifv->ifv_ifp, 1); + /* Trunk should have been destroyed in vlan_unconfig(). */ KASSERT(ifp->if_vlantrunk == NULL, ("%s: purge failed", __func__)); - VLAN_UNLOCK(); + VLAN_XUNLOCK(); } /* @@ -638,15 +744,18 @@ static struct ifnet * vlan_trunkdev(struct ifnet *ifp) { struct ifvlan *ifv; + VLAN_LOCK_READER; if (ifp->if_type != IFT_L2VLAN) return (NULL); + + /* Not clear if callers are sleepable, so acquire the rmlock. */ + VLAN_RLOCK(); ifv = ifp->if_softc; ifp = NULL; - VLAN_LOCK(); if (ifv->ifv_trunk) ifp = PARENT(ifv); - VLAN_UNLOCK(); + VLAN_RUNLOCK(); return (ifp); } @@ -708,17 +817,23 @@ vlan_devat(struct ifnet *ifp, uint16_t vid) { struct ifvlantrunk *trunk; struct ifvlan *ifv; + VLAN_LOCK_READER; TRUNK_LOCK_READER; + /* Not clear if callers are sleepable, so acquire the rmlock. */ + VLAN_RLOCK(); trunk = ifp->if_vlantrunk; - if (trunk == NULL) + if (trunk == NULL) { + VLAN_RUNLOCK(); return (NULL); + } ifp = NULL; TRUNK_RLOCK(trunk); ifv = vlan_gethash(trunk, vid); if (ifv) ifp = ifv->ifv_ifp; TRUNK_RUNLOCK(trunk); + VLAN_RUNLOCK(); return (ifp); } @@ -758,7 +873,7 @@ vlan_modevent(module_t mod, int type, void *data) vlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY); if (iflladdr_tag == NULL) return (ENOMEM); - VLAN_LOCK_INIT(); + VLAN_LOCKING_INIT(); vlan_input_p = vlan_input; vlan_link_state_p = vlan_link_state; vlan_trunk_cap_p = vlan_trunk_capabilities; @@ -795,7 +910,7 @@ vlan_modevent(module_t mod, int type, void *data) vlan_cookie_p = NULL; vlan_setcookie_p = NULL; vlan_devat_p = NULL; - VLAN_LOCK_DESTROY(); + VLAN_LOCKING_DESTROY(); if (bootverbose) printf("vlan: unloaded\n"); break; @@ -1016,9 +1131,6 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) return (error); } - - /* Update flags on the parent, if necessary. */ - vlan_setflags(ifp, 1); } return (0); @@ -1032,6 +1144,12 @@ vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) ether_ifdetach(ifp); /* first, remove it from system-wide lists */ vlan_unconfig(ifp); /* now it can be unconfigured and freed */ + /* + * We should have the only reference to the ifv now, so we can now + * drain any remaining lladdr task before freeing the ifnet and the + * ifvlan. + */ + taskqueue_drain(taskqueue_thread, &ifv->lladdr_task); if_free(ifp); free(ifv, M_VLAN); ifc_free_unit(ifc, unit); @@ -1058,8 +1176,16 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) struct m_tag *mtag; uint16_t tag; int error, len, mcast; + VLAN_LOCK_READER; + VLAN_RLOCK(); ifv = ifp->if_softc; + if (TRUNK(ifv) == NULL) { + if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); + m_freem(m); + return (ENETDOWN); + } p = PARENT(ifv); len = m->m_pkthdr.len; mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0; @@ -1071,8 +1197,9 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) * or parent's driver will cause a system crash. */ if (!UP_AND_RUNNING(p)) { - m_freem(m); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); + m_freem(m); return (ENETDOWN); } @@ -1100,6 +1227,7 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) if (n > 0) { if_printf(ifp, "cannot pad short frame\n"); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); m_freem(m); return (0); } @@ -1125,6 +1253,7 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) if (m == NULL) { if_printf(ifp, "unable to prepend VLAN header\n"); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); return (0); } } @@ -1139,6 +1268,7 @@ vlan_transmit(struct ifnet *ifp, struct mbuf *m) if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast); } else if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + VLAN_RUNLOCK(); return (error); } @@ -1153,13 +1283,20 @@ vlan_qflush(struct ifnet *ifp __unused) static void vlan_input(struct ifnet *ifp, struct mbuf *m) { - struct ifvlantrunk *trunk = ifp->if_vlantrunk; + struct ifvlantrunk *trunk; struct ifvlan *ifv; + VLAN_LOCK_READER; TRUNK_LOCK_READER; struct m_tag *mtag; uint16_t vid, tag; - KASSERT(trunk != NULL, ("%s: no trunk", __func__)); + VLAN_RLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_RUNLOCK(); + m_freem(m); + return; + } if (m->m_flags & M_VLANTAG) { /* @@ -1179,6 +1316,7 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) if (m->m_len < sizeof(*evl) && (m = m_pullup(m, sizeof(*evl))) == NULL) { if_printf(ifp, "cannot pullup VLAN header\n"); + VLAN_RUNLOCK(); return; } evl = mtod(m, struct ether_vlan_header *); @@ -1200,8 +1338,9 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) panic("%s: %s has unsupported if_type %u", __func__, ifp->if_xname, ifp->if_type); #endif - m_freem(m); if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); + VLAN_RUNLOCK(); + m_freem(m); return; } } @@ -1212,8 +1351,9 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) ifv = vlan_gethash(trunk, vid); if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) { TRUNK_RUNLOCK(trunk); - m_freem(m); if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); + VLAN_RUNLOCK(); + m_freem(m); return; } TRUNK_RUNLOCK(trunk); @@ -1231,8 +1371,9 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_IN, sizeof(uint8_t), M_NOWAIT); if (mtag == NULL) { - m_freem(m); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + VLAN_RUNLOCK(); + m_freem(m); return; } m_tag_prepend(m, mtag); @@ -1242,9 +1383,22 @@ vlan_input(struct ifnet *ifp, struct mbuf *m) m->m_pkthdr.rcvif = ifv->ifv_ifp; if_inc_counter(ifv->ifv_ifp, IFCOUNTER_IPACKETS, 1); + VLAN_RUNLOCK(); /* Pass it back through the parent's input routine. */ - (*ifp->if_input)(ifv->ifv_ifp, m); + (*ifv->ifv_ifp->if_input)(ifv->ifv_ifp, m); +} + +static void +vlan_lladdr_fn(void *arg, int pending __unused) +{ + struct ifvlan *ifv; + struct ifnet *ifp; + + ifv = (struct ifvlan *)arg; + ifp = ifv->ifv_ifp; + /* The ifv_ifp already has the lladdr copied in. */ + if_setlladdr(ifp, IF_LLADDR(ifp), ifp->if_addrlen); } static int @@ -1273,27 +1427,22 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid) if (ifv->ifv_trunk) return (EBUSY); + /* Acquire rmlock after the branch so we can M_WAITOK. */ + VLAN_XLOCK(); if (p->if_vlantrunk == NULL) { trunk = malloc(sizeof(struct ifvlantrunk), M_VLAN, M_WAITOK | M_ZERO); vlan_inithash(trunk); - VLAN_LOCK(); - if (p->if_vlantrunk != NULL) { - /* A race that is very unlikely to be hit. */ - vlan_freehash(trunk); - free(trunk, M_VLAN); - goto exists; - } TRUNK_LOCK_INIT(trunk); - TRUNK_LOCK(trunk); + VLAN_WLOCK(); + TRUNK_WLOCK(trunk); p->if_vlantrunk = trunk; trunk->parent = p; if_ref(trunk->parent); } else { - VLAN_LOCK(); -exists: + VLAN_WLOCK(); trunk = p->if_vlantrunk; - TRUNK_LOCK(trunk); + TRUNK_WLOCK(trunk); } ifv->ifv_vid = vid; /* must set this before vlan_inshash() */ @@ -1370,15 +1519,25 @@ exists: * Configure multicast addresses that may already be * joined on the vlan device. */ - (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */ + (void)vlan_setmulti(ifp); + + TASK_INIT(&ifv->lladdr_task, 0, vlan_lladdr_fn, ifv); /* We are ready for operation now. */ ifp->if_drv_flags |= IFF_DRV_RUNNING; + + /* Update flags on the parent, if necessary. */ + vlan_setflags(ifp, 1); done: - TRUNK_UNLOCK(trunk); + /* + * We need to drop the non-sleepable rmlock so that the underlying + * devices can sleep in their vlan_config hooks. + */ + TRUNK_WUNLOCK(trunk); + VLAN_WUNLOCK(); if (error == 0) EVENTHANDLER_INVOKE(vlan_config, p, ifv->ifv_vid); - VLAN_UNLOCK(); + VLAN_XUNLOCK(); return (error); } @@ -1387,9 +1546,9 @@ static void vlan_unconfig(struct ifnet *ifp) { - VLAN_LOCK(); + VLAN_XLOCK(); vlan_unconfig_locked(ifp, 0); - VLAN_UNLOCK(); + VLAN_XUNLOCK(); } static void @@ -1401,15 +1560,20 @@ vlan_unconfig_locked(struct ifnet *ifp, int departing) struct ifnet *parent; int error; - VLAN_LOCK_ASSERT(); + VLAN_XLOCK_ASSERT(); ifv = ifp->if_softc; trunk = ifv->ifv_trunk; parent = NULL; if (trunk != NULL) { - - TRUNK_LOCK(trunk); + /* + * Both vlan_transmit and vlan_input rely on the trunk fields + * being NULL to determine whether to bail, so we need to get + * an exclusive lock here to prevent them from using bad + * ifvlans. + */ + VLAN_WLOCK(); parent = trunk->parent; /* @@ -1439,7 +1603,14 @@ vlan_unconfig_locked(struct ifnet *ifp, int departing) } vlan_setflags(ifp, 0); /* clear special flags on parent */ + + /* + * The trunk lock isn't actually required here, but + * vlan_remhash expects it. + */ + TRUNK_WLOCK(trunk); vlan_remhash(trunk, ifv); + TRUNK_WUNLOCK(trunk); ifv->ifv_trunk = NULL; /* @@ -1447,17 +1618,9 @@ vlan_unconfig_locked(struct ifnet *ifp, int departing) */ if (trunk->refcnt == 0) { parent->if_vlantrunk = NULL; - /* - * XXXGL: If some ithread has already entered - * vlan_input() and is now blocked on the trunk - * lock, then it should preempt us right after - * unlock and finish its work. Then we will acquire - * lock again in trunk_destroy(). - */ - TRUNK_UNLOCK(trunk); trunk_destroy(trunk); - } else - TRUNK_UNLOCK(trunk); + } + VLAN_WUNLOCK(); } /* Disconnect from parent. */ @@ -1484,7 +1647,7 @@ vlan_setflag(struct ifnet *ifp, int flag, int status, struct ifvlan *ifv; int error; - /* XXX VLAN_LOCK_ASSERT(); */ + VLAN_SXLOCK_ASSERT(); ifv = ifp->if_softc; status = status ? (ifp->if_flags & flag) : 0; @@ -1532,36 +1695,41 @@ vlan_setflags(struct ifnet *ifp, int status) static void vlan_link_state(struct ifnet *ifp) { - struct ifvlantrunk *trunk = ifp->if_vlantrunk; + struct ifvlantrunk *trunk; struct ifvlan *ifv; - int i; + VLAN_LOCK_READER; - TRUNK_LOCK(trunk); -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if (trunk->vlans[i] != NULL) { - ifv = trunk->vlans[i]; -#else - for (i = 0; i < (1 << trunk->hwidth); i++) - LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) { -#endif - ifv->ifv_ifp->if_baudrate = trunk->parent->if_baudrate; - if_link_state_change(ifv->ifv_ifp, - trunk->parent->if_link_state); - } - TRUNK_UNLOCK(trunk); + /* Called from a taskqueue_swi task, so we cannot sleep. */ + VLAN_RLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_RUNLOCK(); + return; + } + + TRUNK_WLOCK(trunk); + VLAN_FOREACH(ifv, trunk) { + ifv->ifv_ifp->if_baudrate = trunk->parent->if_baudrate; + if_link_state_change(ifv->ifv_ifp, + trunk->parent->if_link_state); + } + TRUNK_WUNLOCK(trunk); + VLAN_RUNLOCK(); } static void vlan_capabilities(struct ifvlan *ifv) { - struct ifnet *p = PARENT(ifv); - struct ifnet *ifp = ifv->ifv_ifp; + struct ifnet *p; + struct ifnet *ifp; struct ifnet_hw_tsomax hw_tsomax; int cap = 0, ena = 0, mena; u_long hwa = 0; - TRUNK_LOCK_ASSERT(TRUNK(ifv)); + VLAN_SXLOCK_ASSERT(); + TRUNK_WLOCK_ASSERT(TRUNK(ifv)); + p = PARENT(ifv); + ifp = ifv->ifv_ifp; /* Mask parent interface enabled capabilities disabled by user. */ mena = p->if_capenable & ifv->ifv_capenable; @@ -1651,22 +1819,21 @@ vlan_capabilities(struct ifvlan *ifv) static void vlan_trunk_capabilities(struct ifnet *ifp) { - struct ifvlantrunk *trunk = ifp->if_vlantrunk; + struct ifvlantrunk *trunk; struct ifvlan *ifv; - int i; - TRUNK_LOCK(trunk); -#ifdef VLAN_ARRAY - for (i = 0; i < VLAN_ARRAY_SIZE; i++) - if (trunk->vlans[i] != NULL) { - ifv = trunk->vlans[i]; -#else - for (i = 0; i < (1 << trunk->hwidth); i++) { - LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) -#endif - vlan_capabilities(ifv); + VLAN_SLOCK(); + trunk = ifp->if_vlantrunk; + if (trunk == NULL) { + VLAN_SUNLOCK(); + return; + } + TRUNK_WLOCK(trunk); + VLAN_FOREACH(ifv, trunk) { + vlan_capabilities(ifv); } - TRUNK_UNLOCK(trunk); + TRUNK_WUNLOCK(trunk); + VLAN_SUNLOCK(); } static int @@ -1679,6 +1846,7 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ifvlantrunk *trunk; struct vlanreq vlr; int error = 0; + VLAN_LOCK_READER; ifr = (struct ifreq *)data; ifa = (struct ifaddr *) data; @@ -1701,11 +1869,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } break; case SIOCGIFMEDIA: - VLAN_LOCK(); + VLAN_SLOCK(); if (TRUNK(ifv) != NULL) { p = PARENT(ifv); if_ref(p); - VLAN_UNLOCK(); error = (*p->if_ioctl)(p, SIOCGIFMEDIA, data); if_rele(p); /* Limit the result to the parent's current config. */ @@ -1721,9 +1888,9 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } } } else { - VLAN_UNLOCK(); error = EINVAL; } + VLAN_SUNLOCK(); break; case SIOCSIFMEDIA: @@ -1734,8 +1901,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) /* * Set the interface MTU. */ - VLAN_LOCK(); - if (TRUNK(ifv) != NULL) { + VLAN_SLOCK(); + trunk = TRUNK(ifv); + if (trunk != NULL) { + TRUNK_WLOCK(trunk); if (ifr->ifr_mtu > (PARENT(ifv)->if_mtu - ifv->ifv_mtufudge) || ifr->ifr_mtu < @@ -1743,9 +1912,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = EINVAL; else ifp->if_mtu = ifr->ifr_mtu; + TRUNK_WUNLOCK(trunk); } else error = EINVAL; - VLAN_UNLOCK(); + VLAN_SUNLOCK(); break; case SIOCSETVLAN: @@ -1776,11 +1946,6 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } error = vlan_config(ifv, p, vlr.vlr_tag); if_rele(p); - if (error) - break; - - /* Update flags on the parent, if necessary. */ - vlan_setflags(ifp, 1); break; case SIOCGETVLAN: @@ -1791,13 +1956,13 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } #endif bzero(&vlr, sizeof(vlr)); - VLAN_LOCK(); + VLAN_SLOCK(); if (TRUNK(ifv) != NULL) { strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname, sizeof(vlr.vlr_parent)); vlr.vlr_tag = ifv->ifv_vid; } - VLAN_UNLOCK(); + VLAN_SUNLOCK(); error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); break; @@ -1806,8 +1971,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) * We should propagate selected flags to the parent, * e.g., promiscuous mode. */ + VLAN_XLOCK(); if (TRUNK(ifv) != NULL) error = vlan_setflags(ifp, 1); + VLAN_XUNLOCK(); break; case SIOCADDMULTI: @@ -1815,13 +1982,18 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) /* * If we don't have a parent, just remember the membership for * when we do. + * + * XXX We need the rmlock here to avoid sleeping while + * holding in6_multi_mtx. */ + VLAN_RLOCK(); trunk = TRUNK(ifv); if (trunk != NULL) { - TRUNK_LOCK(trunk); + TRUNK_WLOCK(trunk); error = vlan_setmulti(ifp); - TRUNK_UNLOCK(trunk); + TRUNK_WUNLOCK(trunk); } + VLAN_RUNLOCK(); break; case SIOCGVLANPCP: @@ -1853,15 +2025,15 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCSIFCAP: - VLAN_LOCK(); + VLAN_SLOCK(); ifv->ifv_capenable = ifr->ifr_reqcap; trunk = TRUNK(ifv); if (trunk != NULL) { - TRUNK_LOCK(trunk); + TRUNK_WLOCK(trunk); vlan_capabilities(ifv); - TRUNK_UNLOCK(trunk); + TRUNK_WUNLOCK(trunk); } - VLAN_UNLOCK(); + VLAN_SUNLOCK(); break; default: diff --git a/freebsd/sys/net/iflib.h b/freebsd/sys/net/iflib.h index 6ac75dbb..7249686b 100644 --- a/freebsd/sys/net/iflib.h +++ b/freebsd/sys/net/iflib.h @@ -173,6 +173,11 @@ typedef struct pci_vendor_info { #define PVID_OEM(vendor, devid, svid, sdevid, revid, name) {vendor, devid, svid, sdevid, revid, 0, name} #define PVID_END {0, 0, 0, 0, 0, 0, NULL} +#define IFLIB_PNP_DESCR "U32:vendor;U32:device;U32:subvendor;U32:subdevice;" \ + "U32:revision;U32:class;D:human" +#define IFLIB_PNP_INFO(b, u, t) \ + MODULE_PNP_INFO(IFLIB_PNP_DESCR, b, u, t, sizeof(t[0]), nitems(t)) + typedef struct if_txrx { int (*ift_txd_encap) (void *, if_pkt_info_t); void (*ift_txd_flush) (void *, uint16_t, qidx_t pidx); @@ -305,6 +310,10 @@ typedef enum { * Interface doesn't align IP header */ #define IFLIB_DO_RX_FIXUP 0x40 +/* + * Driver needs csum zeroed for offloading + */ +#define IFLIB_NEED_ZERO_CSUM 0x80 diff --git a/freebsd/sys/net/route.h b/freebsd/sys/net/route.h index 444559b5..ae052f19 100644 --- a/freebsd/sys/net/route.h +++ b/freebsd/sys/net/route.h @@ -67,8 +67,6 @@ struct route { #define RT_MAY_LOOP_BIT 3 /* dst may require loop copy */ #define RT_HAS_HEADER_BIT 4 /* mbuf already have its header prepended */ -#define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */ -#define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */ #define RT_L2_ME (1 << RT_L2_ME_BIT) /* 0x0004 */ #define RT_MAY_LOOP (1 << RT_MAY_LOOP_BIT) /* 0x0008 */ #define RT_HAS_HEADER (1 << RT_HAS_HEADER_BIT) /* 0x0010 */ @@ -411,14 +409,8 @@ struct rt_addrinfo { #define RO_RTFREE(_ro) do { \ if ((_ro)->ro_rt) { \ - if ((_ro)->ro_flags & RT_NORTREF) { \ - (_ro)->ro_flags &= ~RT_NORTREF; \ - (_ro)->ro_rt = NULL; \ - (_ro)->ro_lle = NULL; \ - } else { \ - RT_LOCK((_ro)->ro_rt); \ - RTFREE_LOCKED((_ro)->ro_rt); \ - } \ + RT_LOCK((_ro)->ro_rt); \ + RTFREE_LOCKED((_ro)->ro_rt); \ } \ } while (0) diff --git a/freebsd/sys/net80211/ieee80211_ioctl.c b/freebsd/sys/net80211/ieee80211_ioctl.c index 8f9e4658..68a0f9ae 100644 --- a/freebsd/sys/net80211/ieee80211_ioctl.c +++ b/freebsd/sys/net80211/ieee80211_ioctl.c @@ -2016,9 +2016,10 @@ setcurchan(struct ieee80211vap *vap, struct ieee80211_channel *c) /* XXX need state machine for other vap's to follow */ ieee80211_setcurchan(ic, vap->iv_des_chan); vap->iv_bss->ni_chan = ic->ic_curchan; - } else + } else { ic->ic_curchan = vap->iv_des_chan; ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); + } } else { /* * Need to go through the state machine in case we diff --git a/freebsd/sys/net80211/ieee80211_mesh.c b/freebsd/sys/net80211/ieee80211_mesh.c index 3abe5a26..df2865f4 100644 --- a/freebsd/sys/net80211/ieee80211_mesh.c +++ b/freebsd/sys/net80211/ieee80211_mesh.c @@ -2632,7 +2632,7 @@ mesh_recv_action_meshgate(struct ieee80211_node *ni, /* popagate only if decremented ttl >= 1 && forwarding is enabled */ if ((ie.gann_ttl - 1) < 1 && !(ms->ms_flags & IEEE80211_MESHFLAGS_FWD)) return 0; - pgann.gann_flags = ie.gann_flags; /* Reserved */ + pgann.gann_flags = ie.gann_flags; /* Reserved */ pgann.gann_hopcount = ie.gann_hopcount + 1; pgann.gann_ttl = ie.gann_ttl - 1; IEEE80211_ADDR_COPY(pgann.gann_addr, ie.gann_addr); diff --git a/freebsd/sys/net80211/ieee80211_output.c b/freebsd/sys/net80211/ieee80211_output.c index 85bfeb0a..93b4dc46 100644 --- a/freebsd/sys/net80211/ieee80211_output.c +++ b/freebsd/sys/net80211/ieee80211_output.c @@ -2502,7 +2502,7 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) capinfo |= IEEE80211_CAPINFO_PRIVACY; /* * NB: Some 11a AP's reject the request when - * short premable is set. + * short preamble is set. */ if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) diff --git a/freebsd/sys/netinet/if_ether.c b/freebsd/sys/netinet/if_ether.c index 802fedbb..bdb3b054 100644 --- a/freebsd/sys/netinet/if_ether.c +++ b/freebsd/sys/netinet/if_ether.c @@ -1281,7 +1281,7 @@ arp_mark_lle_reachable(struct llentry *la) } /* - * Add pernament link-layer record for given interface address. + * Add permanent link-layer record for given interface address. */ static __noinline void arp_add_ifa_lle(struct ifnet *ifp, const struct sockaddr *dst) diff --git a/freebsd/sys/netinet/in_pcb.c b/freebsd/sys/netinet/in_pcb.c index 3d43ed92..44890e3f 100644 --- a/freebsd/sys/netinet/in_pcb.c +++ b/freebsd/sys/netinet/in_pcb.c @@ -2809,6 +2809,35 @@ in_pcbquery_txrtlmt(struct inpcb *inp, uint32_t *p_max_pacing_rate) } /* + * Query existing TX queue level based on the existing + * "inp->inp_snd_tag", if any. + */ +int +in_pcbquery_txrlevel(struct inpcb *inp, uint32_t *p_txqueue_level) +{ + union if_snd_tag_query_params params = { }; + struct m_snd_tag *mst; + struct ifnet *ifp; + int error; + + mst = inp->inp_snd_tag; + if (mst == NULL) + return (EINVAL); + + ifp = mst->ifp; + if (ifp == NULL) + return (EINVAL); + + if (ifp->if_snd_tag_query == NULL) + return (EOPNOTSUPP); + + error = ifp->if_snd_tag_query(mst, ¶ms); + if (error == 0 && p_txqueue_level != NULL) + *p_txqueue_level = params.rate_limit.queue_level; + return (error); +} + +/* * Allocate a new TX rate limit send tag from the network interface * given by the "ifp" argument and save it in "inp->inp_snd_tag": */ @@ -2817,7 +2846,8 @@ in_pcbattach_txrtlmt(struct inpcb *inp, struct ifnet *ifp, uint32_t flowtype, uint32_t flowid, uint32_t max_pacing_rate) { union if_snd_tag_alloc_params params = { - .rate_limit.hdr.type = IF_SND_TAG_TYPE_RATE_LIMIT, + .rate_limit.hdr.type = (max_pacing_rate == -1U) ? + IF_SND_TAG_TYPE_UNLIMITED : IF_SND_TAG_TYPE_RATE_LIMIT, .rate_limit.hdr.flowid = flowid, .rate_limit.hdr.flowtype = flowtype, .rate_limit.max_rate = max_pacing_rate, diff --git a/freebsd/sys/netinet/in_pcb.h b/freebsd/sys/netinet/in_pcb.h index 42fd23d0..059ea90c 100644 --- a/freebsd/sys/netinet/in_pcb.h +++ b/freebsd/sys/netinet/in_pcb.h @@ -761,6 +761,7 @@ int in_pcbattach_txrtlmt(struct inpcb *, struct ifnet *, uint32_t, uint32_t, uin void in_pcbdetach_txrtlmt(struct inpcb *); int in_pcbmodify_txrtlmt(struct inpcb *, uint32_t); int in_pcbquery_txrtlmt(struct inpcb *, uint32_t *); +int in_pcbquery_txrlevel(struct inpcb *, uint32_t *); void in_pcboutput_txrtlmt(struct inpcb *, struct ifnet *, struct mbuf *); void in_pcboutput_eagain(struct inpcb *); #endif diff --git a/freebsd/sys/netinet/ip_icmp.c b/freebsd/sys/netinet/ip_icmp.c index acc2e6b6..4843efcd 100644 --- a/freebsd/sys/netinet/ip_icmp.c +++ b/freebsd/sys/netinet/ip_icmp.c @@ -187,17 +187,14 @@ kmod_icmpstat_inc(int statnum) void icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu) { - struct ip *oip = mtod(n, struct ip *), *nip; - unsigned oiphlen = oip->ip_hl << 2; + struct ip *oip, *nip; struct icmp *icp; struct mbuf *m; - unsigned icmplen, icmpelen, nlen; + unsigned icmplen, icmpelen, nlen, oiphlen; + + KASSERT((u_int)type <= ICMP_MAXTYPE, ("%s: illegal ICMP type", + __func__)); - KASSERT((u_int)type <= ICMP_MAXTYPE, ("%s: illegal ICMP type", __func__)); -#ifdef ICMPPRINTFS - if (icmpprintfs) - printf("icmp_error(%p, %x, %d)\n", oip, type, code); -#endif if (type != ICMP_REDIRECT) ICMPSTAT_INC(icps_error); /* @@ -209,19 +206,28 @@ icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu) */ if (n->m_flags & M_DECRYPTED) goto freeit; - if (oip->ip_off & htons(~(IP_MF|IP_DF))) - goto freeit; if (n->m_flags & (M_BCAST|M_MCAST)) goto freeit; + + /* Drop if IP header plus 8 bytes is not contiguous in first mbuf. */ + if (n->m_len < sizeof(struct ip) + ICMP_MINLEN) + goto freeit; + oip = mtod(n, struct ip *); + oiphlen = oip->ip_hl << 2; + if (n->m_len < oiphlen + ICMP_MINLEN) + goto freeit; +#ifdef ICMPPRINTFS + if (icmpprintfs) + printf("icmp_error(%p, %x, %d)\n", oip, type, code); +#endif + if (oip->ip_off & htons(~(IP_MF|IP_DF))) + goto freeit; if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && - n->m_len >= oiphlen + ICMP_MINLEN && - !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiphlen))->icmp_type)) { + !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + + oiphlen))->icmp_type)) { ICMPSTAT_INC(icps_oldicmp); goto freeit; } - /* Drop if IP header plus 8 bytes is not contignous in first mbuf. */ - if (oiphlen + 8 > n->m_len) - goto freeit; /* * Calculate length to quote from original packet and * prevent the ICMP mbuf from overflowing. @@ -237,9 +243,10 @@ icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu) n->m_next == NULL) goto stdreply; if (n->m_len < oiphlen + sizeof(struct tcphdr) && - ((n = m_pullup(n, oiphlen + sizeof(struct tcphdr))) == NULL)) + (n = m_pullup(n, oiphlen + sizeof(struct tcphdr))) == NULL) goto freeit; - th = (struct tcphdr *)((caddr_t)oip + oiphlen); + oip = mtod(n, struct ip *); + th = mtodo(n, oiphlen); tcphlen = th->th_off << 2; if (tcphlen < sizeof(struct tcphdr)) goto freeit; @@ -247,8 +254,8 @@ icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu) goto freeit; if (oiphlen + tcphlen > n->m_len && n->m_next == NULL) goto stdreply; - if (n->m_len < oiphlen + tcphlen && - ((n = m_pullup(n, oiphlen + tcphlen)) == NULL)) + if (n->m_len < oiphlen + tcphlen && + (n = m_pullup(n, oiphlen + tcphlen)) == NULL) goto freeit; icmpelen = max(tcphlen, min(V_icmp_quotelen, ntohs(oip->ip_len) - oiphlen)); @@ -264,24 +271,31 @@ icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu) if (n->m_len < oiphlen + sizeof(struct sctphdr) && (n = m_pullup(n, oiphlen + sizeof(struct sctphdr))) == NULL) goto freeit; + oip = mtod(n, struct ip *); icmpelen = max(sizeof(struct sctphdr), min(V_icmp_quotelen, ntohs(oip->ip_len) - oiphlen)); - sh = (struct sctphdr *)((caddr_t)oip + oiphlen); + sh = mtodo(n, oiphlen); if (ntohl(sh->v_tag) == 0 && - ntohs(oip->ip_len) >= oiphlen + sizeof(struct sctphdr) + 8 && + ntohs(oip->ip_len) >= oiphlen + + sizeof(struct sctphdr) + 8 && (n->m_len >= oiphlen + sizeof(struct sctphdr) + 8 || n->m_next != NULL)) { if (n->m_len < oiphlen + sizeof(struct sctphdr) + 8 && - (n = m_pullup(n, oiphlen + sizeof(struct sctphdr) + 8)) == NULL) + (n = m_pullup(n, oiphlen + + sizeof(struct sctphdr) + 8)) == NULL) goto freeit; + oip = mtod(n, struct ip *); + sh = mtodo(n, oiphlen); ch = (struct sctp_chunkhdr *)(sh + 1); if (ch->chunk_type == SCTP_INITIATION) { icmpelen = max(sizeof(struct sctphdr) + 8, - min(V_icmp_quotelen, ntohs(oip->ip_len) - oiphlen)); + min(V_icmp_quotelen, ntohs(oip->ip_len) - + oiphlen)); } } } else -stdreply: icmpelen = max(8, min(V_icmp_quotelen, ntohs(oip->ip_len) - oiphlen)); +stdreply: icmpelen = max(8, min(V_icmp_quotelen, ntohs(oip->ip_len) - + oiphlen)); icmplen = min(oiphlen + icmpelen, nlen); if (icmplen < sizeof(struct ip)) @@ -296,7 +310,8 @@ stdreply: icmpelen = max(8, min(V_icmp_quotelen, ntohs(oip->ip_len) - oiphlen)); #ifdef MAC mac_netinet_icmp_reply(n, m); #endif - icmplen = min(icmplen, M_TRAILINGSPACE(m) - sizeof(struct ip) - ICMP_MINLEN); + icmplen = min(icmplen, M_TRAILINGSPACE(m) - + sizeof(struct ip) - ICMP_MINLEN); m_align(m, ICMP_MINLEN + icmplen); m->m_len = ICMP_MINLEN + icmplen; diff --git a/freebsd/sys/netinet/sctp.h b/freebsd/sys/netinet/sctp.h index ec42cffa..578be4f6 100644 --- a/freebsd/sys/netinet/sctp.h +++ b/freebsd/sys/netinet/sctp.h @@ -545,7 +545,6 @@ struct sctp_error_auth_invalid_hmac { #define SCTP_PCB_FLAGS_INTERLEAVE_STRMS 0x0000000000000010 #define SCTP_PCB_FLAGS_DO_ASCONF 0x0000000000000020 #define SCTP_PCB_FLAGS_AUTO_ASCONF 0x0000000000000040 -#define SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE 0x0000000000000080 /* socket options */ #define SCTP_PCB_FLAGS_NODELAY 0x0000000000000100 #define SCTP_PCB_FLAGS_AUTOCLOSE 0x0000000000000200 diff --git a/freebsd/sys/netinet/sctp_asconf.c b/freebsd/sys/netinet/sctp_asconf.c index aa31e488..5f1c4e8f 100644 --- a/freebsd/sys/netinet/sctp_asconf.c +++ b/freebsd/sys/netinet/sctp_asconf.c @@ -2307,39 +2307,6 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) return (0); } -void -sctp_set_primary_ip_address(struct sctp_ifa *ifa) -{ - struct sctp_inpcb *inp; - - /* go through all our PCB's */ - LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) { - struct sctp_tcb *stcb; - - /* process for all associations for this endpoint */ - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - /* queue an ASCONF:SET_PRIM_ADDR to be sent */ - if (!sctp_asconf_queue_add(stcb, ifa, - SCTP_SET_PRIM_ADDR)) { - /* set primary queuing succeeded */ - SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ", - (void *)stcb); - SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa); - if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { -#ifdef SCTP_TIMER_BASED_ASCONF - sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, - stcb->sctp_ep, stcb, - stcb->asoc.primary_destination); -#else - sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED); -#endif - } - } - } /* for each stcb */ - } /* for each inp */ -} - int sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa) { diff --git a/freebsd/sys/netinet/sctp_asconf.h b/freebsd/sys/netinet/sctp_asconf.h index c8d670e5..ed9160e1 100644 --- a/freebsd/sys/netinet/sctp_asconf.h +++ b/freebsd/sys/netinet/sctp_asconf.h @@ -73,9 +73,6 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *, struct sockaddr *); extern void - sctp_set_primary_ip_address(struct sctp_ifa *ifa); - -extern void sctp_check_address_list(struct sctp_tcb *, struct mbuf *, int, int, struct sockaddr *, uint16_t, uint16_t, uint16_t, uint16_t); diff --git a/freebsd/sys/netinet/sctp_constants.h b/freebsd/sys/netinet/sctp_constants.h index dca34cc5..56772b34 100644 --- a/freebsd/sys/netinet/sctp_constants.h +++ b/freebsd/sys/netinet/sctp_constants.h @@ -555,11 +555,9 @@ __FBSDID("$FreeBSD$"); #define SCTP_TIMER_TYPE_INPKILL 15 #define SCTP_TIMER_TYPE_ASOCKILL 16 #define SCTP_TIMER_TYPE_ADDR_WQ 17 -#define SCTP_TIMER_TYPE_ZERO_COPY 18 -#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 19 -#define SCTP_TIMER_TYPE_PRIM_DELETED 20 +#define SCTP_TIMER_TYPE_PRIM_DELETED 18 /* add new timers here - and increment LAST */ -#define SCTP_TIMER_TYPE_LAST 21 +#define SCTP_TIMER_TYPE_LAST 19 #define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \ ((t) < SCTP_TIMER_TYPE_LAST)) @@ -971,9 +969,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_SO_NOT_LOCKED 0 -#define SCTP_HOLDS_LOCK 1 -#define SCTP_NOT_LOCKED 0 - /*- * For address locks, do we hold the lock? */ diff --git a/freebsd/sys/netinet/sctp_indata.c b/freebsd/sys/netinet/sctp_indata.c index 1924aeab..c27dd485 100644 --- a/freebsd/sys/netinet/sctp_indata.c +++ b/freebsd/sys/netinet/sctp_indata.c @@ -1381,10 +1381,10 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, } if (sctp_place_control_in_stream(strm, asoc, control)) { /* Duplicate SSN? */ - sctp_clean_up_control(stcb, control); sctp_abort_in_reasm(stcb, control, chk, abort_flag, SCTP_FROM_SCTP_INDATA + SCTP_LOC_6); + sctp_clean_up_control(stcb, control); return; } if ((tsn == (asoc->cumulative_tsn + 1) && (asoc->idata_supported == 0))) { @@ -1596,9 +1596,17 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, next_fsn, control->fsn_included); TAILQ_REMOVE(&control->reasm, at, sctp_next); lenadded = sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD); - asoc->size_on_all_streams += lenadded; if (control->on_read_q) { do_wakeup = 1; + } else { + /* + * We only add to the + * size-on-all-streams if its not on + * the read q. The read q flag will + * cause a sballoc so its accounted + * for there. + */ + asoc->size_on_all_streams += lenadded; } next_fsn++; if (control->end_added && control->pdapi_started) { @@ -1611,7 +1619,6 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc, control, &stcb->sctp_socket->so_rcv, control->end_added, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); - do_wakeup = 1; } break; } @@ -4207,8 +4214,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, again: j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - int to_ticks; - if (win_probe_recovery && (net->window_probe)) { win_probe_recovered = 1; /* @@ -4224,15 +4229,9 @@ again: } } } - if (net->RTO == 0) { - to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); - } else { - to_ticks = MSEC_TO_TICKS(net->RTO); - } if (net->flight_size) { j++; - (void)SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks, - sctp_timeout_handler, &net->rxt_timer); + sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); if (net->window_probe) { net->window_probe = 0; } @@ -4244,8 +4243,7 @@ again: */ net->window_probe = 0; if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { - SCTP_OS_TIMER_START(&net->rxt_timer.timer, to_ticks, - sctp_timeout_handler, &net->rxt_timer); + sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net); } } else if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, diff --git a/freebsd/sys/netinet/sctp_input.c b/freebsd/sys/netinet/sctp_input.c index 2e844fb5..0871bdb8 100644 --- a/freebsd/sys/netinet/sctp_input.c +++ b/freebsd/sys/netinet/sctp_input.c @@ -199,8 +199,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, sctp_send_initiate_ack(inp, stcb, net, m, iphlen, offset, src, dst, sh, cp, mflowtype, mflowid, - vrf_id, port, - ((stcb == NULL) ? SCTP_HOLDS_LOCK : SCTP_NOT_LOCKED)); + vrf_id, port); } outnow: if (stcb == NULL) { @@ -702,6 +701,14 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb) */ struct sctpasochead *head; + if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) || + (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) { + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_INP_INFO_WLOCK(); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + } if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) { /* generate a new vtag and send init */ LIST_REMOVE(stcb, sctp_asocs); @@ -713,6 +720,7 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb) */ LIST_INSERT_HEAD(head, stcb, sctp_asocs); sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); + SCTP_INP_INFO_WUNLOCK(); return (1); } if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { @@ -734,6 +742,7 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb) */ LIST_INSERT_HEAD(head, stcb, sctp_asocs); sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); + SCTP_INP_INFO_WUNLOCK(); return (1); } return (0); @@ -2555,15 +2564,12 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, /* Expire time is in Ticks, so we convert to seconds */ time_expires.tv_sec = cookie->time_entered.tv_sec + TICKS_TO_SEC(cookie->cookie_life); time_expires.tv_usec = cookie->time_entered.tv_usec; - /* - * TODO sctp_constants.h needs alternative time macros when _KERNEL - * is undefined. - */ if (timevalcmp(&now, &time_expires, >)) { /* cookie is stale! */ struct mbuf *op_err; struct sctp_error_stale_cookie *cause; - uint32_t tim; + struct timeval diff; + uint32_t staleness; op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_error_stale_cookie), 0, M_NOWAIT, 1, MT_DATA); @@ -2577,12 +2583,19 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, cause->cause.code = htons(SCTP_CAUSE_STALE_COOKIE); cause->cause.length = htons((sizeof(struct sctp_paramhdr) + (sizeof(uint32_t)))); - /* seconds to usec */ - tim = (now.tv_sec - time_expires.tv_sec) * 1000000; - /* add in usec */ - if (tim == 0) - tim = now.tv_usec - cookie->time_entered.tv_usec; - cause->stale_time = htonl(tim); + diff = now; + timevalsub(&diff, &time_expires); + if (diff.tv_sec > UINT32_MAX / 1000000) { + staleness = UINT32_MAX; + } else { + staleness = diff.tv_sec * 1000000; + } + if (UINT32_MAX - staleness >= (uint32_t)diff.tv_usec) { + staleness += diff.tv_usec; + } else { + staleness = UINT32_MAX; + } + cause->stale_time = htonl(staleness); sctp_send_operr_to(src, dst, sh, cookie->peers_vtag, op_err, mflowtype, mflowid, l_inp->fibnum, vrf_id, port); @@ -3135,14 +3148,14 @@ sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb, struct sct * make sure that we have a covered ECNE in the control chunk part. * If so remove it. */ - struct sctp_tmit_chunk *chk; + struct sctp_tmit_chunk *chk, *nchk; struct sctp_ecne_chunk *ecne; int override; uint32_t cwr_tsn; cwr_tsn = ntohl(cp->tsn); override = cp->ch.chunk_flags & SCTP_CWR_REDUCE_OVERRIDE; - TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { + TAILQ_FOREACH_SAFE(chk, &stcb->asoc.control_send_queue, sctp_next, nchk) { if (chk->rec.chunk_id.id != SCTP_ECN_ECHO) { continue; } diff --git a/freebsd/sys/netinet/sctp_os_bsd.h b/freebsd/sys/netinet/sctp_os_bsd.h index 194a03ed..045ccc38 100644 --- a/freebsd/sys/netinet/sctp_os_bsd.h +++ b/freebsd/sys/netinet/sctp_os_bsd.h @@ -404,11 +404,6 @@ typedef struct rtentry sctp_rtentry_t; #define SCTP_RTALLOC(ro, vrf_id, fibnum) \ rtalloc_ign_fib((struct route *)ro, 0UL, fibnum) -/* Future zero copy wakeup/send function */ -#define SCTP_ZERO_COPY_EVENT(inp, so) -/* This is re-pulse ourselves for sendbuf */ -#define SCTP_ZERO_COPY_SENDQ_EVENT(inp, so) - /* * SCTP protocol specific mbuf flags. */ diff --git a/freebsd/sys/netinet/sctp_output.c b/freebsd/sys/netinet/sctp_output.c index 5e2fbbc2..2540b5b9 100644 --- a/freebsd/sys/netinet/sctp_output.c +++ b/freebsd/sys/netinet/sctp_output.c @@ -4279,11 +4279,13 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, uint32_t mtu; mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); - if (net->port) { - mtu -= sizeof(struct udphdr); - } - if (mtu && (stcb->asoc.smallest_mtu > mtu)) { - sctp_mtu_size_reset(inp, &stcb->asoc, mtu); + if (mtu > 0) { + if (net->port) { + mtu -= sizeof(struct udphdr); + } + if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { + sctp_mtu_size_reset(inp, &stcb->asoc, mtu); + } net->mtu = mtu; } } else if (ro->ro_rt == NULL) { @@ -4635,13 +4637,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, uint32_t mtu; mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); - if (mtu && - (stcb->asoc.smallest_mtu > mtu)) { - sctp_mtu_size_reset(inp, &stcb->asoc, mtu); - net->mtu = mtu; + if (mtu > 0) { if (net->port) { - net->mtu -= sizeof(struct udphdr); + mtu -= sizeof(struct udphdr); + } + if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { + sctp_mtu_size_reset(inp, &stcb->asoc, mtu); } + net->mtu = mtu; } } else if (ifp) { if (ND_IFINFO(ifp)->linkmtu && @@ -5490,7 +5493,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sockaddr *src, struct sockaddr *dst, struct sctphdr *sh, struct sctp_init_chunk *init_chk, uint8_t mflowtype, uint32_t mflowid, - uint32_t vrf_id, uint16_t port, int hold_inp_lock) + uint32_t vrf_id, uint16_t port) { struct sctp_association *asoc; struct mbuf *m, *m_tmp, *m_last, *m_cookie, *op_err; @@ -5838,10 +5841,6 @@ do_a_abort: } else { uint32_t vtag, itsn; - if (hold_inp_lock) { - SCTP_INP_INCR_REF(inp); - SCTP_INP_RUNLOCK(inp); - } if (asoc) { atomic_add_int(&asoc->refcnt, 1); SCTP_TCB_UNLOCK(stcb); @@ -5861,12 +5860,12 @@ do_a_abort: SCTP_TCB_LOCK(stcb); atomic_add_int(&asoc->refcnt, -1); } else { + SCTP_INP_INCR_REF(inp); + SCTP_INP_RUNLOCK(inp); vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); initack->init.initiate_tag = htonl(vtag); /* get a TSN to use too */ initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); - } - if (hold_inp_lock) { SCTP_INP_RLOCK(inp); SCTP_INP_DECR_REF(inp); } @@ -12423,7 +12422,6 @@ sctp_copy_it_in(struct sctp_tcb *stcb, resv_in_first = SCTP_DATA_CHUNK_OVERHEAD(stcb); sp->data = sp->tail_mbuf = NULL; if (sp->length == 0) { - *error = 0; goto skip_copy; } if (srcv->sinfo_keynumber_valid) { @@ -13156,7 +13154,7 @@ skip_preblock: if (strm->last_msg_incomplete == 0) { do_a_copy_in: sp = sctp_copy_it_in(stcb, asoc, srcv, uio, net, max_len, user_marks_eor, &error); - if ((sp == NULL) || (error)) { + if (error) { goto out; } SCTP_TCB_SEND_LOCK(stcb); diff --git a/freebsd/sys/netinet/sctp_output.h b/freebsd/sys/netinet/sctp_output.h index 32f968c1..0a5cf10b 100644 --- a/freebsd/sys/netinet/sctp_output.h +++ b/freebsd/sys/netinet/sctp_output.h @@ -86,7 +86,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *, struct sockaddr *, struct sockaddr *, struct sctphdr *, struct sctp_init_chunk *, uint8_t, uint32_t, - uint32_t, uint16_t, int); + uint32_t, uint16_t); struct mbuf * sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *, diff --git a/freebsd/sys/netinet/sctp_pcb.c b/freebsd/sys/netinet/sctp_pcb.c index 1907991e..46a91110 100644 --- a/freebsd/sys/netinet/sctp_pcb.c +++ b/freebsd/sys/netinet/sctp_pcb.c @@ -711,12 +711,11 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, SCTP_WQ_ADDR_LOCK(); LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - SCTP_WQ_ADDR_UNLOCK(); - sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, (struct sctp_inpcb *)NULL, (struct sctp_tcb *)NULL, (struct sctp_nets *)NULL); + SCTP_WQ_ADDR_UNLOCK(); } else { /* it's ready for use */ sctp_ifap->localifa_flags &= ~SCTP_ADDR_DEFER_USE; @@ -823,12 +822,11 @@ out_now: * the newest first :-0 */ LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - SCTP_WQ_ADDR_UNLOCK(); - sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, (struct sctp_inpcb *)NULL, (struct sctp_tcb *)NULL, (struct sctp_nets *)NULL); + SCTP_WQ_ADDR_UNLOCK(); } return; } @@ -2488,7 +2486,9 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE | SCTP_PCB_FLAGS_UNBOUND); /* Be sure we have blocking IO by default */ + SOCK_LOCK(so); SCTP_CLEAR_SO_NBIO(so); + SOCK_UNLOCK(so); } else { /* * unsupported socket type (RAW, etc)- in case we missed it @@ -2921,9 +2921,9 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, */ /* got to be root to get at low ports */ if (ntohs(lport) < IPPORT_RESERVED) { - if (p && (error = + if ((p != NULL) && ((error = priv_check(p, PRIV_NETINET_RESERVEDPORT) - )) { + ) != 0)) { SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); diff --git a/freebsd/sys/netinet/sctp_pcb.h b/freebsd/sys/netinet/sctp_pcb.h index 86fae1f4..acc68311 100644 --- a/freebsd/sys/netinet/sctp_pcb.h +++ b/freebsd/sys/netinet/sctp_pcb.h @@ -314,10 +314,6 @@ struct sctp_pcb { */ struct sctp_timer signature_change; - /* Zero copy full buffer timer */ - struct sctp_timer zero_copy_timer; - /* Zero copy app to transport (sendq) read repulse timer */ - struct sctp_timer zero_copy_sendq_timer; uint32_t def_cookie_life; /* defaults to 0 */ int auto_close_time; diff --git a/freebsd/sys/netinet/sctp_sysctl.c b/freebsd/sys/netinet/sctp_sysctl.c index a2364431..52361602 100644 --- a/freebsd/sys/netinet/sctp_sysctl.c +++ b/freebsd/sys/netinet/sctp_sysctl.c @@ -508,6 +508,14 @@ sctp_sysctl_handle_assoclist(SYSCTL_HANDLER_ARGS) xraddr.rtt = net->rtt / 1000; xraddr.heartbeat_interval = net->heart_beat_delay; xraddr.ssthresh = net->ssthresh; + xraddr.encaps_port = net->port; + if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { + xraddr.state = SCTP_UNCONFIRMED; + } else if (net->dest_state & SCTP_ADDR_REACHABLE) { + xraddr.state = SCTP_ACTIVE; + } else { + xraddr.state = SCTP_INACTIVE; + } xraddr.start_time.tv_sec = (uint32_t)net->start_time.tv_sec; xraddr.start_time.tv_usec = (uint32_t)net->start_time.tv_usec; SCTP_INP_RUNLOCK(inp); diff --git a/freebsd/sys/netinet/sctp_uio.h b/freebsd/sys/netinet/sctp_uio.h index d6055163..daa6847d 100644 --- a/freebsd/sys/netinet/sctp_uio.h +++ b/freebsd/sys/netinet/sctp_uio.h @@ -1239,7 +1239,9 @@ struct xsctp_raddr { uint32_t rtt; uint32_t heartbeat_interval; uint32_t ssthresh; - uint32_t extra_padding[30]; /* future */ + uint16_t encaps_port; + uint16_t state; + uint32_t extra_padding[29]; /* future */ }; #define SCTP_MAX_LOGGING_SIZE 30000 diff --git a/freebsd/sys/netinet/sctp_usrreq.c b/freebsd/sys/netinet/sctp_usrreq.c index fa136d4e..6ab04456 100644 --- a/freebsd/sys/netinet/sctp_usrreq.c +++ b/freebsd/sys/netinet/sctp_usrreq.c @@ -1961,6 +1961,7 @@ flags_out: SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); } else { id->assoc_value = stcb->asoc.vrf_id; + SCTP_TCB_UNLOCK(stcb); *optsize = sizeof(struct sctp_assoc_value); } break; @@ -3065,7 +3066,6 @@ flags_out: if (event_type > 0) { if (stcb) { event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); - SCTP_TCB_UNLOCK(stcb); } else { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || @@ -3079,6 +3079,9 @@ flags_out: } } } + if (stcb != NULL) { + SCTP_TCB_UNLOCK(stcb); + } if (error == 0) { *optsize = sizeof(struct sctp_event); } @@ -3649,12 +3652,16 @@ flags_out: sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0]; sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0]; #endif - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_prstatus); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } + if (stcb != NULL) { + SCTP_TCB_UNLOCK(stcb); + } + if (error == 0) { + *optsize = sizeof(struct sctp_prstatus); + } break; } case SCTP_PR_ASSOC_STATUS: @@ -3677,12 +3684,16 @@ flags_out: sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy]; sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy]; } - SCTP_TCB_UNLOCK(stcb); - *optsize = sizeof(struct sctp_prstatus); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } + if (stcb != NULL) { + SCTP_TCB_UNLOCK(stcb); + } + if (error == 0) { + *optsize = sizeof(struct sctp_prstatus); + } break; } case SCTP_MAX_CWND: diff --git a/freebsd/sys/netinet/sctputil.c b/freebsd/sys/netinet/sctputil.c index 75c989d3..f8fd23f1 100644 --- a/freebsd/sys/netinet/sctputil.c +++ b/freebsd/sys/netinet/sctputil.c @@ -1464,13 +1464,11 @@ sctp_handle_addr_wq(void) LIST_INIT(&asc->list_of_work); asc->cnt = 0; - SCTP_WQ_ADDR_LOCK(); LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { LIST_REMOVE(wi, sctp_nxt_addr); LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); asc->cnt++; } - SCTP_WQ_ADDR_UNLOCK(); if (asc->cnt == 0) { SCTP_FREE(asc, SCTP_M_ASC_IT); @@ -1494,11 +1492,9 @@ sctp_handle_addr_wq(void) if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { sctp_asconf_iterator_end(asc, 0); } else { - SCTP_WQ_ADDR_LOCK(); LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) { LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); } - SCTP_WQ_ADDR_UNLOCK(); SCTP_FREE(asc, SCTP_M_ASC_IT); } } @@ -1567,8 +1563,7 @@ sctp_timeout_handler(void *t) (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) && (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) && (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) && - (tmr->type != SCTP_TIMER_TYPE_ASOCKILL)) - ) { + (tmr->type != SCTP_TIMER_TYPE_ASOCKILL))) { SCTP_INP_DECR_REF(inp); CURVNET_RESTORE(); return; @@ -1614,6 +1609,12 @@ sctp_timeout_handler(void *t) CURVNET_RESTORE(); return; } + } else if (inp != NULL) { + if (type != SCTP_TIMER_TYPE_INPKILL) { + SCTP_INP_WLOCK(inp); + } + } else { + SCTP_WQ_ADDR_LOCK(); } /* record in stopped what t-o occurred */ tmr->stopped_from = type; @@ -1635,22 +1636,6 @@ sctp_timeout_handler(void *t) /* call the handler for the appropriate timer type */ switch (type) { - case SCTP_TIMER_TYPE_ZERO_COPY: - if (inp == NULL) { - break; - } - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { - SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); - } - break; - case SCTP_TIMER_TYPE_ZCOPY_SENDQ: - if (inp == NULL) { - break; - } - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { - SCTP_ZERO_COPY_SENDQ_EVENT(inp, inp->sctp_socket); - } - break; case SCTP_TIMER_TYPE_ADDR_WQ: sctp_handle_addr_wq(); break; @@ -1777,7 +1762,6 @@ sctp_timeout_handler(void *t) } SCTP_STAT_INCR(sctps_timosecret); (void)SCTP_GETTIME_TIMEVAL(&tv); - SCTP_INP_WLOCK(inp); inp->sctp_ep.time_of_secret_change = tv.tv_sec; inp->sctp_ep.last_secret_number = inp->sctp_ep.current_secret_number; @@ -1791,7 +1775,6 @@ sctp_timeout_handler(void *t) inp->sctp_ep.secret_key[secret][i] = sctp_select_initial_TSN(&inp->sctp_ep); } - SCTP_INP_WUNLOCK(inp); sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net); } did_output = 0; @@ -1939,7 +1922,12 @@ sctp_timeout_handler(void *t) get_out: if (stcb) { SCTP_TCB_UNLOCK(stcb); + } else if (inp != NULL) { + SCTP_INP_WUNLOCK(inp); + } else { + SCTP_WQ_ADDR_UNLOCK(); } + out_decr: if (inp) { SCTP_INP_DECR_REF(inp); @@ -1964,14 +1952,6 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, SCTP_TCB_LOCK_ASSERT(stcb); } switch (t_type) { - case SCTP_TIMER_TYPE_ZERO_COPY: - tmr = &inp->sctp_ep.zero_copy_timer; - to_ticks = SCTP_ZERO_COPY_TICK_DELAY; - break; - case SCTP_TIMER_TYPE_ZCOPY_SENDQ: - tmr = &inp->sctp_ep.zero_copy_sendq_timer; - to_ticks = SCTP_ZERO_COPY_SENDQ_TICK_DELAY; - break; case SCTP_TIMER_TYPE_ADDR_WQ: /* Only 1 tick away :-) */ tmr = &SCTP_BASE_INFO(addr_wq_timer); @@ -2253,12 +2233,6 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, SCTP_TCB_LOCK_ASSERT(stcb); } switch (t_type) { - case SCTP_TIMER_TYPE_ZERO_COPY: - tmr = &inp->sctp_ep.zero_copy_timer; - break; - case SCTP_TIMER_TYPE_ZCOPY_SENDQ: - tmr = &inp->sctp_ep.zero_copy_sendq_timer; - break; case SCTP_TIMER_TYPE_ADDR_WQ: tmr = &SCTP_BASE_INFO(addr_wq_timer); break; @@ -4472,36 +4446,32 @@ sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, ) { if ((inp != NULL) && (inp->sctp_socket != NULL)) { - if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { - SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); - } else { #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - struct socket *so; + struct socket *so; - so = SCTP_INP_SO(inp); - if (!so_locked) { - if (stcb) { - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - } - SCTP_SOCKET_LOCK(so, 1); - if (stcb) { - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { - SCTP_SOCKET_UNLOCK(so, 1); - return; - } + so = SCTP_INP_SO(inp); + if (!so_locked) { + if (stcb) { + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); } -#endif - sctp_sorwakeup(inp, inp->sctp_socket); -#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - if (!so_locked) { + SCTP_SOCKET_LOCK(so, 1); + if (stcb) { + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); + } + if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { SCTP_SOCKET_UNLOCK(so, 1); + return; } + } #endif + sctp_sorwakeup(inp, inp->sctp_socket); +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + if (!so_locked) { + SCTP_SOCKET_UNLOCK(so, 1); } +#endif } } @@ -6182,11 +6152,11 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) * newest first :-0 */ LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - SCTP_WQ_ADDR_UNLOCK(); sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, (struct sctp_inpcb *)NULL, (struct sctp_tcb *)NULL, (struct sctp_nets *)NULL); + SCTP_WQ_ADDR_UNLOCK(); return (0); } diff --git a/freebsd/sys/netinet/tcp_input.c b/freebsd/sys/netinet/tcp_input.c index 2195a778..663b8bc2 100644 --- a/freebsd/sys/netinet/tcp_input.c +++ b/freebsd/sys/netinet/tcp_input.c @@ -1696,25 +1696,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, to.to_tsecr = 0; } /* - * If timestamps were negotiated during SYN/ACK they should - * appear on every segment during this session and vice versa. - */ - if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS)) { - if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { - log(LOG_DEBUG, "%s; %s: Timestamp missing, " - "no action\n", s, __func__); - free(s, M_TCPLOG); - } - } - if (!(tp->t_flags & TF_RCVD_TSTMP) && (to.to_flags & TOF_TS)) { - if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { - log(LOG_DEBUG, "%s; %s: Timestamp not expected, " - "no action\n", s, __func__); - free(s, M_TCPLOG); - } - } - - /* * Process options only when we get SYN/ACK back. The SYN case * for incoming connections is handled in tcp_syncache. * According to RFC1323 the window field in a SYN (i.e., a <SYN> @@ -1745,6 +1726,25 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, } /* + * If timestamps were negotiated during SYN/ACK they should + * appear on every segment during this session and vice versa. + */ + if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS)) { + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: Timestamp missing, " + "no action\n", s, __func__); + free(s, M_TCPLOG); + } + } + if (!(tp->t_flags & TF_RCVD_TSTMP) && (to.to_flags & TOF_TS)) { + if ((s = tcp_log_addrs(inc, th, NULL, NULL))) { + log(LOG_DEBUG, "%s; %s: Timestamp not expected, " + "no action\n", s, __func__); + free(s, M_TCPLOG); + } + } + + /* * Header prediction: check for the two common cases * of a uni-directional data xfer. If the packet has * no control flags, is in-sequence, the window didn't diff --git a/freebsd/sys/netinet/tcp_syncache.c b/freebsd/sys/netinet/tcp_syncache.c index cf1f0ad1..a30def41 100644 --- a/freebsd/sys/netinet/tcp_syncache.c +++ b/freebsd/sys/netinet/tcp_syncache.c @@ -1644,9 +1644,7 @@ syncache_respond(struct syncache *sc, struct syncache_head *sch, int locked, tlen = hlen + sizeof(struct tcphdr); /* Determine MSS we advertize to other end of connection. */ - mssopt = tcp_mssopt(&sc->sc_inc); - if (sc->sc_peer_mss) - mssopt = max( min(sc->sc_peer_mss, mssopt), V_tcp_minmss); + mssopt = max(tcp_mssopt(&sc->sc_inc), V_tcp_minmss); /* XXX: Assume that the entire packet will fit in a header mbuf. */ KASSERT(max_linkhdr + tlen + TCP_MAXOLEN <= MHLEN, @@ -1995,7 +1993,7 @@ syncookie_mac(struct in_conninfo *inc, tcp_seq irs, uint8_t flags, static tcp_seq syncookie_generate(struct syncache_head *sch, struct syncache *sc) { - u_int i, mss, secbit, wscale; + u_int i, secbit, wscale; uint32_t iss, hash; uint8_t *secbits; union syncookie cookie; @@ -2005,8 +2003,8 @@ syncookie_generate(struct syncache_head *sch, struct syncache *sc) cookie.cookie = 0; /* Map our computed MSS into the 3-bit index. */ - mss = min(tcp_mssopt(&sc->sc_inc), max(sc->sc_peer_mss, V_tcp_minmss)); - for (i = nitems(tcp_sc_msstab) - 1; tcp_sc_msstab[i] > mss && i > 0; + for (i = nitems(tcp_sc_msstab) - 1; + tcp_sc_msstab[i] > sc->sc_peer_mss && i > 0; i--) ; cookie.flags.mss_idx = i; diff --git a/freebsd/sys/netinet/tcp_timer.c b/freebsd/sys/netinet/tcp_timer.c index ebd9e852..b4528801 100644 --- a/freebsd/sys/netinet/tcp_timer.c +++ b/freebsd/sys/netinet/tcp_timer.c @@ -150,29 +150,6 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_detection, &VNET_NAME(tcp_pmtud_blackhole_detect), 0, "Path MTU Discovery Black Hole Detection Enabled"); -static VNET_DEFINE(int, tcp_pmtud_blackhole_activated); -#define V_tcp_pmtud_blackhole_activated \ - VNET(tcp_pmtud_blackhole_activated) -SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_activated, - CTLFLAG_RD|CTLFLAG_VNET, - &VNET_NAME(tcp_pmtud_blackhole_activated), 0, - "Path MTU Discovery Black Hole Detection, Activation Count"); - -static VNET_DEFINE(int, tcp_pmtud_blackhole_activated_min_mss); -#define V_tcp_pmtud_blackhole_activated_min_mss \ - VNET(tcp_pmtud_blackhole_activated_min_mss) -SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_activated_min_mss, - CTLFLAG_RD|CTLFLAG_VNET, - &VNET_NAME(tcp_pmtud_blackhole_activated_min_mss), 0, - "Path MTU Discovery Black Hole Detection, Activation Count at min MSS"); - -static VNET_DEFINE(int, tcp_pmtud_blackhole_failed); -#define V_tcp_pmtud_blackhole_failed VNET(tcp_pmtud_blackhole_failed) -SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_failed, - CTLFLAG_RD|CTLFLAG_VNET, - &VNET_NAME(tcp_pmtud_blackhole_failed), 0, - "Path MTU Discovery Black Hole Detection, Failure Count"); - #ifdef INET static VNET_DEFINE(int, tcp_pmtud_blackhole_mss) = 1200; #define V_tcp_pmtud_blackhole_mss VNET(tcp_pmtud_blackhole_mss) @@ -751,18 +728,20 @@ tcp_timer_rexmt(void * xtp) */ if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) && - (tp->t_rxtshift >= 2 && tp->t_rxtshift % 2 == 0)) { + (tp->t_rxtshift >= 2 && tp->t_rxtshift < 6 && + tp->t_rxtshift % 2 == 0)) { /* * Enter Path MTU Black-hole Detection mechanism: * - Disable Path MTU Discovery (IP "DF" bit). * - Reduce MTU to lower value than what we * negotiated with peer. */ - /* Record that we may have found a black hole. */ - tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; - - /* Keep track of previous MSS. */ - tp->t_pmtud_saved_maxseg = tp->t_maxseg; + if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) { + /* Record that we may have found a black hole. */ + tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; + /* Keep track of previous MSS. */ + tp->t_pmtud_saved_maxseg = tp->t_maxseg; + } /* * Reduce the MSS to blackhole value or to the default @@ -774,7 +753,7 @@ tcp_timer_rexmt(void * xtp) tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) { /* Use the sysctl tuneable blackhole MSS. */ tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss; - V_tcp_pmtud_blackhole_activated++; + TCPSTAT_INC(tcps_pmtud_blackhole_activated); } else if (isipv6) { /* Use the default MSS. */ tp->t_maxseg = V_tcp_v6mssdflt; @@ -783,7 +762,7 @@ tcp_timer_rexmt(void * xtp) * minmss. */ tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; - V_tcp_pmtud_blackhole_activated_min_mss++; + TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); } #endif #if defined(INET6) && defined(INET) @@ -793,7 +772,7 @@ tcp_timer_rexmt(void * xtp) if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) { /* Use the sysctl tuneable blackhole MSS. */ tp->t_maxseg = V_tcp_pmtud_blackhole_mss; - V_tcp_pmtud_blackhole_activated++; + TCPSTAT_INC(tcps_pmtud_blackhole_activated); } else { /* Use the default MSS. */ tp->t_maxseg = V_tcp_mssdflt; @@ -802,7 +781,7 @@ tcp_timer_rexmt(void * xtp) * minmss. */ tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; - V_tcp_pmtud_blackhole_activated_min_mss++; + TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); } #endif /* @@ -821,11 +800,11 @@ tcp_timer_rexmt(void * xtp) * stage (1448, 1188, 524) 2 chances to recover. */ if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && - (tp->t_rxtshift > 6)) { + (tp->t_rxtshift >= 6)) { tp->t_flags2 |= TF2_PLPMTU_PMTUD; tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; tp->t_maxseg = tp->t_pmtud_saved_maxseg; - V_tcp_pmtud_blackhole_failed++; + TCPSTAT_INC(tcps_pmtud_blackhole_failed); /* * Reset the slow-start flight size as it * may depend on the new MSS. diff --git a/freebsd/sys/netinet/tcp_usrreq.c b/freebsd/sys/netinet/tcp_usrreq.c index 198291f2..88cc3501 100644 --- a/freebsd/sys/netinet/tcp_usrreq.c +++ b/freebsd/sys/netinet/tcp_usrreq.c @@ -1920,6 +1920,8 @@ tcp_attach(struct socket *so) #ifdef INET6 if (inp->inp_vflag & INP_IPV6PROTO) { inp->inp_vflag |= INP_IPV6; + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) + inp->inp_vflag |= INP_IPV4; inp->in6p_hops = -1; /* use kernel default */ } else diff --git a/freebsd/sys/netinet/tcp_var.h b/freebsd/sys/netinet/tcp_var.h index 2e2f88ac..967a5139 100644 --- a/freebsd/sys/netinet/tcp_var.h +++ b/freebsd/sys/netinet/tcp_var.h @@ -580,6 +580,11 @@ struct tcpstat { uint64_t tcps_sig_err_sigopt; /* No signature expected by socket */ uint64_t tcps_sig_err_nosigopt; /* No signature provided by segment */ + /* Path MTU Discovery Black Hole Detection related stats */ + uint64_t tcps_pmtud_blackhole_activated; /* Black Hole Count */ + uint64_t tcps_pmtud_blackhole_activated_min_mss; /* BH at min MSS Count */ + uint64_t tcps_pmtud_blackhole_failed; /* Black Hole Failure Count */ + uint64_t _pad[12]; /* 6 UTO, 6 TBD */ }; @@ -650,7 +655,7 @@ struct tcp_hhook_data { struct xtcpcb { size_t xt_len; /* length of this structure */ struct xinpcb xt_inp; - char xt_stack[TCP_FUNCTION_NAME_LEN_MAX]; /* (n) */ + char xt_stack[TCP_FUNCTION_NAME_LEN_MAX]; /* (s) */ int64_t spare64[8]; int32_t t_state; /* (s,p) */ uint32_t t_flags; /* (s,p) */ diff --git a/freebsd/sys/netinet6/sctp6_usrreq.c b/freebsd/sys/netinet6/sctp6_usrreq.c index cca2ebcf..27fcaa99 100644 --- a/freebsd/sys/netinet6/sctp6_usrreq.c +++ b/freebsd/sys/netinet6/sctp6_usrreq.c @@ -883,7 +883,7 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb) { - SCTP_TCB_UNLOCK(stcb); + SCTP_TCB_LOCK(stcb); } SCTP_INP_RUNLOCK(inp); } else { diff --git a/freebsd/sys/netipsec/ipsec.c b/freebsd/sys/netipsec/ipsec.c index 4b44a8ce..79c9519c 100644 --- a/freebsd/sys/netipsec/ipsec.c +++ b/freebsd/sys/netipsec/ipsec.c @@ -565,7 +565,8 @@ ipsec4_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx) } static struct secpolicy * -ipsec4_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir) +ipsec4_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir, + int needport) { struct secpolicyindex spidx; struct secpolicy *sp; @@ -574,8 +575,7 @@ ipsec4_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir) if (sp == NULL && key_havesp(dir)) { /* Make an index to look for a policy. */ ipsec4_setspidx_ipaddr(m, &spidx); - /* Fill ports in spidx if we have inpcb. */ - ipsec4_get_ulp(m, &spidx, inp != NULL); + ipsec4_get_ulp(m, &spidx, needport); spidx.dir = dir; sp = key_allocsp(&spidx, dir); } @@ -588,12 +588,13 @@ ipsec4_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir) * Check security policy for *OUTBOUND* IPv4 packet. */ struct secpolicy * -ipsec4_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error) +ipsec4_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error, + int needport) { struct secpolicy *sp; *error = 0; - sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_OUTBOUND); + sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_OUTBOUND, needport); if (sp != NULL) sp = ipsec_checkpolicy(sp, inp, error); if (sp == NULL) { @@ -625,7 +626,7 @@ ipsec4_in_reject(const struct mbuf *m, struct inpcb *inp) struct secpolicy *sp; int result; - sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_INBOUND); + sp = ipsec4_getpolicy(m, inp, IPSEC_DIR_INBOUND, 0); result = ipsec_in_reject(sp, inp, m); key_freesp(&sp); if (result != 0) @@ -733,7 +734,8 @@ ipsec6_setspidx_ipaddr(const struct mbuf *m, struct secpolicyindex *spidx) } static struct secpolicy * -ipsec6_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir) +ipsec6_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir, + int needport) { struct secpolicyindex spidx; struct secpolicy *sp; @@ -742,8 +744,7 @@ ipsec6_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir) if (sp == NULL && key_havesp(dir)) { /* Make an index to look for a policy. */ ipsec6_setspidx_ipaddr(m, &spidx); - /* Fill ports in spidx if we have inpcb. */ - ipsec6_get_ulp(m, &spidx, inp != NULL); + ipsec6_get_ulp(m, &spidx, needport); spidx.dir = dir; sp = key_allocsp(&spidx, dir); } @@ -756,12 +757,13 @@ ipsec6_getpolicy(const struct mbuf *m, struct inpcb *inp, u_int dir) * Check security policy for *OUTBOUND* IPv6 packet. */ struct secpolicy * -ipsec6_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error) +ipsec6_checkpolicy(const struct mbuf *m, struct inpcb *inp, int *error, + int needport) { struct secpolicy *sp; *error = 0; - sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_OUTBOUND); + sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_OUTBOUND, needport); if (sp != NULL) sp = ipsec_checkpolicy(sp, inp, error); if (sp == NULL) { @@ -793,7 +795,7 @@ ipsec6_in_reject(const struct mbuf *m, struct inpcb *inp) struct secpolicy *sp; int result; - sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_INBOUND); + sp = ipsec6_getpolicy(m, inp, IPSEC_DIR_INBOUND, 0); result = ipsec_in_reject(sp, inp, m); key_freesp(&sp); if (result) diff --git a/freebsd/sys/netipsec/ipsec.h b/freebsd/sys/netipsec/ipsec.h index a4c3f3d2..a61730ef 100644 --- a/freebsd/sys/netipsec/ipsec.h +++ b/freebsd/sys/netipsec/ipsec.h @@ -320,7 +320,7 @@ int ipsec_if_input(struct mbuf *, struct secasvar *, uint32_t); struct ipsecrequest *ipsec_newisr(void); void ipsec_delisr(struct ipsecrequest *); struct secpolicy *ipsec4_checkpolicy(const struct mbuf *, struct inpcb *, - int *); + int *, int); u_int ipsec_get_reqlevel(struct secpolicy *, u_int); diff --git a/freebsd/sys/netipsec/ipsec6.h b/freebsd/sys/netipsec/ipsec6.h index a5fae4d1..33aa30f3 100644 --- a/freebsd/sys/netipsec/ipsec6.h +++ b/freebsd/sys/netipsec/ipsec6.h @@ -60,7 +60,7 @@ VNET_DECLARE(int, ip6_ipsec_ecn); struct inpcb; struct secpolicy *ipsec6_checkpolicy(const struct mbuf *, - struct inpcb *, int *); + struct inpcb *, int *, int); void ipsec6_setsockaddrs(const struct mbuf *, union sockaddr_union *, union sockaddr_union *); diff --git a/freebsd/sys/netipsec/ipsec_output.c b/freebsd/sys/netipsec/ipsec_output.c index 07e39a8a..ac9529d5 100644 --- a/freebsd/sys/netipsec/ipsec_output.c +++ b/freebsd/sys/netipsec/ipsec_output.c @@ -299,7 +299,7 @@ ipsec4_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) int error; /* Lookup for the corresponding outbound security policy */ - sp = ipsec4_checkpolicy(m, inp, &error); + sp = ipsec4_checkpolicy(m, inp, &error, !forwarding); if (sp == NULL) { if (error == -EINVAL) { /* Discarded by policy. */ @@ -601,7 +601,7 @@ ipsec6_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) int error; /* Lookup for the corresponding outbound security policy */ - sp = ipsec6_checkpolicy(m, inp, &error); + sp = ipsec6_checkpolicy(m, inp, &error, !forwarding); if (sp == NULL) { if (error == -EINVAL) { /* Discarded by policy. */ diff --git a/freebsd/sys/netipsec/key.c b/freebsd/sys/netipsec/key.c index 0dfab7bd..ef5d8419 100644 --- a/freebsd/sys/netipsec/key.c +++ b/freebsd/sys/netipsec/key.c @@ -1405,7 +1405,8 @@ key_msg2sp(struct sadb_x_policy *xpl0, size_t len, int *error) while (tlen > 0) { /* length check */ - if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { + if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr) || + xisr->sadb_x_ipsecrequest_len > tlen) { ipseclog((LOG_DEBUG, "%s: invalid ipsecrequest " "length.\n", __func__)); key_freesp(&newsp); @@ -1519,10 +1520,12 @@ key_msg2sp(struct sadb_x_policy *xpl0, size_t len, int *error) if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { struct sockaddr *paddr; + len = tlen - sizeof(*xisr); paddr = (struct sockaddr *)(xisr + 1); /* validity check */ - if (paddr->sa_len - > sizeof(isr->saidx.src)) { + if (len < sizeof(struct sockaddr) || + len < 2 * paddr->sa_len || + paddr->sa_len > sizeof(isr->saidx.src)) { ipseclog((LOG_DEBUG, "%s: invalid " "request address length.\n", __func__)); @@ -1530,13 +1533,26 @@ key_msg2sp(struct sadb_x_policy *xpl0, size_t len, int *error) *error = EINVAL; return NULL; } + /* + * Request length should be enough to keep + * source and destination addresses. + */ + if (xisr->sadb_x_ipsecrequest_len < + sizeof(*xisr) + 2 * paddr->sa_len) { + ipseclog((LOG_DEBUG, "%s: invalid " + "ipsecrequest length.\n", + __func__)); + key_freesp(&newsp); + *error = EINVAL; + return (NULL); + } bcopy(paddr, &isr->saidx.src, paddr->sa_len); paddr = (struct sockaddr *)((caddr_t)paddr + paddr->sa_len); /* validity check */ - if (paddr->sa_len - > sizeof(isr->saidx.dst)) { + if (paddr->sa_len != + isr->saidx.src.sa.sa_len) { ipseclog((LOG_DEBUG, "%s: invalid " "request address length.\n", __func__)); diff --git a/freebsd/sys/netipsec/udpencap.c b/freebsd/sys/netipsec/udpencap.c index 265461cd..3eb106b2 100644 --- a/freebsd/sys/netipsec/udpencap.c +++ b/freebsd/sys/netipsec/udpencap.c @@ -122,7 +122,7 @@ udp_ipsec_input(struct mbuf *m, int off, int af) struct udphdr *udp; struct ip *ip; uint32_t spi; - int error, hlen; + int hlen; /* * Just return if packet doesn't have enough data. @@ -207,10 +207,7 @@ udp_ipsec_input(struct mbuf *m, int off, int af) * will do this anyway, so don't touch them here. */ ESPSTAT_INC(esps_input); - error = (*sav->tdb_xform->xf_input)(m, sav, hlen, off); - if (error != 0) - key_freesav(&sav); - + (*sav->tdb_xform->xf_input)(m, sav, hlen, off); return (EINPROGRESS); /* Consumed by IPsec. */ } diff --git a/freebsd/sys/netipsec/xform_ah.c b/freebsd/sys/netipsec/xform_ah.c index 9c2620f4..6e9baa1f 100644 --- a/freebsd/sys/netipsec/xform_ah.c +++ b/freebsd/sys/netipsec/xform_ah.c @@ -195,9 +195,9 @@ ah_init0(struct secasvar *sav, struct xformsw *xsp, struct cryptoini *cria) return EINVAL; } keylen = _KEYLEN(sav->key_auth); - if (keylen != thash->keysize && thash->keysize != 0) { + if (keylen > thash->keysize && thash->keysize != 0) { DPRINTF(("%s: invalid keylength %d, algorithm %s requires " - "keysize %d\n", __func__, + "keysize less than %d\n", __func__, keylen, thash->name, thash->keysize)); return EINVAL; } diff --git a/freebsd/sys/netpfil/pf/pf_lb.c b/freebsd/sys/netpfil/pf/pf_lb.c index 8d437667..abbf1c1e 100644 --- a/freebsd/sys/netpfil/pf/pf_lb.c +++ b/freebsd/sys/netpfil/pf/pf_lb.c @@ -261,7 +261,8 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, return (0); } } else { - uint16_t tmp, cut; + uint32_t tmp; + uint16_t cut; if (low > high) { tmp = low; @@ -271,7 +272,7 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, /* low < high */ cut = arc4random() % (1 + high - low) + low; /* low <= cut <= high */ - for (tmp = cut; tmp <= high; ++(tmp)) { + for (tmp = cut; tmp <= high && tmp <= 0xffff; ++tmp) { key.port[1] = htons(tmp); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { @@ -279,7 +280,8 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, return (0); } } - for (tmp = cut - 1; tmp >= low; --(tmp)) { + tmp = cut; + for (tmp -= 1; tmp >= low && tmp <= 0xffff; --tmp) { key.port[1] = htons(tmp); if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { diff --git a/freebsd/sys/opencrypto/crypto.c b/freebsd/sys/opencrypto/crypto.c index c1132ff3..57378e2f 100644 --- a/freebsd/sys/opencrypto/crypto.c +++ b/freebsd/sys/opencrypto/crypto.c @@ -467,7 +467,7 @@ crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid) CRYPTDEB("dev newsession failed"); } else { CRYPTDEB("no driver"); - err = EINVAL; + err = EOPNOTSUPP; } CRYPTO_DRIVER_UNLOCK(); return err; diff --git a/freebsd/sys/opencrypto/cryptodev.c b/freebsd/sys/opencrypto/cryptodev.c index 20c8c89b..9d8b23dc 100644 --- a/freebsd/sys/opencrypto/cryptodev.c +++ b/freebsd/sys/opencrypto/cryptodev.c @@ -526,7 +526,8 @@ cryptof_ioctl( if (thash) { cria.cri_alg = thash->type; cria.cri_klen = sop->mackeylen * 8; - if (sop->mackeylen != thash->keysize) { + if (thash->keysize != 0 && + sop->mackeylen > thash->keysize) { CRYPTDEB("invalid mac key length"); error = EINVAL; goto bail; @@ -758,18 +759,22 @@ cryptodev_op( goto bail; } - if (cse->thash) { - crda = crp->crp_desc; - if (cse->txform) - crde = crda->crd_next; - } else { - if (cse->txform) + if (cse->thash && cse->txform) { + if (cop->flags & COP_F_CIPHER_FIRST) { crde = crp->crp_desc; - else { - SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); - error = EINVAL; - goto bail; + crda = crde->crd_next; + } else { + crda = crp->crp_desc; + crde = crda->crd_next; } + } else if (cse->thash) { + crda = crp->crp_desc; + } else if (cse->txform) { + crde = crp->crp_desc; + } else { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); + error = EINVAL; + goto bail; } if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, @@ -925,7 +930,7 @@ cryptodev_aead( uio->uio_iov = &cse->iovec; uio->uio_iovcnt = 1; uio->uio_offset = 0; - uio->uio_resid = caead->len + caead->aadlen + cse->thash->hashsize; + uio->uio_resid = caead->aadlen + caead->len + cse->thash->hashsize; uio->uio_segflg = UIO_SYSSPACE; uio->uio_rw = UIO_WRITE; uio->uio_td = td; @@ -940,20 +945,33 @@ cryptodev_aead( goto bail; } - crda = crp->crp_desc; - crde = crda->crd_next; + if (caead->flags & COP_F_CIPHER_FIRST) { + crde = crp->crp_desc; + crda = crde->crd_next; + } else { + crda = crp->crp_desc; + crde = crda->crd_next; + } - if ((error = copyin(caead->src, cse->uio.uio_iov[0].iov_base, - caead->len))) + if ((error = copyin(caead->aad, cse->uio.uio_iov[0].iov_base, + caead->aadlen))) goto bail; - if ((error = copyin(caead->aad, (char *)cse->uio.uio_iov[0].iov_base + - caead->len, caead->aadlen))) + if ((error = copyin(caead->src, (char *)cse->uio.uio_iov[0].iov_base + + caead->aadlen, caead->len))) goto bail; - crda->crd_skip = caead->len; - crda->crd_len = caead->aadlen; - crda->crd_inject = caead->len + caead->aadlen; + /* + * For GCM, crd_len covers only the AAD. For other ciphers + * chained with an HMAC, crd_len covers both the AAD and the + * cipher text. + */ + crda->crd_skip = 0; + if (cse->cipher == CRYPTO_AES_NIST_GCM_16) + crda->crd_len = caead->aadlen; + else + crda->crd_len = caead->aadlen + caead->len; + crda->crd_inject = caead->aadlen + caead->len; crda->crd_alg = cse->mac; crda->crd_key = cse->mackey; @@ -963,15 +981,15 @@ cryptodev_aead( crde->crd_flags |= CRD_F_ENCRYPT; else crde->crd_flags &= ~CRD_F_ENCRYPT; - /* crde->crd_skip set below */ + crde->crd_skip = caead->aadlen; crde->crd_len = caead->len; - crde->crd_inject = 0; + crde->crd_inject = caead->aadlen; crde->crd_alg = cse->cipher; crde->crd_key = cse->key; crde->crd_klen = cse->keylen * 8; - crp->crp_ilen = caead->len + caead->aadlen; + crp->crp_ilen = caead->aadlen + caead->len; crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM | (caead->flags & COP_F_BATCH); crp->crp_buf = (caddr_t)&cse->uio.uio_iov; @@ -989,10 +1007,9 @@ cryptodev_aead( goto bail; bcopy(cse->tmp_iv, crde->crd_iv, caead->ivlen); crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; - crde->crd_skip = 0; } else { crde->crd_flags |= CRD_F_IV_PRESENT; - crde->crd_skip = cse->txform->blocksize; + crde->crd_skip += cse->txform->blocksize; crde->crd_len -= cse->txform->blocksize; } @@ -1032,12 +1049,13 @@ again: goto bail; } - if (caead->dst && (error = copyout(cse->uio.uio_iov[0].iov_base, - caead->dst, caead->len))) + if (caead->dst && (error = copyout( + (caddr_t)cse->uio.uio_iov[0].iov_base + caead->aadlen, caead->dst, + caead->len))) goto bail; if ((error = copyout((caddr_t)cse->uio.uio_iov[0].iov_base + - caead->len + caead->aadlen, caead->tag, cse->thash->hashsize))) + caead->aadlen + caead->len, caead->tag, cse->thash->hashsize))) goto bail; bail: diff --git a/freebsd/sys/opencrypto/cryptodev.h b/freebsd/sys/opencrypto/cryptodev.h index ca584694..c42515a6 100644 --- a/freebsd/sys/opencrypto/cryptodev.h +++ b/freebsd/sys/opencrypto/cryptodev.h @@ -95,13 +95,6 @@ #define HMAC_IPAD_VAL 0x36 #define HMAC_OPAD_VAL 0x5C /* HMAC Key Length */ -#define NULL_HMAC_KEY_LEN 0 -#define MD5_HMAC_KEY_LEN 16 -#define SHA1_HMAC_KEY_LEN 20 -#define RIPEMD160_HMAC_KEY_LEN 20 -#define SHA2_256_HMAC_KEY_LEN 32 -#define SHA2_384_HMAC_KEY_LEN 48 -#define SHA2_512_HMAC_KEY_LEN 64 #define AES_128_GMAC_KEY_LEN 16 #define AES_192_GMAC_KEY_LEN 24 #define AES_256_GMAC_KEY_LEN 32 @@ -238,7 +231,8 @@ struct crypt_op { #define COP_ENCRYPT 1 #define COP_DECRYPT 2 u_int16_t flags; -#define COP_F_BATCH 0x0008 /* Batch op if possible */ +#define COP_F_CIPHER_FIRST 0x0001 /* Cipher before MAC. */ +#define COP_F_BATCH 0x0008 /* Batch op if possible */ u_int len; c_caddr_t src; /* become iov[] inside kernel */ caddr_t dst; diff --git a/freebsd/sys/opencrypto/xform_aes_icm.c b/freebsd/sys/opencrypto/xform_aes_icm.c index 94fa377a..8d3694fa 100644 --- a/freebsd/sys/opencrypto/xform_aes_icm.c +++ b/freebsd/sys/opencrypto/xform_aes_icm.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_aes_xts.c b/freebsd/sys/opencrypto/xform_aes_xts.c index ab20368e..dedbe627 100644 --- a/freebsd/sys/opencrypto/xform_aes_xts.c +++ b/freebsd/sys/opencrypto/xform_aes_xts.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_blf.c b/freebsd/sys/opencrypto/xform_blf.c index b88185b6..b4be5f8d 100644 --- a/freebsd/sys/opencrypto/xform_blf.c +++ b/freebsd/sys/opencrypto/xform_blf.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_cast5.c b/freebsd/sys/opencrypto/xform_cast5.c index 6929faa3..85b346eb 100644 --- a/freebsd/sys/opencrypto/xform_cast5.c +++ b/freebsd/sys/opencrypto/xform_cast5.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_cml.c b/freebsd/sys/opencrypto/xform_cml.c index c99b8c65..c807fa97 100644 --- a/freebsd/sys/opencrypto/xform_cml.c +++ b/freebsd/sys/opencrypto/xform_cml.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_deflate.c b/freebsd/sys/opencrypto/xform_deflate.c index a17b87f4..c8864bf6 100644 --- a/freebsd/sys/opencrypto/xform_deflate.c +++ b/freebsd/sys/opencrypto/xform_deflate.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_des1.c b/freebsd/sys/opencrypto/xform_des1.c index 91e52e52..cbce5e29 100644 --- a/freebsd/sys/opencrypto/xform_des1.c +++ b/freebsd/sys/opencrypto/xform_des1.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_des3.c b/freebsd/sys/opencrypto/xform_des3.c index e47de600..1b26b622 100644 --- a/freebsd/sys/opencrypto/xform_des3.c +++ b/freebsd/sys/opencrypto/xform_des3.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_gmac.c b/freebsd/sys/opencrypto/xform_gmac.c index be846fbf..156ed7f1 100644 --- a/freebsd/sys/opencrypto/xform_gmac.c +++ b/freebsd/sys/opencrypto/xform_gmac.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_md5.c b/freebsd/sys/opencrypto/xform_md5.c index fd69a1c7..47dfc75c 100644 --- a/freebsd/sys/opencrypto/xform_md5.c +++ b/freebsd/sys/opencrypto/xform_md5.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), @@ -59,17 +57,27 @@ static int MD5Update_int(void *, const u_int8_t *, u_int16_t); /* Authentication instances */ struct auth_hash auth_hash_hmac_md5 = { - CRYPTO_MD5_HMAC, "HMAC-MD5", - MD5_HMAC_KEY_LEN, MD5_HASH_LEN, sizeof(MD5_CTX), MD5_HMAC_BLOCK_LEN, - (void (*) (void *)) MD5Init, NULL, NULL, MD5Update_int, - (void (*) (u_int8_t *, void *)) MD5Final + .type = CRYPTO_MD5_HMAC, + .name = "HMAC-MD5", + .keysize = MD5_HMAC_BLOCK_LEN, + .hashsize = MD5_HASH_LEN, + .ctxsize = sizeof(MD5_CTX), + .blocksize = MD5_HMAC_BLOCK_LEN, + .Init = (void (*) (void *)) MD5Init, + .Update = MD5Update_int, + .Final = (void (*) (u_int8_t *, void *)) MD5Final, }; struct auth_hash auth_hash_key_md5 = { - CRYPTO_MD5_KPDK, "Keyed MD5", - NULL_HMAC_KEY_LEN, MD5_KPDK_HASH_LEN, sizeof(MD5_CTX), 0, - (void (*)(void *)) MD5Init, NULL, NULL, MD5Update_int, - (void (*)(u_int8_t *, void *)) MD5Final + .type = CRYPTO_MD5_KPDK, + .name = "Keyed MD5", + .keysize = 0, + .hashsize = MD5_KPDK_HASH_LEN, + .ctxsize = sizeof(MD5_CTX), + .blocksize = 0, + .Init = (void (*)(void *)) MD5Init, + .Update = MD5Update_int, + .Final = (void (*)(u_int8_t *, void *)) MD5Final, }; /* diff --git a/freebsd/sys/opencrypto/xform_null.c b/freebsd/sys/opencrypto/xform_null.c index 6dcf3ffd..3c499b31 100644 --- a/freebsd/sys/opencrypto/xform_null.c +++ b/freebsd/sys/opencrypto/xform_null.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), @@ -78,10 +76,18 @@ struct enc_xform enc_xform_null = { }; /* Authentication instances */ -struct auth_hash auth_hash_null = { /* NB: context isn't used */ - CRYPTO_NULL_HMAC, "NULL-HMAC", - NULL_HMAC_KEY_LEN, NULL_HASH_LEN, sizeof(int), NULL_HMAC_BLOCK_LEN, - null_init, null_reinit, null_reinit, null_update, null_final +struct auth_hash auth_hash_null = { + .type = CRYPTO_NULL_HMAC, + .name = "NULL-HMAC", + .keysize = 0, + .hashsize = NULL_HASH_LEN, + .ctxsize = sizeof(int), /* NB: context isn't used */ + .blocksize = NULL_HMAC_BLOCK_LEN, + .Init = null_init, + .Setkey = null_reinit, + .Reinit = null_reinit, + .Update = null_update, + .Final = null_final, }; /* diff --git a/freebsd/sys/opencrypto/xform_rijndael.c b/freebsd/sys/opencrypto/xform_rijndael.c index 9dcb4d3c..2c974f3d 100644 --- a/freebsd/sys/opencrypto/xform_rijndael.c +++ b/freebsd/sys/opencrypto/xform_rijndael.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/opencrypto/xform_rmd160.c b/freebsd/sys/opencrypto/xform_rmd160.c index 016bd627..ee344e80 100644 --- a/freebsd/sys/opencrypto/xform_rmd160.c +++ b/freebsd/sys/opencrypto/xform_rmd160.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), @@ -59,11 +57,15 @@ static int RMD160Update_int(void *, const u_int8_t *, u_int16_t); /* Authentication instances */ struct auth_hash auth_hash_hmac_ripemd_160 = { - CRYPTO_RIPEMD160_HMAC, "HMAC-RIPEMD-160", - RIPEMD160_HMAC_KEY_LEN, RIPEMD160_HASH_LEN, sizeof(RMD160_CTX), - RIPEMD160_HMAC_BLOCK_LEN, - (void (*)(void *)) RMD160Init, NULL, NULL, RMD160Update_int, - (void (*)(u_int8_t *, void *)) RMD160Final + .type = CRYPTO_RIPEMD160_HMAC, + .name = "HMAC-RIPEMD-160", + .keysize = RIPEMD160_HMAC_BLOCK_LEN, + .hashsize = RIPEMD160_HASH_LEN, + .ctxsize = sizeof(RMD160_CTX), + .blocksize = RIPEMD160_HMAC_BLOCK_LEN, + .Init = (void (*)(void *)) RMD160Init, + .Update = RMD160Update_int, + .Final = (void (*)(u_int8_t *, void *)) RMD160Final, }; /* diff --git a/freebsd/sys/opencrypto/xform_sha1.c b/freebsd/sys/opencrypto/xform_sha1.c index 76489048..974dfb8a 100644 --- a/freebsd/sys/opencrypto/xform_sha1.c +++ b/freebsd/sys/opencrypto/xform_sha1.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), @@ -61,15 +59,27 @@ static void SHA1Final_int(u_int8_t *, void *); /* Authentication instances */ struct auth_hash auth_hash_hmac_sha1 = { - CRYPTO_SHA1_HMAC, "HMAC-SHA1", - SHA1_HMAC_KEY_LEN, SHA1_HASH_LEN, sizeof(SHA1_CTX), SHA1_HMAC_BLOCK_LEN, - SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int + .type = CRYPTO_SHA1_HMAC, + .name = "HMAC-SHA1", + .keysize = SHA1_HMAC_BLOCK_LEN, + .hashsize = SHA1_HASH_LEN, + .ctxsize = sizeof(SHA1_CTX), + .blocksize = SHA1_HMAC_BLOCK_LEN, + .Init = SHA1Init_int, + .Update = SHA1Update_int, + .Final = SHA1Final_int, }; struct auth_hash auth_hash_key_sha1 = { - CRYPTO_SHA1_KPDK, "Keyed SHA1", - NULL_HMAC_KEY_LEN, SHA1_KPDK_HASH_LEN, sizeof(SHA1_CTX), 0, - SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int + .type = CRYPTO_SHA1_KPDK, + .name = "Keyed SHA1", + .keysize = 0, + .hashsize = SHA1_KPDK_HASH_LEN, + .ctxsize = sizeof(SHA1_CTX), + .blocksize = 0, + .Init = SHA1Init_int, + .Update = SHA1Update_int, + .Final = SHA1Final_int, }; /* diff --git a/freebsd/sys/opencrypto/xform_sha2.c b/freebsd/sys/opencrypto/xform_sha2.c index f3f895d0..7844b8ff 100644 --- a/freebsd/sys/opencrypto/xform_sha2.c +++ b/freebsd/sys/opencrypto/xform_sha2.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), @@ -63,27 +61,39 @@ static int SHA512Update_int(void *, const u_int8_t *, u_int16_t); /* Authentication instances */ struct auth_hash auth_hash_hmac_sha2_256 = { - CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-256", - SHA2_256_HMAC_KEY_LEN, SHA2_256_HASH_LEN, sizeof(SHA256_CTX), - SHA2_256_HMAC_BLOCK_LEN, - (void (*)(void *)) SHA256_Init, NULL, NULL, SHA256Update_int, - (void (*)(u_int8_t *, void *)) SHA256_Final + .type = CRYPTO_SHA2_256_HMAC, + .name = "HMAC-SHA2-256", + .keysize = SHA2_256_HMAC_BLOCK_LEN, + .hashsize = SHA2_256_HASH_LEN, + .ctxsize = sizeof(SHA256_CTX), + .blocksize = SHA2_256_HMAC_BLOCK_LEN, + .Init = (void (*)(void *)) SHA256_Init, + .Update = SHA256Update_int, + .Final = (void (*)(u_int8_t *, void *)) SHA256_Final, }; struct auth_hash auth_hash_hmac_sha2_384 = { - CRYPTO_SHA2_384_HMAC, "HMAC-SHA2-384", - SHA2_384_HMAC_KEY_LEN, SHA2_384_HASH_LEN, sizeof(SHA384_CTX), - SHA2_384_HMAC_BLOCK_LEN, - (void (*)(void *)) SHA384_Init, NULL, NULL, SHA384Update_int, - (void (*)(u_int8_t *, void *)) SHA384_Final + .type = CRYPTO_SHA2_384_HMAC, + .name = "HMAC-SHA2-384", + .keysize = SHA2_384_HMAC_BLOCK_LEN, + .hashsize = SHA2_384_HASH_LEN, + .ctxsize = sizeof(SHA384_CTX), + .blocksize = SHA2_384_HMAC_BLOCK_LEN, + .Init = (void (*)(void *)) SHA384_Init, + .Update = SHA384Update_int, + .Final = (void (*)(u_int8_t *, void *)) SHA384_Final, }; struct auth_hash auth_hash_hmac_sha2_512 = { - CRYPTO_SHA2_512_HMAC, "HMAC-SHA2-512", - SHA2_512_HMAC_KEY_LEN, SHA2_512_HASH_LEN, sizeof(SHA512_CTX), - SHA2_512_HMAC_BLOCK_LEN, - (void (*)(void *)) SHA512_Init, NULL, NULL, SHA512Update_int, - (void (*)(u_int8_t *, void *)) SHA512_Final + .type = CRYPTO_SHA2_512_HMAC, + .name = "HMAC-SHA2-512", + .keysize = SHA2_512_HMAC_BLOCK_LEN, + .hashsize = SHA2_512_HASH_LEN, + .ctxsize = sizeof(SHA512_CTX), + .blocksize = SHA2_512_HMAC_BLOCK_LEN, + .Init = (void (*)(void *)) SHA512_Init, + .Update = SHA512Update_int, + .Final = (void (*)(u_int8_t *, void *)) SHA512_Final, }; /* diff --git a/freebsd/sys/opencrypto/xform_skipjack.c b/freebsd/sys/opencrypto/xform_skipjack.c index 066381c9..94090d0d 100644 --- a/freebsd/sys/opencrypto/xform_skipjack.c +++ b/freebsd/sys/opencrypto/xform_skipjack.c @@ -1,5 +1,3 @@ -#include <machine/rtems-bsd-kernel-space.h> - /* $OpenBSD: xform.c,v 1.16 2001/08/28 12:20:43 ben Exp $ */ /*- * The authors of this code are John Ioannidis (ji@tla.org), diff --git a/freebsd/sys/powerpc/include/machine/spr.h b/freebsd/sys/powerpc/include/machine/spr.h index d9501153..5efdf961 100644 --- a/freebsd/sys/powerpc/include/machine/spr.h +++ b/freebsd/sys/powerpc/include/machine/spr.h @@ -171,6 +171,7 @@ #define IBMPOWER7PLUS 0x004a #define IBMPOWER8E 0x004b #define IBMPOWER8 0x004d +#define IBMPOWER9 0x004e #define MPC860 0x0050 #define IBMCELLBE 0x0070 #define MPC8240 0x0081 @@ -191,6 +192,10 @@ #define FSL_E500mc 0x8023 #define FSL_E5500 0x8024 #define FSL_E6500 0x8040 +#define FSL_E300C1 0x8083 +#define FSL_E300C2 0x8084 +#define FSL_E300C3 0x8085 +#define FSL_E300C4 0x8086 #define SPR_EPCR 0x133 #define EPCR_EXTGS 0x80000000 @@ -742,6 +747,10 @@ #define SVR_P4080E 0x8209 #define SVR_P5020 0x8220 #define SVR_P5020E 0x8228 +#define SVR_P5021 0x8205 +#define SVR_P5021E 0x820d +#define SVR_P5040 0x8204 +#define SVR_P5040E 0x820c #define SVR_VER(svr) (((svr) >> 16) & 0xffff) #define SPR_PID0 0x030 /* ..8 Process ID Register 0 */ diff --git a/freebsd/sys/sys/_task.h b/freebsd/sys/sys/_task.h index d3be7198..d46659f4 100644 --- a/freebsd/sys/sys/_task.h +++ b/freebsd/sys/sys/_task.h @@ -65,7 +65,8 @@ struct grouptask { void *gt_taskqueue; LIST_ENTRY(grouptask) gt_list; void *gt_uniq; - char *gt_name; +#define GROUPTASK_NAMELEN 32 + char gt_name[GROUPTASK_NAMELEN]; int16_t gt_irq; int16_t gt_cpu; }; diff --git a/freebsd/sys/sys/blist.h b/freebsd/sys/sys/blist.h index 292f9b97..486e04eb 100644 --- a/freebsd/sys/sys/blist.h +++ b/freebsd/sys/sys/blist.h @@ -80,8 +80,7 @@ typedef struct blmeta { typedef struct blist { daddr_t bl_blocks; /* area of coverage */ - daddr_t bl_radix; /* coverage radix */ - daddr_t bl_skip; /* starting skip */ + u_daddr_t bl_radix; /* coverage radix */ daddr_t bl_cursor; /* next-fit search starts at */ blmeta_t *bl_root; /* root of radix tree */ } *blist_t; @@ -91,6 +90,8 @@ typedef struct blist { #define BLIST_MAX_ALLOC BLIST_BMAP_RADIX +struct sbuf; + daddr_t blist_alloc(blist_t blist, daddr_t count); daddr_t blist_avail(blist_t blist); blist_t blist_create(daddr_t blocks, int flags); @@ -99,6 +100,7 @@ daddr_t blist_fill(blist_t bl, daddr_t blkno, daddr_t count); void blist_free(blist_t blist, daddr_t blkno, daddr_t count); void blist_print(blist_t blist); void blist_resize(blist_t *pblist, daddr_t count, int freenew, int flags); +void blist_stats(blist_t blist, struct sbuf *s); #endif /* _SYS_BLIST_H_ */ diff --git a/freebsd/sys/sys/buf.h b/freebsd/sys/sys/buf.h index 58bd91e3..5d4f0dc6 100644 --- a/freebsd/sys/sys/buf.h +++ b/freebsd/sys/sys/buf.h @@ -70,7 +70,7 @@ extern struct bio_ops { struct vm_object; struct vm_page; -typedef unsigned char b_xflags_t; +typedef uint32_t b_xflags_t; /* * The buffer header describes an I/O operation in the kernel. @@ -104,6 +104,8 @@ struct buf { off_t b_iooffset; long b_resid; void (*b_iodone)(struct buf *); + void (*b_ckhashcalc)(struct buf *); + uint64_t b_ckhash; /* B_CKHASH requested check-hash */ daddr_t b_blkno; /* Underlying physical block number. */ off_t b_offset; /* Offset into file. */ TAILQ_ENTRY(buf) b_bobufs; /* (V) Buffer's associated vnode. */ @@ -209,7 +211,7 @@ struct buf { #define B_CACHE 0x00000020 /* Bread found us in the cache. */ #define B_VALIDSUSPWRT 0x00000040 /* Valid write during suspension. */ #define B_DELWRI 0x00000080 /* Delay I/O until buffer reused. */ -#define B_00000100 0x00000100 /* Available flag. */ +#define B_CKHASH 0x00000100 /* checksum hash calculated on read */ #define B_DONE 0x00000200 /* I/O completed. */ #define B_EINTR 0x00000400 /* I/O was interrupted */ #define B_NOREUSE 0x00000800 /* Contents not reused once released. */ @@ -242,12 +244,17 @@ struct buf { /* * These flags are kept in b_xflags. + * + * BX_FSPRIV reserves a set of eight flags that may be used by individual + * filesystems for their own purpose. Their specific definitions are + * found in the header files for each filesystem that uses them. */ #define BX_VNDIRTY 0x00000001 /* On vnode dirty list */ #define BX_VNCLEAN 0x00000002 /* On vnode clean list */ #define BX_BKGRDWRITE 0x00000010 /* Do writes in background */ #define BX_BKGRDMARKER 0x00000020 /* Mark buffer for splay tree */ #define BX_ALTDATA 0x00000040 /* Holds extended data */ +#define BX_FSPRIV 0x00FF0000 /* filesystem-specific flags mask */ #define PRINT_BUF_XFLAGS "\20\7altdata\6bkgrdmarker\5bkgrdwrite\2clean\1dirty" @@ -467,6 +474,7 @@ buf_track(struct buf *bp, const char *location) #define GB_NOWAIT_BD 0x0004 /* Do not wait for bufdaemon. */ #define GB_UNMAPPED 0x0008 /* Do not mmap buffer pages. */ #define GB_KVAALLOC 0x0010 /* But allocate KVA. */ +#define GB_CKHASH 0x0020 /* If reading, calc checksum hash */ #ifdef _KERNEL extern int nbuf; /* The number of buffer headers */ @@ -504,15 +512,15 @@ int buf_dirty_count_severe(void); void bremfree(struct buf *); void bremfreef(struct buf *); /* XXX Force bremfree, only for nfs. */ #define bread(vp, blkno, size, cred, bpp) \ - breadn_flags(vp, blkno, size, NULL, NULL, 0, cred, 0, bpp) + breadn_flags(vp, blkno, size, NULL, NULL, 0, cred, 0, NULL, bpp) #define bread_gb(vp, blkno, size, cred, gbflags, bpp) \ breadn_flags(vp, blkno, size, NULL, NULL, 0, cred, \ - gbflags, bpp) + gbflags, NULL, bpp) #define breadn(vp, blkno, size, rablkno, rabsize, cnt, cred, bpp) \ - breadn_flags(vp, blkno, size, rablkno, rabsize, cnt, cred, 0, bpp) + breadn_flags(vp, blkno, size, rablkno, rabsize, cnt, cred, \ + 0, NULL, bpp) int breadn_flags(struct vnode *, daddr_t, int, daddr_t *, int *, int, - struct ucred *, int, struct buf **); -void breada(struct vnode *, daddr_t *, int *, int, struct ucred *); + struct ucred *, int, void (*)(struct buf *), struct buf **); void bdwrite(struct buf *); void bawrite(struct buf *); void babarrierwrite(struct buf *); diff --git a/freebsd/sys/sys/conf.h b/freebsd/sys/sys/conf.h index a49b6d60..8bf6a3ed 100644 --- a/freebsd/sys/sys/conf.h +++ b/freebsd/sys/sys/conf.h @@ -370,12 +370,13 @@ struct dumperinfo { int set_dumper(struct dumperinfo *di, const char *devname, struct thread *td, uint8_t encrypt, const uint8_t *key, uint32_t encryptedkeysize, const uint8_t *encryptedkey); +void dump_init_header(const struct dumperinfo *di, struct kerneldumpheader *kdh, + char *magic, uint32_t archver, uint64_t dumplen); +int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh, + off_t *dumplop); +int dump_finish(struct dumperinfo *di, struct kerneldumpheader *kdh, + off_t dumplo); int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t); -int dump_write_pad(struct dumperinfo *, void *, vm_offset_t, off_t, size_t, - size_t *); -int dump_write_header(struct dumperinfo *di, struct kerneldumpheader *kdh, - vm_offset_t physical, off_t offset); -int dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset); int doadump(boolean_t); #ifndef __rtems__ extern int dumping; /* system is dumping */ diff --git a/freebsd/sys/sys/gpio.h b/freebsd/sys/sys/gpio.h index 9b0a1b55..dbe55872 100644 --- a/freebsd/sys/sys/gpio.h +++ b/freebsd/sys/sys/gpio.h @@ -70,6 +70,8 @@ #define GPIO_PIN_INVIN 0x00000080 /* invert input */ #define GPIO_PIN_INVOUT 0x00000100 /* invert output */ #define GPIO_PIN_PULSATE 0x00000200 /* pulsate in hardware */ +#define GPIO_PIN_PRESET_LOW 0x00000400 /* preset pin to high or */ +#define GPIO_PIN_PRESET_HIGH 0x00000800 /* low before enabling output */ /* GPIO interrupt capabilities */ #define GPIO_INTR_NONE 0x00000000 /* no interrupt support */ #define GPIO_INTR_LEVEL_LOW 0x00010000 /* level trigger, low */ @@ -95,6 +97,71 @@ struct gpio_req { }; /* + * gpio_access_32 / GPIOACCESS32 + * + * Simultaneously read and/or change up to 32 adjacent pins. + * If the device cannot change the pins simultaneously, returns EOPNOTSUPP. + * + * This accesses an adjacent set of up to 32 pins starting at first_pin within + * the device's collection of pins. How the hardware pins are mapped to the 32 + * bits in the arguments is device-specific. It is expected that lower-numbered + * pins in the device's number space map linearly to lower-ordered bits within + * the 32-bit words (i.e., bit 0 is first_pin, bit 1 is first_pin+1, etc). + * Other mappings are possible; know your device. + * + * Some devices may limit the value of first_pin to 0, or to multiples of 16 or + * 32 or some other hardware-specific number; to access pin 2 would require + * first_pin to be zero and then manipulate bit (1 << 2) in the 32-bit word. + * Invalid values in first_pin result in an EINVAL error return. + * + * The starting state of the pins is captured and stored in orig_pins, then the + * pins are set to ((starting_state & ~clear_pins) ^ change_pins). + * + * Clear Change Hardware pin after call + * 0 0 No change + * 0 1 Opposite of current value + * 1 0 Cleared + * 1 1 Set + */ +struct gpio_access_32 { + uint32_t first_pin; /* First pin in group of 32 adjacent */ + uint32_t clear_pins; /* Pins are changed using: */ + uint32_t change_pins; /* ((hwstate & ~clear_pins) ^ change_pins) */ + uint32_t orig_pins; /* Returned hwstate of pins before change. */ +}; + +/* + * gpio_config_32 / GPIOCONFIG32 + * + * Simultaneously configure up to 32 adjacent pins. This is intended to change + * the configuration of all the pins simultaneously, such that pins configured + * for output all begin to drive the configured values simultaneously, but not + * all hardware can do that, so the driver "does the best it can" in this + * regard. Notably unlike pin_access_32(), this does NOT fail if the pins + * cannot be atomically configured; it is expected that callers understand the + * hardware and have decided to live with any such limitations it may have. + * + * The pin_flags argument is an array of GPIO_PIN_xxxx flags. If the array + * contains any GPIO_PIN_OUTPUT flags, the driver will manipulate the hardware + * such that all output pins become driven with the proper initial values + * simultaneously if it can. The elements in the array map to pins in the same + * way that bits are mapped by pin_acces_32(), and the same restrictions may + * apply. For example, to configure pins 2 and 3 it may be necessary to set + * first_pin to zero and only populate pin_flags[2] and pin_flags[3]. If a + * given array entry doesn't contain GPIO_PIN_INPUT or GPIO_PIN_OUTPUT then no + * configuration is done for that pin. + * + * Some devices may limit the value of first_pin to 0, or to multiples of 16 or + * 32 or some other hardware-specific number. Invalid values in first_pin or + * num_pins result in an error return with errno set to EINVAL. + */ +struct gpio_config_32 { + uint32_t first_pin; + uint32_t num_pins; + uint32_t pin_flags[32]; +}; + +/* * ioctls */ #define GPIOMAXPIN _IOR('G', 0, int) @@ -104,5 +171,7 @@ struct gpio_req { #define GPIOSET _IOW('G', 4, struct gpio_req) #define GPIOTOGGLE _IOWR('G', 5, struct gpio_req) #define GPIOSETNAME _IOW('G', 6, struct gpio_pin) +#define GPIOACCESS32 _IOWR('G', 7, struct gpio_access_32) +#define GPIOCONFIG32 _IOW('G', 8, struct gpio_config_32) #endif /* __GPIO_H__ */ diff --git a/freebsd/sys/sys/gtaskqueue.h b/freebsd/sys/sys/gtaskqueue.h index c9b34e4f..e8519637 100644 --- a/freebsd/sys/sys/gtaskqueue.h +++ b/freebsd/sys/sys/gtaskqueue.h @@ -80,21 +80,6 @@ int taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride); #define TASKQGROUP_DECLARE(name) \ extern struct taskqgroup *qgroup_##name -#ifdef EARLY_AP_STARTUP -#define TASKQGROUP_DEFINE(name, cnt, stride) \ - \ -struct taskqgroup *qgroup_##name; \ - \ -static void \ -taskqgroup_define_##name(void *arg) \ -{ \ - qgroup_##name = taskqgroup_create(#name); \ - taskqgroup_adjust(qgroup_##name, (cnt), (stride)); \ -} \ - \ -SYSINIT(taskqgroup_##name, SI_SUB_INIT_IF, SI_ORDER_FIRST, \ - taskqgroup_define_##name, NULL) -#else /* !EARLY_AP_STARTUP */ #define TASKQGROUP_DEFINE(name, cnt, stride) \ \ struct taskqgroup *qgroup_##name; \ @@ -105,7 +90,7 @@ taskqgroup_define_##name(void *arg) \ qgroup_##name = taskqgroup_create(#name); \ } \ \ -SYSINIT(taskqgroup_##name, SI_SUB_INIT_IF, SI_ORDER_FIRST, \ +SYSINIT(taskqgroup_##name, SI_SUB_TASKQ, SI_ORDER_FIRST, \ taskqgroup_define_##name, NULL); \ \ static void \ @@ -116,7 +101,6 @@ taskqgroup_adjust_##name(void *arg) \ \ SYSINIT(taskqgroup_adj_##name, SI_SUB_SMP, SI_ORDER_ANY, \ taskqgroup_adjust_##name, NULL) -#endif /* EARLY_AP_STARTUP */ TASKQGROUP_DECLARE(net); TASKQGROUP_DECLARE(softirq); diff --git a/freebsd/sys/sys/kernel.h b/freebsd/sys/sys/kernel.h index 3ca8af6e..051173f7 100644 --- a/freebsd/sys/sys/kernel.h +++ b/freebsd/sys/sys/kernel.h @@ -129,6 +129,7 @@ enum sysinit_sub_id { SI_SUB_SCHED_IDLE = 0x2600000, /* required idle procs */ SI_SUB_MBUF = 0x2700000, /* mbuf subsystem */ SI_SUB_INTR = 0x2800000, /* interrupt threads */ + SI_SUB_TASKQ = 0x2880000, /* task queues */ #ifdef EARLY_AP_STARTUP SI_SUB_SMP = 0x2900000, /* start the APs*/ #endif @@ -454,13 +455,16 @@ struct tunable_str { #define TUNABLE_STR_FETCH(path, var, size) #endif /* __rtems__ */ +typedef void (*ich_func_t)(void *_arg); + struct intr_config_hook { TAILQ_ENTRY(intr_config_hook) ich_links; - void (*ich_func)(void *arg); - void *ich_arg; + ich_func_t ich_func; + void *ich_arg; }; int config_intrhook_establish(struct intr_config_hook *hook); void config_intrhook_disestablish(struct intr_config_hook *hook); +void config_intrhook_oneshot(ich_func_t _func, void *_arg); #endif /* !_SYS_KERNEL_H_*/ diff --git a/freebsd/sys/sys/mbuf.h b/freebsd/sys/sys/mbuf.h index 60670697..ec98aaec 100644 --- a/freebsd/sys/sys/mbuf.h +++ b/freebsd/sys/sys/mbuf.h @@ -335,6 +335,16 @@ struct mbuf { * for ordering and distribution without explicit affinity. Additionally, * M_HASHTYPE_OPAQUE_HASH indicates that the flow identifier has hash * properties. + * + * The meaning of the IPV6_EX suffix: + * "o Home address from the home address option in the IPv6 destination + * options header. If the extension header is not present, use the Source + * IPv6 Address. + * o IPv6 address that is contained in the Routing-Header-Type-2 from the + * associated extension header. If the extension header is not present, + * use the Destination IPv6 Address." + * Quoted from: + * https://docs.microsoft.com/en-us/windows-hardware/drivers/network/rss-hashing-types#ndishashipv6ex */ #define M_HASHTYPE_HASHPROP 0x80 /* has hash properties */ #define M_HASHTYPE_HASH(t) (M_HASHTYPE_HASHPROP | (t)) @@ -348,10 +358,7 @@ struct mbuf { * ext hdrs */ #define M_HASHTYPE_RSS_TCP_IPV6_EX M_HASHTYPE_HASH(6) /* TCPv6 4-tuple + * ext hdrs */ -/* Non-standard RSS hash types */ #define M_HASHTYPE_RSS_UDP_IPV4 M_HASHTYPE_HASH(7) /* IPv4 UDP 4-tuple*/ -#define M_HASHTYPE_RSS_UDP_IPV4_EX M_HASHTYPE_HASH(8) /* IPv4 UDP 4-tuple + - * ext hdrs */ #define M_HASHTYPE_RSS_UDP_IPV6 M_HASHTYPE_HASH(9) /* IPv6 UDP 4-tuple*/ #define M_HASHTYPE_RSS_UDP_IPV6_EX M_HASHTYPE_HASH(10)/* IPv6 UDP 4-tuple + * ext hdrs */ diff --git a/freebsd/sys/sys/module.h b/freebsd/sys/sys/module.h index 5a268fc1..75471611 100644 --- a/freebsd/sys/sys/module.h +++ b/freebsd/sys/sys/module.h @@ -183,7 +183,7 @@ struct mod_pnp_match_info &_module_pnp_##b##_##unique, #b); /** * descr is a string that describes each entry in the table. The general - * form is (TYPE:pnp_name[/pnp_name];)* + * form is the grammar (TYPE:pnp_name[/pnp_name];)* * where TYPE is one of the following: * U8 uint8_t element * V8 like U8 and 0xff means match any @@ -196,12 +196,14 @@ struct mod_pnp_match_info * V32 like U32 and 0xffffffff means match any * W32 Two 16-bit values with first pnp_name in LSW and second in MSW. * Z pointer to a string to match exactly - * D like Z, but is the string passed to device_set_descr() + * D pointer to a string to human readable description for device * P A pointer that should be ignored * E EISA PNP Identifier (in binary, but bus publishes string) * K Key for whole table. pnp_name=value. must be last, if present. * * The pnp_name "#" is reserved for other fields that should be ignored. + * Otherwise pnp_name must match the name from the parent device's pnpinfo + * output. The second pnp_name is used for the W32 type. */ extern struct sx modules_sx; diff --git a/freebsd/sys/sys/mutex.h b/freebsd/sys/sys/mutex.h index 5325b363..bd773b58 100644 --- a/freebsd/sys/sys/mutex.h +++ b/freebsd/sys/sys/mutex.h @@ -107,12 +107,12 @@ int _mtx_trylock_flags_(volatile uintptr_t *c, int opts, const char *file, void mutex_init(void); #ifndef __rtems__ #if LOCK_DEBUG > 0 -void __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t v, uintptr_t tid, - int opts, const char *file, int line); +void __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t v, int opts, + const char *file, int line); void __mtx_unlock_sleep(volatile uintptr_t *c, int opts, const char *file, int line); #else -void __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t v, uintptr_t tid); +void __mtx_lock_sleep(volatile uintptr_t *c, uintptr_t v); void __mtx_unlock_sleep(volatile uintptr_t *c); #endif @@ -176,13 +176,13 @@ void thread_lock_flags_(struct thread *, int, const char *, int); #define mtx_trylock_flags_(m, o, f, l) \ _mtx_trylock_flags_(&(m)->mtx_lock, o, f, l) #if LOCK_DEBUG > 0 -#define _mtx_lock_sleep(m, v, t, o, f, l) \ - __mtx_lock_sleep(&(m)->mtx_lock, v, t, o, f, l) +#define _mtx_lock_sleep(m, v, o, f, l) \ + __mtx_lock_sleep(&(m)->mtx_lock, v, o, f, l) #define _mtx_unlock_sleep(m, o, f, l) \ __mtx_unlock_sleep(&(m)->mtx_lock, o, f, l) #else -#define _mtx_lock_sleep(m, v, t, o, f, l) \ - __mtx_lock_sleep(&(m)->mtx_lock, v, t) +#define _mtx_lock_sleep(m, v, o, f, l) \ + __mtx_lock_sleep(&(m)->mtx_lock, v) #define _mtx_unlock_sleep(m, o, f, l) \ __mtx_unlock_sleep(&(m)->mtx_lock) #endif @@ -238,7 +238,7 @@ void thread_lock_flags_(struct thread *, int, const char *, int); \ if (__predict_false(LOCKSTAT_PROFILE_ENABLED(adaptive__acquire) ||\ !_mtx_obtain_lock_fetch((mp), &_v, _tid))) \ - _mtx_lock_sleep((mp), _v, _tid, (opts), (file), (line));\ + _mtx_lock_sleep((mp), _v, (opts), (file), (line)); \ } while (0) /* diff --git a/freebsd/sys/sys/sbuf.h b/freebsd/sys/sys/sbuf.h index c05bafd1..d0f908be 100644 --- a/freebsd/sys/sys/sbuf.h +++ b/freebsd/sys/sys/sbuf.h @@ -49,6 +49,7 @@ struct sbuf { #define SBUF_FIXEDLEN 0x00000000 /* fixed length buffer (default) */ #define SBUF_AUTOEXTEND 0x00000001 /* automatically extend buffer */ #define SBUF_INCLUDENUL 0x00000002 /* nulterm byte is counted in len */ +#define SBUF_DRAINTOEOR 0x00000004 /* use section 0 as drain EOR marker */ #define SBUF_USRFLAGMSK 0x0000ffff /* mask of flags the user may specify */ #define SBUF_DYNAMIC 0x00010000 /* s_buf must be freed */ #define SBUF_FINISHED 0x00020000 /* set by sbuf_finish() */ @@ -56,6 +57,7 @@ struct sbuf { #define SBUF_INSECTION 0x00100000 /* set by sbuf_start_section() */ int s_flags; /* flags */ ssize_t s_sect_len; /* current length of section */ + ssize_t s_rec_off; /* current record start offset */ }; #ifndef HD_COLUMN_MASK diff --git a/freebsd/sys/sys/smp.h b/freebsd/sys/sys/smp.h index 9101bd76..9253304f 100644 --- a/freebsd/sys/sys/smp.h +++ b/freebsd/sys/sys/smp.h @@ -120,8 +120,25 @@ struct topo_node * topo_next_node(struct topo_node *top, struct topo_node * topo_next_nonchild_node(struct topo_node *top, struct topo_node *node); void topo_set_pu_id(struct topo_node *node, cpuid_t id); -int topo_analyze(struct topo_node *topo_root, int all, int *pkg_count, - int *cores_per_pkg, int *thrs_per_core); + +enum topo_level { + TOPO_LEVEL_PKG = 0, + /* + * Some systems have useful sub-package core organizations. On these, + * a package has one or more subgroups. Each subgroup contains one or + * more cache groups (cores that share a last level cache). + */ + TOPO_LEVEL_GROUP, + TOPO_LEVEL_CACHEGROUP, + TOPO_LEVEL_CORE, + TOPO_LEVEL_THREAD, + TOPO_LEVEL_COUNT /* Must be last */ +}; +struct topo_analysis { + int entities[TOPO_LEVEL_COUNT]; +}; +int topo_analyze(struct topo_node *topo_root, int all, + struct topo_analysis *results); #define TOPO_FOREACH(i, root) \ for (i = root; i != NULL; i = topo_next_node(root, i)) diff --git a/freebsd/sys/sys/systm.h b/freebsd/sys/sys/systm.h index 4488c7cd..92be461b 100644 --- a/freebsd/sys/sys/systm.h +++ b/freebsd/sys/sys/systm.h @@ -172,6 +172,7 @@ void kassert_panic(const char *fmt, ...) __printflike(1, 2); * Align variables. */ #define __read_mostly __section(".data.read_mostly") +#define __read_frequently __section(".data.read_frequently") #define __exclusive_cache_line __aligned(CACHE_LINE_SIZE) \ __section(".data.exclusive_cache_line") /* @@ -329,6 +330,12 @@ void hexdump(const void *ptr, int length, const char *hdr, int flags); #ifndef __rtems__ void bcopy(const void * _Nonnull from, void * _Nonnull to, size_t len); void bzero(void * _Nonnull buf, size_t len); +#define bzero(buf, len) ({ \ + if (__builtin_constant_p(len) && (len) <= 64) \ + __builtin_memset((buf), 0, (len)); \ + else \ + bzero((buf), (len)); \ +}) #else /* __rtems__ */ #define bcopy(src, dst, len) memmove((dst), (src), (len)) #define bzero(buf, size) memset((buf), 0, (size)) diff --git a/freebsd/sys/sys/taskqueue.h b/freebsd/sys/sys/taskqueue.h index 7db75c6d..b5091d32 100644 --- a/freebsd/sys/sys/taskqueue.h +++ b/freebsd/sys/sys/taskqueue.h @@ -149,7 +149,7 @@ taskqueue_define_##name(void *arg) \ init; \ } \ \ -SYSINIT(taskqueue_##name, SI_SUB_INIT_IF, SI_ORDER_SECOND, \ +SYSINIT(taskqueue_##name, SI_SUB_TASKQ, SI_ORDER_SECOND, \ taskqueue_define_##name, NULL); \ \ struct __hack @@ -174,7 +174,7 @@ taskqueue_define_##name(void *arg) \ init; \ } \ \ -SYSINIT(taskqueue_##name, SI_SUB_INIT_IF, SI_ORDER_SECOND, \ +SYSINIT(taskqueue_##name, SI_SUB_TASKQ, SI_ORDER_SECOND, \ taskqueue_define_##name, NULL); \ \ struct __hack diff --git a/freebsd/sys/sys/vmmeter.h b/freebsd/sys/sys/vmmeter.h index d7692583..bc536f71 100644 --- a/freebsd/sys/sys/vmmeter.h +++ b/freebsd/sys/sys/vmmeter.h @@ -60,6 +60,12 @@ struct vmtotal { #if defined(_KERNEL) || defined(_WANT_VMMETER) #include <sys/counter.h> +#ifdef _KERNEL +#define VMMETER_ALIGNED __aligned(CACHE_LINE_SIZE) +#else +#define VMMETER_ALIGNED +#endif + /* * System wide statistics counters. * Locking: @@ -126,14 +132,15 @@ struct vmmeter { u_int v_free_target; /* (c) pages desired free */ u_int v_free_min; /* (c) pages desired free */ u_int v_free_count; /* (f) pages free */ - u_int v_wire_count; /* (a) pages wired down */ - u_int v_active_count; /* (q) pages active */ u_int v_inactive_target; /* (c) pages desired inactive */ - u_int v_inactive_count; /* (q) pages inactive */ - u_int v_laundry_count; /* (q) pages eligible for laundering */ u_int v_pageout_free_min; /* (c) min pages reserved for kernel */ u_int v_interrupt_free_min; /* (c) reserved pages for int code */ u_int v_free_severe; /* (c) severe page depletion point */ + u_int v_wire_count VMMETER_ALIGNED; /* (a) pages wired down */ + u_int v_active_count VMMETER_ALIGNED; /* (a) pages active */ + u_int v_inactive_count VMMETER_ALIGNED; /* (a) pages inactive */ + u_int v_laundry_count VMMETER_ALIGNED; /* (a) pages eligible for + laundering */ }; #endif /* _KERNEL || _WANT_VMMETER */ diff --git a/freebsd/sys/sys/vnode.h b/freebsd/sys/sys/vnode.h index 61cbf000..0c533063 100644 --- a/freebsd/sys/sys/vnode.h +++ b/freebsd/sys/sys/vnode.h @@ -251,6 +251,7 @@ struct xvnode { #define VV_DELETED 0x0400 /* should be removed */ #define VV_MD 0x0800 /* vnode backs the md device */ #define VV_FORCEINSMQ 0x1000 /* force the insmntque to succeed */ +#define VV_READLINK 0x2000 /* fdescfs linux vnode */ #define VMP_TMPMNTFREELIST 0x0001 /* Vnode is on mnt's tmp free list */ @@ -399,6 +400,7 @@ extern int vttoif_tab[]; #define V_NORMAL 0x0004 /* vinvalbuf: invalidate only regular bufs */ #define V_CLEANONLY 0x0008 /* vinvalbuf: invalidate only clean bufs */ #define V_VMIO 0x0010 /* vinvalbuf: called during pageout */ +#define V_ALLOWCLEAN 0x0020 /* vinvalbuf: allow clean buffers after flush */ #define REVOKEALL 0x0001 /* vop_revoke: revoke all aliases */ #define V_WAIT 0x0001 /* vn_start_write: sleep for suspend */ #define V_NOWAIT 0x0002 /* vn_start_write: don't sleep for suspend */ diff --git a/freebsd/sys/vm/uma.h b/freebsd/sys/vm/uma.h index c968e67e..3781fc8a 100644 --- a/freebsd/sys/vm/uma.h +++ b/freebsd/sys/vm/uma.h @@ -296,6 +296,7 @@ uma_zone_t uma_zcache_create(char *name, int size, uma_ctor ctor, uma_dtor dtor, #define UMA_ALIGN_SHORT (sizeof(short) - 1) /* "" short */ #define UMA_ALIGN_CHAR (sizeof(char) - 1) /* "" char */ #define UMA_ALIGN_CACHE (0 - 1) /* Cache line size align */ +#define UMA_ALIGNOF(type) (_Alignof(type) - 1) /* Alignment fit for 'type' */ /* * Destroys an empty uma zone. If the zone is not empty uma complains loudly. diff --git a/freebsd/sys/vm/uma_core.c b/freebsd/sys/vm/uma_core.c index 011f6494..c40e682d 100644 --- a/freebsd/sys/vm/uma_core.c +++ b/freebsd/sys/vm/uma_core.c @@ -152,7 +152,7 @@ static LIST_HEAD(,uma_zone) uma_cachezones = LIST_HEAD_INITIALIZER(uma_cachezones); /* This RW lock protects the keg list */ -static struct rwlock_padalign uma_rwlock; +static struct rwlock_padalign __exclusive_cache_line uma_rwlock; #ifndef __rtems__ /* @@ -1367,10 +1367,6 @@ keg_large_init(uma_keg_t keg) keg->uk_ipers = 1; keg->uk_rsize = keg->uk_size; - /* We can't do OFFPAGE if we're internal, bail out here. */ - if (keg->uk_flags & UMA_ZFLAG_INTERNAL) - return; - /* Check whether we have enough space to not do OFFPAGE. */ if ((keg->uk_flags & UMA_ZONE_OFFPAGE) == 0) { shsize = sizeof(struct uma_slab); @@ -1378,8 +1374,17 @@ keg_large_init(uma_keg_t keg) shsize = (shsize & ~UMA_ALIGN_PTR) + (UMA_ALIGN_PTR + 1); - if ((PAGE_SIZE * keg->uk_ppera) - keg->uk_rsize < shsize) - keg->uk_flags |= UMA_ZONE_OFFPAGE; + if (PAGE_SIZE * keg->uk_ppera - keg->uk_rsize < shsize) { + /* + * We can't do OFFPAGE if we're internal, in which case + * we need an extra page per allocation to contain the + * slab header. + */ + if ((keg->uk_flags & UMA_ZFLAG_INTERNAL) == 0) + keg->uk_flags |= UMA_ZONE_OFFPAGE; + else + keg->uk_ppera++; + } } if ((keg->uk_flags & UMA_ZONE_OFFPAGE) && diff --git a/freebsd/sys/vm/uma_int.h b/freebsd/sys/vm/uma_int.h index 35656801..df40efcd 100644 --- a/freebsd/sys/vm/uma_int.h +++ b/freebsd/sys/vm/uma_int.h @@ -28,6 +28,7 @@ * */ +#include <sys/_bitset.h> #include <sys/_task.h> /* @@ -210,7 +211,7 @@ struct uma_keg { vm_offset_t uk_kva; /* Zone base KVA */ uma_zone_t uk_slabzone; /* Slab zone backing us, if OFFPAGE */ - uint16_t uk_pgoff; /* Offset to uma_slab struct */ + uint32_t uk_pgoff; /* Offset to uma_slab struct */ uint16_t uk_ppera; /* pages per allocation from backend */ uint16_t uk_ipers; /* Items per slab */ uint32_t uk_flags; /* Internal flags */ |