diff options
Diffstat (limited to 'sys/dev')
33 files changed, 544 insertions, 265 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index f2ff1d59ccc7..a2159b12876f 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -2139,12 +2139,13 @@ acpi_set_powerstate(device_t child, int state) status = acpi_pwr_switch_consumer(h, state); if (ACPI_SUCCESS(status)) { if (bootverbose) - device_printf(child, "set ACPI power state D%d on %s\n", - state, acpi_name(h)); + device_printf(child, "set ACPI power state %s on %s\n", + acpi_d_state_to_str(state), acpi_name(h)); } else if (status != AE_NOT_FOUND) device_printf(child, - "failed to set ACPI power state D%d on %s: %s\n", state, - acpi_name(h), AcpiFormatException(status)); + "failed to set ACPI power state %s on %s: %s\n", + acpi_d_state_to_str(state), acpi_name(h), + AcpiFormatException(status)); return (0); } diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c index 646295f9eecc..1912350bbc48 100644 --- a/sys/dev/acpica/acpi_pci.c +++ b/sys/dev/acpica/acpi_pci.c @@ -53,9 +53,6 @@ #include <dev/iommu/iommu.h> -#include "pcib_if.h" -#include "pci_if.h" - /* Hooks for the ACPI CA debugging infrastructure. */ #define _COMPONENT ACPI_BUS ACPI_MODULE_NAME("PCI") @@ -266,12 +263,13 @@ acpi_pci_set_powerstate_method(device_t dev, device_t child, int state) status = acpi_pwr_switch_consumer(h, state); if (ACPI_SUCCESS(status)) { if (bootverbose) - device_printf(dev, "set ACPI power state D%d on %s\n", - state, acpi_name(h)); + device_printf(dev, "set ACPI power state %s on %s\n", + acpi_d_state_to_str(state), acpi_name(h)); } else if (status != AE_NOT_FOUND) device_printf(dev, - "failed to set ACPI power state D%d on %s: %s\n", - state, acpi_name(h), AcpiFormatException(status)); + "failed to set ACPI power state %s on %s: %s\n", + acpi_d_state_to_str(state), acpi_name(h), + AcpiFormatException(status)); if (old_state > state && pci_do_power_resume) error = pci_set_powerstate_method(dev, child, state); diff --git a/sys/dev/acpica/acpi_powerres.c b/sys/dev/acpica/acpi_powerres.c index 0f2a25b1d02b..29d1690f1bdd 100644 --- a/sys/dev/acpica/acpi_powerres.c +++ b/sys/dev/acpica/acpi_powerres.c @@ -299,7 +299,7 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) ACPI_BUFFER reslist_buffer; ACPI_OBJECT *reslist_object; ACPI_STATUS status; - char *method_name, *reslist_name; + char *method_name, *reslist_name = NULL; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -318,9 +318,26 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) panic("acpi added power consumer but can't find it"); } - /* Check for valid transitions. We can only go to D0 from D3. */ + /* Stop here if we're already at the target D-state. */ + if (pc->ac_state == state) { + status = AE_OK; + goto out; + } + + /* + * Check for valid transitions. From D3hot or D3cold, we can only go to D0. + * The exception to this is going from D3hot to D3cold or the other way + * around. This is because they both use _PS3, so the only difference when + * doing these transitions is whether or not the power resources for _PR3 + * are on for devices which support D3cold, and turning these power + * resources on/off is always perfectly fine (ACPI 7.3.11). + */ status = AE_BAD_PARAMETER; - if (pc->ac_state == ACPI_STATE_D3 && state != ACPI_STATE_D0) + if (pc->ac_state == ACPI_STATE_D3_HOT && state != ACPI_STATE_D0 && + state != ACPI_STATE_D3_COLD) + goto out; + if (pc->ac_state == ACPI_STATE_D3_COLD && state != ACPI_STATE_D0 && + state != ACPI_STATE_D3_HOT) goto out; /* Find transition mechanism(s) */ @@ -337,15 +354,20 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) method_name = "_PS2"; reslist_name = "_PR2"; break; - case ACPI_STATE_D3: + case ACPI_STATE_D3_HOT: method_name = "_PS3"; reslist_name = "_PR3"; break; + case ACPI_STATE_D3_COLD: + method_name = "_PS3"; + reslist_name = NULL; + break; default: goto out; } - ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s D%d -> D%d\n", - acpi_name(consumer), pc->ac_state, state)); + ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s %s -> %s\n", + acpi_name(consumer), acpi_d_state_to_str(pc->ac_state), + acpi_d_state_to_str(state))); /* * Verify that this state is supported, ie. one of method or @@ -359,7 +381,8 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) */ if (ACPI_FAILURE(AcpiGetHandle(consumer, method_name, &method_handle))) method_handle = NULL; - if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle))) + if (reslist_name == NULL || + ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle))) reslist_handle = NULL; if (reslist_handle == NULL && method_handle == NULL) { if (state == ACPI_STATE_D0) { @@ -367,9 +390,12 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) status = AE_OK; goto out; } - if (state != ACPI_STATE_D3) { + if (state == ACPI_STATE_D3_COLD) + state = ACPI_STATE_D3_HOT; + if (state != ACPI_STATE_D3_HOT) { ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, - "attempt to set unsupported state D%d\n", state)); + "attempt to set unsupported state %s\n", + acpi_d_state_to_str(state))); goto out; } @@ -380,21 +406,23 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) if (ACPI_FAILURE(AcpiGetHandle(consumer, "_PR0", &pr0_handle))) { status = AE_NOT_FOUND; ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, - "device missing _PR0 (desired state was D%d)\n", state)); + "device missing _PR0 (desired state was %s)\n", + acpi_d_state_to_str(state))); goto out; } reslist_buffer.Length = ACPI_ALLOCATE_BUFFER; status = AcpiEvaluateObject(pr0_handle, NULL, NULL, &reslist_buffer); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, - "can't evaluate _PR0 for device %s, state D%d\n", - acpi_name(consumer), state)); + "can't evaluate _PR0 for device %s, state %s\n", + acpi_name(consumer), acpi_d_state_to_str(state))); goto out; } reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer; if (!ACPI_PKG_VALID(reslist_object, 1)) { ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, - "invalid package object for state D%d\n", state)); + "invalid package object for state %s\n", + acpi_d_state_to_str(state))); status = AE_TYPE; goto out; } @@ -450,8 +478,8 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) */ if (ACPI_FAILURE(status = acpi_pwr_switch_power())) { ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, - "failed to switch resources from %s to D%d\n", - acpi_name(consumer), state)); + "failed to switch resources from %s to %s\n", + acpi_name(consumer), acpi_d_state_to_str(state))); /* XXX is this appropriate? Should we return to previous state? */ goto out; diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index 106ec9038820..6887f080311d 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -517,6 +517,16 @@ acpi_get_verbose(struct acpi_softc *sc) return (0); } +static __inline const char * +acpi_d_state_to_str(int state) +{ + const char *strs[ACPI_D_STATE_COUNT] = {"D0", "D1", "D2", "D3hot", + "D3cold"}; + + MPASS(state >= ACPI_STATE_D0 && state <= ACPI_D_STATES_MAX); + return (strs[state]); +} + char *acpi_name(ACPI_HANDLE handle); int acpi_avoid(ACPI_HANDLE handle); int acpi_disabled(char *subsys); diff --git a/sys/dev/amdgpio/amdgpio.c b/sys/dev/amdgpio/amdgpio.c index f39006d95805..2bd455c612b8 100644 --- a/sys/dev/amdgpio/amdgpio.c +++ b/sys/dev/amdgpio/amdgpio.c @@ -408,12 +408,13 @@ amdgpio_attach(device_t dev) GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; } - sc->sc_busdev = gpiobus_attach_bus(dev); + sc->sc_busdev = gpiobus_add_bus(dev); if (sc->sc_busdev == NULL) { device_printf(dev, "could not attach gpiobus\n"); goto err_bus; } + bus_attach_children(dev); return (0); err_bus: diff --git a/sys/dev/bhnd/cores/chipc/chipc_gpio.c b/sys/dev/bhnd/cores/chipc/chipc_gpio.c index a110bdda5fa7..429de0fc1fd8 100644 --- a/sys/dev/bhnd/cores/chipc/chipc_gpio.c +++ b/sys/dev/bhnd/cores/chipc/chipc_gpio.c @@ -173,11 +173,13 @@ chipc_gpio_attach(device_t dev) if (CC_GPIO_QUIRK(sc, NO_GPIOC)) { sc->gpiobus = NULL; } else { - if ((sc->gpiobus = gpiobus_attach_bus(dev)) == NULL) { + if ((sc->gpiobus = gpiobus_add_bus(dev)) == NULL) { device_printf(dev, "failed to attach gpiobus\n"); error = ENXIO; goto failed; } + + bus_attach_children(dev); } /* Register as the bus GPIO provider */ diff --git a/sys/dev/ftgpio/ftgpio.c b/sys/dev/ftgpio/ftgpio.c index 7acfdd5b900e..68787b54bb16 100644 --- a/sys/dev/ftgpio/ftgpio.c +++ b/sys/dev/ftgpio/ftgpio.c @@ -398,12 +398,13 @@ ftgpio_attach(device_t dev) FTGPIO_VERBOSE_PRINTF(sc->dev, "groups GPIO1..GPIO6 enabled\n"); GPIO_UNLOCK(sc); - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { GPIO_LOCK_DESTROY(sc); return (ENXIO); } + bus_attach_children(dev); return (0); } diff --git a/sys/dev/gpio/acpi_gpiobus.c b/sys/dev/gpio/acpi_gpiobus.c index 94f4e5771266..170f23615416 100644 --- a/sys/dev/gpio/acpi_gpiobus.c +++ b/sys/dev/gpio/acpi_gpiobus.c @@ -383,7 +383,8 @@ acpi_gpiobus_detach(device_t dev) } static int -acpi_gpiobus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +acpi_gpiobus_read_ivar(device_t dev, device_t child, int which, + uintptr_t *result) { struct acpi_gpiobus_ivar *devi = device_get_ivars(child); diff --git a/sys/dev/gpio/bytgpio.c b/sys/dev/gpio/bytgpio.c index f7b2a73ec6cb..5d685c155a03 100644 --- a/sys/dev/gpio/bytgpio.c +++ b/sys/dev/gpio/bytgpio.c @@ -608,7 +608,7 @@ bytgpio_attach(device_t dev) sc->sc_pad_funcs[pin] = val & BYTGPIO_PCONF0_FUNC_MASK; } - sc->sc_busdev = gpiobus_attach_bus(dev); + sc->sc_busdev = gpiobus_add_bus(dev); if (sc->sc_busdev == NULL) { BYTGPIO_LOCK_DESTROY(sc); bus_release_resource(dev, SYS_RES_MEMORY, @@ -616,6 +616,7 @@ bytgpio_attach(device_t dev) return (ENXIO); } + bus_attach_children(dev); return (0); error: diff --git a/sys/dev/gpio/chvgpio.c b/sys/dev/gpio/chvgpio.c index 199ad4d6f373..3273aad9242b 100644 --- a/sys/dev/gpio/chvgpio.c +++ b/sys/dev/gpio/chvgpio.c @@ -441,7 +441,7 @@ chvgpio_attach(device_t dev) bus_write_4(sc->sc_mem_res, CHVGPIO_INTERRUPT_MASK, 0); bus_write_4(sc->sc_mem_res, CHVGPIO_INTERRUPT_STATUS, 0xffff); - sc->sc_busdev = gpiobus_attach_bus(dev); + sc->sc_busdev = gpiobus_add_bus(dev); if (sc->sc_busdev == NULL) { CHVGPIO_LOCK_DESTROY(sc); bus_release_resource(dev, SYS_RES_MEMORY, @@ -451,6 +451,7 @@ chvgpio_attach(device_t dev) return (ENXIO); } + bus_attach_children(dev); return (0); } diff --git a/sys/dev/gpio/dwgpio/dwgpio.c b/sys/dev/gpio/dwgpio/dwgpio.c index 5acb99ca591e..3908113d5fd4 100644 --- a/sys/dev/gpio/dwgpio/dwgpio.c +++ b/sys/dev/gpio/dwgpio/dwgpio.c @@ -167,12 +167,13 @@ dwgpio_attach(device_t dev) snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "dwgpio%d.%d", device_get_unit(dev), i); } - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { mtx_destroy(&sc->sc_mtx); return (ENXIO); } + bus_attach_children(dev); return (0); } diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c index 764bcb7e6ee8..c25c41f43042 100644 --- a/sys/dev/gpio/gpiobus.c +++ b/sys/dev/gpio/gpiobus.c @@ -330,24 +330,6 @@ gpiobus_add_bus(device_t dev) return (busdev); } -/* - * Attach a gpiobus child. - * Note that the controller is expected - * to be fully initialized at this point. - */ -device_t -gpiobus_attach_bus(device_t dev) -{ - device_t busdev; - - busdev = gpiobus_add_bus(dev); - if (busdev == NULL) - return (NULL); - - bus_attach_children(dev); - return (busdev); -} - int gpiobus_detach_bus(device_t dev) { diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h index 7f504236a774..0528efe45525 100644 --- a/sys/dev/gpio/gpiobusvar.h +++ b/sys/dev/gpio/gpiobusvar.h @@ -171,7 +171,6 @@ struct resource *gpio_alloc_intr_resource(device_t consumer_dev, int *rid, int gpio_check_flags(uint32_t, uint32_t); device_t gpiobus_add_bus(device_t); -device_t gpiobus_attach_bus(device_t); int gpiobus_detach_bus(device_t); #endif /* __GPIOBUS_H__ */ diff --git a/sys/dev/gpio/pl061.c b/sys/dev/gpio/pl061.c index 87d4310a6396..32109e5982bc 100644 --- a/sys/dev/gpio/pl061.c +++ b/sys/dev/gpio/pl061.c @@ -495,13 +495,14 @@ pl061_attach(device_t dev) goto free_isrc; } - sc->sc_busdev = gpiobus_attach_bus(dev); + sc->sc_busdev = gpiobus_add_bus(dev); if (sc->sc_busdev == NULL) { device_printf(dev, "couldn't attach gpio bus\n"); PL061_LOCK_DESTROY(sc); goto free_isrc; } + bus_attach_children(dev); return (0); free_isrc: diff --git a/sys/dev/gpio/qoriq_gpio.c b/sys/dev/gpio/qoriq_gpio.c index 8b44cd256c79..d11868a23751 100644 --- a/sys/dev/gpio/qoriq_gpio.c +++ b/sys/dev/gpio/qoriq_gpio.c @@ -379,12 +379,13 @@ qoriq_gpio_attach(device_t dev) OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { qoriq_gpio_detach(dev); return (ENOMEM); } + bus_attach_children(dev); return (0); } diff --git a/sys/dev/iicbus/gpio/pcf8574.c b/sys/dev/iicbus/gpio/pcf8574.c index ab6e2bc07d1f..bf60dec67557 100644 --- a/sys/dev/iicbus/gpio/pcf8574.c +++ b/sys/dev/iicbus/gpio/pcf8574.c @@ -142,12 +142,13 @@ pcf8574_attach(device_t dev) (void)pcf8574_write(sc, 0xff); sx_init(&sc->lock, "pcf8574"); - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { device_printf(dev, "Could not create busdev child\n"); sx_destroy(&sc->lock); return (ENXIO); } + bus_attach_children(dev); return (0); } @@ -158,9 +159,7 @@ pcf8574_detach(device_t dev) sc = device_get_softc(dev); - if (sc->busdev != NULL) - gpiobus_detach_bus(sc->busdev); - + gpiobus_detach_bus(dev); sx_destroy(&sc->lock); return (0); } diff --git a/sys/dev/iicbus/gpio/tca64xx.c b/sys/dev/iicbus/gpio/tca64xx.c index cd011ae9be75..ab8fedd3f8fd 100644 --- a/sys/dev/iicbus/gpio/tca64xx.c +++ b/sys/dev/iicbus/gpio/tca64xx.c @@ -262,7 +262,7 @@ tca64xx_attach(device_t dev) mtx_init(&sc->mtx, "tca64xx gpio", "gpio", MTX_DEF); OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { device_printf(dev, "Could not create busdev child\n"); return (ENXIO); @@ -281,6 +281,7 @@ tca64xx_attach(device_t dev) } #endif + bus_attach_children(dev); return (0); } @@ -291,9 +292,7 @@ tca64xx_detach(device_t dev) sc = device_get_softc(dev); - if (sc->busdev != NULL) - gpiobus_detach_bus(sc->busdev); - + gpiobus_detach_bus(dev); mtx_destroy(&sc->mtx); return (0); diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c b/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c index 6e24395b5577..c45f02cdaf42 100644 --- a/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c +++ b/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c @@ -1783,8 +1783,8 @@ mlx5e_add_vxlan_rule(struct mlx5e_priv *priv, sa_family_t family, u_int port) el->refcount++; if (el->installed) return (0); - } - el = mlx5e_vxlan_alloc_db_el(priv, proto, port); + } else + el = mlx5e_vxlan_alloc_db_el(priv, proto, port); if ((if_getcapenable(priv->ifp) & IFCAP_VXLAN_HWCSUM) != 0) { err = mlx5e_add_vxlan_rule_from_db(priv, el); diff --git a/sys/dev/nctgpio/nctgpio.c b/sys/dev/nctgpio/nctgpio.c index 75ea1fbdba17..ddc2ceef7dfb 100644 --- a/sys/dev/nctgpio/nctgpio.c +++ b/sys/dev/nctgpio/nctgpio.c @@ -1258,13 +1258,14 @@ nct_attach(device_t dev) GPIO_UNLOCK(sc); - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { device_printf(dev, "failed to attach to gpiobus\n"); GPIO_LOCK_DESTROY(sc); return (ENXIO); } + bus_attach_children(dev); return (0); } diff --git a/sys/dev/null/null.c b/sys/dev/null/null.c index 7ffc618e63ee..8525eb9543c3 100644 --- a/sys/dev/null/null.c +++ b/sys/dev/null/null.c @@ -4,6 +4,7 @@ * Copyright (c) 2000 Mark R. V. Murray & Jeroen C. van Gelderen * Copyright (c) 2001-2004 Mark R. V. Murray * Copyright (c) 2014 Eitan Adler + * Copyright (c) 2025 Pietro Cerutti * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,6 +40,7 @@ #include <sys/disk.h> #include <sys/bus.h> #include <sys/filio.h> +#include <sys/event.h> #include <machine/bus.h> #include <machine/vmparam.h> @@ -53,12 +55,26 @@ static d_write_t null_write; static d_ioctl_t null_ioctl; static d_ioctl_t zero_ioctl; static d_read_t zero_read; +static d_kqfilter_t kqfilter; +static int one_ev(struct knote *kn, long hint); +static int zero_ev(struct knote *kn, long hint); + +static const struct filterops one_fop = { + .f_isfd = 1, + .f_event = one_ev +}; + +static const struct filterops zero_fop = { + .f_isfd = 1, + .f_event = zero_ev +}; static struct cdevsw full_cdevsw = { .d_version = D_VERSION, .d_read = zero_read, .d_write = full_write, .d_ioctl = zero_ioctl, + .d_kqfilter = kqfilter, .d_name = "full", }; @@ -67,6 +83,7 @@ static struct cdevsw null_cdevsw = { .d_read = (d_read_t *)nullop, .d_write = null_write, .d_ioctl = null_ioctl, + .d_kqfilter = kqfilter, .d_name = "null", }; @@ -75,6 +92,7 @@ static struct cdevsw zero_cdevsw = { .d_read = zero_read, .d_write = null_write, .d_ioctl = zero_ioctl, + .d_kqfilter = kqfilter, .d_name = "zero", .d_flags = D_MMAP_ANON, }; @@ -197,5 +215,35 @@ null_modevent(module_t mod __unused, int type, void *data __unused) return (0); } +static int +one_ev(struct knote *kn, long hint) +{ + + return (1); +} + +static int +zero_ev(struct knote *kn, long hint) +{ + + return (0); +} + +static int +kqfilter(struct cdev *dev, struct knote *kn) +{ + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = dev->si_devsw == &null_cdevsw ? &zero_fop : &one_fop; + return (0); + case EVFILT_WRITE: + kn->kn_fop = dev->si_devsw == &full_cdevsw ? &zero_fop : &one_fop; + return (0); + default: + return (EOPNOTSUPP); + } +} + DEV_MODULE(null, null_modevent, NULL); MODULE_VERSION(null, 1); diff --git a/sys/dev/p2sb/lewisburg_gpio.c b/sys/dev/p2sb/lewisburg_gpio.c index b45d7767602c..3be777ab9524 100644 --- a/sys/dev/p2sb/lewisburg_gpio.c +++ b/sys/dev/p2sb/lewisburg_gpio.c @@ -217,10 +217,11 @@ lbggpio_attach(device_t dev) } /* support gpio */ - sc->sc_busdev = gpiobus_attach_bus(dev); + sc->sc_busdev = gpiobus_add_bus(dev); if (sc->sc_busdev == NULL) return (ENXIO); + bus_attach_children(dev); return (0); } diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index f94438cda041..9e43a4c1909f 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -2896,8 +2896,9 @@ pci_set_powerstate_method(device_t dev, device_t child, int state) } if (bootverbose) - pci_printf(cfg, "Transition from D%d to D%d\n", oldstate, - state); + pci_printf(cfg, "Transition from %s to %s\n", + pci_powerstate_to_str(oldstate), + pci_powerstate_to_str(state)); PCI_WRITE_CONFIG(dev, child, cfg->pp.pp_location + PCIR_POWER_STATUS, status, 2); diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index d1b7d28eae91..4abb5e977346 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -497,24 +497,39 @@ pci_is_vga_memory_range(rman_res_t start, rman_res_t end) /* * PCI power states are as defined by ACPI: * - * D0 State in which device is on and running. It is receiving full - * power from the system and delivering full functionality to the user. - * D1 Class-specific low-power state in which device context may or may not - * be lost. Buses in D1 cannot do anything to the bus that would force - * devices on that bus to lose context. - * D2 Class-specific low-power state in which device context may or may - * not be lost. Attains greater power savings than D1. Buses in D2 - * can cause devices on that bus to lose some context. Devices in D2 - * must be prepared for the bus to be in D2 or higher. - * D3 State in which the device is off and not running. Device context is - * lost. Power can be removed from the device. + * D0 State in which device is on and running. It is receiving full + * power from the system and delivering full functionality to the user. + * D1 Class-specific low-power state in which device context may or may not + * be lost. Buses in D1 cannot do anything to the bus that would force + * devices on that bus to lose context. + * D2 Class-specific low-power state in which device context may or may + * not be lost. Attains greater power savings than D1. Buses in D2 + * can cause devices on that bus to lose some context. Devices in D2 + * must be prepared for the bus to be in D2 or higher. + * D3hot State in which the device is off and not running. Device context is + * lost. Power can be removed from the device. + * D3cold Same as D3hot, but power has been removed from the device. */ #define PCI_POWERSTATE_D0 0 #define PCI_POWERSTATE_D1 1 #define PCI_POWERSTATE_D2 2 -#define PCI_POWERSTATE_D3 3 +#define PCI_POWERSTATE_D3_HOT 3 +#define PCI_POWERSTATE_D3_COLD 4 +#define PCI_POWERSTATE_D3 PCI_POWERSTATE_D3_COLD +#define PCI_POWERSTATE_MAX PCI_POWERSTATE_D3_COLD +#define PCI_POWERSTATE_COUNT 5 #define PCI_POWERSTATE_UNKNOWN -1 +static __inline const char * +pci_powerstate_to_str(int state) +{ + const char *strs[PCI_POWERSTATE_COUNT] = {"D0", "D1", "D2", "D3hot", + "D3cold"}; + + MPASS(state >= PCI_POWERSTATE_D0 && state <= PCI_POWERSTATE_MAX); + return (strs[state]); +} + static __inline int pci_set_powerstate(device_t dev, int state) { diff --git a/sys/dev/qcom_tlmm/qcom_tlmm_ipq4018.c b/sys/dev/qcom_tlmm/qcom_tlmm_ipq4018.c index 2d390cd449af..50f54b896748 100644 --- a/sys/dev/qcom_tlmm/qcom_tlmm_ipq4018.c +++ b/sys/dev/qcom_tlmm/qcom_tlmm_ipq4018.c @@ -346,13 +346,14 @@ qcom_tlmm_ipq4018_attach(device_t dev) fdt_pinctrl_register(dev, NULL); fdt_pinctrl_configure_by_name(dev, "default"); - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { device_printf(dev, "%s: failed to attach bus\n", __func__); qcom_tlmm_ipq4018_detach(dev); return (ENXIO); } + bus_attach_children(dev); return (0); } diff --git a/sys/dev/rccgpio/rccgpio.c b/sys/dev/rccgpio/rccgpio.c index b2b775b879ad..dafd0b511fa9 100644 --- a/sys/dev/rccgpio/rccgpio.c +++ b/sys/dev/rccgpio/rccgpio.c @@ -308,7 +308,7 @@ rcc_gpio_attach(device_t dev) RCC_WRITE(sc, RCC_GPIO_GP_LVL, sc->sc_output); /* Attach the gpiobus. */ - sc->sc_busdev = gpiobus_attach_bus(dev); + sc->sc_busdev = gpiobus_add_bus(dev); if (sc->sc_busdev == NULL) { bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_io_rid, sc->sc_io_res); @@ -316,6 +316,7 @@ rcc_gpio_attach(device_t dev) return (ENXIO); } + bus_attach_children(dev); return (0); } diff --git a/sys/dev/uart/uart_cpu_acpi.c b/sys/dev/uart/uart_cpu_acpi.c index 7382c47a8db6..da77603f0093 100644 --- a/sys/dev/uart/uart_cpu_acpi.c +++ b/sys/dev/uart/uart_cpu_acpi.c @@ -44,23 +44,15 @@ #include <contrib/dev/acpica/include/accommon.h> #include <contrib/dev/acpica/include/actables.h> -static struct acpi_uart_compat_data * +static struct acpi_spcr_compat_data * uart_cpu_acpi_scan(uint8_t interface_type) { - struct acpi_uart_compat_data **cd, *curcd; + struct acpi_spcr_compat_data **cd, *curcd; int i; - SET_FOREACH(cd, uart_acpi_class_and_device_set) { + SET_FOREACH(cd, uart_acpi_spcr_class_set) { curcd = *cd; - for (i = 0; curcd[i].cd_hid != NULL; i++) { - if (curcd[i].cd_port_subtype == interface_type) - return (&curcd[i]); - } - } - - SET_FOREACH(cd, uart_acpi_class_set) { - curcd = *cd; - for (i = 0; curcd[i].cd_hid != NULL; i++) { + for (i = 0; curcd[i].cd_class != NULL; i++) { if (curcd[i].cd_port_subtype == interface_type) return (&curcd[i]); } @@ -143,7 +135,7 @@ uart_cpu_acpi_spcr(int devtype, struct uart_devinfo *di) { vm_paddr_t spcr_physaddr; ACPI_TABLE_SPCR *spcr; - struct acpi_uart_compat_data *cd; + struct acpi_spcr_compat_data *cd; struct uart_class *class; int error = ENXIO; @@ -237,7 +229,7 @@ uart_cpu_acpi_dbg2(struct uart_devinfo *di) ACPI_TABLE_DBG2 *dbg2; ACPI_DBG2_DEVICE *dbg2_dev; ACPI_GENERIC_ADDRESS *base_address; - struct acpi_uart_compat_data *cd; + struct acpi_spcr_compat_data *cd; struct uart_class *class; int error; bool found; diff --git a/sys/dev/uart/uart_cpu_acpi.h b/sys/dev/uart/uart_cpu_acpi.h index 94329e1f1349..218f643c7621 100644 --- a/sys/dev/uart/uart_cpu_acpi.h +++ b/sys/dev/uart/uart_cpu_acpi.h @@ -35,11 +35,18 @@ struct uart_class; +struct acpi_spcr_compat_data { + struct uart_class *cd_class; + uint16_t cd_port_subtype; +}; +SET_DECLARE(uart_acpi_spcr_class_set, struct acpi_spcr_compat_data); +#define UART_ACPI_SPCR_CLASS(data) \ + DATA_SET(uart_acpi_spcr_class_set, data) + struct acpi_uart_compat_data { const char *cd_hid; struct uart_class *cd_class; - uint16_t cd_port_subtype; int cd_regshft; int cd_regiowidth; int cd_rclk; @@ -56,14 +63,6 @@ SET_DECLARE(uart_acpi_class_and_device_set, struct acpi_uart_compat_data); #define UART_ACPI_CLASS_AND_DEVICE(data) \ DATA_SET(uart_acpi_class_and_device_set, data) -/* - * If your UART driver implements uart_class and custom device layer, - * then use UART_ACPI_CLASS for its declaration - */ -SET_DECLARE(uart_acpi_class_set, struct acpi_uart_compat_data); -#define UART_ACPI_CLASS(data) \ - DATA_SET(uart_acpi_class_set, data) - /* Try to initialize UART device from ACPI tables */ int uart_cpu_acpi_setup(int devtype, struct uart_devinfo *di); diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index 0f19ede6d9df..c38d50e54ad8 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -492,24 +492,32 @@ UART_CLASS(uart_ns8250_class); * XXX -- refactor out ACPI and FDT ifdefs */ #ifdef DEV_ACPI +static struct acpi_spcr_compat_data acpi_spcr_compat_data[] = { + { &uart_ns8250_class, ACPI_DBG2_16550_COMPATIBLE }, + { &uart_ns8250_class, ACPI_DBG2_16550_SUBSET }, + { &uart_ns8250_class, ACPI_DBG2_16550_WITH_GAS }, + { NULL, 0 }, +}; +UART_ACPI_SPCR_CLASS(acpi_spcr_compat_data); + static struct acpi_uart_compat_data acpi_compat_data[] = { - {"AMD0020", &uart_ns8250_class, 0, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, - {"AMDI0020", &uart_ns8250_class, 0, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, - {"APMC0D08", &uart_ns8250_class, ACPI_DBG2_16550_COMPATIBLE, 2, 4, 0, 0, "APM compatible UART"}, - {"MRVL0001", &uart_ns8250_class, ACPI_DBG2_16550_SUBSET, 2, 0, 200000000, UART_F_BUSY_DETECT, "Marvell / Synopsys Designware UART"}, - {"SCX0006", &uart_ns8250_class, 0, 2, 0, 62500000, UART_F_BUSY_DETECT, "SynQuacer / Synopsys Designware UART"}, - {"HISI0031", &uart_ns8250_class, 0, 2, 0, 200000000, UART_F_BUSY_DETECT, "HiSilicon / Synopsys Designware UART"}, - {"INTC1006", &uart_ns8250_class, 0, 2, 0, 25000000, 0, "Intel ARM64 UART"}, - {"NXP0018", &uart_ns8250_class, 0, 0, 0, 350000000, UART_F_BUSY_DETECT, "NXP / Synopsys Designware UART"}, - {"PNP0500", &uart_ns8250_class, 0, 0, 0, 0, 0, "Standard PC COM port"}, - {"PNP0501", &uart_ns8250_class, 0, 0, 0, 0, 0, "16550A-compatible COM port"}, - {"PNP0502", &uart_ns8250_class, 0, 0, 0, 0, 0, "Multiport serial device (non-intelligent 16550)"}, - {"PNP0510", &uart_ns8250_class, 0, 0, 0, 0, 0, "Generic IRDA-compatible device"}, - {"PNP0511", &uart_ns8250_class, 0, 0, 0, 0, 0, "Generic IRDA-compatible device"}, - {"WACF004", &uart_ns8250_class, 0, 0, 0, 0, 0, "Wacom Tablet PC Screen"}, - {"WACF00E", &uart_ns8250_class, 0, 0, 0, 0, 0, "Wacom Tablet PC Screen 00e"}, - {"FUJ02E5", &uart_ns8250_class, 0, 0, 0, 0, 0, "Wacom Tablet at FuS Lifebook T"}, - {NULL, NULL, 0, 0 , 0, 0, 0, NULL}, + {"AMD0020", &uart_ns8250_class, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, + {"AMDI0020", &uart_ns8250_class, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, + {"APMC0D08", &uart_ns8250_class, 2, 4, 0, 0, "APM compatible UART"}, + {"MRVL0001", &uart_ns8250_class, 2, 0, 200000000, UART_F_BUSY_DETECT, "Marvell / Synopsys Designware UART"}, + {"SCX0006", &uart_ns8250_class, 2, 0, 62500000, UART_F_BUSY_DETECT, "SynQuacer / Synopsys Designware UART"}, + {"HISI0031", &uart_ns8250_class, 2, 0, 200000000, UART_F_BUSY_DETECT, "HiSilicon / Synopsys Designware UART"}, + {"INTC1006", &uart_ns8250_class, 2, 0, 25000000, 0, "Intel ARM64 UART"}, + {"NXP0018", &uart_ns8250_class, 0, 0, 350000000, UART_F_BUSY_DETECT, "NXP / Synopsys Designware UART"}, + {"PNP0500", &uart_ns8250_class, 0, 0, 0, 0, "Standard PC COM port"}, + {"PNP0501", &uart_ns8250_class, 0, 0, 0, 0, "16550A-compatible COM port"}, + {"PNP0502", &uart_ns8250_class, 0, 0, 0, 0, "Multiport serial device (non-intelligent 16550)"}, + {"PNP0510", &uart_ns8250_class, 0, 0, 0, 0, "Generic IRDA-compatible device"}, + {"PNP0511", &uart_ns8250_class, 0, 0, 0, 0, "Generic IRDA-compatible device"}, + {"WACF004", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet PC Screen"}, + {"WACF00E", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet PC Screen 00e"}, + {"FUJ02E5", &uart_ns8250_class, 0, 0, 0, 0, "Wacom Tablet at FuS Lifebook T"}, + {NULL, NULL, 0 , 0, 0, 0, NULL}, }; UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data); #endif diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c index a0d5a5b1c7e2..6afc693cd347 100644 --- a/sys/dev/uart/uart_dev_pl011.c +++ b/sys/dev/uart/uart_dev_pl011.c @@ -391,11 +391,19 @@ UART_FDT_CLASS_AND_DEVICE(fdt_compat_data); #endif #ifdef DEV_ACPI +static struct acpi_spcr_compat_data acpi_spcr_compat_data[] = { + { &uart_pl011_class, ACPI_DBG2_ARM_PL011 }, + { &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC }, + { &uart_pl011_class, ACPI_DBG2_ARM_SBSA_32BIT }, + { NULL, 0 }, +}; +UART_ACPI_SPCR_CLASS(acpi_spcr_compat_data); + static struct acpi_uart_compat_data acpi_compat_data[] = { - {"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_PL011, 2, 0, 0, 0, "uart pl011"}, - {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC, 2, 0, 0, 0, "uart pl011"}, - {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_32BIT, 2, 0, 0, 0, "uart pl011"}, - {NULL, NULL, 0, 0, 0, 0, 0, NULL}, + {"ARMH0011", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, + {"ARMHB000", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, + {"ARMHB000", &uart_pl011_class, 2, 0, 0, 0, "uart pl011"}, + {NULL, NULL, 0, 0, 0, 0, NULL}, }; UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data); #endif diff --git a/sys/dev/usb/misc/cp2112.c b/sys/dev/usb/misc/cp2112.c index d4776ca342cb..201a3ec51ce4 100644 --- a/sys/dev/usb/misc/cp2112.c +++ b/sys/dev/usb/misc/cp2112.c @@ -708,11 +708,12 @@ cp2112gpio_attach(device_t dev) } } - sc->busdev = gpiobus_attach_bus(dev); + sc->busdev = gpiobus_add_bus(dev); if (sc->busdev == NULL) { - device_printf(dev, "gpiobus_attach_bus failed\n"); + device_printf(dev, "gpiobus_add_bus failed\n"); goto detach; } + bus_attach_children(dev); return (0); detach: diff --git a/sys/dev/usb/net/if_ipheth.c b/sys/dev/usb/net/if_ipheth.c index f70113c53eb4..cfa800707391 100644 --- a/sys/dev/usb/net/if_ipheth.c +++ b/sys/dev/usb/net/if_ipheth.c @@ -55,6 +55,7 @@ #include <net/if_var.h> #include <dev/usb/usb.h> +#include <dev/usb/usb_cdc.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> #include "usbdevs.h" @@ -81,6 +82,9 @@ static uether_fn_t ipheth_start; static uether_fn_t ipheth_setmulti; static uether_fn_t ipheth_setpromisc; +static ipheth_consumer_t ipheth_consume_read; +static ipheth_consumer_t ipheth_consume_read_ncm; + #ifdef USB_DEBUG static int ipheth_debug = 0; @@ -96,7 +100,31 @@ static const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = { .direction = UE_DIR_RX, .frames = IPHETH_RX_FRAMES_MAX, .bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES), - .flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, + .flags = {.short_frames_ok = 1, .short_xfer_ok = 1, .ext_buffer = 1,}, + .callback = ipheth_bulk_read_callback, + .timeout = 0, /* no timeout */ + }, + + [IPHETH_BULK_TX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_TX, + .frames = IPHETH_TX_FRAMES_MAX, + .bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE), + .flags = {.force_short_xfer = 1,}, + .callback = ipheth_bulk_write_callback, + .timeout = IPHETH_TX_TIMEOUT, + }, +}; + +static const struct usb_config ipheth_config_ncm[IPHETH_N_TRANSFER] = { + [IPHETH_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_RX, + .frames = 1, + .bufsize = IPHETH_RX_NCM_BUF_SIZE, + .flags = {.short_frames_ok = 1, .short_xfer_ok = 1,}, .callback = ipheth_bulk_read_callback, .timeout = 0, /* no timeout */ }, @@ -204,6 +232,21 @@ ipheth_get_mac_addr(struct ipheth_softc *sc) return (0); } +static bool +ipheth_enable_ncm(struct ipheth_softc *sc) +{ + struct usb_device_request req; + + req.bmRequestType = UT_WRITE_VENDOR_INTERFACE; + req.bRequest = IPHETH_CMD_ENABLE_NCM; + USETW(req.wValue, 0); + req.wIndex[0] = sc->sc_iface_no; + req.wIndex[1] = 0; + USETW(req.wLength, 0); + + return (usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, NULL) == 0); +} + static int ipheth_probe(device_t dev) { @@ -221,6 +264,7 @@ ipheth_attach(device_t dev) struct ipheth_softc *sc = device_get_softc(dev); struct usb_ether *ue = &sc->sc_ue; struct usb_attach_arg *uaa = device_get_ivars(dev); + const struct usb_config *config; int error; sc->sc_iface_no = uaa->info.bIfaceIndex; @@ -235,18 +279,29 @@ ipheth_attach(device_t dev) device_printf(dev, "Cannot set alternate setting\n"); goto detach; } - error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, - sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); - if (error) { - device_printf(dev, "Cannot setup USB transfers\n"); - goto detach; - } + ue->ue_sc = sc; ue->ue_dev = dev; ue->ue_udev = uaa->device; ue->ue_mtx = &sc->sc_mtx; ue->ue_methods = &ipheth_ue_methods; + if (ipheth_enable_ncm(sc)) { + config = ipheth_config_ncm; + sc->is_ncm = true; + sc->consume = &ipheth_consume_read_ncm; + } else { + config = ipheth_config; + sc->consume = &ipheth_consume_read; + } + + error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, sc->sc_xfer, + config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); + if (error) { + device_printf(dev, "Cannot setup USB transfers\n"); + goto detach; + } + error = ipheth_get_mac_addr(sc); if (error) { device_printf(dev, "Cannot get MAC address\n"); @@ -389,12 +444,9 @@ ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) int actlen; int aframes; - usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); - - DPRINTFN(1, "\n"); - switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: + usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", actlen, aframes); @@ -471,53 +523,40 @@ ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) uint8_t x; int actlen; int aframes; - int len; - - usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: - + usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTF("received %u bytes in %u frames\n", actlen, aframes); - for (x = 0; x != aframes; x++) { - m = sc->sc_rx_buf[x]; - sc->sc_rx_buf[x] = NULL; - len = usbd_xfer_frame_len(xfer, x); - - if (len < (int)(sizeof(struct ether_header) + - IPHETH_RX_ADJ)) { - m_freem(m); - continue; - } - - m_adj(m, IPHETH_RX_ADJ); - - /* queue up mbuf */ - uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); - } + for (x = 0; x != aframes; x++) + sc->consume(xfer, x); /* FALLTHROUGH */ case USB_ST_SETUP: - - for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { - if (sc->sc_rx_buf[x] == NULL) { - m = uether_newbuf(); - if (m == NULL) - goto tr_stall; - - /* cancel alignment for ethernet */ - m_adj(m, ETHER_ALIGN); - - sc->sc_rx_buf[x] = m; - } else { - m = sc->sc_rx_buf[x]; + if (!sc->is_ncm) { + for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { + if (sc->sc_rx_buf[x] == NULL) { + m = uether_newbuf(); + if (m == NULL) + goto tr_stall; + + /* cancel alignment for ethernet */ + m_adj(m, ETHER_ALIGN); + + sc->sc_rx_buf[x] = m; + } else { + m = sc->sc_rx_buf[x]; + } + usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); } - - usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); + usbd_xfer_set_frames(xfer, x); + } else { + usbd_xfer_set_frame_len(xfer, 0, + IPHETH_RX_NCM_BUF_SIZE); + usbd_xfer_set_frames(xfer, 1); } - /* set number of frames and start hardware */ - usbd_xfer_set_frames(xfer, x); + usbd_transfer_submit(xfer); /* flush any received frames */ uether_rxflush(&sc->sc_ue); @@ -539,3 +578,86 @@ ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) break; } } + +static void +ipheth_consume_read(struct usb_xfer *xfer, int x) +{ + struct ipheth_softc *sc = usbd_xfer_softc(xfer); + struct mbuf *m = sc->sc_rx_buf[x]; + int len; + + sc->sc_rx_buf[x] = NULL; + len = usbd_xfer_frame_len(xfer, x); + + if (len < (int)(sizeof(struct ether_header) + IPHETH_RX_ADJ)) { + m_freem(m); + return; + } + + m_adj(m, IPHETH_RX_ADJ); + + /* queue up mbuf */ + uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); +} + +static void +ipheth_consume_read_ncm(struct usb_xfer *xfer, int x) +{ + struct ipheth_softc *sc = usbd_xfer_softc(xfer); + struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0); + struct ncm_data_cache ncm; + if_t ifp = uether_getifp(&sc->sc_ue); + struct mbuf *new_buf; + int i, actlen; + uint16_t dp_offset, dp_len; + + usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); + + if (actlen < IPHETH_NCM_HEADER_SIZE) + return; + + usbd_copy_out(pc, 0, &ncm.hdr, sizeof(ncm.hdr)); + + if (UGETDW(ncm.hdr.dwSignature) != 0x484D434E) + return; + + /* Dpt follows the hdr on iOS */ + if (UGETW(ncm.hdr.wDptIndex) != (int)(sizeof(struct usb_ncm16_hdr))) + return; + + usbd_copy_out(pc, UGETW(ncm.hdr.wDptIndex), &ncm.dpt, sizeof(ncm.dpt)); + + if (UGETDW(ncm.dpt.dwSignature) != 0x304D434E) + return; + + usbd_copy_out(pc, UGETW(ncm.hdr.wDptIndex) + sizeof(ncm.dpt), &ncm.dp, + sizeof(ncm.dp)); + + for (i = 0; i < IPHETH_NCM_DPT_DP_NUM; ++i) { + dp_offset = UGETW(ncm.dp[i].wFrameIndex); + dp_len = UGETW(ncm.dp[i].wFrameLength); + + /* (3.3.1 USB CDC NCM spec v1.0) */ + if (dp_offset == 0 && dp_len == 0) + break; + + if (dp_offset < IPHETH_NCM_HEADER_SIZE || dp_offset >= actlen || + actlen < (dp_len + dp_offset) || + dp_len < sizeof(struct ether_header)) { + if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + continue; + } + if (dp_len > (MCLBYTES - ETHER_ALIGN)) { + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); + continue; + } + + new_buf = uether_newbuf(); + if (new_buf == NULL) { + if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); + continue; + } + usbd_copy_out(pc, dp_offset, new_buf->m_data, dp_len); + uether_rxmbuf(&sc->sc_ue, new_buf, dp_len); + } +} diff --git a/sys/dev/usb/net/if_iphethvar.h b/sys/dev/usb/net/if_iphethvar.h index 203bb96b6f22..d637e8f67d01 100644 --- a/sys/dev/usb/net/if_iphethvar.h +++ b/sys/dev/usb/net/if_iphethvar.h @@ -41,6 +41,7 @@ #define IPHETH_BUF_SIZE 1514 #define IPHETH_TX_TIMEOUT 5000 /* ms */ +#define IPHETH_RX_NCM_BUF_SIZE 65536 #define IPHETH_RX_FRAMES_MAX 1 #define IPHETH_TX_FRAMES_MAX 8 @@ -55,10 +56,20 @@ #define IPHETH_CTRL_TIMEOUT 5000 /* ms */ #define IPHETH_CMD_GET_MACADDR 0x00 +#define IPHETH_CMD_ENABLE_NCM 0x04 #define IPHETH_CMD_CARRIER_CHECK 0x45 #define IPHETH_CARRIER_ON 0x04 +#define IPHETH_NCM_DPT_DP_NUM 22 +#define IPHETH_NCM_DPT_HEADER_SIZE \ + (sizeof(struct usb_ncm16_dpt) + \ + IPHETH_NCM_DPT_DP_NUM * sizeof(struct usb_ncm16_dp)) +#define IPHETH_NCM_HEADER_SIZE \ + (sizeof(struct usb_ncm16_hdr) + IPHETH_NCM_DPT_HEADER_SIZE) + +typedef void (ipheth_consumer_t)(struct usb_xfer *xfer, int idx); + enum { IPHETH_BULK_TX, IPHETH_BULK_RX, @@ -76,6 +87,16 @@ struct ipheth_softc { uint8_t sc_data[IPHETH_CTRL_BUF_SIZE]; uint8_t sc_iface_no; uint8_t sc_carrier_on; + + bool is_ncm; + + ipheth_consumer_t *consume; +}; + +struct ncm_data_cache { + struct usb_ncm16_hdr hdr; + struct usb_ncm16_dpt dpt; + struct usb_ncm16_dp dp[IPHETH_NCM_DPT_DP_NUM]; }; #define IPHETH_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) diff --git a/sys/dev/watchdog/watchdog.c b/sys/dev/watchdog/watchdog.c index e6b6dc1eac70..e1b2e08c3f10 100644 --- a/sys/dev/watchdog/watchdog.c +++ b/sys/dev/watchdog/watchdog.c @@ -50,11 +50,20 @@ #include <sys/syscallsubr.h> /* kern_clock_gettime() */ -static int wd_set_pretimeout(int newtimeout, int disableiftoolong); +#ifdef COMPAT_FREEBSD14 +#define WDIOCPATPAT_14 _IOW('W', 42, u_int) /* pat the watchdog */ +#define WDIOC_SETTIMEOUT_14 _IOW('W', 43, int) /* set/reset the timer */ +#define WDIOC_GETTIMEOUT_14 _IOR('W', 44, int) /* get total timeout */ +#define WDIOC_GETTIMELEFT_14 _IOR('W', 45, int) /* get time left */ +#define WDIOC_GETPRETIMEOUT_14 _IOR('W', 46, int) /* get the pre-timeout */ +#define WDIOC_SETPRETIMEOUT_14 _IOW('W', 47, int) /* set the pre-timeout */ +#endif + +static int wd_set_pretimeout(sbintime_t newtimeout, int disableiftoolong); static void wd_timeout_cb(void *arg); static struct callout wd_pretimeo_handle; -static int wd_pretimeout; +static sbintime_t wd_pretimeout; static int wd_pretimeout_act = WD_SOFT_LOG; static struct callout wd_softtimeo_handle; @@ -63,6 +72,8 @@ static int wd_softtimer; /* true = use softtimer instead of hardware static int wd_softtimeout_act = WD_SOFT_LOG; /* action for the software timeout */ static struct cdev *wd_dev; +static volatile sbintime_t wd_last_sbt; /* last timeout value (sbt) */ +static sbintime_t wd_last_sbt_sysctl; /* last timeout value (sbt) */ static volatile u_int wd_last_u; /* last timeout value set by kern_do_pat */ static u_int wd_last_u_sysctl; /* last timeout value set by kern_do_pat */ static u_int wd_last_u_sysctl_secs; /* wd_last_u in seconds */ @@ -73,6 +84,8 @@ SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u, CTLFLAG_RD, &wd_last_u_sysctl, 0, "Watchdog last update time"); SYSCTL_UINT(_hw_watchdog, OID_AUTO, wd_last_u_secs, CTLFLAG_RD, &wd_last_u_sysctl_secs, 0, "Watchdog last update time"); +SYSCTL_SBINTIME_MSEC(_hw_watchdog, OID_AUTO, wd_last_msecs, CTLFLAG_RD, + &wd_last_sbt_sysctl, "Watchdog last update time (milliseconds)"); static int wd_lastpat_valid = 0; static time_t wd_lastpat = 0; /* when the watchdog was last patted */ @@ -80,105 +93,94 @@ static time_t wd_lastpat = 0; /* when the watchdog was last patted */ /* Hook for external software watchdog to register for use if needed */ void (*wdog_software_attach)(void); -static void -pow2ns_to_ts(int pow2ns, struct timespec *ts) +/* Legacy interface to watchdog. */ +int +wdog_kern_pat(u_int utim) { - uint64_t ns; + sbintime_t sbt; - ns = 1ULL << pow2ns; - ts->tv_sec = ns / 1000000000ULL; - ts->tv_nsec = ns % 1000000000ULL; -} + if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) + return (EINVAL); -static int -pow2ns_to_ticks(int pow2ns) -{ - struct timeval tv; - struct timespec ts; + if ((utim & WD_LASTVAL) != 0) { + return (wdog_control(WD_CTRL_RESET)); + } - pow2ns_to_ts(pow2ns, &ts); - TIMESPEC_TO_TIMEVAL(&tv, &ts); - return (tvtohz(&tv)); + utim &= WD_INTERVAL; + if (utim == WD_TO_NEVER) + sbt = 0; + else + sbt = nstosbt(1 << utim); + + return (wdog_kern_pat_sbt(sbt)); } -static int -seconds_to_pow2ns(int seconds) +int +wdog_control(int ctrl) { - uint64_t power; - uint64_t ns; - uint64_t shifted; - - ns = ((uint64_t)seconds) * 1000000000ULL; - power = flsll(ns); - shifted = 1ULL << power; - if (shifted <= ns) { - power++; + /* Disable takes precedence */ + if (ctrl == WD_CTRL_DISABLE) { + wdog_kern_pat(0); } - return (power); + + if ((ctrl & WD_CTRL_RESET) != 0) { + wdog_kern_pat_sbt(wd_last_sbt); + } else if ((ctrl & WD_CTRL_ENABLE) != 0) { + wdog_kern_pat_sbt(wd_last_sbt); + } + + return (0); } int -wdog_kern_pat(u_int utim) +wdog_kern_pat_sbt(sbintime_t sbt) { - int error; - static int first = 1; - - if ((utim & WD_LASTVAL) != 0 && (utim & WD_INTERVAL) > 0) - return (EINVAL); - - if ((utim & WD_LASTVAL) != 0) { - /* - * if WD_LASTVAL is set, fill in the bits for timeout - * from the saved value in wd_last_u. - */ - MPASS((wd_last_u & ~WD_INTERVAL) == 0); - utim &= ~WD_LASTVAL; - utim |= wd_last_u; - } else { - /* - * Otherwise save the new interval. - * This can be zero (to disable the watchdog) - */ - wd_last_u = (utim & WD_INTERVAL); + sbintime_t error_sbt = 0; + int pow2ns = 0; + int error = 0; + static bool first = true; + + /* legacy uses power-of-2-nanoseconds time. */ + if (sbt != 0) { + pow2ns = flsl(sbttons(sbt)); + } + if (wd_last_sbt != sbt) { + wd_last_u = pow2ns; wd_last_u_sysctl = wd_last_u; - wd_last_u_sysctl_secs = pow2ns_to_ticks(wd_last_u) / hz; + wd_last_u_sysctl_secs = sbt / SBT_1S; + + wd_last_sbt = sbt; } - if ((utim & WD_INTERVAL) == WD_TO_NEVER) { - utim = 0; - /* Assume all is well; watchdog signals failure. */ - error = 0; - } else { - /* Assume no watchdog available; watchdog flags success */ + if (sbt != 0) error = EOPNOTSUPP; - } + if (wd_softtimer) { - if (utim == 0) { + if (sbt == 0) { callout_stop(&wd_softtimeo_handle); } else { - (void) callout_reset(&wd_softtimeo_handle, - pow2ns_to_ticks(utim), wd_timeout_cb, "soft"); + (void) callout_reset_sbt(&wd_softtimeo_handle, + sbt, 0, wd_timeout_cb, "soft", 0); } error = 0; } else { - EVENTHANDLER_INVOKE(watchdog_list, utim, &error); + EVENTHANDLER_INVOKE(watchdog_sbt_list, sbt, &error_sbt, &error); + EVENTHANDLER_INVOKE(watchdog_list, pow2ns, &error); } /* - * If we no hardware watchdog responded, we have not tried to + * If no hardware watchdog responded, we have not tried to * attach an external software watchdog, and one is available, * attach it now and retry. */ - if (error == EOPNOTSUPP && first && *wdog_software_attach != NULL) { + if (error == EOPNOTSUPP && first && wdog_software_attach != NULL) { (*wdog_software_attach)(); - EVENTHANDLER_INVOKE(watchdog_list, utim, &error); + EVENTHANDLER_INVOKE(watchdog_sbt_list, sbt, &error_sbt, &error); + EVENTHANDLER_INVOKE(watchdog_list, pow2ns, &error); } - first = 0; + first = false; + /* TODO: Print a (rate limited?) warning if error_sbt is too far away */ wd_set_pretimeout(wd_pretimeout, true); - /* - * If we were able to arm/strobe the watchdog, then - * update the last time it was strobed for WDIOC_GETTIMELEFT - */ if (!error) { struct timespec ts; @@ -189,6 +191,7 @@ wdog_kern_pat(u_int utim) wd_lastpat_valid = 1; } } + return (error); } @@ -265,16 +268,14 @@ wd_timeout_cb(void *arg) * current actual watchdog timeout. */ static int -wd_set_pretimeout(int newtimeout, int disableiftoolong) +wd_set_pretimeout(sbintime_t newtimeout, int disableiftoolong) { - u_int utime; - struct timespec utime_ts; - int timeout_ticks; + sbintime_t utime; + sbintime_t timeout_left; - utime = wdog_kern_last_timeout(); - pow2ns_to_ts(utime, &utime_ts); + utime = wdog_kern_last_timeout_sbt(); /* do not permit a pre-timeout >= than the timeout. */ - if (newtimeout >= utime_ts.tv_sec) { + if (newtimeout >= utime) { /* * If 'disableiftoolong' then just fall through * so as to disable the pre-watchdog @@ -292,7 +293,7 @@ wd_set_pretimeout(int newtimeout, int disableiftoolong) return 0; } - timeout_ticks = pow2ns_to_ticks(utime) - (hz*newtimeout); + timeout_left = utime - newtimeout; #if 0 printf("wd_set_pretimeout: " "newtimeout: %d, " @@ -306,8 +307,8 @@ wd_set_pretimeout(int newtimeout, int disableiftoolong) #endif /* We determined the value is sane, so reset the callout */ - (void) callout_reset(&wd_pretimeo_handle, - timeout_ticks, wd_timeout_cb, "pre"); + (void) callout_reset_sbt(&wd_pretimeo_handle, + timeout_left, 0, wd_timeout_cb, "pre", 0); wd_pretimeout = newtimeout; return 0; } @@ -316,6 +317,7 @@ static int wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags __unused, struct thread *td) { + sbintime_t sb; u_int u; time_t timeleft; int error; @@ -351,29 +353,55 @@ wd_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, error = EINVAL; } break; - case WDIOC_GETPRETIMEOUT: - *(int *)data = (int)wd_pretimeout; +#ifdef COMPAT_FREEBSD14 + case WDIOC_GETPRETIMEOUT_14: + *(int *)data = (int)(wd_pretimeout / SBT_1S); break; - case WDIOC_SETPRETIMEOUT: - error = wd_set_pretimeout(*(int *)data, false); + case WDIOC_SETPRETIMEOUT_14: + error = wd_set_pretimeout(*(int *)data * SBT_1S, false); break; - case WDIOC_GETTIMELEFT: + case WDIOC_GETTIMELEFT_14: error = wd_get_time_left(td, &timeleft); if (error) break; *(int *)data = (int)timeleft; break; - case WDIOC_SETTIMEOUT: + case WDIOC_SETTIMEOUT_14: u = *(u_int *)data; - error = wdog_kern_pat(seconds_to_pow2ns(u)); + error = wdog_kern_pat_sbt(mstosbt(u * 1000ULL)); break; - case WDIOC_GETTIMEOUT: + case WDIOC_GETTIMEOUT_14: u = wdog_kern_last_timeout(); *(u_int *)data = u; break; - case WDIOCPATPAT: + case WDIOCPATPAT_14: error = wd_ioctl_patpat(data); break; +#endif + + /* New API */ + case WDIOC_CONTROL: + wdog_control(*(int *)data); + break; + case WDIOC_SETTIMEOUT: + sb = *(sbintime_t *)data; + error = wdog_kern_pat_sbt(sb); + break; + case WDIOC_GETTIMEOUT: + *(sbintime_t *)data = wdog_kern_last_timeout_sbt(); + break; + case WDIOC_GETTIMELEFT: + error = wd_get_time_left(td, &timeleft); + if (error) + break; + *(sbintime_t *)data = (sbintime_t)timeleft * SBT_1S; + break; + case WDIOC_GETPRETIMEOUT: + *(sbintime_t *)data = wd_pretimeout; + break; + case WDIOC_SETPRETIMEOUT: + error = wd_set_pretimeout(*(sbintime_t *)data, false); + break; default: error = ENOIOCTL; break; @@ -392,6 +420,12 @@ wdog_kern_last_timeout(void) return (wd_last_u); } +sbintime_t +wdog_kern_last_timeout_sbt(void) +{ + return (wd_last_sbt); +} + static struct cdevsw wd_cdevsw = { .d_version = D_VERSION, .d_ioctl = wd_ioctl, |