diff options
Diffstat (limited to 'sys')
26 files changed, 585 insertions, 104 deletions
diff --git a/sys/compat/linuxkpi/common/include/acpi/acpi.h b/sys/compat/linuxkpi/common/include/acpi/acpi.h index 1e398d05ba20..016c7ede0f6e 100644 --- a/sys/compat/linuxkpi/common/include/acpi/acpi.h +++ b/sys/compat/linuxkpi/common/include/acpi/acpi.h @@ -37,7 +37,7 @@ /* * LINUXKPI_WANT_LINUX_ACPI is a temporary workaround to allow drm-kmod * to update all needed branches without breaking builds. - * Once that happened and checks are implemented based on __FreeBSD_verison + * Once that happened and checks are implemented based on __FreeBSD_version * we will remove these conditions again. */ diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 index 9976e9cfec5d..953da7dd1284 100644 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -146,6 +146,7 @@ dev/hyperv/vmbus/vmbus_et.c optional hyperv dev/hyperv/vmbus/vmbus_if.m optional hyperv dev/hyperv/vmbus/vmbus_res.c optional hyperv dev/hyperv/vmbus/vmbus_xact.c optional hyperv +dev/ichwd/i6300esbwd.c optional ichwd dev/ichwd/ichwd.c optional ichwd dev/imcsmb/imcsmb.c optional imcsmb dev/imcsmb/imcsmb_pci.c optional imcsmb pci diff --git a/sys/contrib/dev/acpica/components/executer/extrace.c b/sys/contrib/dev/acpica/components/executer/extrace.c index d54d4908ca65..b48a5fcb289b 100644 --- a/sys/contrib/dev/acpica/components/executer/extrace.c +++ b/sys/contrib/dev/acpica/components/executer/extrace.c @@ -301,7 +301,7 @@ AcpiExTraceArgs(ACPI_OPERAND_OBJECT **Params, UINT32 Count) switch (obj_desc->Common.Type) { case ACPI_TYPE_INTEGER: - ACPI_DEBUG_PRINT_RAW((ACPI_DB_TRACE_POINT, "%lx", obj_desc->Integer.Value)); + ACPI_DEBUG_PRINT_RAW((ACPI_DB_TRACE_POINT, "%jx", (uintmax_t)obj_desc->Integer.Value)); break; case ACPI_TYPE_STRING: diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c index ab8981e25cb2..0150ce72f0a4 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c @@ -464,7 +464,8 @@ create_pagelist(char __user *buf, size_t count, unsigned short type, (type == PAGELIST_READ ? VM_PROT_WRITE : 0 ) | VM_PROT_READ, pages, num_pages); if (actual_pages != num_pages) { - vm_page_unhold_pages(pages, actual_pages); + if (actual_pages > 0) + vm_page_unhold_pages(pages, actual_pages); free(pagelist, M_VCPAGELIST); return (-ENOMEM); } diff --git a/sys/dev/amdgpio/amdgpio.c b/sys/dev/amdgpio/amdgpio.c index 2bd455c612b8..20589ff71b0b 100644 --- a/sys/dev/amdgpio/amdgpio.c +++ b/sys/dev/amdgpio/amdgpio.c @@ -3,6 +3,10 @@ * * Copyright (c) 2018 Advanced Micro Devices * All rights reserved. + * Copyright (c) 2025 The FreeBSD Foundation + * + * Portions of this software were developed by Aymeric Wibo + * <obiwac@freebsd.org> under sponsorship from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -51,11 +55,11 @@ #include <dev/acpica/acpivar.h> #include <dev/gpio/gpiobusvar.h> -#include "gpio_if.h" #include "amdgpio.h" static struct resource_spec amdgpio_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, { -1, 0, 0 } }; @@ -196,7 +200,7 @@ static int amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct amdgpio_softc *sc; - uint32_t reg, val, allowed; + uint32_t reg, val; sc = device_get_softc(dev); @@ -204,18 +208,19 @@ amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) if (!amdgpio_valid_pin(sc, pin)) return (EINVAL); - allowed = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; + if ((flags & ~AMDGPIO_DEFAULT_CAPS) != 0) { + device_printf(dev, "disallowed flags (0x%x) trying to be set " + "(allowed is 0x%x)\n", flags, AMDGPIO_DEFAULT_CAPS); + return (EINVAL); + } - /* - * Only directtion flag allowed - */ - if (flags & ~allowed) + /* Either input or output must be selected. */ + if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 0) return (EINVAL); - /* - * Not both directions simultaneously - */ - if ((flags & allowed) == allowed) + /* Not both directions simultaneously. */ + if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == + (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) return (EINVAL); /* Set the GPIO mode and state */ @@ -224,16 +229,21 @@ amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) reg = AMDGPIO_PIN_REGISTER(pin); val = amdgpio_read_4(sc, reg); - if (flags & GPIO_PIN_INPUT) { + if ((flags & GPIO_PIN_INPUT) != 0) val &= ~BIT(OUTPUT_ENABLE_OFF); - sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_INPUT; - } else { + else val |= BIT(OUTPUT_ENABLE_OFF); - sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_OUTPUT; - } + + val &= ~(BIT(PULL_DOWN_ENABLE_OFF) | BIT(PULL_UP_ENABLE_OFF)); + + if ((flags & GPIO_PIN_PULLDOWN) != 0) + val |= BIT(PULL_DOWN_ENABLE_OFF); + if ((flags & GPIO_PIN_PULLUP) != 0) + val |= BIT(PULL_UP_ENABLE_OFF); amdgpio_write_4(sc, reg, val); + sc->sc_gpio_pins[pin].gp_flags = flags; dprintf("pin %d flags 0x%x val 0x%x gp_flags 0x%x\n", pin, flags, val, sc->sc_gpio_pins[pin].gp_flags); @@ -359,11 +369,73 @@ amdgpio_probe(device_t dev) return (rv); } +static void +amdgpio_eoi_locked(struct amdgpio_softc *sc) +{ + uint32_t master_reg = amdgpio_read_4(sc, WAKE_INT_MASTER_REG); + + AMDGPIO_ASSERT_LOCKED(sc); + master_reg |= EOI_MASK; + amdgpio_write_4(sc, WAKE_INT_MASTER_REG, master_reg); +} + +static void +amdgpio_eoi(struct amdgpio_softc *sc) +{ + AMDGPIO_LOCK(sc); + amdgpio_eoi_locked(sc); + AMDGPIO_UNLOCK(sc); +} + +static int +amdgpio_intr_filter(void *arg) +{ + struct amdgpio_softc *sc = arg; + int off, rv = FILTER_STRAY; + uint32_t reg; + + /* We can lock in the filter routine as it is MTX_SPIN. */ + AMDGPIO_LOCK(sc); + + /* + * TODO Instead of just reading the registers of all pins, we should + * read WAKE_INT_STATUS_REG0/1. A bit set in here denotes a group of + * 4 pins where at least one has an interrupt for us. Then we can just + * iterate over those 4 pins. + * + * See GPIO_Interrupt_Status_Index_0 in BKDG. + */ + for (size_t pin = 0; pin < AMD_GPIO_PINS_EXPOSED; pin++) { + off = AMDGPIO_PIN_REGISTER(pin); + reg = amdgpio_read_4(sc, off); + if ((reg & UNSERVICED_INTERRUPT_MASK) == 0) + continue; + /* + * Must write 1's to wake/interrupt status bits to clear them. + * We can do this simply by writing back to the register. + */ + amdgpio_write_4(sc, off, reg); + } + + amdgpio_eoi_locked(sc); + AMDGPIO_UNLOCK(sc); + + rv = FILTER_HANDLED; + return (rv); +} + +static void +amdgpio_intr_handler(void *arg) +{ + /* TODO */ +} + static int amdgpio_attach(device_t dev) { struct amdgpio_softc *sc; - int i, pin, bank; + int i, pin, bank, reg; + uint32_t flags; sc = device_get_softc(dev); sc->sc_dev = dev; @@ -386,6 +458,14 @@ amdgpio_attach(device_t dev) sc->sc_bst = rman_get_bustag(sc->sc_res[0]); sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); + /* Set up interrupt handler. */ + if (bus_setup_intr(dev, sc->sc_res[1], INTR_TYPE_MISC | INTR_MPSAFE, + amdgpio_intr_filter, amdgpio_intr_handler, sc, &sc->sc_intr_handle) + != 0) { + device_printf(dev, "couldn't set up interrupt\n"); + goto err_intr; + } + /* Initialize all possible pins to be Invalid */ for (i = 0; i < AMD_GPIO_PINS_MAX ; i++) { snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME, @@ -395,7 +475,12 @@ amdgpio_attach(device_t dev) sc->sc_gpio_pins[i].gp_flags = 0; } - /* Initialize only driver exposed pins with appropriate capabilities */ + /* + * Initialize only driver exposed pins with appropriate capabilities. + * + * XXX Also mask and disable interrupts on all pins, since we don't + * support them at the moment. + */ for (i = 0; i < AMD_GPIO_PINS_EXPOSED ; i++) { pin = kernzp_pins[i].pin_num; bank = pin/AMD_GPIO_PINS_PER_BANK; @@ -406,7 +491,14 @@ amdgpio_attach(device_t dev) sc->sc_gpio_pins[pin].gp_flags = amdgpio_is_pin_output(sc, pin) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; + + reg = AMDGPIO_PIN_REGISTER(pin); + flags = amdgpio_read_4(sc, reg); + flags &= ~(1 << INTERRUPT_ENABLE_OFF); + flags &= ~(1 << INTERRUPT_MASK_OFF); + amdgpio_write_4(sc, reg, flags); } + amdgpio_eoi(sc); sc->sc_busdev = gpiobus_add_bus(dev); if (sc->sc_busdev == NULL) { @@ -418,8 +510,9 @@ amdgpio_attach(device_t dev) return (0); err_bus: + bus_teardown_intr(dev, sc->sc_res[1], sc->sc_intr_handle); +err_intr: bus_release_resources(dev, amdgpio_spec, sc->sc_res); - err_rsrc: AMDGPIO_LOCK_DESTROY(sc); @@ -434,7 +527,8 @@ amdgpio_detach(device_t dev) if (sc->sc_busdev) gpiobus_detach_bus(dev); - + if (sc->sc_intr_handle) + bus_teardown_intr(dev, sc->sc_res[1], sc->sc_intr_handle); bus_release_resources(dev, amdgpio_spec, sc->sc_res); AMDGPIO_LOCK_DESTROY(sc); diff --git a/sys/dev/amdgpio/amdgpio.h b/sys/dev/amdgpio/amdgpio.h index aca3039bfc98..3743eba23e17 100644 --- a/sys/dev/amdgpio/amdgpio.h +++ b/sys/dev/amdgpio/amdgpio.h @@ -50,7 +50,8 @@ AMD_GPIO_PINS_BANK1 + \ AMD_GPIO_PINS_BANK2 + \ AMD_GPIO_PINS_BANK3) -#define AMDGPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) +#define AMDGPIO_DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ + GPIO_PIN_PULLDOWN | GPIO_PIN_PULLUP) /* Register related macros */ #define AMDGPIO_PIN_REGISTER(pin) (pin * 4) @@ -84,6 +85,9 @@ #define INTERRUPT_STS_OFF 28 #define WAKE_STS_OFF 29 +#define UNSERVICED_INTERRUPT_MASK \ + ((1 << INTERRUPT_STS_OFF) | (1 << WAKE_STS_OFF)) + #define DB_TMR_OUT_MASK 0xFUL #define DB_CNTRL_MASK 0x3UL #define ACTIVE_LEVEL_MASK 0x3UL @@ -316,12 +320,13 @@ struct amdgpio_softc { int sc_npins; int sc_ngroups; struct mtx sc_mtx; - struct resource *sc_res[AMD_GPIO_NUM_PIN_BANK + 1]; + struct resource *sc_res[2]; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; struct gpio_pin sc_gpio_pins[AMD_GPIO_PINS_MAX]; const struct pin_info *sc_pin_info; const struct amd_pingroup *sc_groups; + void *sc_intr_handle; }; struct amdgpio_sysctl { diff --git a/sys/dev/ichwd/i6300esbwd.c b/sys/dev/ichwd/i6300esbwd.c new file mode 100644 index 000000000000..d95aeb53c3f5 --- /dev/null +++ b/sys/dev/ichwd/i6300esbwd.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2025 The FreeBSD Foundation + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * Reference: Intel 6300ESB Controller Hub Datasheet Section 16 + */ + +#include <sys/param.h> +#include <sys/eventhandler.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/sysctl.h> +#include <sys/errno.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> +#include <sys/watchdog.h> + +#include <dev/pci/pcireg.h> + +#include <dev/ichwd/ichwd.h> +#include <dev/ichwd/i6300esbwd.h> + +#include <x86/pci_cfgreg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pci_private.h> + +struct i6300esbwd_softc { + device_t dev; + int res_id; + struct resource *res; + eventhandler_tag ev_tag; + bool locked; +}; + +static const struct i6300esbwd_pci_id { + uint16_t id; + const char *name; +} i6300esbwd_pci_devices[] = { + { DEVICEID_6300ESB_2, "6300ESB Watchdog Timer" }, +}; + +static uint16_t +i6300esbwd_cfg_read(struct i6300esbwd_softc *sc) +{ + return (pci_read_config(sc->dev, WDT_CONFIG_REG, 2)); +} + +static void +i6300esbwd_cfg_write(struct i6300esbwd_softc *sc, uint16_t val) +{ + pci_write_config(sc->dev, WDT_CONFIG_REG, val, 2); +} + +static uint8_t +i6300esbwd_lock_read(struct i6300esbwd_softc *sc) +{ + return (pci_read_config(sc->dev, WDT_LOCK_REG, 1)); +} + +static void +i6300esbwd_lock_write(struct i6300esbwd_softc *sc, uint8_t val) +{ + pci_write_config(sc->dev, WDT_LOCK_REG, val, 1); +} + +/* + * According to Intel 6300ESB I/O Controller Hub Datasheet 16.5.2, + * the resource should be unlocked before modifing any registers. + * The way to unlock is by write 0x80, 0x86 to the reload register. + */ +static void +i6300esbwd_unlock_res(struct i6300esbwd_softc *sc) +{ + bus_write_2(sc->res, WDT_RELOAD_REG, WDT_UNLOCK_SEQ_1_VAL); + bus_write_2(sc->res, WDT_RELOAD_REG, WDT_UNLOCK_SEQ_2_VAL); +} + +static int +i6300esbwd_sysctl_locked(SYSCTL_HANDLER_ARGS) +{ + struct i6300esbwd_softc *sc = (struct i6300esbwd_softc *)arg1; + int error; + int result; + + result = sc->locked; + error = sysctl_handle_int(oidp, &result, 0, req); + + if (error || !req->newptr) + return (error); + + if (result == 1 && !sc->locked) { + i6300esbwd_lock_write(sc, i6300esbwd_lock_read(sc) | WDT_LOCK); + sc->locked = true; + } + + return (0); +} + +static void +i6300esbwd_event(void *arg, unsigned int cmd, int *error) +{ + struct i6300esbwd_softc *sc = arg; + uint32_t timeout; + uint16_t regval; + + cmd &= WD_INTERVAL; + if (cmd != 0 && + (cmd < WD_TO_1MS || (cmd - WD_TO_1MS) >= WDT_PRELOAD_BIT)) { + *error = EINVAL; + return; + } + timeout = 1 << (cmd - WD_TO_1MS); + + /* reset the timer to prevent timeout a timeout is about to occur */ + i6300esbwd_unlock_res(sc); + bus_write_2(sc->res, WDT_RELOAD_REG, WDT_RELOAD); + + if (!cmd) { + /* + * when the lock is enabled, we are unable to overwrite LOCK + * register + */ + if (sc->locked) + *error = EPERM; + else + i6300esbwd_lock_write(sc, + i6300esbwd_lock_read(sc) & ~WDT_ENABLE); + return; + } + + i6300esbwd_unlock_res(sc); + bus_write_4(sc->res, WDT_PRELOAD_1_REG, timeout); + + i6300esbwd_unlock_res(sc); + bus_write_4(sc->res, WDT_PRELOAD_2_REG, timeout); + + i6300esbwd_unlock_res(sc); + bus_write_2(sc->res, WDT_RELOAD_REG, WDT_RELOAD); + + if (!sc->locked) { + i6300esbwd_lock_write(sc, WDT_ENABLE); + regval = i6300esbwd_lock_read(sc); + sc->locked = regval & WDT_LOCK; + } +} + +static int +i6300esbwd_probe(device_t dev) +{ + const struct i6300esbwd_pci_id *pci_id; + uint16_t pci_dev_id; + int err = ENXIO; + + if (pci_get_vendor(dev) != VENDORID_INTEL) + goto end; + + pci_dev_id = pci_get_device(dev); + for (pci_id = i6300esbwd_pci_devices; + pci_id < i6300esbwd_pci_devices + nitems(i6300esbwd_pci_devices); + ++pci_id) { + if (pci_id->id == pci_dev_id) { + device_set_desc(dev, pci_id->name); + err = BUS_PROBE_DEFAULT; + break; + } + } + +end: + return (err); +} + +static int +i6300esbwd_attach(device_t dev) +{ + struct i6300esbwd_softc *sc = device_get_softc(dev); + uint16_t regval; + + sc->dev = dev; + sc->res_id = PCIR_BAR(0); + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->res_id, + RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "unable to map memory region\n"); + return (ENXIO); + } + + i6300esbwd_cfg_write(sc, WDT_INT_TYPE_DISABLED_VAL); + regval = i6300esbwd_lock_read(sc); + if (regval & WDT_LOCK) + sc->locked = true; + else { + sc->locked = false; + i6300esbwd_lock_write(sc, WDT_TOUT_CNF_WT_MODE); + } + + i6300esbwd_unlock_res(sc); + bus_write_2(sc->res, WDT_RELOAD_REG, WDT_RELOAD | WDT_TIMEOUT); + + sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, i6300esbwd_event, sc, + 0); + + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "locked", + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, + i6300esbwd_sysctl_locked, "I", + "Lock the timer so that we cannot disable it"); + + return (0); +} + +static int +i6300esbwd_detach(device_t dev) +{ + struct i6300esbwd_softc *sc = device_get_softc(dev); + + if (sc->ev_tag) + EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag); + + if (sc->res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->res_id, sc->res); + + return (0); +} + +static device_method_t i6300esbwd_methods[] = { + DEVMETHOD(device_probe, i6300esbwd_probe), + DEVMETHOD(device_attach, i6300esbwd_attach), + DEVMETHOD(device_detach, i6300esbwd_detach), + DEVMETHOD(device_shutdown, i6300esbwd_detach), + DEVMETHOD_END +}; + +static driver_t i6300esbwd_driver = { + "i6300esbwd", + i6300esbwd_methods, + sizeof(struct i6300esbwd_softc), +}; + +DRIVER_MODULE(i6300esbwd, pci, i6300esbwd_driver, NULL, NULL); diff --git a/sys/dev/ichwd/i6300esbwd.h b/sys/dev/ichwd/i6300esbwd.h new file mode 100644 index 000000000000..39ed5d5a84f6 --- /dev/null +++ b/sys/dev/ichwd/i6300esbwd.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 The FreeBSD Foundation + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _I6300ESBWD_H_ +#define _I6300ESBWD_H_ + +#define WDT_CONFIG_REG 0x60 +#define WDT_LOCK_REG 0x68 + +#define WDT_PRELOAD_1_REG 0x00 +#define WDT_PRELOAD_2_REG 0x04 +#define WDT_INTR_REG 0x08 +#define WDT_RELOAD_REG 0x0C + +/* For config register */ +#define WDT_OUTPUT_EN (0x1 << 5) +#define WDT_PRE_SEL (0x1 << 2) +#define WDT_INT_TYPE_BITS (0x3) +#define WDT_INT_TYPE_IRQ_VAL (0x0) +#define WDT_INT_TYPE_RES_VAL (0x1) +#define WDT_INT_TYPE_SMI_VAL (0x2) +#define WDT_INT_TYPE_DISABLED_VAL (0x3) + +/* For lock register */ +#define WDT_TOUT_CNF_WT_MODE (0x0 << 2) +#define WDT_TOUT_CNF_FR_MODE (0x1 << 2) +#define WDT_ENABLE (0x02) +#define WDT_LOCK (0x01) + +/* For preload 1/2 registers */ +#define WDT_PRELOAD_BIT 20 +#define WDT_PRELOAD_BITS ((0x1 << WDT_PRELOAD_BIT) - 1) + +/* For interrupt register */ +#define WDT_INTR_ACT (0x01 << 0) + +/* For reload register */ +#define WDT_TIMEOUT (0x01 << 9) +#define WDT_RELOAD (0x01 << 8) +#define WDT_UNLOCK_SEQ_1_VAL 0x80 +#define WDT_UNLOCK_SEQ_2_VAL 0x86 + +#endif /* _I6300ESBWD_H_ */ diff --git a/sys/dev/ichwd/ichwd.c b/sys/dev/ichwd/ichwd.c index cade2cc4fb45..5481553cc175 100644 --- a/sys/dev/ichwd/ichwd.c +++ b/sys/dev/ichwd/ichwd.c @@ -90,7 +90,7 @@ static struct ichwd_device ichwd_devices[] = { { DEVICEID_82801E, "Intel 82801E watchdog timer", 5, 1 }, { DEVICEID_82801EB, "Intel 82801EB watchdog timer", 5, 1 }, { DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer", 5, 1 }, - { DEVICEID_6300ESB, "Intel 6300ESB watchdog timer", 5, 1 }, + { DEVICEID_6300ESB_1, "Intel 6300ESB watchdog timer", 5, 1 }, { DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer", 6, 2 }, { DEVICEID_ICH6M, "Intel ICH6M watchdog timer", 6, 2 }, { DEVICEID_ICH6W, "Intel ICH6W watchdog timer", 6, 2 }, diff --git a/sys/dev/ichwd/ichwd.h b/sys/dev/ichwd/ichwd.h index 90fda08b74c1..72d0ca1cd6aa 100644 --- a/sys/dev/ichwd/ichwd.h +++ b/sys/dev/ichwd/ichwd.h @@ -151,7 +151,8 @@ struct ichwd_softc { #define DEVICEID_82801E 0x2450 #define DEVICEID_82801EB 0x24dc #define DEVICEID_82801EBR 0x24d0 -#define DEVICEID_6300ESB 0x25a1 +#define DEVICEID_6300ESB_1 0x25a1 +#define DEVICEID_6300ESB_2 0x25ab #define DEVICEID_82801FBR 0x2640 #define DEVICEID_ICH6M 0x2641 #define DEVICEID_ICH6W 0x2642 diff --git a/sys/dev/puc/pucdata.c b/sys/dev/puc/pucdata.c index e911a407cca9..436af76001da 100644 --- a/sys/dev/puc/pucdata.c +++ b/sys/dev/puc/pucdata.c @@ -64,6 +64,7 @@ static puc_config_f puc_config_quatech; static puc_config_f puc_config_syba; static puc_config_f puc_config_siig; static puc_config_f puc_config_sunix; +static puc_config_f puc_config_systembase; static puc_config_f puc_config_timedia; static puc_config_f puc_config_titan; @@ -1705,6 +1706,23 @@ const struct puc_cfg puc_pci_devices[] = { PUC_PORT_4S, 0x10, 0, 8, .config_function = puc_config_icbook }, + + /* + * Systembase cards using SB16C1050 UARTs: + */ + { 0x14a1, 0x0008, 0x14a1, 0x0008, + "Systembase SB16C1058", + DEFAULT_RCLK * 8, + PUC_PORT_8S, 0x10, 0, 8, + .config_function = puc_config_systembase, + }, + { 0x14a1, 0x0004, 0x14a1, 0x0004, + "Systembase SB16C1054", + DEFAULT_RCLK * 8, + PUC_PORT_4S, 0x10, 0, 8, + .config_function = puc_config_systembase, + }, + { 0xffff, 0, 0xffff, 0, NULL, 0 } }; @@ -2294,3 +2312,28 @@ puc_config_titan(struct puc_softc *sc __unused, enum puc_cfg_cmd cmd, } return (ENXIO); } + +static int +puc_config_systembase(struct puc_softc *sc __unused, + enum puc_cfg_cmd cmd, int port, intptr_t *res) +{ + struct puc_bar *bar; + + switch (cmd) { + case PUC_CFG_SETUP: + bar = puc_get_bar(sc, 0x14); + if (bar == NULL) + return (ENXIO); + + /* + * The Systembase SB16C1058 (and probably other devices + * based on the SB16C1050 UART core) require poking a + * register in the *other* RID to turn on interrupts. + */ + bus_write_1(bar->b_res, /* OPT_IMRREG0 */ 0xc, 0xff); + return (0); + default: + break; + } + return (ENXIO); +} diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c index 14ac213066b8..22af8ee8663c 100644 --- a/sys/dev/uart/uart_bus_pci.c +++ b/sys/dev/uart/uart_bus_pci.c @@ -141,6 +141,8 @@ static const struct pci_id pci_ns8250_ids[] = { 0x10, 16384000 }, { 0x1415, 0xc120, 0xffff, 0, "Oxford Semiconductor OXPCIe952 PCIe 16950 UART", 0x10 }, +{ 0x14a1, 0x0008, 0x14a1, 0x0008, "Systembase SB16C1058", + 0x10, 8 * DEFAULT_RCLK, }, { 0x14e4, 0x160a, 0xffff, 0, "Broadcom TruManage UART", 0x10, 128 * DEFAULT_RCLK, 2}, { 0x14e4, 0x4344, 0xffff, 0, "Sony Ericsson GC89 PC Card", 0x10}, diff --git a/sys/modules/ichwd/Makefile b/sys/modules/ichwd/Makefile index 3c3bbc37eff5..27b4c38437ff 100644 --- a/sys/modules/ichwd/Makefile +++ b/sys/modules/ichwd/Makefile @@ -1,6 +1,6 @@ .PATH: ${SRCTOP}/sys/dev/ichwd KMOD= ichwd -SRCS= ichwd.c device_if.h bus_if.h pci_if.h isa_if.h +SRCS= i6300esbwd.c ichwd.c device_if.h bus_if.h pci_if.h isa_if.h .include <bsd.kmod.mk> diff --git a/sys/net/if.c b/sys/net/if.c index 79c883fd4a0a..202be4794f6e 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -2589,16 +2589,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) * flip. They require special handling because in-kernel * consumers may indepdently toggle them. */ - if ((ifp->if_flags ^ new_flags) & IFF_PPROMISC) { - if (new_flags & IFF_PPROMISC) - ifp->if_flags |= IFF_PROMISC; - else if (ifp->if_pcount == 0) - ifp->if_flags &= ~IFF_PROMISC; - if (log_promisc_mode_change) - if_printf(ifp, "permanently promiscuous mode %s\n", - ((new_flags & IFF_PPROMISC) ? - "enabled" : "disabled")); - } + if_setppromisc(ifp, new_flags & IFF_PPROMISC); if ((ifp->if_flags ^ new_flags) & IFF_PALLMULTI) { if (new_flags & IFF_PALLMULTI) ifp->if_flags |= IFF_ALLMULTI; @@ -4456,6 +4447,32 @@ if_getmtu_family(const if_t ifp, int family) return (ifp->if_mtu); } +void +if_setppromisc(if_t ifp, bool ppromisc) +{ + int new_flags; + + if (ppromisc) + new_flags = ifp->if_flags | IFF_PPROMISC; + else + new_flags = ifp->if_flags & ~IFF_PPROMISC; + if ((ifp->if_flags ^ new_flags) & IFF_PPROMISC) { + if (new_flags & IFF_PPROMISC) + new_flags |= IFF_PROMISC; + /* + * Only unset IFF_PROMISC if there are no more consumers of + * promiscuity, i.e. the ifp->if_pcount refcount is 0. + */ + else if (ifp->if_pcount == 0) + new_flags &= ~IFF_PROMISC; + if (log_promisc_mode_change) + if_printf(ifp, "permanently promiscuous mode %s\n", + ((new_flags & IFF_PPROMISC) ? + "enabled" : "disabled")); + } + ifp->if_flags = new_flags; +} + /* * Methods for drivers to access interface unicast and multicast * link level addresses. Driver shall not know 'struct ifaddr' neither diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c index a213a84e17db..581c2434b8fb 100644 --- a/sys/net/if_epair.c +++ b/sys/net/if_epair.c @@ -67,7 +67,6 @@ #include <net/if_var.h> #include <net/if_clone.h> #include <net/if_media.h> -#include <net/if_var.h> #include <net/if_private.h> #include <net/if_types.h> #include <net/netisr.h> diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 08435e7bd5f6..f2df612b19c1 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -622,6 +622,7 @@ int if_setmtu(if_t ifp, int mtu); int if_getmtu(const if_t ifp); int if_getmtu_family(const if_t ifp, int family); void if_notifymtu(if_t ifp); +void if_setppromisc(const if_t ifp, bool ppromisc); int if_setflagbits(if_t ifp, int set, int clear); int if_setflags(if_t ifp, int flags); int if_getflags(const if_t ifp); diff --git a/sys/netgraph/ng_nat.c b/sys/netgraph/ng_nat.c index defbe817becd..8b82d777caeb 100644 --- a/sys/netgraph/ng_nat.c +++ b/sys/netgraph/ng_nat.c @@ -818,7 +818,8 @@ ng_nat_rcvdata(hook_p hook, item_p item ) if (ip->ip_v != IPVERSION) goto send; /* other IP version, let it pass */ - if (m->m_pkthdr.len < ipofs + ntohs(ip->ip_len)) + uint16_t ip_len = ntohs(ip->ip_len); + if (m->m_pkthdr.len < (ipofs + ip_len)) goto send; /* packet too short (i.e. fragmented or broken) */ /* @@ -852,50 +853,68 @@ ng_nat_rcvdata(hook_p hook, item_p item ) if (rval == PKT_ALIAS_RESPOND) m->m_flags |= M_SKIP_FIREWALL; - m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len) + ipofs; - if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && - ip->ip_p == IPPROTO_TCP) { - struct tcphdr *th = (struct tcphdr *)((caddr_t)ip + - (ip->ip_hl << 2)); + /* Re-read just in case it has been updated */ + ip_len = ntohs(ip->ip_len); + int new_m_len = ip_len + ipofs; + if (new_m_len > (m->m_len + M_TRAILINGSPACE(m))) { /* - * Here is our terrible HACK. - * - * Sometimes LibAlias edits contents of TCP packet. - * In this case it needs to recompute full TCP - * checksum. However, the problem is that LibAlias - * doesn't have any idea about checksum offloading - * in kernel. To workaround this, we do not do - * checksumming in LibAlias, but only mark the - * packets with TH_RES1 in the th_x2 field. If we - * receive a marked packet, we calculate correct - * checksum for it aware of offloading. - * - * Why do I do such a terrible hack instead of - * recalculating checksum for each packet? - * Because the previous checksum was not checked! - * Recalculating checksums for EVERY packet will - * hide ALL transmission errors. Yes, marked packets - * still suffer from this problem. But, sigh, natd(8) - * has this problem, too. + * This is just a safety railguard to make sure LibAlias has not + * screwed the IP packet up somehow, should probably be KASSERT() + * at some point. Calling in_delayed_cksum() will parse IP packet + * again and reliably panic if there is less data than the IP + * header declares, there might be some other places too. */ + log(LOG_ERR, "ng_nat_rcvdata: outgoing packet corrupted, " + "not enough data: expected %d, available (%d - %d)\n", + ip_len, m->m_len + (int)M_TRAILINGSPACE(m), ipofs); + NG_FREE_ITEM(item); + return (ENXIO); + } + + m->m_pkthdr.len = m->m_len = new_m_len; - if (tcp_get_flags(th) & TH_RES1) { - uint16_t ip_len = ntohs(ip->ip_len); + if ((ip->ip_off & htons(IP_OFFMASK)) != 0 || ip->ip_p != IPPROTO_TCP) + goto send; - tcp_set_flags(th, tcp_get_flags(th) & ~TH_RES1); - th->th_sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htons(IPPROTO_TCP + - ip_len - (ip->ip_hl << 2))); + uint16_t pl_offset = ip->ip_hl << 2; + struct tcphdr *th = (struct tcphdr *)((caddr_t)ip + pl_offset); - if ((m->m_pkthdr.csum_flags & CSUM_TCP) == 0) { - m->m_pkthdr.csum_data = offsetof(struct tcphdr, - th_sum); - in_delayed_cksum(m); - } - } - } + /* + * Here is our terrible HACK. + * + * Sometimes LibAlias edits contents of TCP packet. + * In this case it needs to recompute full TCP + * checksum. However, the problem is that LibAlias + * doesn't have any idea about checksum offloading + * in kernel. To workaround this, we do not do + * checksumming in LibAlias, but only mark the + * packets with TH_RES1 in the th_x2 field. If we + * receive a marked packet, we calculate correct + * checksum for it aware of offloading. + * + * Why do I do such a terrible hack instead of + * recalculating checksum for each packet? + * Because the previous checksum was not checked! + * Recalculating checksums for EVERY packet will + * hide ALL transmission errors. Yes, marked packets + * still suffer from this problem. But, sigh, natd(8) + * has this problem, too. + */ + + if (!(tcp_get_flags(th) & TH_RES1)) + goto send; + + tcp_set_flags(th, tcp_get_flags(th) & ~TH_RES1); + th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons(IPPROTO_TCP + ip_len - pl_offset)); + + if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) + goto send; + + m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); + in_delayed_cksum_o(m, ipofs); send: if (hook == priv->in) diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index ec6ba8d92015..ef08b9cfd3d6 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1044,14 +1044,14 @@ done: } void -in_delayed_cksum(struct mbuf *m) +in_delayed_cksum_o(struct mbuf *m, uint16_t iph_offset) { struct ip *ip; struct udphdr *uh; uint16_t cklen, csum, offset; - ip = mtod(m, struct ip *); - offset = ip->ip_hl << 2 ; + ip = (struct ip *)mtodo(m, iph_offset); + offset = iph_offset + (ip->ip_hl << 2); if (m->m_pkthdr.csum_flags & CSUM_UDP) { /* if udp header is not in the first mbuf copy udplen */ @@ -1078,6 +1078,13 @@ in_delayed_cksum(struct mbuf *m) *(u_short *)mtodo(m, offset) = csum; } +void +in_delayed_cksum(struct mbuf *m) +{ + + in_delayed_cksum_o(m, 0); +} + /* * IP socket option processing. */ diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index f782ebc53eb0..c113484079a3 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -271,6 +271,7 @@ VNET_DECLARE(struct pfil_head *, inet_local_pfil_head); #define PFIL_INET_LOCAL_NAME "inet-local" void in_delayed_cksum(struct mbuf *m); +void in_delayed_cksum_o(struct mbuf *m, uint16_t o); /* Hooks for ipfw, dummynet, divert etc. Most are declared in raw_ip.c */ /* diff --git a/sys/netinet/tcp_hpts.c b/sys/netinet/tcp_hpts.c index b77ebc928809..63bbe4bba11b 100644 --- a/sys/netinet/tcp_hpts.c +++ b/sys/netinet/tcp_hpts.c @@ -137,8 +137,6 @@ #include <netinet/in_kdtrace.h> #include <netinet/in_pcb.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> /* required for icmp_var.h */ -#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ #include <netinet/ip_var.h> #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c index fed259f4d8e1..f2d7867df9b4 100644 --- a/sys/netinet/tcp_stacks/bbr.c +++ b/sys/netinet/tcp_stacks/bbr.c @@ -78,8 +78,6 @@ #include <netinet/in_kdtrace.h> #include <netinet/in_pcb.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> /* required for icmp_var.h */ -#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ #include <netinet/ip_var.h> #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c index 71dd4de6baf9..11ef5ba706c5 100644 --- a/sys/netinet/tcp_stacks/rack.c +++ b/sys/netinet/tcp_stacks/rack.c @@ -77,8 +77,6 @@ #include <netinet/in_kdtrace.h> #include <netinet/in_pcb.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> /* required for icmp_var.h */ -#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ #include <netinet/ip_var.h> #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> diff --git a/sys/netinet/tcp_stacks/rack_bbr_common.c b/sys/netinet/tcp_stacks/rack_bbr_common.c index fc12672a45f7..4a0a5fc118f6 100644 --- a/sys/netinet/tcp_stacks/rack_bbr_common.c +++ b/sys/netinet/tcp_stacks/rack_bbr_common.c @@ -76,8 +76,6 @@ #include <netinet/in_kdtrace.h> #include <netinet/in_pcb.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> /* required for icmp_var.h */ -#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ #include <netinet/ip_var.h> #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> diff --git a/sys/netinet/tcp_stacks/rack_pcm.c b/sys/netinet/tcp_stacks/rack_pcm.c index 759bfda98357..1a51097f627c 100644 --- a/sys/netinet/tcp_stacks/rack_pcm.c +++ b/sys/netinet/tcp_stacks/rack_pcm.c @@ -78,8 +78,6 @@ #include <netinet/in_kdtrace.h> #include <netinet/in_pcb.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> /* required for icmp_var.h */ -#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ #include <netinet/ip_var.h> #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> diff --git a/sys/netinet/tcp_stacks/tailq_hash.c b/sys/netinet/tcp_stacks/tailq_hash.c index 5ba3e7cd36c0..ff01640524b6 100644 --- a/sys/netinet/tcp_stacks/tailq_hash.c +++ b/sys/netinet/tcp_stacks/tailq_hash.c @@ -51,8 +51,6 @@ #include <netinet/in_kdtrace.h> #include <netinet/in_pcb.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> /* required for icmp_var.h */ -#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ #include <netinet/ip_var.h> #include <netinet/ip6.h> #include <netinet6/in6_pcb.h> diff --git a/sys/netlink/route/iface_drivers.c b/sys/netlink/route/iface_drivers.c index 21db3017df18..4f1540740ead 100644 --- a/sys/netlink/route/iface_drivers.c +++ b/sys/netlink/route/iface_drivers.c @@ -82,28 +82,39 @@ _nl_modify_ifp_generic(struct ifnet *ifp, struct nl_parsed_link *lattrs, } } - if ((lattrs->ifi_change & IFF_UP) && (lattrs->ifi_flags & IFF_UP) == 0) { - /* Request to down the interface */ - if_down(ifp); + if ((lattrs->ifi_change & IFF_UP) != 0 || lattrs->ifi_change == 0) { + /* Request to up or down the interface */ + if (lattrs->ifi_flags & IFF_UP) + if_up(ifp); + else + if_down(ifp); } if (lattrs->ifla_mtu > 0) { if (nlp_has_priv(npt->nlp, PRIV_NET_SETIFMTU)) { struct ifreq ifr = { .ifr_mtu = lattrs->ifla_mtu }; - error = ifhwioctl(SIOCSIFMTU, ifp, (char *)&ifr, curthread); + error = ifhwioctl(SIOCSIFMTU, ifp, (char *)&ifr, + curthread); + if (error != 0) { + nlmsg_report_err_msg(npt, "Failed to set mtu"); + return (error); + } } else { nlmsg_report_err_msg(npt, "Not enough privileges to set mtu"); return (EPERM); } } - if (lattrs->ifi_change & IFF_PROMISC) { - error = ifpromisc(ifp, lattrs->ifi_flags & IFF_PROMISC); - if (error != 0) { - nlmsg_report_err_msg(npt, "unable to set promisc"); - return (error); - } - } + if ((lattrs->ifi_change & IFF_PROMISC) != 0 || + lattrs->ifi_change == 0) + /* + * When asking for IFF_PROMISC, set permanent flag instead + * (IFF_PPROMISC) as we have no way of doing promiscuity + * reference counting through ifpromisc(). Every call to this + * function either sets or unsets IFF_PROMISC, and ifi_change + * is usually set to 0xFFFFFFFF. + */ + if_setppromisc(ifp, (lattrs->ifi_flags & IFF_PROMISC) != 0); if (lattrs->ifla_address != NULL) { if (nlp_has_priv(npt->nlp, PRIV_NET_SETIFMAC)) { |