diff options
32 files changed, 434 insertions, 246 deletions
diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml index 17e4f20c8d39..c78499a41c72 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -48,6 +48,22 @@ properties: - compatible - "#clock-cells" + reset: + type: object + + properties: + compatible: + const: raspberrypi,firmware-reset + + "#reset-cells": + const: 1 + description: > + The argument is the ID of the firmware reset line to affect. + + required: + - compatible + - "#reset-cells" + additionalProperties: false required: @@ -64,5 +80,10 @@ examples: compatible = "raspberrypi,firmware-clocks"; #clock-cells = <1>; }; + + reset: reset { + compatible = "raspberrypi,firmware-reset"; + #reset-cells = <1>; + }; }; ... diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 222d7825e1ab..e94244a215af 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -4,6 +4,8 @@ #include "bcm2835-rpi.dtsi" #include "bcm283x-rpi-usb-peripheral.dtsi" +#include <dt-bindings/reset/raspberrypi,firmware-reset.h> + / { compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; model = "Raspberry Pi 4 Model B"; @@ -88,6 +90,11 @@ ""; status = "okay"; }; + + reset: reset { + compatible = "raspberrypi,firmware-reset"; + #reset-cells = <1>; + }; }; &gpio { @@ -207,6 +214,21 @@ }; }; +&pcie0 { + pci@1,0 { + #address-cells = <3>; + #size-cells = <2>; + ranges; + + reg = <0 0 0 0 0>; + + usb@1,0 { + reg = <0x10000 0 0 0 0>; + resets = <&reset RASPBERRYPI_FIRMWARE_RESET_ID_USB>; + }; + }; +}; + /* uart0 communicates with the BT module */ &uart0 { pinctrl-names = "default"; diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index fbd785dd0513..4843e94713a4 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -178,9 +178,8 @@ config ISCSI_IBFT Otherwise, say N. config RASPBERRYPI_FIRMWARE - bool "Raspberry Pi Firmware Driver" + tristate "Raspberry Pi Firmware Driver" depends on BCM2835_MBOX - default USB_PCI help This option enables support for communicating with the firmware on the Raspberry Pi. diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 8f2fb4c562da..2371d08bdd17 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -12,8 +12,6 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/pci.h> -#include <linux/delay.h> #include <soc/bcm2835/raspberrypi-firmware.h> #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) @@ -21,8 +19,6 @@ #define MBOX_DATA28(msg) ((msg) & ~0xf) #define MBOX_CHAN_PROPERTY 8 -#define VL805_PCI_CONFIG_VERSION_OFFSET 0x50 - static struct platform_device *rpi_hwmon; static struct platform_device *rpi_clk; @@ -301,63 +297,6 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) } EXPORT_SYMBOL_GPL(rpi_firmware_get); -/* - * The Raspberry Pi 4 gets its USB functionality from VL805, a PCIe chip that - * implements xHCI. After a PCI reset, VL805's firmware may either be loaded - * directly from an EEPROM or, if not present, by the SoC's co-processor, - * VideoCore. RPi4's VideoCore OS contains both the non public firmware load - * logic and the VL805 firmware blob. This function triggers the aforementioned - * process. - */ -int rpi_firmware_init_vl805(struct pci_dev *pdev) -{ - struct device_node *fw_np; - struct rpi_firmware *fw; - u32 dev_addr, version; - int ret; - - fw_np = of_find_compatible_node(NULL, NULL, - "raspberrypi,bcm2835-firmware"); - if (!fw_np) - return 0; - - fw = rpi_firmware_get(fw_np); - of_node_put(fw_np); - if (!fw) - return -ENODEV; - - /* - * Make sure we don't trigger a firmware load unnecessarily. - * - * If something went wrong with PCI, this whole exercise would be - * futile as VideoCore expects from us a configured PCI bus. Just take - * the faulty version (likely ~0) and let xHCI's registration fail - * further down the line. - */ - pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET, &version); - if (version) - goto exit; - - dev_addr = pdev->bus->number << 20 | PCI_SLOT(pdev->devfn) << 15 | - PCI_FUNC(pdev->devfn) << 12; - - ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, - &dev_addr, sizeof(dev_addr)); - if (ret) - return ret; - - /* Wait for vl805 to startup */ - usleep_range(200, 1000); - - pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET, - &version); -exit: - pci_info(pdev, "VL805 firmware version %08x\n", version); - - return 0; -} -EXPORT_SYMBOL_GPL(rpi_firmware_init_vl805); - static const struct of_device_id rpi_firmware_of_match[] = { { .compatible = "raspberrypi,bcm2835-firmware", }, {}, diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 85fa7d54f11f..bac63d04297f 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -28,8 +28,6 @@ #include <linux/string.h> #include <linux/types.h> -#include <soc/bcm2835/raspberrypi-firmware.h> - #include "../pci.h" /* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */ @@ -931,24 +929,9 @@ static int brcm_pcie_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node, *msi_np; struct pci_host_bridge *bridge; - struct device_node *fw_np; struct brcm_pcie *pcie; int ret; - /* - * We have to wait for Raspberry Pi's firmware interface to be up as a - * PCI fixup, rpi_firmware_init_vl805(), depends on it. This driver's - * probe can race with the firmware interface's (see - * drivers/firmware/raspberrypi.c) and potentially break the PCI fixup. - */ - fw_np = of_find_compatible_node(NULL, NULL, - "raspberrypi,bcm2835-firmware"); - if (fw_np && !rpi_firmware_get(fw_np)) { - of_node_put(fw_np); - return -EPROBE_DEFER; - } - of_node_put(fw_np); - bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie)); if (!bridge) return -ENOMEM; diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index d9efbfd29646..97e848740e13 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -140,6 +140,17 @@ config RESET_QCOM_PDC to control reset signals provided by PDC for Modem, Compute, Display, GPU, Debug, AOP, Sensors, Audio, SP and APPS. +config RESET_RASPBERRYPI + tristate "Raspberry Pi 4 Firmware Reset Driver" + depends on RASPBERRYPI_FIRMWARE || (RASPBERRYPI_FIRMWARE=n && COMPILE_TEST) + default USB_XHCI_PCI + help + Raspberry Pi 4's co-processor controls some of the board's HW + initialization process, but it's up to Linux to trigger it when + relevant. This driver provides a reset controller capable of + interfacing with RPi4's co-processor and model these firmware + initialization routines as reset lines. + config RESET_SCMI tristate "Reset driver controlled via ARM SCMI interface" depends on ARM_SCMI_PROTOCOL || COMPILE_TEST diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 249ed357c997..16947610cc3b 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o +obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c new file mode 100644 index 000000000000..02f59c06f69b --- /dev/null +++ b/drivers/reset/reset-raspberrypi.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Raspberry Pi 4 firmware reset driver + * + * Copyright (C) 2020 Nicolas Saenz Julienne <[email protected]> + */ +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <soc/bcm2835/raspberrypi-firmware.h> +#include <dt-bindings/reset/raspberrypi,firmware-reset.h> + +struct rpi_reset { + struct reset_controller_dev rcdev; + struct rpi_firmware *fw; +}; + +static inline struct rpi_reset *to_rpi(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct rpi_reset, rcdev); +} + +static int rpi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct rpi_reset *priv = to_rpi(rcdev); + u32 dev_addr; + int ret; + + switch (id) { + case RASPBERRYPI_FIRMWARE_RESET_ID_USB: + /* + * The Raspberry Pi 4 gets its USB functionality from VL805, a + * PCIe chip that implements xHCI. After a PCI reset, VL805's + * firmware may either be loaded directly from an EEPROM or, if + * not present, by the SoC's co-processor, VideoCore. rpi's + * VideoCore OS contains both the non public firmware load + * logic and the VL805 firmware blob. This triggers the + * aforementioned process. + * + * The pci device address is expected is expected by the + * firmware encoded like this: + * + * PCI_BUS << 20 | PCI_SLOT << 15 | PCI_FUNC << 12 + * + * But since rpi's PCIe is hardwired, we know the address in + * advance. + */ + dev_addr = 0x100000; + ret = rpi_firmware_property(priv->fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, + &dev_addr, sizeof(dev_addr)); + if (ret) + return ret; + + /* Wait for vl805 to startup */ + usleep_range(200, 1000); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static const struct reset_control_ops rpi_reset_ops = { + .reset = rpi_reset_reset, +}; + +static int rpi_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rpi_firmware *fw; + struct device_node *np; + struct rpi_reset *priv; + + np = of_get_parent(dev->of_node); + if (!np) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + fw = rpi_firmware_get(np); + of_node_put(np); + if (!fw) + return -EPROBE_DEFER; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + + priv->fw = fw; + priv->rcdev.owner = THIS_MODULE; + priv->rcdev.nr_resets = RASPBERRYPI_FIRMWARE_RESET_NUM_IDS; + priv->rcdev.ops = &rpi_reset_ops; + priv->rcdev.of_node = dev->of_node; + + return devm_reset_controller_register(dev, &priv->rcdev); +} + +static const struct of_device_id rpi_reset_of_match[] = { + { .compatible = "raspberrypi,firmware-reset" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rpi_reset_of_match); + +static struct platform_driver rpi_reset_driver = { + .probe = rpi_reset_probe, + .driver = { + .name = "raspberrypi-reset", + .of_match_table = rpi_reset_of_match, + }, +}; +module_platform_driver(rpi_reset_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne <[email protected]>"); +MODULE_DESCRIPTION("Raspberry Pi 4 firmware reset driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index ea66f8f385ba..e62a770a5d3b 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -230,12 +230,12 @@ CXACRU__ATTR_INIT(_name) static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf) { - return snprintf(buf, PAGE_SIZE, "%u\n", value); + return sprintf(buf, "%u\n", value); } static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", value); + return sprintf(buf, "%d\n", value); } static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf) @@ -255,8 +255,8 @@ static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) static char *str[] = { "no", "yes" }; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) @@ -264,8 +264,8 @@ static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) static char *str[] = { NULL, "not connected", "connected", "lost" }; if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL)) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf) @@ -275,8 +275,8 @@ static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf) "waiting", "initialising" }; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf) @@ -288,8 +288,8 @@ static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf) "ITU-T G.992.2 (G.LITE)" }; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } /* @@ -309,8 +309,7 @@ static ssize_t mac_address_show(struct device *dev, if (instance == NULL || instance->usbatm->atm_dev == NULL) return -ENODEV; - return snprintf(buf, PAGE_SIZE, "%pM\n", - instance->usbatm->atm_dev->esi); + return sprintf(buf, "%pM\n", instance->usbatm->atm_dev->esi); } static ssize_t adsl_state_show(struct device *dev, @@ -326,8 +325,8 @@ static ssize_t adsl_state_show(struct device *dev, value = instance->card_info[CXINF_LINE_STARTABLE]; if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); + return sprintf(buf, "%u\n", value); + return sprintf(buf, "%s\n", str[value]); } static ssize_t adsl_state_store(struct device *dev, diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 4e12a32ca392..56fe30d247da 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -511,9 +511,10 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance, ** receive ** **************/ -static void usbatm_rx_process(unsigned long data) +static void usbatm_rx_process(struct tasklet_struct *t) { - struct usbatm_data *instance = (struct usbatm_data *)data; + struct usbatm_data *instance = from_tasklet(instance, t, + rx_channel.tasklet); struct urb *urb; while ((urb = usbatm_pop_urb(&instance->rx_channel))) { @@ -564,9 +565,10 @@ static void usbatm_rx_process(unsigned long data) ** send ** ***********/ -static void usbatm_tx_process(unsigned long data) +static void usbatm_tx_process(struct tasklet_struct *t) { - struct usbatm_data *instance = (struct usbatm_data *)data; + struct usbatm_data *instance = from_tasklet(instance, t, + tx_channel.tasklet); struct sk_buff *skb = instance->current_skb; struct urb *urb = NULL; const unsigned int buf_size = instance->tx_channel.buf_size; @@ -1069,8 +1071,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, usbatm_init_channel(&instance->rx_channel); usbatm_init_channel(&instance->tx_channel); - tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance); - tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance); + tasklet_setup(&instance->rx_channel.tasklet, usbatm_rx_process); + tasklet_setup(&instance->tx_channel.tasklet, usbatm_tx_process); instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding; instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding; instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance; diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c index 60f4711717d2..e65f1a0ae80b 100644 --- a/drivers/usb/c67x00/c67x00-sched.c +++ b/drivers/usb/c67x00/c67x00-sched.c @@ -1123,9 +1123,9 @@ static void c67x00_do_work(struct c67x00_hcd *c67x00) /* -------------------------------------------------------------------------- */ -static void c67x00_sched_tasklet(unsigned long __c67x00) +static void c67x00_sched_tasklet(struct tasklet_struct *t) { - struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00; + struct c67x00_hcd *c67x00 = from_tasklet(c67x00, t, tasklet); c67x00_do_work(c67x00); } @@ -1136,8 +1136,7 @@ void c67x00_sched_kick(struct c67x00_hcd *c67x00) int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00) { - tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet, - (unsigned long)c67x00); + tasklet_setup(&c67x00->tasklet, c67x00_sched_tasklet); return 0; } diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index 7b3a21360d7c..6c4e3a19f42c 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -91,14 +91,14 @@ static void usb_conn_detect_cable(struct work_struct *work) return; } - if (info->last_role == USB_ROLE_HOST) + if (info->last_role == USB_ROLE_HOST && info->vbus) regulator_disable(info->vbus); ret = usb_role_switch_set_role(info->role_sw, role); if (ret) dev_err(info->dev, "failed to set role: %d\n", ret); - if (role == USB_ROLE_HOST) { + if (role == USB_ROLE_HOST && info->vbus) { ret = regulator_enable(info->vbus); if (ret) dev_err(info->dev, "enable vbus regulator failed\n"); @@ -106,8 +106,9 @@ static void usb_conn_detect_cable(struct work_struct *work) info->last_role = role; - dev_dbg(info->dev, "vbus regulator is %s\n", - regulator_is_enabled(info->vbus) ? "enabled" : "disabled"); + if (info->vbus) + dev_dbg(info->dev, "vbus regulator is %s\n", + regulator_is_enabled(info->vbus) ? "enabled" : "disabled"); power_supply_changed(info->charger); } @@ -156,6 +157,7 @@ static int usb_conn_probe(struct platform_device *pdev) struct power_supply_config cfg = { .of_node = dev->of_node, }; + bool need_vbus = true; int ret = 0; info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); @@ -185,10 +187,26 @@ static int usb_conn_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&info->dw_det, usb_conn_detect_cable); - info->vbus = devm_regulator_get(dev, "vbus"); + /* + * If the USB connector is a child of a USB port and that port already provides the VBUS + * supply, there's no need for the USB connector to provide it again. + */ + if (dev->parent && dev->parent->of_node) { + if (of_find_property(dev->parent->of_node, "vbus-supply", NULL)) + need_vbus = false; + } + + if (!need_vbus) { + info->vbus = devm_regulator_get_optional(dev, "vbus"); + if (PTR_ERR(info->vbus) == -ENODEV) + info->vbus = NULL; + } else { + info->vbus = devm_regulator_get(dev, "vbus"); + } + if (IS_ERR(info->vbus)) { if (PTR_ERR(info->vbus) != -EPROBE_DEFER) - dev_err(dev, "failed to get vbus\n"); + dev_err(dev, "failed to get vbus: %ld\n", PTR_ERR(info->vbus)); return PTR_ERR(info->vbus); } @@ -266,7 +284,7 @@ static int usb_conn_remove(struct platform_device *pdev) cancel_delayed_work_sync(&info->dw_det); - if (info->last_role == USB_ROLE_HOST) + if (info->last_role == USB_ROLE_HOST && info->vbus) regulator_disable(info->vbus); usb_role_switch_put(info->role_sw); diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 2b2f1ab6e36a..22c887f5c497 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -195,7 +195,7 @@ int usb_choose_configuration(struct usb_device *udev) } EXPORT_SYMBOL_GPL(usb_choose_configuration); -static int __check_usb_generic(struct device_driver *drv, void *data) +static int __check_for_non_generic_match(struct device_driver *drv, void *data) { struct usb_device *udev = data; struct usb_device_driver *udrv; @@ -219,7 +219,7 @@ static bool usb_generic_driver_match(struct usb_device *udev) * If any other driver wants the device, leave the device to this other * driver. */ - if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_usb_generic)) + if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_for_non_generic_match)) return false; return true; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a33b849e8beb..2c6b9578a7d3 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1657,9 +1657,9 @@ static void __usb_hcd_giveback_urb(struct urb *urb) usb_put_urb(urb); } -static void usb_giveback_urb_bh(unsigned long param) +static void usb_giveback_urb_bh(struct tasklet_struct *t) { - struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param; + struct giveback_urb_bh *bh = from_tasklet(bh, t, bh); struct list_head local_list; spin_lock_irq(&bh->lock); @@ -2403,7 +2403,7 @@ static void init_giveback_urb_bh(struct giveback_urb_bh *bh) spin_lock_init(&bh->lock); INIT_LIST_HEAD(&bh->head); - tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh); + tasklet_setup(&bh->bh, usb_giveback_urb_bh); } struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 7bc23469f4e4..27e83e55a590 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -772,11 +772,12 @@ void usb_block_urb(struct urb *urb) EXPORT_SYMBOL_GPL(usb_block_urb); /** - * usb_kill_anchored_urbs - cancel transfer requests en masse + * usb_kill_anchored_urbs - kill all URBs associated with an anchor * @anchor: anchor the requests are bound to * - * this allows all outstanding URBs to be killed starting - * from the back of the queue + * This kills all outstanding URBs starting from the back of the queue, + * with guarantee that no completer callbacks will take place from the + * anchor after this function returns. * * This routine should not be called by a driver after its disconnect * method has returned. @@ -784,20 +785,26 @@ EXPORT_SYMBOL_GPL(usb_block_urb); void usb_kill_anchored_urbs(struct usb_anchor *anchor) { struct urb *victim; + int surely_empty; - spin_lock_irq(&anchor->lock); - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - /* we must make sure the URB isn't freed before we kill it*/ - usb_get_urb(victim); - spin_unlock_irq(&anchor->lock); - /* this will unanchor the URB */ - usb_kill_urb(victim); - usb_put_urb(victim); + do { spin_lock_irq(&anchor->lock); - } - spin_unlock_irq(&anchor->lock); + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, + struct urb, anchor_list); + /* make sure the URB isn't freed before we kill it */ + usb_get_urb(victim); + spin_unlock_irq(&anchor->lock); + /* this will unanchor the URB */ + usb_kill_urb(victim); + usb_put_urb(victim); + spin_lock_irq(&anchor->lock); + } + surely_empty = usb_anchor_check_wakeup(anchor); + + spin_unlock_irq(&anchor->lock); + cpu_relax(); + } while (!surely_empty); } EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); @@ -816,21 +823,27 @@ EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); void usb_poison_anchored_urbs(struct usb_anchor *anchor) { struct urb *victim; + int surely_empty; - spin_lock_irq(&anchor->lock); - anchor->poisoned = 1; - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - /* we must make sure the URB isn't freed before we kill it*/ - usb_get_urb(victim); - spin_unlock_irq(&anchor->lock); - /* this will unanchor the URB */ - usb_poison_urb(victim); - usb_put_urb(victim); + do { spin_lock_irq(&anchor->lock); - } - spin_unlock_irq(&anchor->lock); + anchor->poisoned = 1; + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, + struct urb, anchor_list); + /* make sure the URB isn't freed before we kill it */ + usb_get_urb(victim); + spin_unlock_irq(&anchor->lock); + /* this will unanchor the URB */ + usb_poison_urb(victim); + usb_put_urb(victim); + spin_lock_irq(&anchor->lock); + } + surely_empty = usb_anchor_check_wakeup(anchor); + + spin_unlock_irq(&anchor->lock); + cpu_relax(); + } while (!surely_empty); } EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs); @@ -970,14 +983,20 @@ void usb_scuttle_anchored_urbs(struct usb_anchor *anchor) { struct urb *victim; unsigned long flags; + int surely_empty; + + do { + spin_lock_irqsave(&anchor->lock, flags); + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, + struct urb, anchor_list); + __usb_unanchor_urb(victim, anchor); + } + surely_empty = usb_anchor_check_wakeup(anchor); - spin_lock_irqsave(&anchor->lock, flags); - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - __usb_unanchor_urb(victim, anchor); - } - spin_unlock_irqrestore(&anchor->lock, flags); + spin_unlock_irqrestore(&anchor->lock, flags); + cpu_relax(); + } while (!surely_empty); } EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs); diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 46af0aa07e2e..85cb15734aa8 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -698,9 +698,9 @@ drop_out: f_midi_drop_out_substreams(midi); } -static void f_midi_in_tasklet(unsigned long data) +static void f_midi_in_tasklet(struct tasklet_struct *t) { - struct f_midi *midi = (struct f_midi *) data; + struct f_midi *midi = from_tasklet(midi, t, tasklet); f_midi_transmit(midi); } @@ -875,7 +875,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; - tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); + tasklet_setup(&midi->tasklet, f_midi_in_tasklet); status = f_midi_register_card(midi); if (status < 0) goto fail_register; diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 2707be628298..fa66449b3907 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -923,9 +923,9 @@ static int qe_ep_rxframe_handle(struct qe_ep *ep) return 0; } -static void ep_rx_tasklet(unsigned long data) +static void ep_rx_tasklet(struct tasklet_struct *t) { - struct qe_udc *udc = (struct qe_udc *)data; + struct qe_udc *udc = from_tasklet(udc, t, rx_tasklet); struct qe_ep *ep; struct qe_frame *pframe; struct qe_bd __iomem *bd; @@ -2553,8 +2553,7 @@ static int qe_udc_probe(struct platform_device *ofdev) DMA_TO_DEVICE); } - tasklet_init(&udc->rx_tasklet, ep_rx_tasklet, - (unsigned long)udc); + tasklet_setup(&udc->rx_tasklet, ep_rx_tasklet); /* request irq and disable DR */ udc->usb_irq = irq_of_parse_and_map(np, 0); if (!udc->usb_irq) { diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 8c1bbac6d136..c32b544c043a 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -16,8 +16,7 @@ #include <linux/export.h> #include <linux/acpi.h> #include <linux/dmi.h> - -#include <soc/bcm2835/raspberrypi-firmware.h> +#include <linux/of.h> #include "pci-quirks.h" #include "xhci-ext-caps.h" @@ -1247,7 +1246,8 @@ iounmap: static void quirk_usb_early_handoff(struct pci_dev *pdev) { - int ret; + struct device_node *parent; + bool is_rpi; /* Skip Netlogic mips SoC's internal PCI USB controller. * This device does not need/support EHCI/OHCI handoff @@ -1255,14 +1255,16 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) if (pdev->vendor == 0x184e) /* vendor Netlogic */ return; + /* + * Bypass the Raspberry Pi 4 controller xHCI controller, things are + * taken care of by the board's co-processor. + */ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) { - ret = rpi_firmware_init_vl805(pdev); - if (ret) { - /* Firmware might be outdated, or something failed */ - dev_warn(&pdev->dev, - "Failed to load VL805's firmware: %d. Will continue to attempt to work, but bad things might happen. You should fix this...\n", - ret); - } + parent = of_get_parent(pdev->bus->dev.of_node); + is_rpi = of_device_is_compatible(parent, "brcm,bcm2711-pcie"); + of_node_put(parent); + if (is_rpi) + return; } if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI && diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index b8918f73a432..ae4e4ab638b5 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -288,14 +288,14 @@ static const struct tty_operations dbc_tty_ops = { .unthrottle = dbc_tty_unthrottle, }; -static void dbc_rx_push(unsigned long _port) +static void dbc_rx_push(struct tasklet_struct *t) { struct dbc_request *req; struct tty_struct *tty; unsigned long flags; bool do_push = false; bool disconnect = false; - struct dbc_port *port = (void *)_port; + struct dbc_port *port = from_tasklet(port, t, push); struct list_head *queue = &port->read_queue; spin_lock_irqsave(&port->port_lock, flags); @@ -382,7 +382,7 @@ xhci_dbc_tty_init_port(struct xhci_dbc *dbc, struct dbc_port *port) { tty_port_init(&port->port); spin_lock_init(&port->port_lock); - tasklet_init(&port->push, dbc_rx_push, (unsigned long)port); + tasklet_setup(&port->push, dbc_rx_push); INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queue); INIT_LIST_HEAD(&port->write_pool); diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 4311d4c9b68d..8f321f39ab96 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -77,7 +77,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) { struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs; u32 value, check_val; - int u3_ports_disabed = 0; + int u3_ports_disabled = 0; int ret; int i; @@ -92,7 +92,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) /* power on and enable u3 ports except skipped ones */ for (i = 0; i < mtk->num_u3_ports; i++) { if ((0x1 << i) & mtk->u3p_dis_msk) { - u3_ports_disabed++; + u3_ports_disabled++; continue; } @@ -117,7 +117,7 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk) check_val = STS1_SYSPLL_STABLE | STS1_REF_RST | STS1_SYS125_RST | STS1_XHCI_RST; - if (mtk->num_u3_ports > u3_ports_disabed) + if (mtk->num_u3_ports > u3_ports_disabled) check_val |= STS1_U3_MAC_RST; ret = readl_poll_timeout(&ippc->ip_pw_sts1, value, diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 3feaafebfe58..c26c06e5c88c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/acpi.h> +#include <linux/reset.h> #include "xhci.h" #include "xhci-trace.h" @@ -346,6 +347,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) struct xhci_hcd *xhci; struct usb_hcd *hcd; struct xhci_driver_data *driver_data; + struct reset_control *reset; driver_data = (struct xhci_driver_data *)id->driver_data; if (driver_data && driver_data->quirks & XHCI_RENESAS_FW_QUIRK) { @@ -354,6 +356,11 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return retval; } + reset = devm_reset_control_get_optional_exclusive(&dev->dev, NULL); + if (IS_ERR(reset)) + return PTR_ERR(reset); + reset_control_reset(reset); + /* Prevent runtime suspending between USB-2 and USB-3 initialization */ pm_runtime_get_noresume(&dev->dev); @@ -371,6 +378,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* USB 2.0 roothub is stored in the PCI device now. */ hcd = dev_get_drvdata(&dev->dev); xhci = hcd_to_xhci(hcd); + xhci->reset = reset; xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev, pci_name(dev), hcd); if (!xhci->shared_hcd) { @@ -522,6 +530,8 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval = 0; + reset_control_reset(xhci->reset); + /* The BIOS on systems with the Intel Panther Point chipset may or may * not support xHCI natively. That means that during system resume, it * may switch the ports back to EHCI so that users can use their diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 190923d8b246..934be1686352 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1866,7 +1866,6 @@ static const struct tegra_xusb_phy_type tegra124_phy_types[] = { static const unsigned int tegra124_xusb_context_ipfs[] = { IPFS_XUSB_HOST_MSI_BAR_SZ_0, - IPFS_XUSB_HOST_MSI_BAR_SZ_0, IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0, IPFS_XUSB_HOST_MSI_FPCI_BAR_ST_0, IPFS_XUSB_HOST_MSI_VEC0_0, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ea1754f185a2..ac44b62ca0c5 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1770,6 +1770,8 @@ struct xhci_hcd { /* optional clocks */ struct clk *clk; struct clk *reg_clk; + /* optional reset controller */ + struct reset_control *reset; /* data structures */ struct xhci_device_context_array *dcbaa; struct xhci_ring *cmd_ring; diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 61e9e987fe4a..bb546f624a45 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -187,7 +187,6 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; default: return -ENOTTY; - break; } return 0; diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index b2e09883c7e2..e3165d79b5f6 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -96,15 +96,13 @@ static void yurex_delete(struct kref *kref) if (dev->cntl_urb) { usb_kill_urb(dev->cntl_urb); kfree(dev->cntl_req); - if (dev->cntl_buffer) - usb_free_coherent(dev->udev, YUREX_BUF_SIZE, + usb_free_coherent(dev->udev, YUREX_BUF_SIZE, dev->cntl_buffer, dev->cntl_urb->transfer_dma); usb_free_urb(dev->cntl_urb); } if (dev->urb) { usb_kill_urb(dev->urb); - if (dev->int_buffer) - usb_free_coherent(dev->udev, YUREX_BUF_SIZE, + usb_free_coherent(dev->udev, YUREX_BUF_SIZE, dev->int_buffer, dev->urb->transfer_dma); usb_free_urb(dev->urb); } diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 71f4f02c05c6..aef0a0bba25a 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -370,12 +370,6 @@ static inline struct mtu3 *gadget_to_mtu3(struct usb_gadget *g) return container_of(g, struct mtu3, g); } -static inline int is_first_entry(const struct list_head *list, - const struct list_head *head) -{ - return list_is_last(head, list); -} - static inline struct mtu3_request *to_mtu3_request(struct usb_request *req) { return req ? container_of(req, struct mtu3_request, request) : NULL; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 2ec4eeacebc7..5eed1078fac8 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -282,11 +282,12 @@ static void destroy_urbtracker(struct kref *kref) * port callback had to be deferred because the disconnect mutex could not be * obtained at the time. */ -static void send_deferred_urbs(unsigned long _mos_parport) +static void send_deferred_urbs(struct tasklet_struct *t) { int ret_val; unsigned long flags; - struct mos7715_parport *mos_parport = (void *)_mos_parport; + struct mos7715_parport *mos_parport = from_tasklet(mos_parport, t, + urb_tasklet); struct urbtracker *urbtrack, *tmp; struct list_head *cursor, *next; struct device *dev; @@ -716,8 +717,7 @@ static int mos7715_parport_init(struct usb_serial *serial) INIT_LIST_HEAD(&mos_parport->deferred_urbs); usb_set_serial_data(serial, mos_parport); /* hijack private pointer */ mos_parport->serial = serial; - tasklet_init(&mos_parport->urb_tasklet, send_deferred_urbs, - (unsigned long) mos_parport); + tasklet_setup(&mos_parport->urb_tasklet, send_deferred_urbs); init_completion(&mos_parport->syncmsg_compl); /* cycle parallel port reset bit */ diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 89f5e33a6e6d..3c76336e43bb 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1383,7 +1383,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; isd200_srb_set_bufflen(srb, 0); } else { - usb_stor_dbg(us, " Not removeable media, just report okay\n"); + usb_stor_dbg(us, " Not removable media, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = 0; } diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a48e3f90d196..92806547f485 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -8,8 +8,10 @@ #include <linux/completion.h> #include <linux/debugfs.h> #include <linux/device.h> +#include <linux/hrtimer.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kthread.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/power_supply.h> @@ -28,7 +30,8 @@ #include <linux/usb/role.h> #include <linux/usb/tcpm.h> #include <linux/usb/typec_altmode.h> -#include <linux/workqueue.h> + +#include <uapi/linux/sched/types.h> #define FOREACH_STATE(S) \ S(INVALID_STATE), \ @@ -203,7 +206,7 @@ struct tcpm_port { struct device *dev; struct mutex lock; /* tcpm state machine lock */ - struct workqueue_struct *wq; + struct kthread_worker *wq; struct typec_capability typec_caps; struct typec_port *typec_port; @@ -247,15 +250,17 @@ struct tcpm_port { enum tcpm_state prev_state; enum tcpm_state state; enum tcpm_state delayed_state; - unsigned long delayed_runtime; + ktime_t delayed_runtime; unsigned long delay_ms; spinlock_t pd_event_lock; u32 pd_events; - struct work_struct event_work; - struct delayed_work state_machine; - struct delayed_work vdm_state_machine; + struct kthread_work event_work; + struct hrtimer state_machine_timer; + struct kthread_work state_machine; + struct hrtimer vdm_state_machine_timer; + struct kthread_work vdm_state_machine; bool state_machine_running; struct completion tx_complete; @@ -340,7 +345,7 @@ struct tcpm_port { }; struct pd_rx_event { - struct work_struct work; + struct kthread_work work; struct tcpm_port *port; struct pd_message msg; }; @@ -914,6 +919,27 @@ static int tcpm_pd_send_sink_caps(struct tcpm_port *port) return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg); } +static void mod_tcpm_delayed_work(struct tcpm_port *port, unsigned int delay_ms) +{ + if (delay_ms) { + hrtimer_start(&port->state_machine_timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&port->state_machine_timer); + kthread_queue_work(port->wq, &port->state_machine); + } +} + +static void mod_vdm_delayed_work(struct tcpm_port *port, unsigned int delay_ms) +{ + if (delay_ms) { + hrtimer_start(&port->vdm_state_machine_timer, ms_to_ktime(delay_ms), + HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&port->vdm_state_machine_timer); + kthread_queue_work(port->wq, &port->vdm_state_machine); + } +} + static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, unsigned int delay_ms) { @@ -922,9 +948,8 @@ static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, tcpm_states[port->state], tcpm_states[state], delay_ms); port->delayed_state = state; - mod_delayed_work(port->wq, &port->state_machine, - msecs_to_jiffies(delay_ms)); - port->delayed_runtime = jiffies + msecs_to_jiffies(delay_ms); + mod_tcpm_delayed_work(port, delay_ms); + port->delayed_runtime = ktime_add(ktime_get(), ms_to_ktime(delay_ms)); port->delay_ms = delay_ms; } else { tcpm_log(port, "state change %s -> %s", @@ -939,7 +964,7 @@ static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, * machine. */ if (!port->state_machine_running) - mod_delayed_work(port->wq, &port->state_machine, 0); + mod_tcpm_delayed_work(port, 0); } } @@ -960,7 +985,7 @@ static void tcpm_queue_message(struct tcpm_port *port, enum pd_msg_request message) { port->queued_message = message; - mod_delayed_work(port->wq, &port->state_machine, 0); + mod_tcpm_delayed_work(port, 0); } /* @@ -981,7 +1006,7 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, port->vdm_retries = 0; port->vdm_state = VDM_STATE_READY; - mod_delayed_work(port->wq, &port->vdm_state_machine, 0); + mod_vdm_delayed_work(port, 0); } static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header, @@ -1244,8 +1269,7 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, port->vdm_state = VDM_STATE_WAIT_RSP_BUSY; port->vdo_retry = (p[0] & ~VDO_CMDT_MASK) | CMDT_INIT; - mod_delayed_work(port->wq, &port->vdm_state_machine, - msecs_to_jiffies(PD_T_VDM_BUSY)); + mod_vdm_delayed_work(port, PD_T_VDM_BUSY); return; } port->vdm_state = VDM_STATE_DONE; @@ -1390,8 +1414,7 @@ static void vdm_run_state_machine(struct tcpm_port *port) port->vdm_retries = 0; port->vdm_state = VDM_STATE_BUSY; timeout = vdm_ready_timeout(port->vdo_data[0]); - mod_delayed_work(port->wq, &port->vdm_state_machine, - timeout); + mod_vdm_delayed_work(port, timeout); } break; case VDM_STATE_WAIT_RSP_BUSY: @@ -1420,10 +1443,9 @@ static void vdm_run_state_machine(struct tcpm_port *port) } } -static void vdm_state_machine_work(struct work_struct *work) +static void vdm_state_machine_work(struct kthread_work *work) { - struct tcpm_port *port = container_of(work, struct tcpm_port, - vdm_state_machine.work); + struct tcpm_port *port = container_of(work, struct tcpm_port, vdm_state_machine); enum vdm_states prev_state; mutex_lock(&port->lock); @@ -1591,6 +1613,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode, struct tcpm_port *port = typec_altmode_get_drvdata(altmode); tcpm_queue_vdm_unlocked(port, header, data, count - 1); + return 0; } @@ -2005,7 +2028,7 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, } } -static void tcpm_pd_rx_handler(struct work_struct *work) +static void tcpm_pd_rx_handler(struct kthread_work *work) { struct pd_rx_event *event = container_of(work, struct pd_rx_event, work); @@ -2067,10 +2090,10 @@ void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg) if (!event) return; - INIT_WORK(&event->work, tcpm_pd_rx_handler); + kthread_init_work(&event->work, tcpm_pd_rx_handler); event->port = port; memcpy(&event->msg, msg, sizeof(*msg)); - queue_work(port->wq, &event->work); + kthread_queue_work(port->wq, &event->work); } EXPORT_SYMBOL_GPL(tcpm_pd_receive); @@ -2123,9 +2146,9 @@ static bool tcpm_send_queued_message(struct tcpm_port *port) } while (port->queued_message != PD_MSG_NONE); if (port->delayed_state != INVALID_STATE) { - if (time_is_after_jiffies(port->delayed_runtime)) { - mod_delayed_work(port->wq, &port->state_machine, - port->delayed_runtime - jiffies); + if (ktime_after(port->delayed_runtime, ktime_get())) { + mod_tcpm_delayed_work(port, ktime_to_ms(ktime_sub(port->delayed_runtime, + ktime_get()))); return true; } port->delayed_state = INVALID_STATE; @@ -3258,10 +3281,9 @@ static void run_state_machine(struct tcpm_port *port) case SNK_DISCOVERY_DEBOUNCE_DONE: if (!tcpm_port_is_disconnected(port) && tcpm_port_is_sink(port) && - time_is_after_jiffies(port->delayed_runtime)) { + ktime_after(port->delayed_runtime, ktime_get())) { tcpm_set_state(port, SNK_DISCOVERY, - jiffies_to_msecs(port->delayed_runtime - - jiffies)); + ktime_to_ms(ktime_sub(port->delayed_runtime, ktime_get()))); break; } tcpm_set_state(port, unattached_state(port), 0); @@ -3573,7 +3595,7 @@ static void run_state_machine(struct tcpm_port *port) */ tcpm_set_pwr_role(port, TYPEC_SOURCE); tcpm_pd_send_control(port, PD_CTRL_PS_RDY); - tcpm_set_state(port, SRC_STARTUP, 0); + tcpm_set_state(port, SRC_STARTUP, PD_T_SWAP_SRC_START); break; case VCONN_SWAP_ACCEPT: @@ -3674,10 +3696,9 @@ static void run_state_machine(struct tcpm_port *port) } } -static void tcpm_state_machine_work(struct work_struct *work) +static void tcpm_state_machine_work(struct kthread_work *work) { - struct tcpm_port *port = container_of(work, struct tcpm_port, - state_machine.work); + struct tcpm_port *port = container_of(work, struct tcpm_port, state_machine); enum tcpm_state prev_state; mutex_lock(&port->lock); @@ -4041,7 +4062,7 @@ static void _tcpm_pd_hard_reset(struct tcpm_port *port) 0); } -static void tcpm_pd_event_handler(struct work_struct *work) +static void tcpm_pd_event_handler(struct kthread_work *work) { struct tcpm_port *port = container_of(work, struct tcpm_port, event_work); @@ -4082,7 +4103,7 @@ void tcpm_cc_change(struct tcpm_port *port) spin_lock(&port->pd_event_lock); port->pd_events |= TCPM_CC_EVENT; spin_unlock(&port->pd_event_lock); - queue_work(port->wq, &port->event_work); + kthread_queue_work(port->wq, &port->event_work); } EXPORT_SYMBOL_GPL(tcpm_cc_change); @@ -4091,7 +4112,7 @@ void tcpm_vbus_change(struct tcpm_port *port) spin_lock(&port->pd_event_lock); port->pd_events |= TCPM_VBUS_EVENT; spin_unlock(&port->pd_event_lock); - queue_work(port->wq, &port->event_work); + kthread_queue_work(port->wq, &port->event_work); } EXPORT_SYMBOL_GPL(tcpm_vbus_change); @@ -4100,7 +4121,7 @@ void tcpm_pd_hard_reset(struct tcpm_port *port) spin_lock(&port->pd_event_lock); port->pd_events = TCPM_RESET_EVENT; spin_unlock(&port->pd_event_lock); - queue_work(port->wq, &port->event_work); + kthread_queue_work(port->wq, &port->event_work); } EXPORT_SYMBOL_GPL(tcpm_pd_hard_reset); @@ -4808,6 +4829,22 @@ static int devm_tcpm_psy_register(struct tcpm_port *port) return PTR_ERR_OR_ZERO(port->psy); } +static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer) +{ + struct tcpm_port *port = container_of(timer, struct tcpm_port, state_machine_timer); + + kthread_queue_work(port->wq, &port->state_machine); + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *timer) +{ + struct tcpm_port *port = container_of(timer, struct tcpm_port, vdm_state_machine_timer); + + kthread_queue_work(port->wq, &port->vdm_state_machine); + return HRTIMER_NORESTART; +} + struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) { struct tcpm_port *port; @@ -4829,12 +4866,18 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) mutex_init(&port->lock); mutex_init(&port->swap_lock); - port->wq = create_singlethread_workqueue(dev_name(dev)); - if (!port->wq) - return ERR_PTR(-ENOMEM); - INIT_DELAYED_WORK(&port->state_machine, tcpm_state_machine_work); - INIT_DELAYED_WORK(&port->vdm_state_machine, vdm_state_machine_work); - INIT_WORK(&port->event_work, tcpm_pd_event_handler); + port->wq = kthread_create_worker(0, dev_name(dev)); + if (IS_ERR(port->wq)) + return ERR_CAST(port->wq); + sched_set_fifo(port->wq->task); + + kthread_init_work(&port->state_machine, tcpm_state_machine_work); + kthread_init_work(&port->vdm_state_machine, vdm_state_machine_work); + kthread_init_work(&port->event_work, tcpm_pd_event_handler); + hrtimer_init(&port->state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + port->state_machine_timer.function = state_machine_timer_handler; + hrtimer_init(&port->vdm_state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + port->vdm_state_machine_timer.function = vdm_state_machine_timer_handler; spin_lock_init(&port->pd_event_lock); @@ -4886,7 +4929,7 @@ out_role_sw_put: usb_role_switch_put(port->role_sw); out_destroy_wq: tcpm_debugfs_exit(port); - destroy_workqueue(port->wq); + kthread_destroy_worker(port->wq); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(tcpm_register_port); @@ -4901,7 +4944,7 @@ void tcpm_unregister_port(struct tcpm_port *port) typec_unregister_port(port->typec_port); usb_role_switch_put(port->role_sw); tcpm_debugfs_exit(port); - destroy_workqueue(port->wq); + kthread_destroy_worker(port->wq); } EXPORT_SYMBOL_GPL(tcpm_unregister_port); diff --git a/include/dt-bindings/reset/raspberrypi,firmware-reset.h b/include/dt-bindings/reset/raspberrypi,firmware-reset.h new file mode 100644 index 000000000000..1a4f4c792723 --- /dev/null +++ b/include/dt-bindings/reset/raspberrypi,firmware-reset.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Nicolas Saenz Julienne + * Author: Nicolas Saenz Julienne <[email protected]> + */ + +#ifndef _DT_BINDINGS_RASPBERRYPI_FIRMWARE_RESET_H +#define _DT_BINDINGS_RASPBERRYPI_FIRMWARE_RESET_H + +#define RASPBERRYPI_FIRMWARE_RESET_ID_USB 0 +#define RASPBERRYPI_FIRMWARE_RESET_NUM_IDS 1 + +#endif diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index b6c233e79bd4..f842e4589bd2 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -471,8 +471,10 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_T_VCONN_SOURCE_ON 100 #define PD_T_SINK_REQUEST 100 /* 100 ms minimum */ #define PD_T_ERROR_RECOVERY 100 /* minimum 25 is insufficient */ -#define PD_T_SRCSWAPSTDBY 625 /* Maximum of 650ms */ -#define PD_T_NEWSRC 250 /* Maximum of 275ms */ +#define PD_T_SRCSWAPSTDBY 625 /* Maximum of 650ms */ +#define PD_T_NEWSRC 250 /* Maximum of 275ms */ +#define PD_T_SWAP_SRC_START 20 /* Minimum of 20ms */ +#define PD_T_BIST_CONT_MODE 50 /* 30 - 60 ms */ #define PD_T_DRP_TRY 100 /* 75 - 150 ms */ #define PD_T_DRP_TRYWAIT 600 /* 400 - 800 ms */ @@ -483,5 +485,4 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_N_CAPS_COUNT (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP) #define PD_N_HARD_RESET_COUNT 2 -#define PD_T_BIST_CONT_MODE 50 /* 30 - 60 ms */ #endif /* __LINUX_USB_PD_H */ diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index 3025aca3c358..cc9cdbc66403 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -10,7 +10,6 @@ #include <linux/of_device.h> struct rpi_firmware; -struct pci_dev; enum rpi_firmware_property_status { RPI_FIRMWARE_STATUS_REQUEST = 0, @@ -142,7 +141,6 @@ int rpi_firmware_property(struct rpi_firmware *fw, int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); -int rpi_firmware_init_vl805(struct pci_dev *pdev); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len) @@ -160,11 +158,6 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware { return NULL; } - -static inline int rpi_firmware_init_vl805(struct pci_dev *pdev) -{ - return 0; -} #endif #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ |