diff --git a/Documentation/ABI/testing/sysfs-bus-thunderbolt b/Documentation/ABI/testing/sysfs-bus-thunderbolt index 82e80de78dd00d8f7806637b0c44c2395597259d..dd565c378b4032f18b1e528f6b3c0bdc6e5e0939 100644 --- a/Documentation/ABI/testing/sysfs-bus-thunderbolt +++ b/Documentation/ABI/testing/sysfs-bus-thunderbolt @@ -178,11 +178,18 @@ KernelVersion: 4.13 Contact: thunderbolt-software@lists.01.org Description: When new NVM image is written to the non-active NVM area (through non_activeX NVMem device), the - authentication procedure is started by writing 1 to - this file. If everything goes well, the device is + authentication procedure is started by writing to + this file. + If everything goes well, the device is restarted with the new NVM firmware. If the image verification fails an error code is returned instead. + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and authenticate the image in one action. + - Writing "2" will run some basic validation on the image + and flush it to the storage area. + When read holds status of the last authentication operation if an error occurred during the process. This is directly the status value from the DMA configuration @@ -236,3 +243,49 @@ KernelVersion: 4.15 Contact: thunderbolt-software@lists.01.org Description: This contains XDomain service specific settings as bitmask. Format: %x + +What: /sys/bus/thunderbolt/devices/<device>:<port>.<index>/device +Date: Oct 2020 +KernelVersion: v5.9 +Contact: Mika Westerberg <mika.westerberg@linux.intel.com> +Description: Retimer device identifier read from the hardware. + +What: /sys/bus/thunderbolt/devices/<device>:<port>.<index>/nvm_authenticate +Date: Oct 2020 +KernelVersion: v5.9 +Contact: Mika Westerberg <mika.westerberg@linux.intel.com> +Description: When new NVM image is written to the non-active NVM + area (through non_activeX NVMem device), the + authentication procedure is started by writing 1 to + this file. If everything goes well, the device is + restarted with the new NVM firmware. If the image + verification fails an error code is returned instead. + + When read holds status of the last authentication + operation if an error occurred during the process. + Format: %x. + +What: /sys/bus/thunderbolt/devices/<device>:<port>.<index>/nvm_version +Date: Oct 2020 +KernelVersion: v5.9 +Contact: Mika Westerberg <mika.westerberg@linux.intel.com> +Description: Holds retimer NVM version number. Format: %x.%x, major.minor. + +What: /sys/bus/thunderbolt/devices/<device>:<port>.<index>/vendor +Date: Oct 2020 +KernelVersion: v5.9 +Contact: Mika Westerberg <mika.westerberg@linux.intel.com> +Description: Retimer vendor identifier read from the hardware. + +What: /sys/bus/thunderbolt/devices/.../nvm_authenticate_on_disconnect +Date: Oct 2020 +KernelVersion: v5.9 +Contact: Mario Limonciello <mario.limonciello@dell.com> +Description: For supported devices, automatically authenticate the new Thunderbolt + image when the device is disconnected from the host system. + + This file will accept writing values "1" or "2" + - Writing "1" will flush the image to the storage + area and prepare the device for authentication on disconnect. + - Writing "2" will run some basic validation on the image + and flush it to the storage area. diff --git a/Documentation/admin-guide/thunderbolt.rst b/Documentation/admin-guide/thunderbolt.rst index 10c4f0ce2ad001729e337f03ca470a2135ae8cbf..613cb24c76c7cce99e4c0dcd772bdcff540697dd 100644 --- a/Documentation/admin-guide/thunderbolt.rst +++ b/Documentation/admin-guide/thunderbolt.rst @@ -173,8 +173,8 @@ following ``udev`` rule:: ACTION=="add", SUBSYSTEM=="thunderbolt", ATTRS{iommu_dma_protection}=="1", ATTR{authorized}=="0", ATTR{authorized}="1" -Upgrading NVM on Thunderbolt device or host -------------------------------------------- +Upgrading NVM on Thunderbolt device, host or retimer +---------------------------------------------------- Since most of the functionality is handled in firmware running on a host controller or a device, it is important that the firmware can be upgraded to the latest where possible bugs in it have been fixed. @@ -185,9 +185,10 @@ for some machines: `Thunderbolt Updates <https://thunderbolttechnology.net/updates>`_ -Before you upgrade firmware on a device or host, please make sure it is a -suitable upgrade. Failing to do that may render the device (or host) in a -state where it cannot be used properly anymore without special tools! +Before you upgrade firmware on a device, host or retimer, please make +sure it is a suitable upgrade. Failing to do that may render the device +in a state where it cannot be used properly anymore without special +tools! Host NVM upgrade on Apple Macs is not supported. diff --git a/Documentation/devicetree/bindings/usb/brcm,bdc.txt b/Documentation/devicetree/bindings/usb/brcm,bdc.txt index 63e63af3bf593926fb908861aad2718f43a77e16..c9f52b97cef12bf2d740febd1fce0fcb0bec7eb0 100644 --- a/Documentation/devicetree/bindings/usb/brcm,bdc.txt +++ b/Documentation/devicetree/bindings/usb/brcm,bdc.txt @@ -4,7 +4,7 @@ Broadcom USB Device Controller (BDC) Required properties: - compatible: must be one of: - "brcm,bdc-v0.16" + "brcm,bdc-udc-v2" "brcm,bdc" - reg: the base register address and length - interrupts: the interrupt line for this controller @@ -21,7 +21,7 @@ On Broadcom STB platforms, these properties are required: Example: bdc@f0b02000 { - compatible = "brcm,bdc-v0.16"; + compatible = "brcm,bdc-udc-v2"; reg = <0xf0b02000 0xfc4>; interrupts = <0x0 0x60 0x0>; phys = <&usbphy_0 0x0>; diff --git a/Documentation/devicetree/bindings/usb/ingenic,jz4770-phy.yaml b/Documentation/devicetree/bindings/usb/ingenic,jz4770-phy.yaml index a81b0b1a2226949c6a7121ff54ed647f7fbd303f..2d61166ea5cf73807f7ea1f02777b283ebbee4e2 100644 --- a/Documentation/devicetree/bindings/usb/ingenic,jz4770-phy.yaml +++ b/Documentation/devicetree/bindings/usb/ingenic,jz4770-phy.yaml @@ -4,10 +4,11 @@ $id: http://devicetree.org/schemas/usb/ingenic,jz4770-phy.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Ingenic JZ4770 USB PHY devicetree bindings +title: Ingenic SoCs USB PHY devicetree bindings maintainers: - Paul Cercueil <paul@crapouillou.net> + - å‘¨ç°æ° (Zhou Yanjie) <zhouyanjie@wanyeetech.com> properties: $nodename: @@ -16,6 +17,9 @@ properties: compatible: enum: - ingenic,jz4770-phy + - ingenic,jz4780-phy + - ingenic,x1000-phy + - ingenic,x1830-phy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml index f127535feb0bb9f5f4da5b6f1b1c96bd693cbab5..804b9b4f66540d3231de52f3a971aa576fc6d780 100644 --- a/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/ti,keystone-dwc3.yaml @@ -11,22 +11,36 @@ maintainers: properties: compatible: - oneOf: - - const: "ti,keystone-dwc3" - - const: "ti,am654-dwc3" + items: + - enum: + - ti,keystone-dwc3 + - ti,am654-dwc3 reg: maxItems: 1 - description: Address and length of the register set for the USB subsystem on - the SOC. + + '#address-cells': + const: 1 + + '#size-cells': + const: 1 + + ranges: true interrupts: maxItems: 1 - description: The irq number of this device that is used to interrupt the MPU. - clocks: - description: Clock ID for USB functional clock. + minItems: 1 + maxItems: 2 + + assigned-clocks: + minItems: 1 + maxItems: 2 + + assigned-clock-parents: + minItems: 1 + maxItems: 2 power-domains: description: Should contain a phandle to a PM domain provider node @@ -42,33 +56,42 @@ properties: phy-names: items: - - const: "usb3-phy" + - const: usb3-phy + + dma-coherent: true - dwc3: + dma-ranges: true + +patternProperties: + "usb@[a-f0-9]+$": + type: object description: This is the node representing the DWC3 controller instance Documentation/devicetree/bindings/usb/dwc3.txt required: - compatible - reg + - "#address-cells" + - "#size-cells" + - ranges - interrupts - - clocks + +additionalProperties: false examples: - | #include <dt-bindings/interrupt-controller/arm-gic.h> - usb: usb@2680000 { + dwc3@2680000 { compatible = "ti,keystone-dwc3"; #address-cells = <1>; #size-cells = <1>; reg = <0x2680000 0x10000>; clocks = <&clkusb>; - clock-names = "usb"; interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>; ranges; - dwc3@2690000 { + usb@2690000 { compatible = "synopsys,dwc3"; reg = <0x2690000 0x70000>; interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>; diff --git a/Documentation/driver-api/usb/URB.rst b/Documentation/driver-api/usb/URB.rst index 61a54da9fce94f4d952fdf67c8a311db810cfac0..1e4abc896a0d85fe7b748ec528718e2d0b48afb4 100644 --- a/Documentation/driver-api/usb/URB.rst +++ b/Documentation/driver-api/usb/URB.rst @@ -240,7 +240,7 @@ How to do isochronous (ISO) transfers? ====================================== Besides the fields present on a bulk transfer, for ISO, you also -also have to set ``urb->interval`` to say how often to make transfers; it's +have to set ``urb->interval`` to say how often to make transfers; it's often one per frame (which is once every microframe for highspeed devices). The actual interval used will be a power of two that's no bigger than what you specify. You can use the :c:func:`usb_fill_int_urb` macro to fill diff --git a/Documentation/usb/gadget_hid.rst b/Documentation/usb/gadget_hid.rst index 098d563040ccd6275ad4472434dcaa1d0640f64f..e623416de4f1bae24ed12ae0f7fe0463b291ab5b 100644 --- a/Documentation/usb/gadget_hid.rst +++ b/Documentation/usb/gadget_hid.rst @@ -11,7 +11,7 @@ and HID reports can be sent/received through I/O on the /dev/hidgX character devices. For more details about HID, see the developer page on -http://www.usb.org/developers/hidpage/ +https://www.usb.org/developers/hidpage/ Configuration ============= diff --git a/Documentation/usb/gadget_multi.rst b/Documentation/usb/gadget_multi.rst index 9806b55af301b5ebb95a5620ae340c3d2c1ac2b4..3a22c1b2f39effd1b7305215ef15497bf3cecc8e 100644 --- a/Documentation/usb/gadget_multi.rst +++ b/Documentation/usb/gadget_multi.rst @@ -142,7 +142,7 @@ Footnotes ========= [1] Remote Network Driver Interface Specification, -[[http://msdn.microsoft.com/en-us/library/ee484414.aspx]]. +[[https://msdn.microsoft.com/en-us/library/ee484414.aspx]]. [2] Communications Device Class Abstract Control Model, spec for this and other USB classes can be found at @@ -150,9 +150,9 @@ and other USB classes can be found at [3] CDC Ethernet Control Model. -[4] [[http://msdn.microsoft.com/en-us/library/ff537109(v=VS.85).aspx]] +[4] [[https://msdn.microsoft.com/en-us/library/ff537109(v=VS.85).aspx]] -[5] [[http://msdn.microsoft.com/en-us/library/ff539234(v=VS.85).aspx]] +[5] [[https://msdn.microsoft.com/en-us/library/ff539234(v=VS.85).aspx]] [6] To put it in some other nice words, Windows failed to respond to any user input. @@ -160,6 +160,6 @@ any user input. [7] You may find [[http://www.cygnal.org/ubb/Forum9/HTML/001050.html]] useful. -[8] http://www.nirsoft.net/utils/usb_devices_view.html +[8] https://www.nirsoft.net/utils/usb_devices_view.html -[9] [[http://msdn.microsoft.com/en-us/library/ff570620.aspx]] +[9] [[https://msdn.microsoft.com/en-us/library/ff570620.aspx]] diff --git a/Documentation/usb/linux.inf b/Documentation/usb/linux.inf index 4ffa715b0ae8826f7f88c430ca140350ba9361ce..c569ac6bec58fcb4de61b547d425213482fb8933 100644 --- a/Documentation/usb/linux.inf +++ b/Documentation/usb/linux.inf @@ -1,5 +1,5 @@ ; Based on template INF file found at -; <http://msdn.microsoft.com/en-us/library/ff570620.aspx> +; <https://msdn.microsoft.com/en-us/library/ff570620.aspx> ; which was: ; Copyright (c) Microsoft Corporation ; and released under the MLPL as found at: diff --git a/MAINTAINERS b/MAINTAINERS index 8c881b4bfdfff320d1b7ce6554a0fc37adc73131..183f76ea211cb1131ccc85ce9f90b13bfae5baef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7013,6 +7013,13 @@ L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/usb/gadget/udc/fsl* +FREESCALE USB PHY DRIVER +M: Ran Wang <ran.wang_1@nxp.com> +L: linux-usb@vger.kernel.org +L: linuxppc-dev@lists.ozlabs.org +S: Maintained +F: drivers/usb/phy/phy-fsl-usb* + FREEVXFS FILESYSTEM M: Christoph Hellwig <hch@infradead.org> S: Maintained diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 4df15e693b6ef61c0814699f9c9cd23364374c6c..144b9caa935c42053cb030ff3eb5cb77284873eb 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -26,6 +26,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/gpio.h> +#include <linux/gpio/machine.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> @@ -55,6 +56,9 @@ #include "common.h" +/* Name of the GPIO chip used by the OMAP for GPIOs 0..15 */ +#define OMAP_GPIO_LABEL "gpio-0-15" + /* At OMAP5912 OSK the Ethernet is directly connected to CS1 */ #define OMAP_OSK_ETHR_START 0x04800300 @@ -240,7 +244,9 @@ static struct tps65010_board tps_board = { static struct i2c_board_info __initdata osk_i2c_board_info[] = { { + /* This device will get the name "i2c-tps65010" */ I2C_BOARD_INFO("tps65010", 0x48), + .dev_name = "tps65010", .platform_data = &tps_board, }, @@ -278,6 +284,16 @@ static void __init osk_init_cf(void) irq_set_irq_type(gpio_to_irq(62), IRQ_TYPE_EDGE_FALLING); } +static struct gpiod_lookup_table osk_usb_gpio_table = { + .dev_id = "ohci", + .table = { + /* Power GPIO on the I2C-attached TPS65010 */ + GPIO_LOOKUP("i2c-tps65010", 1, "power", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP(OMAP_GPIO_LABEL, 9, "overcurrent", + GPIO_ACTIVE_HIGH), + }, +}; + static struct omap_usb_config osk_usb_config __initdata = { /* has usb host connector (A) ... for development it can also * be used, with a NONSTANDARD gender-bending cable/dongle, as @@ -581,6 +597,7 @@ static void __init osk_init(void) l |= (3 << 1); omap_writel(l, USB_TRANSCEIVER_CTRL); + gpiod_add_lookup_table(&osk_usb_gpio_table); omap1_usb_init(&osk_usb_config); /* irq for tps65010 chip */ diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig index 6466e83067b4f087f49296683705c5ffea90ed2e..023b4e644b1cd32f66a3a8ccbaaccf5a52cb396d 100644 --- a/arch/mips/configs/fuloong2e_defconfig +++ b/arch/mips/configs/fuloong2e_defconfig @@ -159,7 +159,7 @@ CONFIG_USB_KBD=y CONFIG_USB_MOUSE=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_OTG_WHITELIST=y +CONFIG_USB_OTG_PRODUCTLIST=y CONFIG_USB_WUSB_CBAF=m CONFIG_USB_C67X00_HCD=m CONFIG_USB_EHCI_HCD=y diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig index 48131cb47e66216312a686a7ea41bc690a00558f..4994749b9eaad9554ad7166e29fb7593596b7d1a 100644 --- a/arch/mips/configs/gcw0_defconfig +++ b/arch/mips/configs/gcw0_defconfig @@ -96,7 +96,7 @@ CONFIG_SND_SIMPLE_CARD=y CONFIG_USB_CONN_GPIO=y CONFIG_USB=y CONFIG_USB_OTG=y -CONFIG_USB_OTG_BLACKLIST_HUB=y +CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB=y CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_MUSB_HDRC=y diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 8254d7d1396f301d8dcb44010985407a949ebf59..3a9a453b126419978b421c8348c2b2a5e7b2aad0 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -207,7 +207,7 @@ CONFIG_ZEROPLUS_FF=y CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_DYNAMIC_MINORS=y -CONFIG_USB_OTG_WHITELIST=y +CONFIG_USB_OTG_PRODUCTLIST=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y diff --git a/drivers/net/thunderbolt.c b/drivers/net/thunderbolt.c index dacb4f680fd48b41d4dc430d95744edde794d240..a812726703a4aa7fb6dc941962dc73d8c0bccd25 100644 --- a/drivers/net/thunderbolt.c +++ b/drivers/net/thunderbolt.c @@ -866,8 +866,8 @@ static int tbnet_open(struct net_device *dev) eof_mask = BIT(TBIP_PDF_FRAME_END); ring = tb_ring_alloc_rx(xd->tb->nhi, -1, TBNET_RING_SIZE, - RING_FLAG_FRAME | RING_FLAG_E2E, sof_mask, - eof_mask, tbnet_start_poll, net); + RING_FLAG_FRAME, sof_mask, eof_mask, + tbnet_start_poll, net); if (!ring) { netdev_err(dev, "failed to allocate Rx ring\n"); tb_ring_free(net->tx_ring.ring); diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig index f02010738bb6624686c249720a55bc29a5393f99..354e61c0f2e5daac67a95a3d14351d912888f48a 100644 --- a/drivers/thunderbolt/Kconfig +++ b/drivers/thunderbolt/Kconfig @@ -8,10 +8,15 @@ menuconfig USB4 select CRYPTO_HASH select NVMEM help - USB4 and Thunderbolt driver. USB4 is the public speficiation - based on Thunderbolt 3 protocol. This driver is required if + USB4 and Thunderbolt driver. USB4 is the public specification + based on the Thunderbolt 3 protocol. This driver is required if you want to hotplug Thunderbolt and USB4 compliant devices on Apple hardware or on PCs with Intel Falcon Ridge or newer. To compile this driver a module, choose M here. The module will be called thunderbolt. + +config USB4_KUNIT_TEST + bool "KUnit tests" + depends on KUNIT=y + depends on USB4=y diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile index eae28dd45250ad02b72d28747c2a237393411c07..4ab5bfad7bfd69f1b81a9655707569f848eb2fbd 100644 --- a/drivers/thunderbolt/Makefile +++ b/drivers/thunderbolt/Makefile @@ -2,3 +2,6 @@ obj-${CONFIG_USB4} := thunderbolt.o thunderbolt-objs := nhi.o nhi_ops.o ctl.o tb.o switch.o cap.o path.o tunnel.o eeprom.o thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o tmu.o usb4.o +thunderbolt-objs += nvm.o retimer.o quirks.o + +obj-${CONFIG_USB4_KUNIT_TEST} += test.o diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c index 68c1b93ac5d9ea90eccd3a25ea7b18cf15242ee9..bba4cbfa9759bf2b6fed9f9e7ad4e4ec51186926 100644 --- a/drivers/thunderbolt/domain.c +++ b/drivers/thunderbolt/domain.c @@ -812,6 +812,6 @@ void tb_domain_exit(void) { bus_unregister(&tb_bus_type); ida_destroy(&tb_domain_ida); - tb_switch_exit(); + tb_nvm_exit(); tb_xdomain_exit(); } diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index b451a5aa90b5003256a956186d0867ddf04759db..3ebca44ab3faa38de775099a2fc135711f1ec855 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -599,6 +599,7 @@ int tb_drom_read(struct tb_switch *sw) sw->uid = header->uid; sw->vendor = header->vendor_id; sw->device = header->model_id; + tb_check_quirks(sw); crc = tb_crc32(sw->drom + TB_DROM_DATA_START, header->data_len); if (crc != header->data_crc32) { diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c index bd44d50246d2c8171ba94698925cd40f55b71a62..19be627d090fd0decb5c534c6ed02850f6cee9b7 100644 --- a/drivers/thunderbolt/lc.c +++ b/drivers/thunderbolt/lc.c @@ -366,3 +366,17 @@ int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in) tb_port_dbg(in, "sink %d de-allocated\n", sink); return 0; } + +/** + * tb_lc_force_power() - Forces LC to be powered on + * @sw: Thunderbolt switch + * + * This is useful to let authentication cycle pass even without + * a Thunderbolt link present. + */ +int tb_lc_force_power(struct tb_switch *sw) +{ + u32 in = 0xffff; + + return tb_sw_write(sw, &in, TB_CFG_SWITCH, TB_LC_POWER, 1); +} diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index d299dc168147105881ff65baf2b69ba5c43c79bb..5f7489fa1327b8ac139e7a186ac36a91460a5736 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -24,12 +24,7 @@ #define RING_TYPE(ring) ((ring)->is_tx ? "TX ring" : "RX ring") -/* - * Used to enable end-to-end workaround for missing RX packets. Do not - * use this ring for anything else. - */ -#define RING_E2E_UNUSED_HOPID 2 -#define RING_FIRST_USABLE_HOPID TB_PATH_MIN_HOPID +#define RING_FIRST_USABLE_HOPID 1 /* * Minimal number of vectors when we use MSI-X. Two for control channel @@ -440,7 +435,7 @@ static int nhi_alloc_hop(struct tb_nhi *nhi, struct tb_ring *ring) /* * Automatically allocate HopID from the non-reserved - * range 8 .. hop_count - 1. + * range 1 .. hop_count - 1. */ for (i = RING_FIRST_USABLE_HOPID; i < nhi->hop_count; i++) { if (ring->is_tx) { @@ -496,10 +491,6 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size, dev_dbg(&nhi->pdev->dev, "allocating %s ring %d of size %d\n", transmit ? "TX" : "RX", hop, size); - /* Tx Ring 2 is reserved for E2E workaround */ - if (transmit && hop == RING_E2E_UNUSED_HOPID) - return NULL; - ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) return NULL; @@ -614,19 +605,6 @@ void tb_ring_start(struct tb_ring *ring) flags = RING_FLAG_ENABLE | RING_FLAG_RAW; } - if (ring->flags & RING_FLAG_E2E && !ring->is_tx) { - u32 hop; - - /* - * In order not to lose Rx packets we enable end-to-end - * workaround which transfers Rx credits to an unused Tx - * HopID. - */ - hop = RING_E2E_UNUSED_HOPID << REG_RX_OPTIONS_E2E_HOP_SHIFT; - hop &= REG_RX_OPTIONS_E2E_HOP_MASK; - flags |= hop | RING_FLAG_E2E_FLOW_CONTROL; - } - ring_iowrite64desc(ring, ring->descriptors_dma, 0); if (ring->is_tx) { ring_iowrite32desc(ring, ring->size, 12); @@ -1123,9 +1101,7 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* cannot fail - table is allocated bin pcim_iomap_regions */ nhi->iobase = pcim_iomap_table(pdev)[0]; nhi->hop_count = ioread32(nhi->iobase + REG_HOP_COUNT) & 0x3ff; - if (nhi->hop_count != 12 && nhi->hop_count != 32) - dev_warn(&pdev->dev, "unexpected hop count: %d\n", - nhi->hop_count); + dev_dbg(&pdev->dev, "total paths: %d\n", nhi->hop_count); nhi->tx_rings = devm_kcalloc(&pdev->dev, nhi->hop_count, sizeof(*nhi->tx_rings), GFP_KERNEL); diff --git a/drivers/thunderbolt/nvm.c b/drivers/thunderbolt/nvm.c new file mode 100644 index 0000000000000000000000000000000000000000..29de6d95c6e7fa8ad62c19c050a1babf34ba00a0 --- /dev/null +++ b/drivers/thunderbolt/nvm.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVM helpers + * + * Copyright (C) 2020, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + */ + +#include <linux/idr.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "tb.h" + +static DEFINE_IDA(nvm_ida); + +/** + * tb_nvm_alloc() - Allocate new NVM structure + * @dev: Device owning the NVM + * + * Allocates new NVM structure with unique @id and returns it. In case + * of error returns ERR_PTR(). + */ +struct tb_nvm *tb_nvm_alloc(struct device *dev) +{ + struct tb_nvm *nvm; + int ret; + + nvm = kzalloc(sizeof(*nvm), GFP_KERNEL); + if (!nvm) + return ERR_PTR(-ENOMEM); + + ret = ida_simple_get(&nvm_ida, 0, 0, GFP_KERNEL); + if (ret < 0) { + kfree(nvm); + return ERR_PTR(ret); + } + + nvm->id = ret; + nvm->dev = dev; + + return nvm; +} + +/** + * tb_nvm_add_active() - Adds active NVMem device to NVM + * @nvm: NVM structure + * @size: Size of the active NVM in bytes + * @reg_read: Pointer to the function to read the NVM (passed directly to the + * NVMem device) + * + * Registers new active NVmem device for @nvm. The @reg_read is called + * directly from NVMem so it must handle possible concurrent access if + * needed. The first parameter passed to @reg_read is @nvm structure. + * Returns %0 in success and negative errno otherwise. + */ +int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read) +{ + struct nvmem_config config; + struct nvmem_device *nvmem; + + memset(&config, 0, sizeof(config)); + + config.name = "nvm_active"; + config.reg_read = reg_read; + config.read_only = true; + config.id = nvm->id; + config.stride = 4; + config.word_size = 4; + config.size = size; + config.dev = nvm->dev; + config.owner = THIS_MODULE; + config.priv = nvm; + + nvmem = nvmem_register(&config); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + nvm->active = nvmem; + return 0; +} + +/** + * tb_nvm_write_buf() - Write data to @nvm buffer + * @nvm: NVM structure + * @offset: Offset where to write the data + * @val: Data buffer to write + * @bytes: Number of bytes to write + * + * Helper function to cache the new NVM image before it is actually + * written to the flash. Copies @bytes from @val to @nvm->buf starting + * from @offset. + */ +int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, + size_t bytes) +{ + if (!nvm->buf) { + nvm->buf = vmalloc(NVM_MAX_SIZE); + if (!nvm->buf) + return -ENOMEM; + } + + nvm->flushed = false; + nvm->buf_data_size = offset + bytes; + memcpy(nvm->buf + offset, val, bytes); + return 0; +} + +/** + * tb_nvm_add_non_active() - Adds non-active NVMem device to NVM + * @nvm: NVM structure + * @size: Size of the non-active NVM in bytes + * @reg_write: Pointer to the function to write the NVM (passed directly + * to the NVMem device) + * + * Registers new non-active NVmem device for @nvm. The @reg_write is called + * directly from NVMem so it must handle possible concurrent access if + * needed. The first parameter passed to @reg_write is @nvm structure. + * Returns %0 in success and negative errno otherwise. + */ +int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size, + nvmem_reg_write_t reg_write) +{ + struct nvmem_config config; + struct nvmem_device *nvmem; + + memset(&config, 0, sizeof(config)); + + config.name = "nvm_non_active"; + config.reg_write = reg_write; + config.root_only = true; + config.id = nvm->id; + config.stride = 4; + config.word_size = 4; + config.size = size; + config.dev = nvm->dev; + config.owner = THIS_MODULE; + config.priv = nvm; + + nvmem = nvmem_register(&config); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + nvm->non_active = nvmem; + return 0; +} + +/** + * tb_nvm_free() - Release NVM and its resources + * @nvm: NVM structure to release + * + * Releases NVM and the NVMem devices if they were registered. + */ +void tb_nvm_free(struct tb_nvm *nvm) +{ + if (nvm) { + if (nvm->non_active) + nvmem_unregister(nvm->non_active); + if (nvm->active) + nvmem_unregister(nvm->active); + vfree(nvm->buf); + ida_simple_remove(&nvm_ida, nvm->id); + } + kfree(nvm); +} + +void tb_nvm_exit(void) +{ + ida_destroy(&nvm_ida); +} diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c index ad58559ea88e518711e9bea8f9bd40f01cd31489..03e7b714deab7ed6f324926b629fd3910e1f6f2b 100644 --- a/drivers/thunderbolt/path.c +++ b/drivers/thunderbolt/path.c @@ -229,7 +229,7 @@ struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid, struct tb_port *dst, int dst_hopid, int link_nr, const char *name) { - struct tb_port *in_port, *out_port; + struct tb_port *in_port, *out_port, *first_port, *last_port; int in_hopid, out_hopid; struct tb_path *path; size_t num_hops; @@ -239,12 +239,23 @@ struct tb_path *tb_path_alloc(struct tb *tb, struct tb_port *src, int src_hopid, if (!path) return NULL; - /* - * Number of hops on a path is the distance between the two - * switches plus the source adapter port. - */ - num_hops = abs(tb_route_length(tb_route(src->sw)) - - tb_route_length(tb_route(dst->sw))) + 1; + first_port = last_port = NULL; + i = 0; + tb_for_each_port_on_path(src, dst, in_port) { + if (!first_port) + first_port = in_port; + last_port = in_port; + i++; + } + + /* Check that src and dst are reachable */ + if (first_port != src || last_port != dst) { + kfree(path); + return NULL; + } + + /* Each hop takes two ports */ + num_hops = i / 2; path->hops = kcalloc(num_hops, sizeof(*path->hops), GFP_KERNEL); if (!path->hops) { @@ -559,21 +570,20 @@ bool tb_path_is_invalid(struct tb_path *path) } /** - * tb_path_switch_on_path() - Does the path go through certain switch + * tb_path_port_on_path() - Does the path go through certain port * @path: Path to check - * @sw: Switch to check + * @port: Switch to check * - * Goes over all hops on path and checks if @sw is any of them. + * Goes over all hops on path and checks if @port is any of them. * Direction does not matter. */ -bool tb_path_switch_on_path(const struct tb_path *path, - const struct tb_switch *sw) +bool tb_path_port_on_path(const struct tb_path *path, const struct tb_port *port) { int i; for (i = 0; i < path->path_length; i++) { - if (path->hops[i].in_port->sw == sw || - path->hops[i].out_port->sw == sw) + if (path->hops[i].in_port == port || + path->hops[i].out_port == port) return true; } diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c new file mode 100644 index 0000000000000000000000000000000000000000..7eac3e0f90a2ded4adb07563aefad346608a686e --- /dev/null +++ b/drivers/thunderbolt/quirks.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Thunderbolt driver - quirks + * + * Copyright (c) 2020 Mario Limonciello <mario.limonciello@dell.com> + */ + +#include "tb.h" + +static void quirk_force_power_link(struct tb_switch *sw) +{ + sw->quirks |= QUIRK_FORCE_POWER_LINK_CONTROLLER; +} + +struct tb_quirk { + u16 vendor; + u16 device; + void (*hook)(struct tb_switch *sw); +}; + +static const struct tb_quirk tb_quirks[] = { + /* Dell WD19TB supports self-authentication on unplug */ + { 0x00d4, 0xb070, quirk_force_power_link }, +}; + +/** + * tb_check_quirks() - Check for quirks to apply + * @sw: Thunderbolt switch + * + * Apply any quirks for the Thunderbolt controller + */ +void tb_check_quirks(struct tb_switch *sw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(tb_quirks); i++) { + const struct tb_quirk *q = &tb_quirks[i]; + + if (sw->device == q->device && sw->vendor == q->vendor) + q->hook(sw); + } +} diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c new file mode 100644 index 0000000000000000000000000000000000000000..620bcf586ee2416fd5c193b0dc84057d5d5ec777 --- /dev/null +++ b/drivers/thunderbolt/retimer.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Thunderbolt/USB4 retimer support. + * + * Copyright (C) 2020, Intel Corporation + * Authors: Kranthi Kuntala <kranthi.kuntala@intel.com> + * Mika Westerberg <mika.westerberg@linux.intel.com> + */ + +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/sched/signal.h> + +#include "sb_regs.h" +#include "tb.h" + +#define TB_MAX_RETIMER_INDEX 6 + +static int tb_retimer_nvm_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct tb_nvm *nvm = priv; + struct tb_retimer *rt = tb_to_retimer(nvm->dev); + int ret; + + pm_runtime_get_sync(&rt->dev); + + if (!mutex_trylock(&rt->tb->lock)) { + ret = restart_syscall(); + goto out; + } + + ret = usb4_port_retimer_nvm_read(rt->port, rt->index, offset, val, bytes); + mutex_unlock(&rt->tb->lock); + +out: + pm_runtime_mark_last_busy(&rt->dev); + pm_runtime_put_autosuspend(&rt->dev); + + return ret; +} + +static int tb_retimer_nvm_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct tb_nvm *nvm = priv; + struct tb_retimer *rt = tb_to_retimer(nvm->dev); + int ret = 0; + + if (!mutex_trylock(&rt->tb->lock)) + return restart_syscall(); + + ret = tb_nvm_write_buf(nvm, offset, val, bytes); + mutex_unlock(&rt->tb->lock); + + return ret; +} + +static int tb_retimer_nvm_add(struct tb_retimer *rt) +{ + struct tb_nvm *nvm; + u32 val, nvm_size; + int ret; + + nvm = tb_nvm_alloc(&rt->dev); + if (IS_ERR(nvm)) + return PTR_ERR(nvm); + + ret = usb4_port_retimer_nvm_read(rt->port, rt->index, NVM_VERSION, &val, + sizeof(val)); + if (ret) + goto err_nvm; + + nvm->major = val >> 16; + nvm->minor = val >> 8; + + ret = usb4_port_retimer_nvm_read(rt->port, rt->index, NVM_FLASH_SIZE, + &val, sizeof(val)); + if (ret) + goto err_nvm; + + nvm_size = (SZ_1M << (val & 7)) / 8; + nvm_size = (nvm_size - SZ_16K) / 2; + + ret = tb_nvm_add_active(nvm, nvm_size, tb_retimer_nvm_read); + if (ret) + goto err_nvm; + + ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE, tb_retimer_nvm_write); + if (ret) + goto err_nvm; + + rt->nvm = nvm; + return 0; + +err_nvm: + tb_nvm_free(nvm); + return ret; +} + +static int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt) +{ + unsigned int image_size, hdr_size; + const u8 *buf = rt->nvm->buf; + u16 ds_size, device; + + image_size = rt->nvm->buf_data_size; + if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE) + return -EINVAL; + + /* + * FARB pointer must point inside the image and must at least + * contain parts of the digital section we will be reading here. + */ + hdr_size = (*(u32 *)buf) & 0xffffff; + if (hdr_size + NVM_DEVID + 2 >= image_size) + return -EINVAL; + + /* Digital section start should be aligned to 4k page */ + if (!IS_ALIGNED(hdr_size, SZ_4K)) + return -EINVAL; + + /* + * Read digital section size and check that it also fits inside + * the image. + */ + ds_size = *(u16 *)(buf + hdr_size); + if (ds_size >= image_size) + return -EINVAL; + + /* + * Make sure the device ID in the image matches the retimer + * hardware. + */ + device = *(u16 *)(buf + hdr_size + NVM_DEVID); + if (device != rt->device) + return -EINVAL; + + /* Skip headers in the image */ + buf += hdr_size; + image_size -= hdr_size; + + return usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf, + image_size); +} + +static ssize_t device_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tb_retimer *rt = tb_to_retimer(dev); + + return sprintf(buf, "%#x\n", rt->device); +} +static DEVICE_ATTR_RO(device); + +static ssize_t nvm_authenticate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tb_retimer *rt = tb_to_retimer(dev); + int ret; + + if (!mutex_trylock(&rt->tb->lock)) + return restart_syscall(); + + if (!rt->nvm) + ret = -EAGAIN; + else + ret = sprintf(buf, "%#x\n", rt->auth_status); + + mutex_unlock(&rt->tb->lock); + + return ret; +} + +static ssize_t nvm_authenticate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tb_retimer *rt = tb_to_retimer(dev); + bool val; + int ret; + + pm_runtime_get_sync(&rt->dev); + + if (!mutex_trylock(&rt->tb->lock)) { + ret = restart_syscall(); + goto exit_rpm; + } + + if (!rt->nvm) { + ret = -EAGAIN; + goto exit_unlock; + } + + ret = kstrtobool(buf, &val); + if (ret) + goto exit_unlock; + + /* Always clear status */ + rt->auth_status = 0; + + if (val) { + if (!rt->nvm->buf) { + ret = -EINVAL; + goto exit_unlock; + } + + ret = tb_retimer_nvm_validate_and_write(rt); + if (ret) + goto exit_unlock; + + ret = usb4_port_retimer_nvm_authenticate(rt->port, rt->index); + } + +exit_unlock: + mutex_unlock(&rt->tb->lock); +exit_rpm: + pm_runtime_mark_last_busy(&rt->dev); + pm_runtime_put_autosuspend(&rt->dev); + + if (ret) + return ret; + return count; +} +static DEVICE_ATTR_RW(nvm_authenticate); + +static ssize_t nvm_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tb_retimer *rt = tb_to_retimer(dev); + int ret; + + if (!mutex_trylock(&rt->tb->lock)) + return restart_syscall(); + + if (!rt->nvm) + ret = -EAGAIN; + else + ret = sprintf(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor); + + mutex_unlock(&rt->tb->lock); + return ret; +} +static DEVICE_ATTR_RO(nvm_version); + +static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tb_retimer *rt = tb_to_retimer(dev); + + return sprintf(buf, "%#x\n", rt->vendor); +} +static DEVICE_ATTR_RO(vendor); + +static struct attribute *retimer_attrs[] = { + &dev_attr_device.attr, + &dev_attr_nvm_authenticate.attr, + &dev_attr_nvm_version.attr, + &dev_attr_vendor.attr, + NULL +}; + +static const struct attribute_group retimer_group = { + .attrs = retimer_attrs, +}; + +static const struct attribute_group *retimer_groups[] = { + &retimer_group, + NULL +}; + +static void tb_retimer_release(struct device *dev) +{ + struct tb_retimer *rt = tb_to_retimer(dev); + + kfree(rt); +} + +struct device_type tb_retimer_type = { + .name = "thunderbolt_retimer", + .groups = retimer_groups, + .release = tb_retimer_release, +}; + +static int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status) +{ + struct tb_retimer *rt; + u32 vendor, device; + int ret; + + if (!port->cap_usb4) + return -EINVAL; + + ret = usb4_port_retimer_read(port, index, USB4_SB_VENDOR_ID, &vendor, + sizeof(vendor)); + if (ret) { + if (ret != -ENODEV) + tb_port_warn(port, "failed read retimer VendorId: %d\n", ret); + return ret; + } + + ret = usb4_port_retimer_read(port, index, USB4_SB_PRODUCT_ID, &device, + sizeof(device)); + if (ret) { + if (ret != -ENODEV) + tb_port_warn(port, "failed read retimer ProductId: %d\n", ret); + return ret; + } + + if (vendor != PCI_VENDOR_ID_INTEL && vendor != 0x8087) { + tb_port_info(port, "retimer NVM format of vendor %#x is not supported\n", + vendor); + return -EOPNOTSUPP; + } + + /* + * Check that it supports NVM operations. If not then don't add + * the device at all. + */ + ret = usb4_port_retimer_nvm_sector_size(port, index); + if (ret < 0) + return ret; + + rt = kzalloc(sizeof(*rt), GFP_KERNEL); + if (!rt) + return -ENOMEM; + + rt->index = index; + rt->vendor = vendor; + rt->device = device; + rt->auth_status = auth_status; + rt->port = port; + rt->tb = port->sw->tb; + + rt->dev.parent = &port->sw->dev; + rt->dev.bus = &tb_bus_type; + rt->dev.type = &tb_retimer_type; + dev_set_name(&rt->dev, "%s:%u.%u", dev_name(&port->sw->dev), + port->port, index); + + ret = device_register(&rt->dev); + if (ret) { + dev_err(&rt->dev, "failed to register retimer: %d\n", ret); + put_device(&rt->dev); + return ret; + } + + ret = tb_retimer_nvm_add(rt); + if (ret) { + dev_err(&rt->dev, "failed to add NVM devices: %d\n", ret); + device_del(&rt->dev); + return ret; + } + + dev_info(&rt->dev, "new retimer found, vendor=%#x device=%#x\n", + rt->vendor, rt->device); + + pm_runtime_no_callbacks(&rt->dev); + pm_runtime_set_active(&rt->dev); + pm_runtime_enable(&rt->dev); + pm_runtime_set_autosuspend_delay(&rt->dev, TB_AUTOSUSPEND_DELAY); + pm_runtime_mark_last_busy(&rt->dev); + pm_runtime_use_autosuspend(&rt->dev); + + return 0; +} + +static void tb_retimer_remove(struct tb_retimer *rt) +{ + dev_info(&rt->dev, "retimer disconnected\n"); + tb_nvm_free(rt->nvm); + device_unregister(&rt->dev); +} + +struct tb_retimer_lookup { + const struct tb_port *port; + u8 index; +}; + +static int retimer_match(struct device *dev, void *data) +{ + const struct tb_retimer_lookup *lookup = data; + struct tb_retimer *rt = tb_to_retimer(dev); + + return rt && rt->port == lookup->port && rt->index == lookup->index; +} + +static struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index) +{ + struct tb_retimer_lookup lookup = { .port = port, .index = index }; + struct device *dev; + + dev = device_find_child(&port->sw->dev, &lookup, retimer_match); + if (dev) + return tb_to_retimer(dev); + + return NULL; +} + +/** + * tb_retimer_scan() - Scan for on-board retimers under port + * @port: USB4 port to scan + * + * Tries to enumerate on-board retimers connected to @port. Found + * retimers are registered as children of @port. Does not scan for cable + * retimers for now. + */ +int tb_retimer_scan(struct tb_port *port) +{ + u32 status[TB_MAX_RETIMER_INDEX] = {}; + int ret, i, last_idx = 0; + + if (!port->cap_usb4) + return 0; + + /* + * Send broadcast RT to make sure retimer indices facing this + * port are set. + */ + ret = usb4_port_enumerate_retimers(port); + if (ret) + return ret; + + /* + * Before doing anything else, read the authentication status. + * If the retimer has it set, store it for the new retimer + * device instance. + */ + for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) + usb4_port_retimer_nvm_authenticate_status(port, i, &status[i]); + + for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) { + /* + * Last retimer is true only for the last on-board + * retimer (the one connected directly to the Type-C + * port). + */ + ret = usb4_port_retimer_is_last(port, i); + if (ret > 0) + last_idx = i; + else if (ret < 0) + break; + } + + if (!last_idx) + return 0; + + /* Add on-board retimers if they do not exist already */ + for (i = 1; i <= last_idx; i++) { + struct tb_retimer *rt; + + rt = tb_port_find_retimer(port, i); + if (rt) { + put_device(&rt->dev); + } else { + ret = tb_retimer_add(port, i, status[i]); + if (ret && ret != -EOPNOTSUPP) + return ret; + } + } + + return 0; +} + +static int remove_retimer(struct device *dev, void *data) +{ + struct tb_retimer *rt = tb_to_retimer(dev); + struct tb_port *port = data; + + if (rt && rt->port == port) + tb_retimer_remove(rt); + return 0; +} + +/** + * tb_retimer_remove_all() - Remove all retimers under port + * @port: USB4 port whose retimers to remove + * + * This removes all previously added retimers under @port. + */ +void tb_retimer_remove_all(struct tb_port *port) +{ + if (port->cap_usb4) + device_for_each_child_reverse(&port->sw->dev, port, + remove_retimer); +} diff --git a/drivers/thunderbolt/sb_regs.h b/drivers/thunderbolt/sb_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..9dafd696612f274e0c260ff643ba82882c7a7d82 --- /dev/null +++ b/drivers/thunderbolt/sb_regs.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * USB4 port sideband registers found on routers and retimers + * + * Copyright (C) 2020, Intel Corporation + * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> + * Rajmohan Mani <rajmohan.mani@intel.com> + */ + +#ifndef _SB_REGS +#define _SB_REGS + +#define USB4_SB_VENDOR_ID 0x00 +#define USB4_SB_PRODUCT_ID 0x01 +#define USB4_SB_OPCODE 0x08 + +enum usb4_sb_opcode { + USB4_SB_OPCODE_ERR = 0x20525245, /* "ERR " */ + USB4_SB_OPCODE_ONS = 0x444d4321, /* "!CMD" */ + USB4_SB_OPCODE_ENUMERATE_RETIMERS = 0x4d554e45, /* "ENUM" */ + USB4_SB_OPCODE_QUERY_LAST_RETIMER = 0x5453414c, /* "LAST" */ + USB4_SB_OPCODE_GET_NVM_SECTOR_SIZE = 0x53534e47, /* "GNSS" */ + USB4_SB_OPCODE_NVM_SET_OFFSET = 0x53504f42, /* "BOPS" */ + USB4_SB_OPCODE_NVM_BLOCK_WRITE = 0x574b4c42, /* "BLKW" */ + USB4_SB_OPCODE_NVM_AUTH_WRITE = 0x48545541, /* "AUTH" */ + USB4_SB_OPCODE_NVM_READ = 0x52524641, /* "AFRR" */ +}; + +#define USB4_SB_METADATA 0x09 +#define USB4_SB_METADATA_NVM_AUTH_WRITE_MASK GENMASK(5, 0) +#define USB4_SB_DATA 0x12 + +#endif diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index d7d60cd9226f7e7a6bd7a4a7c3d0c99d8460c332..712395f518b82225e06f58699f23c2fca470cb4d 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -13,21 +13,12 @@ #include <linux/sched/signal.h> #include <linux/sizes.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include "tb.h" /* Switch NVM support */ -#define NVM_DEVID 0x05 -#define NVM_VERSION 0x08 #define NVM_CSS 0x10 -#define NVM_FLASH_SIZE 0x45 - -#define NVM_MIN_SIZE SZ_32K -#define NVM_MAX_SIZE SZ_512K - -static DEFINE_IDA(nvm_ida); struct nvm_auth_status { struct list_head list; @@ -35,6 +26,11 @@ struct nvm_auth_status { u32 status; }; +enum nvm_write_ops { + WRITE_AND_AUTHENTICATE = 1, + WRITE_ONLY = 2, +}; + /* * Hold NVM authentication failure status per switch This information * needs to stay around even when the switch gets power cycled so we @@ -164,8 +160,12 @@ static int nvm_validate_and_write(struct tb_switch *sw) } if (tb_switch_is_usb4(sw)) - return usb4_switch_nvm_write(sw, 0, buf, image_size); - return dma_port_flash_write(sw->dma_port, 0, buf, image_size); + ret = usb4_switch_nvm_write(sw, 0, buf, image_size); + else + ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size); + if (!ret) + sw->nvm->flushed = true; + return ret; } static int nvm_authenticate_host_dma_port(struct tb_switch *sw) @@ -328,7 +328,8 @@ static int nvm_authenticate(struct tb_switch *sw) static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, size_t bytes) { - struct tb_switch *sw = priv; + struct tb_nvm *nvm = priv; + struct tb_switch *sw = tb_to_switch(nvm->dev); int ret; pm_runtime_get_sync(&sw->dev); @@ -351,8 +352,9 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, size_t bytes) { - struct tb_switch *sw = priv; - int ret = 0; + struct tb_nvm *nvm = priv; + struct tb_switch *sw = tb_to_switch(nvm->dev); + int ret; if (!mutex_trylock(&sw->tb->lock)) return restart_syscall(); @@ -363,55 +365,15 @@ static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, * locally here and handle the special cases when the user asks * us to authenticate the image. */ - if (!sw->nvm->buf) { - sw->nvm->buf = vmalloc(NVM_MAX_SIZE); - if (!sw->nvm->buf) { - ret = -ENOMEM; - goto unlock; - } - } - - sw->nvm->buf_data_size = offset + bytes; - memcpy(sw->nvm->buf + offset, val, bytes); - -unlock: + ret = tb_nvm_write_buf(nvm, offset, val, bytes); mutex_unlock(&sw->tb->lock); return ret; } -static struct nvmem_device *register_nvmem(struct tb_switch *sw, int id, - size_t size, bool active) -{ - struct nvmem_config config; - - memset(&config, 0, sizeof(config)); - - if (active) { - config.name = "nvm_active"; - config.reg_read = tb_switch_nvm_read; - config.read_only = true; - } else { - config.name = "nvm_non_active"; - config.reg_write = tb_switch_nvm_write; - config.root_only = true; - } - - config.id = id; - config.stride = 4; - config.word_size = 4; - config.size = size; - config.dev = &sw->dev; - config.owner = THIS_MODULE; - config.priv = sw; - - return nvmem_register(&config); -} - static int tb_switch_nvm_add(struct tb_switch *sw) { - struct nvmem_device *nvm_dev; - struct tb_switch_nvm *nvm; + struct tb_nvm *nvm; u32 val; int ret; @@ -423,18 +385,17 @@ static int tb_switch_nvm_add(struct tb_switch *sw) * currently restrict NVM upgrade for Intel hardware. We may * relax this in the future when we learn other NVM formats. */ - if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL) { + if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL && + sw->config.vendor_id != 0x8087) { dev_info(&sw->dev, "NVM format of vendor %#x is not known, disabling NVM upgrade\n", sw->config.vendor_id); return 0; } - nvm = kzalloc(sizeof(*nvm), GFP_KERNEL); - if (!nvm) - return -ENOMEM; - - nvm->id = ida_simple_get(&nvm_ida, 0, 0, GFP_KERNEL); + nvm = tb_nvm_alloc(&sw->dev); + if (IS_ERR(nvm)) + return PTR_ERR(nvm); /* * If the switch is in safe-mode the only accessible portion of @@ -446,7 +407,7 @@ static int tb_switch_nvm_add(struct tb_switch *sw) ret = nvm_read(sw, NVM_FLASH_SIZE, &val, sizeof(val)); if (ret) - goto err_ida; + goto err_nvm; hdr_size = sw->generation < 3 ? SZ_8K : SZ_16K; nvm_size = (SZ_1M << (val & 7)) / 8; @@ -454,44 +415,34 @@ static int tb_switch_nvm_add(struct tb_switch *sw) ret = nvm_read(sw, NVM_VERSION, &val, sizeof(val)); if (ret) - goto err_ida; + goto err_nvm; nvm->major = val >> 16; nvm->minor = val >> 8; - nvm_dev = register_nvmem(sw, nvm->id, nvm_size, true); - if (IS_ERR(nvm_dev)) { - ret = PTR_ERR(nvm_dev); - goto err_ida; - } - nvm->active = nvm_dev; + ret = tb_nvm_add_active(nvm, nvm_size, tb_switch_nvm_read); + if (ret) + goto err_nvm; } if (!sw->no_nvm_upgrade) { - nvm_dev = register_nvmem(sw, nvm->id, NVM_MAX_SIZE, false); - if (IS_ERR(nvm_dev)) { - ret = PTR_ERR(nvm_dev); - goto err_nvm_active; - } - nvm->non_active = nvm_dev; + ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE, + tb_switch_nvm_write); + if (ret) + goto err_nvm; } sw->nvm = nvm; return 0; -err_nvm_active: - if (nvm->active) - nvmem_unregister(nvm->active); -err_ida: - ida_simple_remove(&nvm_ida, nvm->id); - kfree(nvm); - +err_nvm: + tb_nvm_free(nvm); return ret; } static void tb_switch_nvm_remove(struct tb_switch *sw) { - struct tb_switch_nvm *nvm; + struct tb_nvm *nvm; nvm = sw->nvm; sw->nvm = NULL; @@ -503,13 +454,7 @@ static void tb_switch_nvm_remove(struct tb_switch *sw) if (!nvm->authenticating) nvm_clear_auth_status(sw); - if (nvm->non_active) - nvmem_unregister(nvm->non_active); - if (nvm->active) - nvmem_unregister(nvm->active); - ida_simple_remove(&nvm_ida, nvm->id); - vfree(nvm->buf); - kfree(nvm); + tb_nvm_free(nvm); } /* port utility functions */ @@ -789,8 +734,11 @@ static int tb_port_alloc_hopid(struct tb_port *port, bool in, int min_hopid, ida = &port->out_hopids; } - /* HopIDs 0-7 are reserved */ - if (min_hopid < TB_PATH_MIN_HOPID) + /* + * NHI can use HopIDs 1-max for other adapters HopIDs 0-7 are + * reserved. + */ + if (port->config.type != TB_TYPE_NHI && min_hopid < TB_PATH_MIN_HOPID) min_hopid = TB_PATH_MIN_HOPID; if (max_hopid < 0 || max_hopid > port_max_hopid) @@ -847,6 +795,13 @@ void tb_port_release_out_hopid(struct tb_port *port, int hopid) ida_simple_remove(&port->out_hopids, hopid); } +static inline bool tb_switch_is_reachable(const struct tb_switch *parent, + const struct tb_switch *sw) +{ + u64 mask = (1ULL << parent->config.depth * 8) - 1; + return (tb_route(parent) & mask) == (tb_route(sw) & mask); +} + /** * tb_next_port_on_path() - Return next port for given port on a path * @start: Start port of the walk @@ -876,12 +831,12 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end, return end; } - if (start->sw->config.depth < end->sw->config.depth) { + if (tb_switch_is_reachable(prev->sw, end->sw)) { + next = tb_port_at(tb_route(end->sw), prev->sw); + /* Walk down the topology if next == prev */ if (prev->remote && - prev->remote->sw->config.depth > prev->sw->config.depth) + (next == prev || next->dual_link_port == prev)) next = prev->remote; - else - next = tb_port_at(tb_route(end->sw), prev->sw); } else { if (tb_is_upstream_port(prev)) { next = prev->remote; @@ -898,10 +853,16 @@ struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end, } } - return next; + return next != prev ? next : NULL; } -static int tb_port_get_link_speed(struct tb_port *port) +/** + * tb_port_get_link_speed() - Get current link speed + * @port: Port to check (USB4 or CIO) + * + * Returns link speed in Gb/s or negative errno in case of failure. + */ +int tb_port_get_link_speed(struct tb_port *port) { u32 val, speed; int ret; @@ -1532,11 +1493,11 @@ static ssize_t nvm_authenticate_show(struct device *dev, return sprintf(buf, "%#x\n", status); } -static ssize_t nvm_authenticate_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static ssize_t nvm_authenticate_sysfs(struct device *dev, const char *buf, + bool disconnect) { struct tb_switch *sw = tb_to_switch(dev); - bool val; + int val; int ret; pm_runtime_get_sync(&sw->dev); @@ -1552,25 +1513,32 @@ static ssize_t nvm_authenticate_store(struct device *dev, goto exit_unlock; } - ret = kstrtobool(buf, &val); + ret = kstrtoint(buf, 10, &val); if (ret) goto exit_unlock; /* Always clear the authentication status */ nvm_clear_auth_status(sw); - if (val) { - if (!sw->nvm->buf) { - ret = -EINVAL; - goto exit_unlock; - } - - ret = nvm_validate_and_write(sw); - if (ret) - goto exit_unlock; + if (val > 0) { + if (!sw->nvm->flushed) { + if (!sw->nvm->buf) { + ret = -EINVAL; + goto exit_unlock; + } - sw->nvm->authenticating = true; - ret = nvm_authenticate(sw); + ret = nvm_validate_and_write(sw); + if (ret || val == WRITE_ONLY) + goto exit_unlock; + } + if (val == WRITE_AND_AUTHENTICATE) { + if (disconnect) { + ret = tb_lc_force_power(sw); + } else { + sw->nvm->authenticating = true; + ret = nvm_authenticate(sw); + } + } } exit_unlock: @@ -1579,12 +1547,35 @@ static ssize_t nvm_authenticate_store(struct device *dev, pm_runtime_mark_last_busy(&sw->dev); pm_runtime_put_autosuspend(&sw->dev); + return ret; +} + +static ssize_t nvm_authenticate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = nvm_authenticate_sysfs(dev, buf, false); if (ret) return ret; return count; } static DEVICE_ATTR_RW(nvm_authenticate); +static ssize_t nvm_authenticate_on_disconnect_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return nvm_authenticate_show(dev, attr, buf); +} + +static ssize_t nvm_authenticate_on_disconnect_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + + ret = nvm_authenticate_sysfs(dev, buf, true); + return ret ? ret : count; +} +static DEVICE_ATTR_RW(nvm_authenticate_on_disconnect); + static ssize_t nvm_version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1642,6 +1633,7 @@ static struct attribute *switch_attrs[] = { &dev_attr_generation.attr, &dev_attr_key.attr, &dev_attr_nvm_authenticate.attr, + &dev_attr_nvm_authenticate_on_disconnect.attr, &dev_attr_nvm_version.attr, &dev_attr_rx_speed.attr, &dev_attr_rx_lanes.attr, @@ -1696,6 +1688,10 @@ static umode_t switch_attr_is_visible(struct kobject *kobj, if (tb_route(sw)) return attr->mode; return 0; + } else if (attr == &dev_attr_nvm_authenticate_on_disconnect.attr) { + if (sw->quirks & QUIRK_FORCE_POWER_LINK_CONTROLLER) + return attr->mode; + return 0; } return sw->safe_mode ? 0 : attr->mode; @@ -2440,6 +2436,9 @@ void tb_switch_remove(struct tb_switch *sw) tb_xdomain_remove(port->xdomain); port->xdomain = NULL; } + + /* Remove any downstream retimers */ + tb_retimer_remove_all(port); } if (!sw->is_unplugged) @@ -2755,8 +2754,3 @@ struct tb_port *tb_switch_find_port(struct tb_switch *sw, return NULL; } - -void tb_switch_exit(void) -{ - ida_destroy(&nvm_ida); -} diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 107cd232f486c8203ffae944fe28d4f1e266af98..f507815040ebd6aca20cf036005bde134c9adc45 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -206,27 +206,197 @@ static struct tb_port *tb_find_unused_port(struct tb_switch *sw, } static struct tb_port *tb_find_usb3_down(struct tb_switch *sw, - const struct tb_port *port) + const struct tb_port *port) { struct tb_port *down; down = usb4_switch_map_usb3_down(sw, port); - if (down) { - if (WARN_ON(!tb_port_is_usb3_down(down))) - goto out; - if (WARN_ON(tb_usb3_port_is_enabled(down))) - goto out; - + if (down && !tb_usb3_port_is_enabled(down)) return down; + return NULL; +} + +static struct tb_tunnel *tb_find_tunnel(struct tb *tb, enum tb_tunnel_type type, + struct tb_port *src_port, + struct tb_port *dst_port) +{ + struct tb_cm *tcm = tb_priv(tb); + struct tb_tunnel *tunnel; + + list_for_each_entry(tunnel, &tcm->tunnel_list, list) { + if (tunnel->type == type && + ((src_port && src_port == tunnel->src_port) || + (dst_port && dst_port == tunnel->dst_port))) { + return tunnel; + } } -out: - return tb_find_unused_port(sw, TB_TYPE_USB3_DOWN); + return NULL; +} + +static struct tb_tunnel *tb_find_first_usb3_tunnel(struct tb *tb, + struct tb_port *src_port, + struct tb_port *dst_port) +{ + struct tb_port *port, *usb3_down; + struct tb_switch *sw; + + /* Pick the router that is deepest in the topology */ + if (dst_port->sw->config.depth > src_port->sw->config.depth) + sw = dst_port->sw; + else + sw = src_port->sw; + + /* Can't be the host router */ + if (sw == tb->root_switch) + return NULL; + + /* Find the downstream USB4 port that leads to this router */ + port = tb_port_at(tb_route(sw), tb->root_switch); + /* Find the corresponding host router USB3 downstream port */ + usb3_down = usb4_switch_map_usb3_down(tb->root_switch, port); + if (!usb3_down) + return NULL; + + return tb_find_tunnel(tb, TB_TUNNEL_USB3, usb3_down, NULL); +} + +static int tb_available_bandwidth(struct tb *tb, struct tb_port *src_port, + struct tb_port *dst_port, int *available_up, int *available_down) +{ + int usb3_consumed_up, usb3_consumed_down, ret; + struct tb_cm *tcm = tb_priv(tb); + struct tb_tunnel *tunnel; + struct tb_port *port; + + tb_port_dbg(dst_port, "calculating available bandwidth\n"); + + tunnel = tb_find_first_usb3_tunnel(tb, src_port, dst_port); + if (tunnel) { + ret = tb_tunnel_consumed_bandwidth(tunnel, &usb3_consumed_up, + &usb3_consumed_down); + if (ret) + return ret; + } else { + usb3_consumed_up = 0; + usb3_consumed_down = 0; + } + + *available_up = *available_down = 40000; + + /* Find the minimum available bandwidth over all links */ + tb_for_each_port_on_path(src_port, dst_port, port) { + int link_speed, link_width, up_bw, down_bw; + + if (!tb_port_is_null(port)) + continue; + + if (tb_is_upstream_port(port)) { + link_speed = port->sw->link_speed; + } else { + link_speed = tb_port_get_link_speed(port); + if (link_speed < 0) + return link_speed; + } + + link_width = port->bonded ? 2 : 1; + + up_bw = link_speed * link_width * 1000; /* Mb/s */ + /* Leave 10% guard band */ + up_bw -= up_bw / 10; + down_bw = up_bw; + + tb_port_dbg(port, "link total bandwidth %d Mb/s\n", up_bw); + + /* + * Find all DP tunnels that cross the port and reduce + * their consumed bandwidth from the available. + */ + list_for_each_entry(tunnel, &tcm->tunnel_list, list) { + int dp_consumed_up, dp_consumed_down; + + if (!tb_tunnel_is_dp(tunnel)) + continue; + + if (!tb_tunnel_port_on_path(tunnel, port)) + continue; + + ret = tb_tunnel_consumed_bandwidth(tunnel, + &dp_consumed_up, + &dp_consumed_down); + if (ret) + return ret; + + up_bw -= dp_consumed_up; + down_bw -= dp_consumed_down; + } + + /* + * If USB3 is tunneled from the host router down to the + * branch leading to port we need to take USB3 consumed + * bandwidth into account regardless whether it actually + * crosses the port. + */ + up_bw -= usb3_consumed_up; + down_bw -= usb3_consumed_down; + + if (up_bw < *available_up) + *available_up = up_bw; + if (down_bw < *available_down) + *available_down = down_bw; + } + + if (*available_up < 0) + *available_up = 0; + if (*available_down < 0) + *available_down = 0; + + return 0; +} + +static int tb_release_unused_usb3_bandwidth(struct tb *tb, + struct tb_port *src_port, + struct tb_port *dst_port) +{ + struct tb_tunnel *tunnel; + + tunnel = tb_find_first_usb3_tunnel(tb, src_port, dst_port); + return tunnel ? tb_tunnel_release_unused_bandwidth(tunnel) : 0; +} + +static void tb_reclaim_usb3_bandwidth(struct tb *tb, struct tb_port *src_port, + struct tb_port *dst_port) +{ + int ret, available_up, available_down; + struct tb_tunnel *tunnel; + + tunnel = tb_find_first_usb3_tunnel(tb, src_port, dst_port); + if (!tunnel) + return; + + tb_dbg(tb, "reclaiming unused bandwidth for USB3\n"); + + /* + * Calculate available bandwidth for the first hop USB3 tunnel. + * That determines the whole USB3 bandwidth for this branch. + */ + ret = tb_available_bandwidth(tb, tunnel->src_port, tunnel->dst_port, + &available_up, &available_down); + if (ret) { + tb_warn(tb, "failed to calculate available bandwidth\n"); + return; + } + + tb_dbg(tb, "available bandwidth for USB3 %d/%d Mb/s\n", + available_up, available_down); + + tb_tunnel_reclaim_available_bandwidth(tunnel, &available_up, &available_down); } static int tb_tunnel_usb3(struct tb *tb, struct tb_switch *sw) { struct tb_switch *parent = tb_switch_parent(sw); + int ret, available_up, available_down; struct tb_port *up, *down, *port; struct tb_cm *tcm = tb_priv(tb); struct tb_tunnel *tunnel; @@ -235,6 +405,9 @@ static int tb_tunnel_usb3(struct tb *tb, struct tb_switch *sw) if (!up) return 0; + if (!sw->link_usb4) + return 0; + /* * Look up available down port. Since we are chaining it should * be found right above this switch. @@ -254,21 +427,48 @@ static int tb_tunnel_usb3(struct tb *tb, struct tb_switch *sw) parent_up = tb_switch_find_port(parent, TB_TYPE_USB3_UP); if (!parent_up || !tb_port_is_enabled(parent_up)) return 0; + + /* Make all unused bandwidth available for the new tunnel */ + ret = tb_release_unused_usb3_bandwidth(tb, down, up); + if (ret) + return ret; } - tunnel = tb_tunnel_alloc_usb3(tb, up, down); - if (!tunnel) - return -ENOMEM; + ret = tb_available_bandwidth(tb, down, up, &available_up, + &available_down); + if (ret) + goto err_reclaim; + + tb_port_dbg(up, "available bandwidth for new USB3 tunnel %d/%d Mb/s\n", + available_up, available_down); + + tunnel = tb_tunnel_alloc_usb3(tb, up, down, available_up, + available_down); + if (!tunnel) { + ret = -ENOMEM; + goto err_reclaim; + } if (tb_tunnel_activate(tunnel)) { tb_port_info(up, "USB3 tunnel activation failed, aborting\n"); - tb_tunnel_free(tunnel); - return -EIO; + ret = -EIO; + goto err_free; } list_add_tail(&tunnel->list, &tcm->tunnel_list); + if (tb_route(parent)) + tb_reclaim_usb3_bandwidth(tb, down, up); + return 0; + +err_free: + tb_tunnel_free(tunnel); +err_reclaim: + if (tb_route(parent)) + tb_reclaim_usb3_bandwidth(tb, down, up); + + return ret; } static int tb_create_usb3_tunnels(struct tb_switch *sw) @@ -339,6 +539,9 @@ static void tb_scan_port(struct tb_port *port) tb_port_dbg(port, "port already has a remote\n"); return; } + + tb_retimer_scan(port); + sw = tb_switch_alloc(port->sw->tb, &port->sw->dev, tb_downstream_route(port)); if (IS_ERR(sw)) { @@ -395,6 +598,9 @@ static void tb_scan_port(struct tb_port *port) if (tb_enable_tmu(sw)) tb_sw_warn(sw, "failed to enable TMU\n"); + /* Scan upstream retimers */ + tb_retimer_scan(upstream_port); + /* * Create USB 3.x tunnels only when the switch is plugged to the * domain. This is because we scan the domain also during discovery @@ -404,43 +610,44 @@ static void tb_scan_port(struct tb_port *port) if (tcm->hotplug_active && tb_tunnel_usb3(sw->tb, sw)) tb_sw_warn(sw, "USB3 tunnel creation failed\n"); + tb_add_dp_resources(sw); tb_scan_switch(sw); } -static struct tb_tunnel *tb_find_tunnel(struct tb *tb, enum tb_tunnel_type type, - struct tb_port *src_port, - struct tb_port *dst_port) -{ - struct tb_cm *tcm = tb_priv(tb); - struct tb_tunnel *tunnel; - - list_for_each_entry(tunnel, &tcm->tunnel_list, list) { - if (tunnel->type == type && - ((src_port && src_port == tunnel->src_port) || - (dst_port && dst_port == tunnel->dst_port))) { - return tunnel; - } - } - - return NULL; -} - static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel) { + struct tb_port *src_port, *dst_port; + struct tb *tb; + if (!tunnel) return; tb_tunnel_deactivate(tunnel); list_del(&tunnel->list); - /* - * In case of DP tunnel make sure the DP IN resource is deallocated - * properly. - */ - if (tb_tunnel_is_dp(tunnel)) { - struct tb_port *in = tunnel->src_port; + tb = tunnel->tb; + src_port = tunnel->src_port; + dst_port = tunnel->dst_port; + + switch (tunnel->type) { + case TB_TUNNEL_DP: + /* + * In case of DP tunnel make sure the DP IN resource is + * deallocated properly. + */ + tb_switch_dealloc_dp_resource(src_port->sw, src_port); + fallthrough; - tb_switch_dealloc_dp_resource(in->sw, in); + case TB_TUNNEL_USB3: + tb_reclaim_usb3_bandwidth(tb, src_port, dst_port); + break; + + default: + /* + * PCIe and DMA tunnels do not consume guaranteed + * bandwidth. + */ + break; } tb_tunnel_free(tunnel); @@ -473,6 +680,7 @@ static void tb_free_unplugged_children(struct tb_switch *sw) continue; if (port->remote->sw->is_unplugged) { + tb_retimer_remove_all(port); tb_remove_dp_resources(port->remote->sw); tb_switch_lane_bonding_disable(port->remote->sw); tb_switch_remove(port->remote->sw); @@ -524,7 +732,7 @@ static struct tb_port *tb_find_pcie_down(struct tb_switch *sw, if (down) { if (WARN_ON(!tb_port_is_pcie_down(down))) goto out; - if (WARN_ON(tb_pci_port_is_enabled(down))) + if (tb_pci_port_is_enabled(down)) goto out; return down; @@ -534,51 +742,49 @@ static struct tb_port *tb_find_pcie_down(struct tb_switch *sw, return tb_find_unused_port(sw, TB_TYPE_PCIE_DOWN); } -static int tb_available_bw(struct tb_cm *tcm, struct tb_port *in, - struct tb_port *out) +static struct tb_port *tb_find_dp_out(struct tb *tb, struct tb_port *in) { - struct tb_switch *sw = out->sw; - struct tb_tunnel *tunnel; - int bw, available_bw = 40000; + struct tb_port *host_port, *port; + struct tb_cm *tcm = tb_priv(tb); - while (sw && sw != in->sw) { - bw = sw->link_speed * sw->link_width * 1000; /* Mb/s */ - /* Leave 10% guard band */ - bw -= bw / 10; + host_port = tb_route(in->sw) ? + tb_port_at(tb_route(in->sw), tb->root_switch) : NULL; + + list_for_each_entry(port, &tcm->dp_resources, list) { + if (!tb_port_is_dpout(port)) + continue; + + if (tb_port_is_enabled(port)) { + tb_port_dbg(port, "in use\n"); + continue; + } + + tb_port_dbg(port, "DP OUT available\n"); /* - * Check for any active DP tunnels that go through this - * switch and reduce their consumed bandwidth from - * available. + * Keep the DP tunnel under the topology starting from + * the same host router downstream port. */ - list_for_each_entry(tunnel, &tcm->tunnel_list, list) { - int consumed_bw; + if (host_port && tb_route(port->sw)) { + struct tb_port *p; - if (!tb_tunnel_switch_on_path(tunnel, sw)) + p = tb_port_at(tb_route(port->sw), tb->root_switch); + if (p != host_port) continue; - - consumed_bw = tb_tunnel_consumed_bandwidth(tunnel); - if (consumed_bw < 0) - return consumed_bw; - - bw -= consumed_bw; } - if (bw < available_bw) - available_bw = bw; - - sw = tb_switch_parent(sw); + return port; } - return available_bw; + return NULL; } static void tb_tunnel_dp(struct tb *tb) { + int available_up, available_down, ret; struct tb_cm *tcm = tb_priv(tb); struct tb_port *port, *in, *out; struct tb_tunnel *tunnel; - int available_bw; /* * Find pair of inactive DP IN and DP OUT adapters and then @@ -589,17 +795,21 @@ static void tb_tunnel_dp(struct tb *tb) in = NULL; out = NULL; list_for_each_entry(port, &tcm->dp_resources, list) { + if (!tb_port_is_dpin(port)) + continue; + if (tb_port_is_enabled(port)) { tb_port_dbg(port, "in use\n"); continue; } - tb_port_dbg(port, "available\n"); + tb_port_dbg(port, "DP IN available\n"); - if (!in && tb_port_is_dpin(port)) + out = tb_find_dp_out(tb, port); + if (out) { in = port; - else if (!out && tb_port_is_dpout(port)) - out = port; + break; + } } if (!in) { @@ -616,32 +826,41 @@ static void tb_tunnel_dp(struct tb *tb) return; } - /* Calculate available bandwidth between in and out */ - available_bw = tb_available_bw(tcm, in, out); - if (available_bw < 0) { - tb_warn(tb, "failed to determine available bandwidth\n"); - return; + /* Make all unused USB3 bandwidth available for the new DP tunnel */ + ret = tb_release_unused_usb3_bandwidth(tb, in, out); + if (ret) { + tb_warn(tb, "failed to release unused bandwidth\n"); + goto err_dealloc_dp; } - tb_dbg(tb, "available bandwidth for new DP tunnel %u Mb/s\n", - available_bw); + ret = tb_available_bandwidth(tb, in, out, &available_up, + &available_down); + if (ret) + goto err_reclaim; + + tb_dbg(tb, "available bandwidth for new DP tunnel %u/%u Mb/s\n", + available_up, available_down); - tunnel = tb_tunnel_alloc_dp(tb, in, out, available_bw); + tunnel = tb_tunnel_alloc_dp(tb, in, out, available_up, available_down); if (!tunnel) { tb_port_dbg(out, "could not allocate DP tunnel\n"); - goto dealloc_dp; + goto err_reclaim; } if (tb_tunnel_activate(tunnel)) { tb_port_info(out, "DP tunnel activation failed, aborting\n"); - tb_tunnel_free(tunnel); - goto dealloc_dp; + goto err_free; } list_add_tail(&tunnel->list, &tcm->tunnel_list); + tb_reclaim_usb3_bandwidth(tb, in, out); return; -dealloc_dp: +err_free: + tb_tunnel_free(tunnel); +err_reclaim: + tb_reclaim_usb3_bandwidth(tb, in, out); +err_dealloc_dp: tb_switch_dealloc_dp_resource(in->sw, in); } @@ -827,6 +1046,8 @@ static void tb_handle_hotplug(struct work_struct *work) goto put_sw; } if (ev->unplug) { + tb_retimer_remove_all(port); + if (tb_port_has_remote(port)) { tb_port_dbg(port, "switch unplugged\n"); tb_sw_set_unplugged(port->remote->sw); @@ -1071,6 +1292,7 @@ static int tb_free_unplugged_xdomains(struct tb_switch *sw) if (tb_is_upstream_port(port)) continue; if (port->xdomain && port->xdomain->is_unplugged) { + tb_retimer_remove_all(port); tb_xdomain_remove(port->xdomain); port->xdomain = NULL; ret++; diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 2eb2bcd3cca35477e763737f7b0ce2470d8d7c66..a413d55b5f8b3d40aff34f0db6fab9dd98a63c9e 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -18,8 +18,17 @@ #include "ctl.h" #include "dma_port.h" +#define NVM_MIN_SIZE SZ_32K +#define NVM_MAX_SIZE SZ_512K + +/* Intel specific NVM offsets */ +#define NVM_DEVID 0x05 +#define NVM_VERSION 0x08 +#define NVM_FLASH_SIZE 0x45 + /** - * struct tb_switch_nvm - Structure holding switch NVM information + * struct tb_nvm - Structure holding NVM information + * @dev: Owner of the NVM * @major: Major version number of the active NVM portion * @minor: Minor version number of the active NVM portion * @id: Identifier used with both NVM portions @@ -29,9 +38,14 @@ * the actual NVM flash device * @buf_data_size: Number of bytes actually consumed by the new NVM * image - * @authenticating: The switch is authenticating the new NVM + * @authenticating: The device is authenticating the new NVM + * @flushed: The image has been flushed to the storage area + * + * The user of this structure needs to handle serialization of possible + * concurrent access. */ -struct tb_switch_nvm { +struct tb_nvm { + struct device *dev; u8 major; u8 minor; int id; @@ -40,6 +54,7 @@ struct tb_switch_nvm { void *buf; size_t buf_data_size; bool authenticating; + bool flushed; }; #define TB_SWITCH_KEY_SIZE 32 @@ -97,6 +112,7 @@ struct tb_switch_tmu { * @device_name: Name of the device (or %NULL if not known) * @link_speed: Speed of the link in Gb/s * @link_width: Width of the link (1 or 2) + * @link_usb4: Upstream link is USB4 * @generation: Switch Thunderbolt generation * @cap_plug_events: Offset to the plug events capability (%0 if not found) * @cap_lc: Offset to the link controller capability (%0 if not found) @@ -117,6 +133,7 @@ struct tb_switch_tmu { * @depth: Depth in the chain this switch is connected (ICM only) * @rpm_complete: Completion used to wait for runtime resume to * complete (ICM only) + * @quirks: Quirks used for this Thunderbolt switch * * When the switch is being added or removed to the domain (other * switches) you need to have domain lock held. @@ -136,12 +153,13 @@ struct tb_switch { const char *device_name; unsigned int link_speed; unsigned int link_width; + bool link_usb4; unsigned int generation; int cap_plug_events; int cap_lc; bool is_unplugged; u8 *drom; - struct tb_switch_nvm *nvm; + struct tb_nvm *nvm; bool no_nvm_upgrade; bool safe_mode; bool boot; @@ -154,6 +172,7 @@ struct tb_switch { u8 link; u8 depth; struct completion rpm_complete; + unsigned long quirks; }; /** @@ -195,6 +214,28 @@ struct tb_port { struct list_head list; }; +/** + * tb_retimer: Thunderbolt retimer + * @dev: Device for the retimer + * @tb: Pointer to the domain the retimer belongs to + * @index: Retimer index facing the router USB4 port + * @vendor: Vendor ID of the retimer + * @device: Device ID of the retimer + * @port: Pointer to the lane 0 adapter + * @nvm: Pointer to the NVM if the retimer has one (%NULL otherwise) + * @auth_status: Status of last NVM authentication + */ +struct tb_retimer { + struct device dev; + struct tb *tb; + u8 index; + u32 vendor; + u32 device; + struct tb_port *port; + struct tb_nvm *nvm; + u32 auth_status; +}; + /** * struct tb_path_hop - routing information for a tb_path * @in_port: Ingress port of a switch @@ -286,7 +327,11 @@ struct tb_path { /* HopIDs 0-7 are reserved by the Thunderbolt protocol */ #define TB_PATH_MIN_HOPID 8 -#define TB_PATH_MAX_HOPS 7 +/* + * Support paths from the farthest (depth 6) router to the host and back + * to the same level (not necessarily to the same router). + */ +#define TB_PATH_MAX_HOPS (7 * 2) /** * struct tb_cm_ops - Connection manager specific operations vector @@ -534,11 +579,11 @@ struct tb *icm_probe(struct tb_nhi *nhi); struct tb *tb_probe(struct tb_nhi *nhi); extern struct device_type tb_domain_type; +extern struct device_type tb_retimer_type; extern struct device_type tb_switch_type; int tb_domain_init(void); void tb_domain_exit(void); -void tb_switch_exit(void); int tb_xdomain_init(void); void tb_xdomain_exit(void); @@ -571,6 +616,15 @@ static inline void tb_domain_put(struct tb *tb) put_device(&tb->dev); } +struct tb_nvm *tb_nvm_alloc(struct device *dev); +int tb_nvm_add_active(struct tb_nvm *nvm, size_t size, nvmem_reg_read_t reg_read); +int tb_nvm_write_buf(struct tb_nvm *nvm, unsigned int offset, void *val, + size_t bytes); +int tb_nvm_add_non_active(struct tb_nvm *nvm, size_t size, + nvmem_reg_write_t reg_write); +void tb_nvm_free(struct tb_nvm *nvm); +void tb_nvm_exit(void); + struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent, u64 route); struct tb_switch *tb_switch_alloc_safe_mode(struct tb *tb, @@ -741,6 +795,20 @@ void tb_port_release_out_hopid(struct tb_port *port, int hopid); struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end, struct tb_port *prev); +/** + * tb_for_each_port_on_path() - Iterate over each port on path + * @src: Source port + * @dst: Destination port + * @p: Port used as iterator + * + * Walks over each port on path from @src to @dst. + */ +#define tb_for_each_port_on_path(src, dst, p) \ + for ((p) = tb_next_port_on_path((src), (dst), NULL); (p); \ + (p) = tb_next_port_on_path((src), (dst), (p))) + +int tb_port_get_link_speed(struct tb_port *port); + int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec); int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap); int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap); @@ -769,8 +837,8 @@ void tb_path_free(struct tb_path *path); int tb_path_activate(struct tb_path *path); void tb_path_deactivate(struct tb_path *path); bool tb_path_is_invalid(struct tb_path *path); -bool tb_path_switch_on_path(const struct tb_path *path, - const struct tb_switch *sw); +bool tb_path_port_on_path(const struct tb_path *path, + const struct tb_port *port); int tb_drom_read(struct tb_switch *sw); int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid); @@ -783,6 +851,7 @@ bool tb_lc_lane_bonding_possible(struct tb_switch *sw); bool tb_lc_dp_sink_query(struct tb_switch *sw, struct tb_port *in); int tb_lc_dp_sink_alloc(struct tb_switch *sw, struct tb_port *in); int tb_lc_dp_sink_dealloc(struct tb_switch *sw, struct tb_port *in); +int tb_lc_force_power(struct tb_switch *sw); static inline int tb_route_length(u64 route) { @@ -812,6 +881,21 @@ void tb_xdomain_remove(struct tb_xdomain *xd); struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, u8 depth); +int tb_retimer_scan(struct tb_port *port); +void tb_retimer_remove_all(struct tb_port *port); + +static inline bool tb_is_retimer(const struct device *dev) +{ + return dev->type == &tb_retimer_type; +} + +static inline struct tb_retimer *tb_to_retimer(struct device *dev) +{ + if (tb_is_retimer(dev)) + return container_of(dev, struct tb_retimer, dev); + return NULL; +} + int usb4_switch_setup(struct tb_switch *sw); int usb4_switch_read_uid(struct tb_switch *sw, u64 *uid); int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf, @@ -835,4 +919,35 @@ struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw, const struct tb_port *port); int usb4_port_unlock(struct tb_port *port); +int usb4_port_enumerate_retimers(struct tb_port *port); + +int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf, + u8 size); +int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg, + const void *buf, u8 size); +int usb4_port_retimer_is_last(struct tb_port *port, u8 index); +int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index); +int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index, + unsigned int address, const void *buf, + size_t size); +int usb4_port_retimer_nvm_authenticate(struct tb_port *port, u8 index); +int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, + u32 *status); +int usb4_port_retimer_nvm_read(struct tb_port *port, u8 index, + unsigned int address, void *buf, size_t size); + +int usb4_usb3_port_max_link_rate(struct tb_port *port); +int usb4_usb3_port_actual_link_rate(struct tb_port *port); +int usb4_usb3_port_allocated_bandwidth(struct tb_port *port, int *upstream_bw, + int *downstream_bw); +int usb4_usb3_port_allocate_bandwidth(struct tb_port *port, int *upstream_bw, + int *downstream_bw); +int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw, + int *downstream_bw); + +/* keep link controller awake during update */ +#define QUIRK_FORCE_POWER_LINK_CONTROLLER BIT(0) + +void tb_check_quirks(struct tb_switch *sw); + #endif diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index c29c5075525af16f2e5dde0d71a8690444fa9a18..fd4fc144d17f654d1187c48ef914231e5514aace 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -288,8 +288,19 @@ struct tb_regs_port_header { #define LANE_ADP_CS_1_CURRENT_WIDTH_SHIFT 20 /* USB4 port registers */ +#define PORT_CS_1 0x01 +#define PORT_CS_1_LENGTH_SHIFT 8 +#define PORT_CS_1_TARGET_MASK GENMASK(18, 16) +#define PORT_CS_1_TARGET_SHIFT 16 +#define PORT_CS_1_RETIMER_INDEX_SHIFT 20 +#define PORT_CS_1_WNR_WRITE BIT(24) +#define PORT_CS_1_NR BIT(25) +#define PORT_CS_1_RC BIT(26) +#define PORT_CS_1_PND BIT(31) +#define PORT_CS_2 0x02 #define PORT_CS_18 0x12 #define PORT_CS_18_BE BIT(8) +#define PORT_CS_18_TCM BIT(9) #define PORT_CS_19 0x13 #define PORT_CS_19_PC BIT(3) @@ -337,6 +348,25 @@ struct tb_regs_port_header { #define ADP_USB3_CS_0 0x00 #define ADP_USB3_CS_0_V BIT(30) #define ADP_USB3_CS_0_PE BIT(31) +#define ADP_USB3_CS_1 0x01 +#define ADP_USB3_CS_1_CUBW_MASK GENMASK(11, 0) +#define ADP_USB3_CS_1_CDBW_MASK GENMASK(23, 12) +#define ADP_USB3_CS_1_CDBW_SHIFT 12 +#define ADP_USB3_CS_1_HCA BIT(31) +#define ADP_USB3_CS_2 0x02 +#define ADP_USB3_CS_2_AUBW_MASK GENMASK(11, 0) +#define ADP_USB3_CS_2_ADBW_MASK GENMASK(23, 12) +#define ADP_USB3_CS_2_ADBW_SHIFT 12 +#define ADP_USB3_CS_2_CMR BIT(31) +#define ADP_USB3_CS_3 0x03 +#define ADP_USB3_CS_3_SCALE_MASK GENMASK(5, 0) +#define ADP_USB3_CS_4 0x04 +#define ADP_USB3_CS_4_ALR_MASK GENMASK(6, 0) +#define ADP_USB3_CS_4_ALR_20G 0x1 +#define ADP_USB3_CS_4_ULV BIT(7) +#define ADP_USB3_CS_4_MSLR_MASK GENMASK(18, 12) +#define ADP_USB3_CS_4_MSLR_SHIFT 12 +#define ADP_USB3_CS_4_MSLR_20G 0x1 /* Hop register from TB_CFG_HOPS. 8 byte per entry. */ struct tb_regs_hop { @@ -379,6 +409,7 @@ struct tb_regs_hop { #define TB_LC_SNK_ALLOCATION_SNK1_SHIFT 4 #define TB_LC_SNK_ALLOCATION_SNK1_MASK GENMASK(7, 4) #define TB_LC_SNK_ALLOCATION_SNK1_CM 0x1 +#define TB_LC_POWER 0x740 /* Link controller registers */ #define TB_LC_PORT_ATTR 0x8d diff --git a/drivers/thunderbolt/test.c b/drivers/thunderbolt/test.c new file mode 100644 index 0000000000000000000000000000000000000000..acb8b62568471b3ecb5d05ef550d7611232e2a17 --- /dev/null +++ b/drivers/thunderbolt/test.c @@ -0,0 +1,1626 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests + * + * Copyright (C) 2020, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + */ + +#include <kunit/test.h> +#include <linux/idr.h> + +#include "tb.h" +#include "tunnel.h" + +static int __ida_init(struct kunit_resource *res, void *context) +{ + struct ida *ida = context; + + ida_init(ida); + res->allocation = ida; + return 0; +} + +static void __ida_destroy(struct kunit_resource *res) +{ + struct ida *ida = res->allocation; + + ida_destroy(ida); +} + +static void kunit_ida_init(struct kunit *test, struct ida *ida) +{ + kunit_alloc_resource(test, __ida_init, __ida_destroy, GFP_KERNEL, ida); +} + +static struct tb_switch *alloc_switch(struct kunit *test, u64 route, + u8 upstream_port, u8 max_port_number) +{ + struct tb_switch *sw; + size_t size; + int i; + + sw = kunit_kzalloc(test, sizeof(*sw), GFP_KERNEL); + if (!sw) + return NULL; + + sw->config.upstream_port_number = upstream_port; + sw->config.depth = tb_route_length(route); + sw->config.route_hi = upper_32_bits(route); + sw->config.route_lo = lower_32_bits(route); + sw->config.enabled = 0; + sw->config.max_port_number = max_port_number; + + size = (sw->config.max_port_number + 1) * sizeof(*sw->ports); + sw->ports = kunit_kzalloc(test, size, GFP_KERNEL); + if (!sw->ports) + return NULL; + + for (i = 0; i <= sw->config.max_port_number; i++) { + sw->ports[i].sw = sw; + sw->ports[i].port = i; + sw->ports[i].config.port_number = i; + if (i) { + kunit_ida_init(test, &sw->ports[i].in_hopids); + kunit_ida_init(test, &sw->ports[i].out_hopids); + } + } + + return sw; +} + +static struct tb_switch *alloc_host(struct kunit *test) +{ + struct tb_switch *sw; + + sw = alloc_switch(test, 0, 7, 13); + if (!sw) + return NULL; + + sw->config.vendor_id = 0x8086; + sw->config.device_id = 0x9a1b; + + sw->ports[0].config.type = TB_TYPE_PORT; + sw->ports[0].config.max_in_hop_id = 7; + sw->ports[0].config.max_out_hop_id = 7; + + sw->ports[1].config.type = TB_TYPE_PORT; + sw->ports[1].config.max_in_hop_id = 19; + sw->ports[1].config.max_out_hop_id = 19; + sw->ports[1].dual_link_port = &sw->ports[2]; + + sw->ports[2].config.type = TB_TYPE_PORT; + sw->ports[2].config.max_in_hop_id = 19; + sw->ports[2].config.max_out_hop_id = 19; + sw->ports[2].dual_link_port = &sw->ports[1]; + sw->ports[2].link_nr = 1; + + sw->ports[3].config.type = TB_TYPE_PORT; + sw->ports[3].config.max_in_hop_id = 19; + sw->ports[3].config.max_out_hop_id = 19; + sw->ports[3].dual_link_port = &sw->ports[4]; + + sw->ports[4].config.type = TB_TYPE_PORT; + sw->ports[4].config.max_in_hop_id = 19; + sw->ports[4].config.max_out_hop_id = 19; + sw->ports[4].dual_link_port = &sw->ports[3]; + sw->ports[4].link_nr = 1; + + sw->ports[5].config.type = TB_TYPE_DP_HDMI_IN; + sw->ports[5].config.max_in_hop_id = 9; + sw->ports[5].config.max_out_hop_id = 9; + sw->ports[5].cap_adap = -1; + + sw->ports[6].config.type = TB_TYPE_DP_HDMI_IN; + sw->ports[6].config.max_in_hop_id = 9; + sw->ports[6].config.max_out_hop_id = 9; + sw->ports[6].cap_adap = -1; + + sw->ports[7].config.type = TB_TYPE_NHI; + sw->ports[7].config.max_in_hop_id = 11; + sw->ports[7].config.max_out_hop_id = 11; + + sw->ports[8].config.type = TB_TYPE_PCIE_DOWN; + sw->ports[8].config.max_in_hop_id = 8; + sw->ports[8].config.max_out_hop_id = 8; + + sw->ports[9].config.type = TB_TYPE_PCIE_DOWN; + sw->ports[9].config.max_in_hop_id = 8; + sw->ports[9].config.max_out_hop_id = 8; + + sw->ports[10].disabled = true; + sw->ports[11].disabled = true; + + sw->ports[12].config.type = TB_TYPE_USB3_DOWN; + sw->ports[12].config.max_in_hop_id = 8; + sw->ports[12].config.max_out_hop_id = 8; + + sw->ports[13].config.type = TB_TYPE_USB3_DOWN; + sw->ports[13].config.max_in_hop_id = 8; + sw->ports[13].config.max_out_hop_id = 8; + + return sw; +} + +static struct tb_switch *alloc_dev_default(struct kunit *test, + struct tb_switch *parent, + u64 route, bool bonded) +{ + struct tb_port *port, *upstream_port; + struct tb_switch *sw; + + sw = alloc_switch(test, route, 1, 19); + if (!sw) + return NULL; + + sw->config.vendor_id = 0x8086; + sw->config.device_id = 0x15ef; + + sw->ports[0].config.type = TB_TYPE_PORT; + sw->ports[0].config.max_in_hop_id = 8; + sw->ports[0].config.max_out_hop_id = 8; + + sw->ports[1].config.type = TB_TYPE_PORT; + sw->ports[1].config.max_in_hop_id = 19; + sw->ports[1].config.max_out_hop_id = 19; + sw->ports[1].dual_link_port = &sw->ports[2]; + + sw->ports[2].config.type = TB_TYPE_PORT; + sw->ports[2].config.max_in_hop_id = 19; + sw->ports[2].config.max_out_hop_id = 19; + sw->ports[2].dual_link_port = &sw->ports[1]; + sw->ports[2].link_nr = 1; + + sw->ports[3].config.type = TB_TYPE_PORT; + sw->ports[3].config.max_in_hop_id = 19; + sw->ports[3].config.max_out_hop_id = 19; + sw->ports[3].dual_link_port = &sw->ports[4]; + + sw->ports[4].config.type = TB_TYPE_PORT; + sw->ports[4].config.max_in_hop_id = 19; + sw->ports[4].config.max_out_hop_id = 19; + sw->ports[4].dual_link_port = &sw->ports[3]; + sw->ports[4].link_nr = 1; + + sw->ports[5].config.type = TB_TYPE_PORT; + sw->ports[5].config.max_in_hop_id = 19; + sw->ports[5].config.max_out_hop_id = 19; + sw->ports[5].dual_link_port = &sw->ports[6]; + + sw->ports[6].config.type = TB_TYPE_PORT; + sw->ports[6].config.max_in_hop_id = 19; + sw->ports[6].config.max_out_hop_id = 19; + sw->ports[6].dual_link_port = &sw->ports[5]; + sw->ports[6].link_nr = 1; + + sw->ports[7].config.type = TB_TYPE_PORT; + sw->ports[7].config.max_in_hop_id = 19; + sw->ports[7].config.max_out_hop_id = 19; + sw->ports[7].dual_link_port = &sw->ports[8]; + + sw->ports[8].config.type = TB_TYPE_PORT; + sw->ports[8].config.max_in_hop_id = 19; + sw->ports[8].config.max_out_hop_id = 19; + sw->ports[8].dual_link_port = &sw->ports[7]; + sw->ports[8].link_nr = 1; + + sw->ports[9].config.type = TB_TYPE_PCIE_UP; + sw->ports[9].config.max_in_hop_id = 8; + sw->ports[9].config.max_out_hop_id = 8; + + sw->ports[10].config.type = TB_TYPE_PCIE_DOWN; + sw->ports[10].config.max_in_hop_id = 8; + sw->ports[10].config.max_out_hop_id = 8; + + sw->ports[11].config.type = TB_TYPE_PCIE_DOWN; + sw->ports[11].config.max_in_hop_id = 8; + sw->ports[11].config.max_out_hop_id = 8; + + sw->ports[12].config.type = TB_TYPE_PCIE_DOWN; + sw->ports[12].config.max_in_hop_id = 8; + sw->ports[12].config.max_out_hop_id = 8; + + sw->ports[13].config.type = TB_TYPE_DP_HDMI_OUT; + sw->ports[13].config.max_in_hop_id = 9; + sw->ports[13].config.max_out_hop_id = 9; + sw->ports[13].cap_adap = -1; + + sw->ports[14].config.type = TB_TYPE_DP_HDMI_OUT; + sw->ports[14].config.max_in_hop_id = 9; + sw->ports[14].config.max_out_hop_id = 9; + sw->ports[14].cap_adap = -1; + + sw->ports[15].disabled = true; + + sw->ports[16].config.type = TB_TYPE_USB3_UP; + sw->ports[16].config.max_in_hop_id = 8; + sw->ports[16].config.max_out_hop_id = 8; + + sw->ports[17].config.type = TB_TYPE_USB3_DOWN; + sw->ports[17].config.max_in_hop_id = 8; + sw->ports[17].config.max_out_hop_id = 8; + + sw->ports[18].config.type = TB_TYPE_USB3_DOWN; + sw->ports[18].config.max_in_hop_id = 8; + sw->ports[18].config.max_out_hop_id = 8; + + sw->ports[19].config.type = TB_TYPE_USB3_DOWN; + sw->ports[19].config.max_in_hop_id = 8; + sw->ports[19].config.max_out_hop_id = 8; + + if (!parent) + return sw; + + /* Link them */ + upstream_port = tb_upstream_port(sw); + port = tb_port_at(route, parent); + port->remote = upstream_port; + upstream_port->remote = port; + if (port->dual_link_port && upstream_port->dual_link_port) { + port->dual_link_port->remote = upstream_port->dual_link_port; + upstream_port->dual_link_port->remote = port->dual_link_port; + } + + if (bonded) { + /* Bonding is used */ + port->bonded = true; + port->dual_link_port->bonded = true; + upstream_port->bonded = true; + upstream_port->dual_link_port->bonded = true; + } + + return sw; +} + +static struct tb_switch *alloc_dev_with_dpin(struct kunit *test, + struct tb_switch *parent, + u64 route, bool bonded) +{ + struct tb_switch *sw; + + sw = alloc_dev_default(test, parent, route, bonded); + if (!sw) + return NULL; + + sw->ports[13].config.type = TB_TYPE_DP_HDMI_IN; + sw->ports[13].config.max_in_hop_id = 9; + sw->ports[13].config.max_out_hop_id = 9; + + sw->ports[14].config.type = TB_TYPE_DP_HDMI_IN; + sw->ports[14].config.max_in_hop_id = 9; + sw->ports[14].config.max_out_hop_id = 9; + + return sw; +} + +static void tb_test_path_basic(struct kunit *test) +{ + struct tb_port *src_port, *dst_port, *p; + struct tb_switch *host; + + host = alloc_host(test); + + src_port = &host->ports[5]; + dst_port = src_port; + + p = tb_next_port_on_path(src_port, dst_port, NULL); + KUNIT_EXPECT_PTR_EQ(test, p, dst_port); + + p = tb_next_port_on_path(src_port, dst_port, p); + KUNIT_EXPECT_TRUE(test, !p); +} + +static void tb_test_path_not_connected_walk(struct kunit *test) +{ + struct tb_port *src_port, *dst_port, *p; + struct tb_switch *host, *dev; + + host = alloc_host(test); + /* No connection between host and dev */ + dev = alloc_dev_default(test, NULL, 3, true); + + src_port = &host->ports[12]; + dst_port = &dev->ports[16]; + + p = tb_next_port_on_path(src_port, dst_port, NULL); + KUNIT_EXPECT_PTR_EQ(test, p, src_port); + + p = tb_next_port_on_path(src_port, dst_port, p); + KUNIT_EXPECT_PTR_EQ(test, p, &host->ports[3]); + + p = tb_next_port_on_path(src_port, dst_port, p); + KUNIT_EXPECT_TRUE(test, !p); + + /* Other direction */ + + p = tb_next_port_on_path(dst_port, src_port, NULL); + KUNIT_EXPECT_PTR_EQ(test, p, dst_port); + + p = tb_next_port_on_path(dst_port, src_port, p); + KUNIT_EXPECT_PTR_EQ(test, p, &dev->ports[1]); + + p = tb_next_port_on_path(dst_port, src_port, p); + KUNIT_EXPECT_TRUE(test, !p); +} + +struct port_expectation { + u64 route; + u8 port; + enum tb_port_type type; +}; + +static void tb_test_path_single_hop_walk(struct kunit *test) +{ + /* + * Walks from Host PCIe downstream port to Device #1 PCIe + * upstream port. + * + * [Host] + * 1 | + * 1 | + * [Device] + */ + static const struct port_expectation test_data[] = { + { .route = 0x0, .port = 8, .type = TB_TYPE_PCIE_DOWN }, + { .route = 0x0, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 9, .type = TB_TYPE_PCIE_UP }, + }; + struct tb_port *src_port, *dst_port, *p; + struct tb_switch *host, *dev; + int i; + + host = alloc_host(test); + dev = alloc_dev_default(test, host, 1, true); + + src_port = &host->ports[8]; + dst_port = &dev->ports[9]; + + /* Walk both directions */ + + i = 0; + tb_for_each_port_on_path(src_port, dst_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i++; + } + + KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data)); + + i = ARRAY_SIZE(test_data) - 1; + tb_for_each_port_on_path(dst_port, src_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i--; + } + + KUNIT_EXPECT_EQ(test, i, -1); +} + +static void tb_test_path_daisy_chain_walk(struct kunit *test) +{ + /* + * Walks from Host DP IN to Device #2 DP OUT. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * 3 / + * 1 / + * [Device #2] + */ + static const struct port_expectation test_data[] = { + { .route = 0x0, .port = 5, .type = TB_TYPE_DP_HDMI_IN }, + { .route = 0x0, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x301, .port = 13, .type = TB_TYPE_DP_HDMI_OUT }, + }; + struct tb_port *src_port, *dst_port, *p; + struct tb_switch *host, *dev1, *dev2; + int i; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x301, true); + + src_port = &host->ports[5]; + dst_port = &dev2->ports[13]; + + /* Walk both directions */ + + i = 0; + tb_for_each_port_on_path(src_port, dst_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i++; + } + + KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data)); + + i = ARRAY_SIZE(test_data) - 1; + tb_for_each_port_on_path(dst_port, src_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i--; + } + + KUNIT_EXPECT_EQ(test, i, -1); +} + +static void tb_test_path_simple_tree_walk(struct kunit *test) +{ + /* + * Walks from Host DP IN to Device #3 DP OUT. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * 3 / | 5 \ 7 + * 1 / | \ 1 + * [Device #2] | [Device #4] + * | 1 + * [Device #3] + */ + static const struct port_expectation test_data[] = { + { .route = 0x0, .port = 5, .type = TB_TYPE_DP_HDMI_IN }, + { .route = 0x0, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 5, .type = TB_TYPE_PORT }, + { .route = 0x501, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x501, .port = 13, .type = TB_TYPE_DP_HDMI_OUT }, + }; + struct tb_port *src_port, *dst_port, *p; + struct tb_switch *host, *dev1, *dev3; + int i; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + alloc_dev_default(test, dev1, 0x301, true); + dev3 = alloc_dev_default(test, dev1, 0x501, true); + alloc_dev_default(test, dev1, 0x701, true); + + src_port = &host->ports[5]; + dst_port = &dev3->ports[13]; + + /* Walk both directions */ + + i = 0; + tb_for_each_port_on_path(src_port, dst_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i++; + } + + KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data)); + + i = ARRAY_SIZE(test_data) - 1; + tb_for_each_port_on_path(dst_port, src_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i--; + } + + KUNIT_EXPECT_EQ(test, i, -1); +} + +static void tb_test_path_complex_tree_walk(struct kunit *test) +{ + /* + * Walks from Device #3 DP IN to Device #9 DP OUT. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * 3 / | 5 \ 7 + * 1 / | \ 1 + * [Device #2] | [Device #5] + * 5 | | 1 \ 7 + * 1 | [Device #4] \ 1 + * [Device #3] [Device #6] + * 3 / + * 1 / + * [Device #7] + * 3 / | 5 + * 1 / | + * [Device #8] | 1 + * [Device #9] + */ + static const struct port_expectation test_data[] = { + { .route = 0x50301, .port = 13, .type = TB_TYPE_DP_HDMI_IN }, + { .route = 0x50301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x301, .port = 5, .type = TB_TYPE_PORT }, + { .route = 0x301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 7, .type = TB_TYPE_PORT }, + { .route = 0x701, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x701, .port = 7, .type = TB_TYPE_PORT }, + { .route = 0x70701, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x70701, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x3070701, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x3070701, .port = 5, .type = TB_TYPE_PORT }, + { .route = 0x503070701, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x503070701, .port = 14, .type = TB_TYPE_DP_HDMI_OUT }, + }; + struct tb_switch *host, *dev1, *dev2, *dev3, *dev5, *dev6, *dev7, *dev9; + struct tb_port *src_port, *dst_port, *p; + int i; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x301, true); + dev3 = alloc_dev_with_dpin(test, dev2, 0x50301, true); + alloc_dev_default(test, dev1, 0x501, true); + dev5 = alloc_dev_default(test, dev1, 0x701, true); + dev6 = alloc_dev_default(test, dev5, 0x70701, true); + dev7 = alloc_dev_default(test, dev6, 0x3070701, true); + alloc_dev_default(test, dev7, 0x303070701, true); + dev9 = alloc_dev_default(test, dev7, 0x503070701, true); + + src_port = &dev3->ports[13]; + dst_port = &dev9->ports[14]; + + /* Walk both directions */ + + i = 0; + tb_for_each_port_on_path(src_port, dst_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i++; + } + + KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data)); + + i = ARRAY_SIZE(test_data) - 1; + tb_for_each_port_on_path(dst_port, src_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i--; + } + + KUNIT_EXPECT_EQ(test, i, -1); +} + +static void tb_test_path_max_length_walk(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2, *dev3, *dev4, *dev5, *dev6; + struct tb_switch *dev7, *dev8, *dev9, *dev10, *dev11, *dev12; + struct tb_port *src_port, *dst_port, *p; + int i; + + /* + * Walks from Device #6 DP IN to Device #12 DP OUT. + * + * [Host] + * 1 / \ 3 + * 1 / \ 1 + * [Device #1] [Device #7] + * 3 | | 3 + * 1 | | 1 + * [Device #2] [Device #8] + * 3 | | 3 + * 1 | | 1 + * [Device #3] [Device #9] + * 3 | | 3 + * 1 | | 1 + * [Device #4] [Device #10] + * 3 | | 3 + * 1 | | 1 + * [Device #5] [Device #11] + * 3 | | 3 + * 1 | | 1 + * [Device #6] [Device #12] + */ + static const struct port_expectation test_data[] = { + { .route = 0x30303030301, .port = 13, .type = TB_TYPE_DP_HDMI_IN }, + { .route = 0x30303030301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x303030301, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x303030301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x3030301, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x3030301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x30301, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x30301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x301, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x301, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x1, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x0, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x0, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x3, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x3, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x303, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x303, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x30303, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x30303, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x3030303, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x3030303, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x303030303, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x303030303, .port = 3, .type = TB_TYPE_PORT }, + { .route = 0x30303030303, .port = 1, .type = TB_TYPE_PORT }, + { .route = 0x30303030303, .port = 13, .type = TB_TYPE_DP_HDMI_OUT }, + }; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x301, true); + dev3 = alloc_dev_default(test, dev2, 0x30301, true); + dev4 = alloc_dev_default(test, dev3, 0x3030301, true); + dev5 = alloc_dev_default(test, dev4, 0x303030301, true); + dev6 = alloc_dev_with_dpin(test, dev5, 0x30303030301, true); + dev7 = alloc_dev_default(test, host, 0x3, true); + dev8 = alloc_dev_default(test, dev7, 0x303, true); + dev9 = alloc_dev_default(test, dev8, 0x30303, true); + dev10 = alloc_dev_default(test, dev9, 0x3030303, true); + dev11 = alloc_dev_default(test, dev10, 0x303030303, true); + dev12 = alloc_dev_default(test, dev11, 0x30303030303, true); + + src_port = &dev6->ports[13]; + dst_port = &dev12->ports[13]; + + /* Walk both directions */ + + i = 0; + tb_for_each_port_on_path(src_port, dst_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i++; + } + + KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(test_data)); + + i = ARRAY_SIZE(test_data) - 1; + tb_for_each_port_on_path(dst_port, src_port, p) { + KUNIT_EXPECT_TRUE(test, i < ARRAY_SIZE(test_data)); + KUNIT_EXPECT_EQ(test, tb_route(p->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, p->port, test_data[i].port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)p->config.type, + test_data[i].type); + i--; + } + + KUNIT_EXPECT_EQ(test, i, -1); +} + +static void tb_test_path_not_connected(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2; + struct tb_port *down, *up; + struct tb_path *path; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x3, false); + /* Not connected to anything */ + dev2 = alloc_dev_default(test, NULL, 0x303, false); + + down = &dev1->ports[10]; + up = &dev2->ports[9]; + + path = tb_path_alloc(NULL, down, 8, up, 8, 0, "PCIe Down"); + KUNIT_ASSERT_TRUE(test, path == NULL); + path = tb_path_alloc(NULL, down, 8, up, 8, 1, "PCIe Down"); + KUNIT_ASSERT_TRUE(test, path == NULL); +} + +struct hop_expectation { + u64 route; + u8 in_port; + enum tb_port_type in_type; + u8 out_port; + enum tb_port_type out_type; +}; + +static void tb_test_path_not_bonded_lane0(struct kunit *test) +{ + /* + * PCIe path from host to device using lane 0. + * + * [Host] + * 3 |: 4 + * 1 |: 2 + * [Device] + */ + static const struct hop_expectation test_data[] = { + { + .route = 0x0, + .in_port = 9, + .in_type = TB_TYPE_PCIE_DOWN, + .out_port = 3, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x3, + .in_port = 1, + .in_type = TB_TYPE_PORT, + .out_port = 9, + .out_type = TB_TYPE_PCIE_UP, + }, + }; + struct tb_switch *host, *dev; + struct tb_port *down, *up; + struct tb_path *path; + int i; + + host = alloc_host(test); + dev = alloc_dev_default(test, host, 0x3, false); + + down = &host->ports[9]; + up = &dev->ports[9]; + + path = tb_path_alloc(NULL, down, 8, up, 8, 0, "PCIe Down"); + KUNIT_ASSERT_TRUE(test, path != NULL); + KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data)); + for (i = 0; i < ARRAY_SIZE(test_data); i++) { + const struct tb_port *in_port, *out_port; + + in_port = path->hops[i].in_port; + out_port = path->hops[i].out_port; + + KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type, + test_data[i].in_type); + KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type, + test_data[i].out_type); + } + tb_path_free(path); +} + +static void tb_test_path_not_bonded_lane1(struct kunit *test) +{ + /* + * DP Video path from host to device using lane 1. Paths like + * these are only used with Thunderbolt 1 devices where lane + * bonding is not possible. USB4 specifically does not allow + * paths like this (you either use lane 0 where lane 1 is + * disabled or both lanes are bonded). + * + * [Host] + * 1 :| 2 + * 1 :| 2 + * [Device] + */ + static const struct hop_expectation test_data[] = { + { + .route = 0x0, + .in_port = 5, + .in_type = TB_TYPE_DP_HDMI_IN, + .out_port = 2, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x1, + .in_port = 2, + .in_type = TB_TYPE_PORT, + .out_port = 13, + .out_type = TB_TYPE_DP_HDMI_OUT, + }, + }; + struct tb_switch *host, *dev; + struct tb_port *in, *out; + struct tb_path *path; + int i; + + host = alloc_host(test); + dev = alloc_dev_default(test, host, 0x1, false); + + in = &host->ports[5]; + out = &dev->ports[13]; + + path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video"); + KUNIT_ASSERT_TRUE(test, path != NULL); + KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data)); + for (i = 0; i < ARRAY_SIZE(test_data); i++) { + const struct tb_port *in_port, *out_port; + + in_port = path->hops[i].in_port; + out_port = path->hops[i].out_port; + + KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type, + test_data[i].in_type); + KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type, + test_data[i].out_type); + } + tb_path_free(path); +} + +static void tb_test_path_not_bonded_lane1_chain(struct kunit *test) +{ + /* + * DP Video path from host to device 3 using lane 1. + * + * [Host] + * 1 :| 2 + * 1 :| 2 + * [Device #1] + * 7 :| 8 + * 1 :| 2 + * [Device #2] + * 5 :| 6 + * 1 :| 2 + * [Device #3] + */ + static const struct hop_expectation test_data[] = { + { + .route = 0x0, + .in_port = 5, + .in_type = TB_TYPE_DP_HDMI_IN, + .out_port = 2, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x1, + .in_port = 2, + .in_type = TB_TYPE_PORT, + .out_port = 8, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x701, + .in_port = 2, + .in_type = TB_TYPE_PORT, + .out_port = 6, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x50701, + .in_port = 2, + .in_type = TB_TYPE_PORT, + .out_port = 13, + .out_type = TB_TYPE_DP_HDMI_OUT, + }, + }; + struct tb_switch *host, *dev1, *dev2, *dev3; + struct tb_port *in, *out; + struct tb_path *path; + int i; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, false); + dev2 = alloc_dev_default(test, dev1, 0x701, false); + dev3 = alloc_dev_default(test, dev2, 0x50701, false); + + in = &host->ports[5]; + out = &dev3->ports[13]; + + path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video"); + KUNIT_ASSERT_TRUE(test, path != NULL); + KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data)); + for (i = 0; i < ARRAY_SIZE(test_data); i++) { + const struct tb_port *in_port, *out_port; + + in_port = path->hops[i].in_port; + out_port = path->hops[i].out_port; + + KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type, + test_data[i].in_type); + KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type, + test_data[i].out_type); + } + tb_path_free(path); +} + +static void tb_test_path_not_bonded_lane1_chain_reverse(struct kunit *test) +{ + /* + * DP Video path from device 3 to host using lane 1. + * + * [Host] + * 1 :| 2 + * 1 :| 2 + * [Device #1] + * 7 :| 8 + * 1 :| 2 + * [Device #2] + * 5 :| 6 + * 1 :| 2 + * [Device #3] + */ + static const struct hop_expectation test_data[] = { + { + .route = 0x50701, + .in_port = 13, + .in_type = TB_TYPE_DP_HDMI_IN, + .out_port = 2, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x701, + .in_port = 6, + .in_type = TB_TYPE_PORT, + .out_port = 2, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x1, + .in_port = 8, + .in_type = TB_TYPE_PORT, + .out_port = 2, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x0, + .in_port = 2, + .in_type = TB_TYPE_PORT, + .out_port = 5, + .out_type = TB_TYPE_DP_HDMI_IN, + }, + }; + struct tb_switch *host, *dev1, *dev2, *dev3; + struct tb_port *in, *out; + struct tb_path *path; + int i; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, false); + dev2 = alloc_dev_default(test, dev1, 0x701, false); + dev3 = alloc_dev_with_dpin(test, dev2, 0x50701, false); + + in = &dev3->ports[13]; + out = &host->ports[5]; + + path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video"); + KUNIT_ASSERT_TRUE(test, path != NULL); + KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data)); + for (i = 0; i < ARRAY_SIZE(test_data); i++) { + const struct tb_port *in_port, *out_port; + + in_port = path->hops[i].in_port; + out_port = path->hops[i].out_port; + + KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type, + test_data[i].in_type); + KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type, + test_data[i].out_type); + } + tb_path_free(path); +} + +static void tb_test_path_mixed_chain(struct kunit *test) +{ + /* + * DP Video path from host to device 4 where first and last link + * is bonded. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * 7 :| 8 + * 1 :| 2 + * [Device #2] + * 5 :| 6 + * 1 :| 2 + * [Device #3] + * 3 | + * 1 | + * [Device #4] + */ + static const struct hop_expectation test_data[] = { + { + .route = 0x0, + .in_port = 5, + .in_type = TB_TYPE_DP_HDMI_IN, + .out_port = 1, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x1, + .in_port = 1, + .in_type = TB_TYPE_PORT, + .out_port = 8, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x701, + .in_port = 2, + .in_type = TB_TYPE_PORT, + .out_port = 6, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x50701, + .in_port = 2, + .in_type = TB_TYPE_PORT, + .out_port = 3, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x3050701, + .in_port = 1, + .in_type = TB_TYPE_PORT, + .out_port = 13, + .out_type = TB_TYPE_DP_HDMI_OUT, + }, + }; + struct tb_switch *host, *dev1, *dev2, *dev3, *dev4; + struct tb_port *in, *out; + struct tb_path *path; + int i; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x701, false); + dev3 = alloc_dev_default(test, dev2, 0x50701, false); + dev4 = alloc_dev_default(test, dev3, 0x3050701, true); + + in = &host->ports[5]; + out = &dev4->ports[13]; + + path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video"); + KUNIT_ASSERT_TRUE(test, path != NULL); + KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data)); + for (i = 0; i < ARRAY_SIZE(test_data); i++) { + const struct tb_port *in_port, *out_port; + + in_port = path->hops[i].in_port; + out_port = path->hops[i].out_port; + + KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type, + test_data[i].in_type); + KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type, + test_data[i].out_type); + } + tb_path_free(path); +} + +static void tb_test_path_mixed_chain_reverse(struct kunit *test) +{ + /* + * DP Video path from device 4 to host where first and last link + * is bonded. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * 7 :| 8 + * 1 :| 2 + * [Device #2] + * 5 :| 6 + * 1 :| 2 + * [Device #3] + * 3 | + * 1 | + * [Device #4] + */ + static const struct hop_expectation test_data[] = { + { + .route = 0x3050701, + .in_port = 13, + .in_type = TB_TYPE_DP_HDMI_OUT, + .out_port = 1, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x50701, + .in_port = 3, + .in_type = TB_TYPE_PORT, + .out_port = 2, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x701, + .in_port = 6, + .in_type = TB_TYPE_PORT, + .out_port = 2, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x1, + .in_port = 8, + .in_type = TB_TYPE_PORT, + .out_port = 1, + .out_type = TB_TYPE_PORT, + }, + { + .route = 0x0, + .in_port = 1, + .in_type = TB_TYPE_PORT, + .out_port = 5, + .out_type = TB_TYPE_DP_HDMI_IN, + }, + }; + struct tb_switch *host, *dev1, *dev2, *dev3, *dev4; + struct tb_port *in, *out; + struct tb_path *path; + int i; + + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x701, false); + dev3 = alloc_dev_default(test, dev2, 0x50701, false); + dev4 = alloc_dev_default(test, dev3, 0x3050701, true); + + in = &dev4->ports[13]; + out = &host->ports[5]; + + path = tb_path_alloc(NULL, in, 9, out, 9, 1, "Video"); + KUNIT_ASSERT_TRUE(test, path != NULL); + KUNIT_ASSERT_EQ(test, path->path_length, (int)ARRAY_SIZE(test_data)); + for (i = 0; i < ARRAY_SIZE(test_data); i++) { + const struct tb_port *in_port, *out_port; + + in_port = path->hops[i].in_port; + out_port = path->hops[i].out_port; + + KUNIT_EXPECT_EQ(test, tb_route(in_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, in_port->port, test_data[i].in_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)in_port->config.type, + test_data[i].in_type); + KUNIT_EXPECT_EQ(test, tb_route(out_port->sw), test_data[i].route); + KUNIT_EXPECT_EQ(test, out_port->port, test_data[i].out_port); + KUNIT_EXPECT_EQ(test, (enum tb_port_type)out_port->config.type, + test_data[i].out_type); + } + tb_path_free(path); +} + +static void tb_test_tunnel_pcie(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2; + struct tb_tunnel *tunnel1, *tunnel2; + struct tb_port *down, *up; + + /* + * Create PCIe tunnel between host and two devices. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * 5 | + * 1 | + * [Device #2] + */ + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x501, true); + + down = &host->ports[8]; + up = &dev1->ports[9]; + tunnel1 = tb_tunnel_alloc_pci(NULL, up, down); + KUNIT_ASSERT_TRUE(test, tunnel1 != NULL); + KUNIT_EXPECT_EQ(test, tunnel1->type, (enum tb_tunnel_type)TB_TUNNEL_PCI); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->src_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->dst_port, up); + KUNIT_ASSERT_EQ(test, tunnel1->npaths, (size_t)2); + KUNIT_ASSERT_EQ(test, tunnel1->paths[0]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[0].in_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[1].out_port, up); + KUNIT_ASSERT_EQ(test, tunnel1->paths[1]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[0].in_port, up); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[1].out_port, down); + + down = &dev1->ports[10]; + up = &dev2->ports[9]; + tunnel2 = tb_tunnel_alloc_pci(NULL, up, down); + KUNIT_ASSERT_TRUE(test, tunnel2 != NULL); + KUNIT_EXPECT_EQ(test, tunnel2->type, (enum tb_tunnel_type)TB_TUNNEL_PCI); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->src_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->dst_port, up); + KUNIT_ASSERT_EQ(test, tunnel2->npaths, (size_t)2); + KUNIT_ASSERT_EQ(test, tunnel2->paths[0]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[0].in_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[1].out_port, up); + KUNIT_ASSERT_EQ(test, tunnel2->paths[1]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[0].in_port, up); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[1].out_port, down); + + tb_tunnel_free(tunnel2); + tb_tunnel_free(tunnel1); +} + +static void tb_test_tunnel_dp(struct kunit *test) +{ + struct tb_switch *host, *dev; + struct tb_port *in, *out; + struct tb_tunnel *tunnel; + + /* + * Create DP tunnel between Host and Device + * + * [Host] + * 1 | + * 1 | + * [Device] + */ + host = alloc_host(test); + dev = alloc_dev_default(test, host, 0x3, true); + + in = &host->ports[5]; + out = &dev->ports[13]; + + tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3); + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[1].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[1].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[1].out_port, in); + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_dp_chain(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev4; + struct tb_port *in, *out; + struct tb_tunnel *tunnel; + + /* + * Create DP tunnel from Host DP IN to Device #4 DP OUT. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * 3 / | 5 \ 7 + * 1 / | \ 1 + * [Device #2] | [Device #4] + * | 1 + * [Device #3] + */ + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + alloc_dev_default(test, dev1, 0x301, true); + alloc_dev_default(test, dev1, 0x501, true); + dev4 = alloc_dev_default(test, dev1, 0x701, true); + + in = &host->ports[5]; + out = &dev4->ports[14]; + + tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3); + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 3); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[2].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 3); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[2].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 3); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[2].out_port, in); + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_dp_tree(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2, *dev3, *dev5; + struct tb_port *in, *out; + struct tb_tunnel *tunnel; + + /* + * Create DP tunnel from Device #2 DP IN to Device #5 DP OUT. + * + * [Host] + * 3 | + * 1 | + * [Device #1] + * 3 / | 5 \ 7 + * 1 / | \ 1 + * [Device #2] | [Device #4] + * | 1 + * [Device #3] + * | 5 + * | 1 + * [Device #5] + */ + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x3, true); + dev2 = alloc_dev_with_dpin(test, dev1, 0x303, true); + dev3 = alloc_dev_default(test, dev1, 0x503, true); + alloc_dev_default(test, dev1, 0x703, true); + dev5 = alloc_dev_default(test, dev3, 0x50503, true); + + in = &dev2->ports[13]; + out = &dev5->ports[13]; + + tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3); + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 4); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[3].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 4); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[3].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 4); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[3].out_port, in); + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_dp_max_length(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2, *dev3, *dev4, *dev5, *dev6; + struct tb_switch *dev7, *dev8, *dev9, *dev10, *dev11, *dev12; + struct tb_port *in, *out; + struct tb_tunnel *tunnel; + + /* + * Creates DP tunnel from Device #6 to Device #12. + * + * [Host] + * 1 / \ 3 + * 1 / \ 1 + * [Device #1] [Device #7] + * 3 | | 3 + * 1 | | 1 + * [Device #2] [Device #8] + * 3 | | 3 + * 1 | | 1 + * [Device #3] [Device #9] + * 3 | | 3 + * 1 | | 1 + * [Device #4] [Device #10] + * 3 | | 3 + * 1 | | 1 + * [Device #5] [Device #11] + * 3 | | 3 + * 1 | | 1 + * [Device #6] [Device #12] + */ + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x301, true); + dev3 = alloc_dev_default(test, dev2, 0x30301, true); + dev4 = alloc_dev_default(test, dev3, 0x3030301, true); + dev5 = alloc_dev_default(test, dev4, 0x303030301, true); + dev6 = alloc_dev_with_dpin(test, dev5, 0x30303030301, true); + dev7 = alloc_dev_default(test, host, 0x3, true); + dev8 = alloc_dev_default(test, dev7, 0x303, true); + dev9 = alloc_dev_default(test, dev8, 0x30303, true); + dev10 = alloc_dev_default(test, dev9, 0x3030303, true); + dev11 = alloc_dev_default(test, dev10, 0x303030303, true); + dev12 = alloc_dev_default(test, dev11, 0x30303030303, true); + + in = &dev6->ports[13]; + out = &dev12->ports[13]; + + tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0); + KUNIT_ASSERT_TRUE(test, tunnel != NULL); + KUNIT_EXPECT_EQ(test, tunnel->type, (enum tb_tunnel_type)TB_TUNNEL_DP); + KUNIT_EXPECT_PTR_EQ(test, tunnel->src_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->dst_port, out); + KUNIT_ASSERT_EQ(test, tunnel->npaths, (size_t)3); + KUNIT_ASSERT_EQ(test, tunnel->paths[0]->path_length, 13); + /* First hop */ + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[0].in_port, in); + /* Middle */ + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[6].in_port, + &host->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[6].out_port, + &host->ports[3]); + /* Last */ + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[0]->hops[12].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[1]->path_length, 13); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[0].in_port, in); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[6].in_port, + &host->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[6].out_port, + &host->ports[3]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[1]->hops[12].out_port, out); + KUNIT_ASSERT_EQ(test, tunnel->paths[2]->path_length, 13); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[0].in_port, out); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[6].in_port, + &host->ports[3]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[6].out_port, + &host->ports[1]); + KUNIT_EXPECT_PTR_EQ(test, tunnel->paths[2]->hops[12].out_port, in); + tb_tunnel_free(tunnel); +} + +static void tb_test_tunnel_usb3(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2; + struct tb_tunnel *tunnel1, *tunnel2; + struct tb_port *down, *up; + + /* + * Create USB3 tunnel between host and two devices. + * + * [Host] + * 1 | + * 1 | + * [Device #1] + * \ 7 + * \ 1 + * [Device #2] + */ + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x1, true); + dev2 = alloc_dev_default(test, dev1, 0x701, true); + + down = &host->ports[12]; + up = &dev1->ports[16]; + tunnel1 = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0); + KUNIT_ASSERT_TRUE(test, tunnel1 != NULL); + KUNIT_EXPECT_EQ(test, tunnel1->type, (enum tb_tunnel_type)TB_TUNNEL_USB3); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->src_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->dst_port, up); + KUNIT_ASSERT_EQ(test, tunnel1->npaths, (size_t)2); + KUNIT_ASSERT_EQ(test, tunnel1->paths[0]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[0].in_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[0]->hops[1].out_port, up); + KUNIT_ASSERT_EQ(test, tunnel1->paths[1]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[0].in_port, up); + KUNIT_EXPECT_PTR_EQ(test, tunnel1->paths[1]->hops[1].out_port, down); + + down = &dev1->ports[17]; + up = &dev2->ports[16]; + tunnel2 = tb_tunnel_alloc_usb3(NULL, up, down, 0, 0); + KUNIT_ASSERT_TRUE(test, tunnel2 != NULL); + KUNIT_EXPECT_EQ(test, tunnel2->type, (enum tb_tunnel_type)TB_TUNNEL_USB3); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->src_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->dst_port, up); + KUNIT_ASSERT_EQ(test, tunnel2->npaths, (size_t)2); + KUNIT_ASSERT_EQ(test, tunnel2->paths[0]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[0].in_port, down); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[0]->hops[1].out_port, up); + KUNIT_ASSERT_EQ(test, tunnel2->paths[1]->path_length, 2); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[0].in_port, up); + KUNIT_EXPECT_PTR_EQ(test, tunnel2->paths[1]->hops[1].out_port, down); + + tb_tunnel_free(tunnel2); + tb_tunnel_free(tunnel1); +} + +static void tb_test_tunnel_port_on_path(struct kunit *test) +{ + struct tb_switch *host, *dev1, *dev2, *dev3, *dev4, *dev5; + struct tb_port *in, *out, *port; + struct tb_tunnel *dp_tunnel; + + /* + * [Host] + * 3 | + * 1 | + * [Device #1] + * 3 / | 5 \ 7 + * 1 / | \ 1 + * [Device #2] | [Device #4] + * | 1 + * [Device #3] + * | 5 + * | 1 + * [Device #5] + */ + host = alloc_host(test); + dev1 = alloc_dev_default(test, host, 0x3, true); + dev2 = alloc_dev_with_dpin(test, dev1, 0x303, true); + dev3 = alloc_dev_default(test, dev1, 0x503, true); + dev4 = alloc_dev_default(test, dev1, 0x703, true); + dev5 = alloc_dev_default(test, dev3, 0x50503, true); + + in = &dev2->ports[13]; + out = &dev5->ports[13]; + + dp_tunnel = tb_tunnel_alloc_dp(NULL, in, out, 0, 0); + KUNIT_ASSERT_TRUE(test, dp_tunnel != NULL); + + KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, in)); + KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, out)); + + port = &host->ports[8]; + KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &host->ports[3]; + KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &dev1->ports[1]; + KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &dev1->ports[3]; + KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &dev1->ports[5]; + KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &dev1->ports[7]; + KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &dev3->ports[1]; + KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &dev5->ports[1]; + KUNIT_EXPECT_TRUE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + port = &dev4->ports[1]; + KUNIT_EXPECT_FALSE(test, tb_tunnel_port_on_path(dp_tunnel, port)); + + tb_tunnel_free(dp_tunnel); +} + +static struct kunit_case tb_test_cases[] = { + KUNIT_CASE(tb_test_path_basic), + KUNIT_CASE(tb_test_path_not_connected_walk), + KUNIT_CASE(tb_test_path_single_hop_walk), + KUNIT_CASE(tb_test_path_daisy_chain_walk), + KUNIT_CASE(tb_test_path_simple_tree_walk), + KUNIT_CASE(tb_test_path_complex_tree_walk), + KUNIT_CASE(tb_test_path_max_length_walk), + KUNIT_CASE(tb_test_path_not_connected), + KUNIT_CASE(tb_test_path_not_bonded_lane0), + KUNIT_CASE(tb_test_path_not_bonded_lane1), + KUNIT_CASE(tb_test_path_not_bonded_lane1_chain), + KUNIT_CASE(tb_test_path_not_bonded_lane1_chain_reverse), + KUNIT_CASE(tb_test_path_mixed_chain), + KUNIT_CASE(tb_test_path_mixed_chain_reverse), + KUNIT_CASE(tb_test_tunnel_pcie), + KUNIT_CASE(tb_test_tunnel_dp), + KUNIT_CASE(tb_test_tunnel_dp_chain), + KUNIT_CASE(tb_test_tunnel_dp_tree), + KUNIT_CASE(tb_test_tunnel_dp_max_length), + KUNIT_CASE(tb_test_tunnel_port_on_path), + KUNIT_CASE(tb_test_tunnel_usb3), + { } +}; + +static struct kunit_suite tb_test_suite = { + .name = "thunderbolt", + .test_cases = tb_test_cases, +}; +kunit_test_suite(tb_test_suite); diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index c144ca9b032ce0ede441ae1c8afb73285cb129ed..2aae2c76d880dd49074b2e040627523691f3df94 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -124,8 +124,9 @@ static void tb_pci_init_path(struct tb_path *path) path->drop_packages = 0; path->nfc_credits = 0; path->hops[0].initial_credits = 7; - path->hops[1].initial_credits = - tb_initial_credits(path->hops[1].in_port->sw); + if (path->path_length > 1) + path->hops[1].initial_credits = + tb_initial_credits(path->hops[1].in_port->sw); } /** @@ -422,7 +423,7 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel) u32 out_dp_cap, out_rate, out_lanes, in_dp_cap, in_rate, in_lanes, bw; struct tb_port *out = tunnel->dst_port; struct tb_port *in = tunnel->src_port; - int ret; + int ret, max_bw; /* * Copy DP_LOCAL_CAP register to DP_REMOTE_CAP register for @@ -471,10 +472,15 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel) tb_port_dbg(out, "maximum supported bandwidth %u Mb/s x%u = %u Mb/s\n", out_rate, out_lanes, bw); - if (tunnel->max_bw && bw > tunnel->max_bw) { + if (in->sw->config.depth < out->sw->config.depth) + max_bw = tunnel->max_down; + else + max_bw = tunnel->max_up; + + if (max_bw && bw > max_bw) { u32 new_rate, new_lanes, new_bw; - ret = tb_dp_reduce_bandwidth(tunnel->max_bw, in_rate, in_lanes, + ret = tb_dp_reduce_bandwidth(max_bw, in_rate, in_lanes, out_rate, out_lanes, &new_rate, &new_lanes); if (ret) { @@ -535,7 +541,8 @@ static int tb_dp_activate(struct tb_tunnel *tunnel, bool active) return 0; } -static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel) +static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up, + int *consumed_down) { struct tb_port *in = tunnel->src_port; const struct tb_switch *sw = in->sw; @@ -543,7 +550,7 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel) int ret; if (tb_dp_is_usb4(sw)) { - int timeout = 10; + int timeout = 20; /* * Wait for DPRX done. Normally it should be already set @@ -579,10 +586,20 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel) lanes = tb_dp_cap_get_lanes(val); } else { /* No bandwidth management for legacy devices */ + *consumed_up = 0; + *consumed_down = 0; return 0; } - return tb_dp_bandwidth(rate, lanes); + if (in->sw->config.depth < tunnel->dst_port->sw->config.depth) { + *consumed_up = 0; + *consumed_down = tb_dp_bandwidth(rate, lanes); + } else { + *consumed_up = tb_dp_bandwidth(rate, lanes); + *consumed_down = 0; + } + + return 0; } static void tb_dp_init_aux_path(struct tb_path *path) @@ -708,7 +725,10 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in) * @tb: Pointer to the domain structure * @in: DP in adapter port * @out: DP out adapter port - * @max_bw: Maximum available bandwidth for the DP tunnel (%0 if not limited) + * @max_up: Maximum available upstream bandwidth for the DP tunnel (%0 + * if not limited) + * @max_down: Maximum available downstream bandwidth for the DP tunnel + * (%0 if not limited) * * Allocates a tunnel between @in and @out that is capable of tunneling * Display Port traffic. @@ -716,7 +736,8 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in) * Return: Returns a tb_tunnel on success or NULL on failure. */ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, - struct tb_port *out, int max_bw) + struct tb_port *out, int max_up, + int max_down) { struct tb_tunnel *tunnel; struct tb_path **paths; @@ -734,7 +755,8 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, tunnel->consumed_bandwidth = tb_dp_consumed_bandwidth; tunnel->src_port = in; tunnel->dst_port = out; - tunnel->max_bw = max_bw; + tunnel->max_up = max_up; + tunnel->max_down = max_down; paths = tunnel->paths; @@ -854,6 +876,33 @@ struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, return tunnel; } +static int tb_usb3_max_link_rate(struct tb_port *up, struct tb_port *down) +{ + int ret, up_max_rate, down_max_rate; + + ret = usb4_usb3_port_max_link_rate(up); + if (ret < 0) + return ret; + up_max_rate = ret; + + ret = usb4_usb3_port_max_link_rate(down); + if (ret < 0) + return ret; + down_max_rate = ret; + + return min(up_max_rate, down_max_rate); +} + +static int tb_usb3_init(struct tb_tunnel *tunnel) +{ + tb_tunnel_dbg(tunnel, "allocating initial bandwidth %d/%d Mb/s\n", + tunnel->allocated_up, tunnel->allocated_down); + + return usb4_usb3_port_allocate_bandwidth(tunnel->src_port, + &tunnel->allocated_up, + &tunnel->allocated_down); +} + static int tb_usb3_activate(struct tb_tunnel *tunnel, bool activate) { int res; @@ -868,6 +917,86 @@ static int tb_usb3_activate(struct tb_tunnel *tunnel, bool activate) return 0; } +static int tb_usb3_consumed_bandwidth(struct tb_tunnel *tunnel, + int *consumed_up, int *consumed_down) +{ + /* + * PCIe tunneling affects the USB3 bandwidth so take that it + * into account here. + */ + *consumed_up = tunnel->allocated_up * (3 + 1) / 3; + *consumed_down = tunnel->allocated_down * (3 + 1) / 3; + return 0; +} + +static int tb_usb3_release_unused_bandwidth(struct tb_tunnel *tunnel) +{ + int ret; + + ret = usb4_usb3_port_release_bandwidth(tunnel->src_port, + &tunnel->allocated_up, + &tunnel->allocated_down); + if (ret) + return ret; + + tb_tunnel_dbg(tunnel, "decreased bandwidth allocation to %d/%d Mb/s\n", + tunnel->allocated_up, tunnel->allocated_down); + return 0; +} + +static void tb_usb3_reclaim_available_bandwidth(struct tb_tunnel *tunnel, + int *available_up, + int *available_down) +{ + int ret, max_rate, allocate_up, allocate_down; + + ret = usb4_usb3_port_actual_link_rate(tunnel->src_port); + if (ret <= 0) { + tb_tunnel_warn(tunnel, "tunnel is not up\n"); + return; + } + /* + * 90% of the max rate can be allocated for isochronous + * transfers. + */ + max_rate = ret * 90 / 100; + + /* No need to reclaim if already at maximum */ + if (tunnel->allocated_up >= max_rate && + tunnel->allocated_down >= max_rate) + return; + + /* Don't go lower than what is already allocated */ + allocate_up = min(max_rate, *available_up); + if (allocate_up < tunnel->allocated_up) + allocate_up = tunnel->allocated_up; + + allocate_down = min(max_rate, *available_down); + if (allocate_down < tunnel->allocated_down) + allocate_down = tunnel->allocated_down; + + /* If no changes no need to do more */ + if (allocate_up == tunnel->allocated_up && + allocate_down == tunnel->allocated_down) + return; + + ret = usb4_usb3_port_allocate_bandwidth(tunnel->src_port, &allocate_up, + &allocate_down); + if (ret) { + tb_tunnel_info(tunnel, "failed to allocate bandwidth\n"); + return; + } + + tunnel->allocated_up = allocate_up; + *available_up -= tunnel->allocated_up; + + tunnel->allocated_down = allocate_down; + *available_down -= tunnel->allocated_down; + + tb_tunnel_dbg(tunnel, "increased bandwidth allocation to %d/%d Mb/s\n", + tunnel->allocated_up, tunnel->allocated_down); +} + static void tb_usb3_init_path(struct tb_path *path) { path->egress_fc_enable = TB_PATH_SOURCE | TB_PATH_INTERNAL; @@ -879,8 +1008,9 @@ static void tb_usb3_init_path(struct tb_path *path) path->drop_packages = 0; path->nfc_credits = 0; path->hops[0].initial_credits = 7; - path->hops[1].initial_credits = - tb_initial_credits(path->hops[1].in_port->sw); + if (path->path_length > 1) + path->hops[1].initial_credits = + tb_initial_credits(path->hops[1].in_port->sw); } /** @@ -947,6 +1077,29 @@ struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down) goto err_deactivate; } + if (!tb_route(down->sw)) { + int ret; + + /* + * Read the initial bandwidth allocation for the first + * hop tunnel. + */ + ret = usb4_usb3_port_allocated_bandwidth(down, + &tunnel->allocated_up, &tunnel->allocated_down); + if (ret) + goto err_deactivate; + + tb_tunnel_dbg(tunnel, "currently allocated bandwidth %d/%d Mb/s\n", + tunnel->allocated_up, tunnel->allocated_down); + + tunnel->init = tb_usb3_init; + tunnel->consumed_bandwidth = tb_usb3_consumed_bandwidth; + tunnel->release_unused_bandwidth = + tb_usb3_release_unused_bandwidth; + tunnel->reclaim_available_bandwidth = + tb_usb3_reclaim_available_bandwidth; + } + tb_tunnel_dbg(tunnel, "discovered\n"); return tunnel; @@ -963,6 +1116,10 @@ struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down) * @tb: Pointer to the domain structure * @up: USB3 upstream adapter port * @down: USB3 downstream adapter port + * @max_up: Maximum available upstream bandwidth for the USB3 tunnel (%0 + * if not limited). + * @max_down: Maximum available downstream bandwidth for the USB3 tunnel + * (%0 if not limited). * * Allocate an USB3 tunnel. The ports must be of type @TB_TYPE_USB3_UP and * @TB_TYPE_USB3_DOWN. @@ -970,10 +1127,32 @@ struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down) * Return: Returns a tb_tunnel on success or %NULL on failure. */ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, - struct tb_port *down) + struct tb_port *down, int max_up, + int max_down) { struct tb_tunnel *tunnel; struct tb_path *path; + int max_rate = 0; + + /* + * Check that we have enough bandwidth available for the new + * USB3 tunnel. + */ + if (max_up > 0 || max_down > 0) { + max_rate = tb_usb3_max_link_rate(down, up); + if (max_rate < 0) + return NULL; + + /* Only 90% can be allocated for USB3 isochronous transfers */ + max_rate = max_rate * 90 / 100; + tb_port_dbg(up, "required bandwidth for USB3 tunnel %d Mb/s\n", + max_rate); + + if (max_rate > max_up || max_rate > max_down) { + tb_port_warn(up, "not enough bandwidth for USB3 tunnel\n"); + return NULL; + } + } tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_USB3); if (!tunnel) @@ -982,6 +1161,8 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, tunnel->activate = tb_usb3_activate; tunnel->src_port = down; tunnel->dst_port = up; + tunnel->max_up = max_up; + tunnel->max_down = max_down; path = tb_path_alloc(tb, down, TB_USB3_HOPID, up, TB_USB3_HOPID, 0, "USB3 Down"); @@ -1001,6 +1182,18 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, tb_usb3_init_path(path); tunnel->paths[TB_USB3_PATH_UP] = path; + if (!tb_route(down->sw)) { + tunnel->allocated_up = max_rate; + tunnel->allocated_down = max_rate; + + tunnel->init = tb_usb3_init; + tunnel->consumed_bandwidth = tb_usb3_consumed_bandwidth; + tunnel->release_unused_bandwidth = + tb_usb3_release_unused_bandwidth; + tunnel->reclaim_available_bandwidth = + tb_usb3_reclaim_available_bandwidth; + } + return tunnel; } @@ -1133,22 +1326,23 @@ void tb_tunnel_deactivate(struct tb_tunnel *tunnel) } /** - * tb_tunnel_switch_on_path() - Does the tunnel go through switch + * tb_tunnel_port_on_path() - Does the tunnel go through port * @tunnel: Tunnel to check - * @sw: Switch to check + * @port: Port to check * - * Returns true if @tunnel goes through @sw (direction does not matter), + * Returns true if @tunnel goes through @port (direction does not matter), * false otherwise. */ -bool tb_tunnel_switch_on_path(const struct tb_tunnel *tunnel, - const struct tb_switch *sw) +bool tb_tunnel_port_on_path(const struct tb_tunnel *tunnel, + const struct tb_port *port) { int i; for (i = 0; i < tunnel->npaths; i++) { if (!tunnel->paths[i]) continue; - if (tb_path_switch_on_path(tunnel->paths[i], sw)) + + if (tb_path_port_on_path(tunnel->paths[i], port)) return true; } @@ -1172,21 +1366,87 @@ static bool tb_tunnel_is_active(const struct tb_tunnel *tunnel) /** * tb_tunnel_consumed_bandwidth() - Return bandwidth consumed by the tunnel * @tunnel: Tunnel to check + * @consumed_up: Consumed bandwidth in Mb/s from @dst_port to @src_port. + * Can be %NULL. + * @consumed_down: Consumed bandwidth in Mb/s from @src_port to @dst_port. + * Can be %NULL. * - * Returns bandwidth currently consumed by @tunnel and %0 if the @tunnel - * is not active or does consume bandwidth. + * Stores the amount of isochronous bandwidth @tunnel consumes in + * @consumed_up and @consumed_down. In case of success returns %0, + * negative errno otherwise. */ -int tb_tunnel_consumed_bandwidth(struct tb_tunnel *tunnel) +int tb_tunnel_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up, + int *consumed_down) { + int up_bw = 0, down_bw = 0; + if (!tb_tunnel_is_active(tunnel)) - return 0; + goto out; if (tunnel->consumed_bandwidth) { - int ret = tunnel->consumed_bandwidth(tunnel); + int ret; - tb_tunnel_dbg(tunnel, "consumed bandwidth %d Mb/s\n", ret); - return ret; + ret = tunnel->consumed_bandwidth(tunnel, &up_bw, &down_bw); + if (ret) + return ret; + + tb_tunnel_dbg(tunnel, "consumed bandwidth %d/%d Mb/s\n", up_bw, + down_bw); } +out: + if (consumed_up) + *consumed_up = up_bw; + if (consumed_down) + *consumed_down = down_bw; + return 0; } + +/** + * tb_tunnel_release_unused_bandwidth() - Release unused bandwidth + * @tunnel: Tunnel whose unused bandwidth to release + * + * If tunnel supports dynamic bandwidth management (USB3 tunnels at the + * moment) this function makes it to release all the unused bandwidth. + * + * Returns %0 in case of success and negative errno otherwise. + */ +int tb_tunnel_release_unused_bandwidth(struct tb_tunnel *tunnel) +{ + if (!tb_tunnel_is_active(tunnel)) + return 0; + + if (tunnel->release_unused_bandwidth) { + int ret; + + ret = tunnel->release_unused_bandwidth(tunnel); + if (ret) + return ret; + } + + return 0; +} + +/** + * tb_tunnel_reclaim_available_bandwidth() - Reclaim available bandwidth + * @tunnel: Tunnel reclaiming available bandwidth + * @available_up: Available upstream bandwidth (in Mb/s) + * @available_down: Available downstream bandwidth (in Mb/s) + * + * Reclaims bandwidth from @available_up and @available_down and updates + * the variables accordingly (e.g decreases both according to what was + * reclaimed by the tunnel). If nothing was reclaimed the values are + * kept as is. + */ +void tb_tunnel_reclaim_available_bandwidth(struct tb_tunnel *tunnel, + int *available_up, + int *available_down) +{ + if (!tb_tunnel_is_active(tunnel)) + return; + + if (tunnel->reclaim_available_bandwidth) + tunnel->reclaim_available_bandwidth(tunnel, available_up, + available_down); +} diff --git a/drivers/thunderbolt/tunnel.h b/drivers/thunderbolt/tunnel.h index 3f5ba93225e7832d05968d3bc085ed78ade70481..1d2a64eb060d54409b088984a8e801247f205e3f 100644 --- a/drivers/thunderbolt/tunnel.h +++ b/drivers/thunderbolt/tunnel.h @@ -29,10 +29,16 @@ enum tb_tunnel_type { * @init: Optional tunnel specific initialization * @activate: Optional tunnel specific activation/deactivation * @consumed_bandwidth: Return how much bandwidth the tunnel consumes + * @release_unused_bandwidth: Release all unused bandwidth + * @reclaim_available_bandwidth: Reclaim back available bandwidth * @list: Tunnels are linked using this field * @type: Type of the tunnel - * @max_bw: Maximum bandwidth (Mb/s) available for the tunnel (only for DP). + * @max_up: Maximum upstream bandwidth (Mb/s) available for the tunnel. * Only set if the bandwidth needs to be limited. + * @max_down: Maximum downstream bandwidth (Mb/s) available for the tunnel. + * Only set if the bandwidth needs to be limited. + * @allocated_up: Allocated upstream bandwidth (only for USB3) + * @allocated_down: Allocated downstream bandwidth (only for USB3) */ struct tb_tunnel { struct tb *tb; @@ -42,10 +48,18 @@ struct tb_tunnel { size_t npaths; int (*init)(struct tb_tunnel *tunnel); int (*activate)(struct tb_tunnel *tunnel, bool activate); - int (*consumed_bandwidth)(struct tb_tunnel *tunnel); + int (*consumed_bandwidth)(struct tb_tunnel *tunnel, int *consumed_up, + int *consumed_down); + int (*release_unused_bandwidth)(struct tb_tunnel *tunnel); + void (*reclaim_available_bandwidth)(struct tb_tunnel *tunnel, + int *available_up, + int *available_down); struct list_head list; enum tb_tunnel_type type; - unsigned int max_bw; + int max_up; + int max_down; + int allocated_up; + int allocated_down; }; struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down); @@ -53,23 +67,30 @@ struct tb_tunnel *tb_tunnel_alloc_pci(struct tb *tb, struct tb_port *up, struct tb_port *down); struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in); struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, - struct tb_port *out, int max_bw); + struct tb_port *out, int max_up, + int max_down); struct tb_tunnel *tb_tunnel_alloc_dma(struct tb *tb, struct tb_port *nhi, struct tb_port *dst, int transmit_ring, int transmit_path, int receive_ring, int receive_path); struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down); struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up, - struct tb_port *down); + struct tb_port *down, int max_up, + int max_down); void tb_tunnel_free(struct tb_tunnel *tunnel); int tb_tunnel_activate(struct tb_tunnel *tunnel); int tb_tunnel_restart(struct tb_tunnel *tunnel); void tb_tunnel_deactivate(struct tb_tunnel *tunnel); bool tb_tunnel_is_invalid(struct tb_tunnel *tunnel); -bool tb_tunnel_switch_on_path(const struct tb_tunnel *tunnel, - const struct tb_switch *sw); -int tb_tunnel_consumed_bandwidth(struct tb_tunnel *tunnel); +bool tb_tunnel_port_on_path(const struct tb_tunnel *tunnel, + const struct tb_port *port); +int tb_tunnel_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up, + int *consumed_down); +int tb_tunnel_release_unused_bandwidth(struct tb_tunnel *tunnel); +void tb_tunnel_reclaim_available_bandwidth(struct tb_tunnel *tunnel, + int *available_up, + int *available_down); static inline bool tb_tunnel_is_pci(const struct tb_tunnel *tunnel) { diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index 50c7534ba31e9ac65b03d55d7c42de93dcec1341..2b8355e6b65f4d6825cbafbcbd910f9196e8f590 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/ktime.h> +#include "sb_regs.h" #include "tb.h" #define USB4_DATA_DWORDS 16 @@ -27,6 +28,12 @@ enum usb4_switch_op { USB4_SWITCH_OP_NVM_SECTOR_SIZE = 0x25, }; +enum usb4_sb_target { + USB4_SB_TARGET_ROUTER, + USB4_SB_TARGET_PARTNER, + USB4_SB_TARGET_RETIMER, +}; + #define USB4_NVM_READ_OFFSET_MASK GENMASK(23, 2) #define USB4_NVM_READ_OFFSET_SHIFT 2 #define USB4_NVM_READ_LENGTH_MASK GENMASK(27, 24) @@ -42,8 +49,8 @@ enum usb4_switch_op { #define USB4_NVM_SECTOR_SIZE_MASK GENMASK(23, 0) -typedef int (*read_block_fn)(struct tb_switch *, unsigned int, void *, size_t); -typedef int (*write_block_fn)(struct tb_switch *, const void *, size_t); +typedef int (*read_block_fn)(void *, unsigned int, void *, size_t); +typedef int (*write_block_fn)(void *, const void *, size_t); static int usb4_switch_wait_for_bit(struct tb_switch *sw, u32 offset, u32 bit, u32 value, int timeout_msec) @@ -95,8 +102,8 @@ static int usb4_switch_op_write_metadata(struct tb_switch *sw, u32 metadata) return tb_sw_write(sw, &metadata, TB_CFG_SWITCH, ROUTER_CS_25, 1); } -static int usb4_switch_do_read_data(struct tb_switch *sw, u16 address, - void *buf, size_t size, read_block_fn read_block) +static int usb4_do_read_data(u16 address, void *buf, size_t size, + read_block_fn read_block, void *read_block_data) { unsigned int retries = USB4_DATA_RETRIES; unsigned int offset; @@ -113,13 +120,10 @@ static int usb4_switch_do_read_data(struct tb_switch *sw, u16 address, dwaddress = address / 4; dwords = ALIGN(nbytes, 4) / 4; - ret = read_block(sw, dwaddress, data, dwords); + ret = read_block(read_block_data, dwaddress, data, dwords); if (ret) { - if (ret == -ETIMEDOUT) { - if (retries--) - continue; - ret = -EIO; - } + if (ret != -ENODEV && retries--) + continue; return ret; } @@ -133,8 +137,8 @@ static int usb4_switch_do_read_data(struct tb_switch *sw, u16 address, return 0; } -static int usb4_switch_do_write_data(struct tb_switch *sw, u16 address, - const void *buf, size_t size, write_block_fn write_next_block) +static int usb4_do_write_data(unsigned int address, const void *buf, size_t size, + write_block_fn write_next_block, void *write_block_data) { unsigned int retries = USB4_DATA_RETRIES; unsigned int offset; @@ -149,7 +153,7 @@ static int usb4_switch_do_write_data(struct tb_switch *sw, u16 address, memcpy(data + offset, buf, nbytes); - ret = write_next_block(sw, data, nbytes / 4); + ret = write_next_block(write_block_data, data, nbytes / 4); if (ret) { if (ret == -ETIMEDOUT) { if (retries--) @@ -192,6 +196,20 @@ static int usb4_switch_op(struct tb_switch *sw, u16 opcode, u8 *status) return 0; } +static bool link_is_usb4(struct tb_port *port) +{ + u32 val; + + if (!port->cap_usb4) + return false; + + if (tb_port_read(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_18, 1)) + return false; + + return !(val & PORT_CS_18_TCM); +} + /** * usb4_switch_setup() - Additional setup for USB4 device * @sw: USB4 router to setup @@ -205,6 +223,7 @@ static int usb4_switch_op(struct tb_switch *sw, u16 opcode, u8 *status) */ int usb4_switch_setup(struct tb_switch *sw) { + struct tb_port *downstream_port; struct tb_switch *parent; bool tbt3, xhci; u32 val = 0; @@ -217,6 +236,11 @@ int usb4_switch_setup(struct tb_switch *sw) if (ret) return ret; + parent = tb_switch_parent(sw); + downstream_port = tb_port_at(tb_route(sw), parent); + sw->link_usb4 = link_is_usb4(downstream_port); + tb_sw_dbg(sw, "link: %s\n", sw->link_usb4 ? "USB4" : "TBT3"); + xhci = val & ROUTER_CS_6_HCI; tbt3 = !(val & ROUTER_CS_6_TNS); @@ -227,9 +251,7 @@ int usb4_switch_setup(struct tb_switch *sw) if (ret) return ret; - parent = tb_switch_parent(sw); - - if (tb_switch_find_port(parent, TB_TYPE_USB3_DOWN)) { + if (sw->link_usb4 && tb_switch_find_port(parent, TB_TYPE_USB3_DOWN)) { val |= ROUTER_CS_5_UTO; xhci = false; } @@ -271,10 +293,11 @@ int usb4_switch_read_uid(struct tb_switch *sw, u64 *uid) return tb_sw_read(sw, uid, TB_CFG_SWITCH, ROUTER_CS_7, 2); } -static int usb4_switch_drom_read_block(struct tb_switch *sw, +static int usb4_switch_drom_read_block(void *data, unsigned int dwaddress, void *buf, size_t dwords) { + struct tb_switch *sw = data; u8 status = 0; u32 metadata; int ret; @@ -311,8 +334,8 @@ static int usb4_switch_drom_read_block(struct tb_switch *sw, int usb4_switch_drom_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size) { - return usb4_switch_do_read_data(sw, address, buf, size, - usb4_switch_drom_read_block); + return usb4_do_read_data(address, buf, size, + usb4_switch_drom_read_block, sw); } static int usb4_set_port_configured(struct tb_port *port, bool configured) @@ -445,9 +468,10 @@ int usb4_switch_nvm_sector_size(struct tb_switch *sw) return metadata & USB4_NVM_SECTOR_SIZE_MASK; } -static int usb4_switch_nvm_read_block(struct tb_switch *sw, +static int usb4_switch_nvm_read_block(void *data, unsigned int dwaddress, void *buf, size_t dwords) { + struct tb_switch *sw = data; u8 status = 0; u32 metadata; int ret; @@ -484,8 +508,8 @@ static int usb4_switch_nvm_read_block(struct tb_switch *sw, int usb4_switch_nvm_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size) { - return usb4_switch_do_read_data(sw, address, buf, size, - usb4_switch_nvm_read_block); + return usb4_do_read_data(address, buf, size, + usb4_switch_nvm_read_block, sw); } static int usb4_switch_nvm_set_offset(struct tb_switch *sw, @@ -510,9 +534,10 @@ static int usb4_switch_nvm_set_offset(struct tb_switch *sw, return status ? -EIO : 0; } -static int usb4_switch_nvm_write_next_block(struct tb_switch *sw, - const void *buf, size_t dwords) +static int usb4_switch_nvm_write_next_block(void *data, const void *buf, + size_t dwords) { + struct tb_switch *sw = data; u8 status; int ret; @@ -546,8 +571,8 @@ int usb4_switch_nvm_write(struct tb_switch *sw, unsigned int address, if (ret) return ret; - return usb4_switch_do_write_data(sw, address, buf, size, - usb4_switch_nvm_write_next_block); + return usb4_do_write_data(address, buf, size, + usb4_switch_nvm_write_next_block, sw); } /** @@ -710,7 +735,7 @@ struct tb_port *usb4_switch_map_pcie_down(struct tb_switch *sw, if (!tb_port_is_pcie_down(p)) continue; - if (pcie_idx == usb4_idx && !tb_pci_port_is_enabled(p)) + if (pcie_idx == usb4_idx) return p; pcie_idx++; @@ -741,7 +766,7 @@ struct tb_port *usb4_switch_map_usb3_down(struct tb_switch *sw, if (!tb_port_is_usb3_down(p)) continue; - if (usb_idx == usb4_idx && !tb_usb3_port_is_enabled(p)) + if (usb_idx == usb4_idx) return p; usb_idx++; @@ -769,3 +794,796 @@ int usb4_port_unlock(struct tb_port *port) val &= ~ADP_CS_4_LCK; return tb_port_write(port, &val, TB_CFG_PORT, ADP_CS_4, 1); } + +static int usb4_port_wait_for_bit(struct tb_port *port, u32 offset, u32 bit, + u32 value, int timeout_msec) +{ + ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec); + + do { + u32 val; + int ret; + + ret = tb_port_read(port, &val, TB_CFG_PORT, offset, 1); + if (ret) + return ret; + + if ((val & bit) == value) + return 0; + + usleep_range(50, 100); + } while (ktime_before(ktime_get(), timeout)); + + return -ETIMEDOUT; +} + +static int usb4_port_read_data(struct tb_port *port, void *data, size_t dwords) +{ + if (dwords > USB4_DATA_DWORDS) + return -EINVAL; + + return tb_port_read(port, data, TB_CFG_PORT, port->cap_usb4 + PORT_CS_2, + dwords); +} + +static int usb4_port_write_data(struct tb_port *port, const void *data, + size_t dwords) +{ + if (dwords > USB4_DATA_DWORDS) + return -EINVAL; + + return tb_port_write(port, data, TB_CFG_PORT, port->cap_usb4 + PORT_CS_2, + dwords); +} + +static int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, + u8 index, u8 reg, void *buf, u8 size) +{ + size_t dwords = DIV_ROUND_UP(size, 4); + int ret; + u32 val; + + if (!port->cap_usb4) + return -EINVAL; + + val = reg; + val |= size << PORT_CS_1_LENGTH_SHIFT; + val |= (target << PORT_CS_1_TARGET_SHIFT) & PORT_CS_1_TARGET_MASK; + if (target == USB4_SB_TARGET_RETIMER) + val |= (index << PORT_CS_1_RETIMER_INDEX_SHIFT); + val |= PORT_CS_1_PND; + + ret = tb_port_write(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_1, 1); + if (ret) + return ret; + + ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1, + PORT_CS_1_PND, 0, 500); + if (ret) + return ret; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_1, 1); + if (ret) + return ret; + + if (val & PORT_CS_1_NR) + return -ENODEV; + if (val & PORT_CS_1_RC) + return -EIO; + + return buf ? usb4_port_read_data(port, buf, dwords) : 0; +} + +static int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target, + u8 index, u8 reg, const void *buf, u8 size) +{ + size_t dwords = DIV_ROUND_UP(size, 4); + int ret; + u32 val; + + if (!port->cap_usb4) + return -EINVAL; + + if (buf) { + ret = usb4_port_write_data(port, buf, dwords); + if (ret) + return ret; + } + + val = reg; + val |= size << PORT_CS_1_LENGTH_SHIFT; + val |= PORT_CS_1_WNR_WRITE; + val |= (target << PORT_CS_1_TARGET_SHIFT) & PORT_CS_1_TARGET_MASK; + if (target == USB4_SB_TARGET_RETIMER) + val |= (index << PORT_CS_1_RETIMER_INDEX_SHIFT); + val |= PORT_CS_1_PND; + + ret = tb_port_write(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_1, 1); + if (ret) + return ret; + + ret = usb4_port_wait_for_bit(port, port->cap_usb4 + PORT_CS_1, + PORT_CS_1_PND, 0, 500); + if (ret) + return ret; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_usb4 + PORT_CS_1, 1); + if (ret) + return ret; + + if (val & PORT_CS_1_NR) + return -ENODEV; + if (val & PORT_CS_1_RC) + return -EIO; + + return 0; +} + +static int usb4_port_sb_op(struct tb_port *port, enum usb4_sb_target target, + u8 index, enum usb4_sb_opcode opcode, int timeout_msec) +{ + ktime_t timeout; + u32 val; + int ret; + + val = opcode; + ret = usb4_port_sb_write(port, target, index, USB4_SB_OPCODE, &val, + sizeof(val)); + if (ret) + return ret; + + timeout = ktime_add_ms(ktime_get(), timeout_msec); + + do { + /* Check results */ + ret = usb4_port_sb_read(port, target, index, USB4_SB_OPCODE, + &val, sizeof(val)); + if (ret) + return ret; + + switch (val) { + case 0: + return 0; + + case USB4_SB_OPCODE_ERR: + return -EAGAIN; + + case USB4_SB_OPCODE_ONS: + return -EOPNOTSUPP; + + default: + if (val != opcode) + return -EIO; + break; + } + } while (ktime_before(ktime_get(), timeout)); + + return -ETIMEDOUT; +} + +/** + * usb4_port_enumerate_retimers() - Send RT broadcast transaction + * @port: USB4 port + * + * This forces the USB4 port to send broadcast RT transaction which + * makes the retimers on the link to assign index to themselves. Returns + * %0 in case of success and negative errno if there was an error. + */ +int usb4_port_enumerate_retimers(struct tb_port *port) +{ + u32 val; + + val = USB4_SB_OPCODE_ENUMERATE_RETIMERS; + return usb4_port_sb_write(port, USB4_SB_TARGET_ROUTER, 0, + USB4_SB_OPCODE, &val, sizeof(val)); +} + +static inline int usb4_port_retimer_op(struct tb_port *port, u8 index, + enum usb4_sb_opcode opcode, + int timeout_msec) +{ + return usb4_port_sb_op(port, USB4_SB_TARGET_RETIMER, index, opcode, + timeout_msec); +} + +/** + * usb4_port_retimer_read() - Read from retimer sideband registers + * @port: USB4 port + * @index: Retimer index + * @reg: Sideband register to read + * @buf: Data from @reg is stored here + * @size: Number of bytes to read + * + * Function reads retimer sideband registers starting from @reg. The + * retimer is connected to @port at @index. Returns %0 in case of + * success, and read data is copied to @buf. If there is no retimer + * present at given @index returns %-ENODEV. In any other failure + * returns negative errno. + */ +int usb4_port_retimer_read(struct tb_port *port, u8 index, u8 reg, void *buf, + u8 size) +{ + return usb4_port_sb_read(port, USB4_SB_TARGET_RETIMER, index, reg, buf, + size); +} + +/** + * usb4_port_retimer_write() - Write to retimer sideband registers + * @port: USB4 port + * @index: Retimer index + * @reg: Sideband register to write + * @buf: Data that is written starting from @reg + * @size: Number of bytes to write + * + * Writes retimer sideband registers starting from @reg. The retimer is + * connected to @port at @index. Returns %0 in case of success. If there + * is no retimer present at given @index returns %-ENODEV. In any other + * failure returns negative errno. + */ +int usb4_port_retimer_write(struct tb_port *port, u8 index, u8 reg, + const void *buf, u8 size) +{ + return usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, reg, buf, + size); +} + +/** + * usb4_port_retimer_is_last() - Is the retimer last on-board retimer + * @port: USB4 port + * @index: Retimer index + * + * If the retimer at @index is last one (connected directly to the + * Type-C port) this function returns %1. If it is not returns %0. If + * the retimer is not present returns %-ENODEV. Otherwise returns + * negative errno. + */ +int usb4_port_retimer_is_last(struct tb_port *port, u8 index) +{ + u32 metadata; + int ret; + + ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_QUERY_LAST_RETIMER, + 500); + if (ret) + return ret; + + ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata, + sizeof(metadata)); + return ret ? ret : metadata & 1; +} + +/** + * usb4_port_retimer_nvm_sector_size() - Read retimer NVM sector size + * @port: USB4 port + * @index: Retimer index + * + * Reads NVM sector size (in bytes) of a retimer at @index. This + * operation can be used to determine whether the retimer supports NVM + * upgrade for example. Returns sector size in bytes or negative errno + * in case of error. Specifically returns %-ENODEV if there is no + * retimer at @index. + */ +int usb4_port_retimer_nvm_sector_size(struct tb_port *port, u8 index) +{ + u32 metadata; + int ret; + + ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_GET_NVM_SECTOR_SIZE, + 500); + if (ret) + return ret; + + ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, &metadata, + sizeof(metadata)); + return ret ? ret : metadata & USB4_NVM_SECTOR_SIZE_MASK; +} + +static int usb4_port_retimer_nvm_set_offset(struct tb_port *port, u8 index, + unsigned int address) +{ + u32 metadata, dwaddress; + int ret; + + dwaddress = address / 4; + metadata = (dwaddress << USB4_NVM_SET_OFFSET_SHIFT) & + USB4_NVM_SET_OFFSET_MASK; + + ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata, + sizeof(metadata)); + if (ret) + return ret; + + return usb4_port_retimer_op(port, index, USB4_SB_OPCODE_NVM_SET_OFFSET, + 500); +} + +struct retimer_info { + struct tb_port *port; + u8 index; +}; + +static int usb4_port_retimer_nvm_write_next_block(void *data, const void *buf, + size_t dwords) + +{ + const struct retimer_info *info = data; + struct tb_port *port = info->port; + u8 index = info->index; + int ret; + + ret = usb4_port_retimer_write(port, index, USB4_SB_DATA, + buf, dwords * 4); + if (ret) + return ret; + + return usb4_port_retimer_op(port, index, + USB4_SB_OPCODE_NVM_BLOCK_WRITE, 1000); +} + +/** + * usb4_port_retimer_nvm_write() - Write to retimer NVM + * @port: USB4 port + * @index: Retimer index + * @address: Byte address where to start the write + * @buf: Data to write + * @size: Size in bytes how much to write + * + * Writes @size bytes from @buf to the retimer NVM. Used for NVM + * upgrade. Returns %0 if the data was written successfully and negative + * errno in case of failure. Specifically returns %-ENODEV if there is + * no retimer at @index. + */ +int usb4_port_retimer_nvm_write(struct tb_port *port, u8 index, unsigned int address, + const void *buf, size_t size) +{ + struct retimer_info info = { .port = port, .index = index }; + int ret; + + ret = usb4_port_retimer_nvm_set_offset(port, index, address); + if (ret) + return ret; + + return usb4_do_write_data(address, buf, size, + usb4_port_retimer_nvm_write_next_block, &info); +} + +/** + * usb4_port_retimer_nvm_authenticate() - Start retimer NVM upgrade + * @port: USB4 port + * @index: Retimer index + * + * After the new NVM image has been written via usb4_port_retimer_nvm_write() + * this function can be used to trigger the NVM upgrade process. If + * successful the retimer restarts with the new NVM and may not have the + * index set so one needs to call usb4_port_enumerate_retimers() to + * force index to be assigned. + */ +int usb4_port_retimer_nvm_authenticate(struct tb_port *port, u8 index) +{ + u32 val; + + /* + * We need to use the raw operation here because once the + * authentication completes the retimer index is not set anymore + * so we do not get back the status now. + */ + val = USB4_SB_OPCODE_NVM_AUTH_WRITE; + return usb4_port_sb_write(port, USB4_SB_TARGET_RETIMER, index, + USB4_SB_OPCODE, &val, sizeof(val)); +} + +/** + * usb4_port_retimer_nvm_authenticate_status() - Read status of NVM upgrade + * @port: USB4 port + * @index: Retimer index + * @status: Raw status code read from metadata + * + * This can be called after usb4_port_retimer_nvm_authenticate() and + * usb4_port_enumerate_retimers() to fetch status of the NVM upgrade. + * + * Returns %0 if the authentication status was successfully read. The + * completion metadata (the result) is then stored into @status. If + * reading the status fails, returns negative errno. + */ +int usb4_port_retimer_nvm_authenticate_status(struct tb_port *port, u8 index, + u32 *status) +{ + u32 metadata, val; + int ret; + + ret = usb4_port_retimer_read(port, index, USB4_SB_OPCODE, &val, + sizeof(val)); + if (ret) + return ret; + + switch (val) { + case 0: + *status = 0; + return 0; + + case USB4_SB_OPCODE_ERR: + ret = usb4_port_retimer_read(port, index, USB4_SB_METADATA, + &metadata, sizeof(metadata)); + if (ret) + return ret; + + *status = metadata & USB4_SB_METADATA_NVM_AUTH_WRITE_MASK; + return 0; + + case USB4_SB_OPCODE_ONS: + return -EOPNOTSUPP; + + default: + return -EIO; + } +} + +static int usb4_port_retimer_nvm_read_block(void *data, unsigned int dwaddress, + void *buf, size_t dwords) +{ + const struct retimer_info *info = data; + struct tb_port *port = info->port; + u8 index = info->index; + u32 metadata; + int ret; + + metadata = dwaddress << USB4_NVM_READ_OFFSET_SHIFT; + if (dwords < USB4_DATA_DWORDS) + metadata |= dwords << USB4_NVM_READ_LENGTH_SHIFT; + + ret = usb4_port_retimer_write(port, index, USB4_SB_METADATA, &metadata, + sizeof(metadata)); + if (ret) + return ret; + + ret = usb4_port_retimer_op(port, index, USB4_SB_OPCODE_NVM_READ, 500); + if (ret) + return ret; + + return usb4_port_retimer_read(port, index, USB4_SB_DATA, buf, + dwords * 4); +} + +/** + * usb4_port_retimer_nvm_read() - Read contents of retimer NVM + * @port: USB4 port + * @index: Retimer index + * @address: NVM address (in bytes) to start reading + * @buf: Data read from NVM is stored here + * @size: Number of bytes to read + * + * Reads retimer NVM and copies the contents to @buf. Returns %0 if the + * read was successful and negative errno in case of failure. + * Specifically returns %-ENODEV if there is no retimer at @index. + */ +int usb4_port_retimer_nvm_read(struct tb_port *port, u8 index, + unsigned int address, void *buf, size_t size) +{ + struct retimer_info info = { .port = port, .index = index }; + + return usb4_do_read_data(address, buf, size, + usb4_port_retimer_nvm_read_block, &info); +} + +/** + * usb4_usb3_port_max_link_rate() - Maximum support USB3 link rate + * @port: USB3 adapter port + * + * Return maximum supported link rate of a USB3 adapter in Mb/s. + * Negative errno in case of error. + */ +int usb4_usb3_port_max_link_rate(struct tb_port *port) +{ + int ret, lr; + u32 val; + + if (!tb_port_is_usb3_down(port) && !tb_port_is_usb3_up(port)) + return -EINVAL; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_4, 1); + if (ret) + return ret; + + lr = (val & ADP_USB3_CS_4_MSLR_MASK) >> ADP_USB3_CS_4_MSLR_SHIFT; + return lr == ADP_USB3_CS_4_MSLR_20G ? 20000 : 10000; +} + +/** + * usb4_usb3_port_actual_link_rate() - Established USB3 link rate + * @port: USB3 adapter port + * + * Return actual established link rate of a USB3 adapter in Mb/s. If the + * link is not up returns %0 and negative errno in case of failure. + */ +int usb4_usb3_port_actual_link_rate(struct tb_port *port) +{ + int ret, lr; + u32 val; + + if (!tb_port_is_usb3_down(port) && !tb_port_is_usb3_up(port)) + return -EINVAL; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_4, 1); + if (ret) + return ret; + + if (!(val & ADP_USB3_CS_4_ULV)) + return 0; + + lr = val & ADP_USB3_CS_4_ALR_MASK; + return lr == ADP_USB3_CS_4_ALR_20G ? 20000 : 10000; +} + +static int usb4_usb3_port_cm_request(struct tb_port *port, bool request) +{ + int ret; + u32 val; + + if (!tb_port_is_usb3_down(port)) + return -EINVAL; + if (tb_route(port->sw)) + return -EINVAL; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_2, 1); + if (ret) + return ret; + + if (request) + val |= ADP_USB3_CS_2_CMR; + else + val &= ~ADP_USB3_CS_2_CMR; + + ret = tb_port_write(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_2, 1); + if (ret) + return ret; + + /* + * We can use val here directly as the CMR bit is in the same place + * as HCA. Just mask out others. + */ + val &= ADP_USB3_CS_2_CMR; + return usb4_port_wait_for_bit(port, port->cap_adap + ADP_USB3_CS_1, + ADP_USB3_CS_1_HCA, val, 1500); +} + +static inline int usb4_usb3_port_set_cm_request(struct tb_port *port) +{ + return usb4_usb3_port_cm_request(port, true); +} + +static inline int usb4_usb3_port_clear_cm_request(struct tb_port *port) +{ + return usb4_usb3_port_cm_request(port, false); +} + +static unsigned int usb3_bw_to_mbps(u32 bw, u8 scale) +{ + unsigned long uframes; + + uframes = bw * 512UL << scale; + return DIV_ROUND_CLOSEST(uframes * 8000, 1000 * 1000); +} + +static u32 mbps_to_usb3_bw(unsigned int mbps, u8 scale) +{ + unsigned long uframes; + + /* 1 uframe is 1/8 ms (125 us) -> 1 / 8000 s */ + uframes = ((unsigned long)mbps * 1000 * 1000) / 8000; + return DIV_ROUND_UP(uframes, 512UL << scale); +} + +static int usb4_usb3_port_read_allocated_bandwidth(struct tb_port *port, + int *upstream_bw, + int *downstream_bw) +{ + u32 val, bw, scale; + int ret; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_2, 1); + if (ret) + return ret; + + ret = tb_port_read(port, &scale, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_3, 1); + if (ret) + return ret; + + scale &= ADP_USB3_CS_3_SCALE_MASK; + + bw = val & ADP_USB3_CS_2_AUBW_MASK; + *upstream_bw = usb3_bw_to_mbps(bw, scale); + + bw = (val & ADP_USB3_CS_2_ADBW_MASK) >> ADP_USB3_CS_2_ADBW_SHIFT; + *downstream_bw = usb3_bw_to_mbps(bw, scale); + + return 0; +} + +/** + * usb4_usb3_port_allocated_bandwidth() - Bandwidth allocated for USB3 + * @port: USB3 adapter port + * @upstream_bw: Allocated upstream bandwidth is stored here + * @downstream_bw: Allocated downstream bandwidth is stored here + * + * Stores currently allocated USB3 bandwidth into @upstream_bw and + * @downstream_bw in Mb/s. Returns %0 in case of success and negative + * errno in failure. + */ +int usb4_usb3_port_allocated_bandwidth(struct tb_port *port, int *upstream_bw, + int *downstream_bw) +{ + int ret; + + ret = usb4_usb3_port_set_cm_request(port); + if (ret) + return ret; + + ret = usb4_usb3_port_read_allocated_bandwidth(port, upstream_bw, + downstream_bw); + usb4_usb3_port_clear_cm_request(port); + + return ret; +} + +static int usb4_usb3_port_read_consumed_bandwidth(struct tb_port *port, + int *upstream_bw, + int *downstream_bw) +{ + u32 val, bw, scale; + int ret; + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_1, 1); + if (ret) + return ret; + + ret = tb_port_read(port, &scale, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_3, 1); + if (ret) + return ret; + + scale &= ADP_USB3_CS_3_SCALE_MASK; + + bw = val & ADP_USB3_CS_1_CUBW_MASK; + *upstream_bw = usb3_bw_to_mbps(bw, scale); + + bw = (val & ADP_USB3_CS_1_CDBW_MASK) >> ADP_USB3_CS_1_CDBW_SHIFT; + *downstream_bw = usb3_bw_to_mbps(bw, scale); + + return 0; +} + +static int usb4_usb3_port_write_allocated_bandwidth(struct tb_port *port, + int upstream_bw, + int downstream_bw) +{ + u32 val, ubw, dbw, scale; + int ret; + + /* Read the used scale, hardware default is 0 */ + ret = tb_port_read(port, &scale, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_3, 1); + if (ret) + return ret; + + scale &= ADP_USB3_CS_3_SCALE_MASK; + ubw = mbps_to_usb3_bw(upstream_bw, scale); + dbw = mbps_to_usb3_bw(downstream_bw, scale); + + ret = tb_port_read(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_2, 1); + if (ret) + return ret; + + val &= ~(ADP_USB3_CS_2_AUBW_MASK | ADP_USB3_CS_2_ADBW_MASK); + val |= dbw << ADP_USB3_CS_2_ADBW_SHIFT; + val |= ubw; + + return tb_port_write(port, &val, TB_CFG_PORT, + port->cap_adap + ADP_USB3_CS_2, 1); +} + +/** + * usb4_usb3_port_allocate_bandwidth() - Allocate bandwidth for USB3 + * @port: USB3 adapter port + * @upstream_bw: New upstream bandwidth + * @downstream_bw: New downstream bandwidth + * + * This can be used to set how much bandwidth is allocated for the USB3 + * tunneled isochronous traffic. @upstream_bw and @downstream_bw are the + * new values programmed to the USB3 adapter allocation registers. If + * the values are lower than what is currently consumed the allocation + * is set to what is currently consumed instead (consumed bandwidth + * cannot be taken away by CM). The actual new values are returned in + * @upstream_bw and @downstream_bw. + * + * Returns %0 in case of success and negative errno if there was a + * failure. + */ +int usb4_usb3_port_allocate_bandwidth(struct tb_port *port, int *upstream_bw, + int *downstream_bw) +{ + int ret, consumed_up, consumed_down, allocate_up, allocate_down; + + ret = usb4_usb3_port_set_cm_request(port); + if (ret) + return ret; + + ret = usb4_usb3_port_read_consumed_bandwidth(port, &consumed_up, + &consumed_down); + if (ret) + goto err_request; + + /* Don't allow it go lower than what is consumed */ + allocate_up = max(*upstream_bw, consumed_up); + allocate_down = max(*downstream_bw, consumed_down); + + ret = usb4_usb3_port_write_allocated_bandwidth(port, allocate_up, + allocate_down); + if (ret) + goto err_request; + + *upstream_bw = allocate_up; + *downstream_bw = allocate_down; + +err_request: + usb4_usb3_port_clear_cm_request(port); + return ret; +} + +/** + * usb4_usb3_port_release_bandwidth() - Release allocated USB3 bandwidth + * @port: USB3 adapter port + * @upstream_bw: New allocated upstream bandwidth + * @downstream_bw: New allocated downstream bandwidth + * + * Releases USB3 allocated bandwidth down to what is actually consumed. + * The new bandwidth is returned in @upstream_bw and @downstream_bw. + * + * Returns 0% in success and negative errno in case of failure. + */ +int usb4_usb3_port_release_bandwidth(struct tb_port *port, int *upstream_bw, + int *downstream_bw) +{ + int ret, consumed_up, consumed_down; + + ret = usb4_usb3_port_set_cm_request(port); + if (ret) + return ret; + + ret = usb4_usb3_port_read_consumed_bandwidth(port, &consumed_up, + &consumed_down); + if (ret) + goto err_request; + + /* + * Always keep 1000 Mb/s to make sure xHCI has at least some + * bandwidth available for isochronous traffic. + */ + if (consumed_up < 1000) + consumed_up = 1000; + if (consumed_down < 1000) + consumed_down = 1000; + + ret = usb4_usb3_port_write_allocated_bandwidth(port, consumed_up, + consumed_down); + if (ret) + goto err_request; + + *upstream_bw = consumed_up; + *downstream_bw = consumed_down; + +err_request: + usb4_usb3_port_clear_cm_request(port); + return ret; +} diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index 053f918e00e8bcf6b31e855f7a74ff2fcbd7db99..48907853732ac2a2f56a38b4d87849c33fbacbbe 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -501,6 +501,55 @@ void tb_unregister_protocol_handler(struct tb_protocol_handler *handler) } EXPORT_SYMBOL_GPL(tb_unregister_protocol_handler); +static int rebuild_property_block(void) +{ + u32 *block, len; + int ret; + + ret = tb_property_format_dir(xdomain_property_dir, NULL, 0); + if (ret < 0) + return ret; + + len = ret; + + block = kcalloc(len, sizeof(u32), GFP_KERNEL); + if (!block) + return -ENOMEM; + + ret = tb_property_format_dir(xdomain_property_dir, block, len); + if (ret) { + kfree(block); + return ret; + } + + kfree(xdomain_property_block); + xdomain_property_block = block; + xdomain_property_block_len = len; + xdomain_property_block_gen++; + + return 0; +} + +static void finalize_property_block(void) +{ + const struct tb_property *nodename; + + /* + * On first XDomain connection we set up the the system + * nodename. This delayed here because userspace may not have it + * set when the driver is first probed. + */ + mutex_lock(&xdomain_lock); + nodename = tb_property_find(xdomain_property_dir, "deviceid", + TB_PROPERTY_TYPE_TEXT); + if (!nodename) { + tb_property_add_text(xdomain_property_dir, "deviceid", + utsname()->nodename); + rebuild_property_block(); + } + mutex_unlock(&xdomain_lock); +} + static void tb_xdp_handle_request(struct work_struct *work) { struct xdomain_request_work *xw = container_of(work, typeof(*xw), work); @@ -529,6 +578,8 @@ static void tb_xdp_handle_request(struct work_struct *work) goto out; } + finalize_property_block(); + switch (pkg->type) { case PROPERTIES_REQUEST: ret = tb_xdp_properties_response(tb, ctl, route, sequence, uuid, @@ -1569,35 +1620,6 @@ bool tb_xdomain_handle_request(struct tb *tb, enum tb_cfg_pkg_type type, return ret > 0; } -static int rebuild_property_block(void) -{ - u32 *block, len; - int ret; - - ret = tb_property_format_dir(xdomain_property_dir, NULL, 0); - if (ret < 0) - return ret; - - len = ret; - - block = kcalloc(len, sizeof(u32), GFP_KERNEL); - if (!block) - return -ENOMEM; - - ret = tb_property_format_dir(xdomain_property_dir, block, len); - if (ret) { - kfree(block); - return ret; - } - - kfree(xdomain_property_block); - xdomain_property_block = block; - xdomain_property_block_len = len; - xdomain_property_block_gen++; - - return 0; -} - static int update_xdomain(struct device *dev, void *data) { struct tb_xdomain *xd; @@ -1702,8 +1724,6 @@ EXPORT_SYMBOL_GPL(tb_unregister_property_dir); int tb_xdomain_init(void) { - int ret; - xdomain_property_dir = tb_property_create_dir(NULL); if (!xdomain_property_dir) return -ENOMEM; @@ -1712,22 +1732,16 @@ int tb_xdomain_init(void) * Initialize standard set of properties without any service * directories. Those will be added by service drivers * themselves when they are loaded. + * + * We also add node name later when first connection is made. */ tb_property_add_immediate(xdomain_property_dir, "vendorid", PCI_VENDOR_ID_INTEL); tb_property_add_text(xdomain_property_dir, "vendorid", "Intel Corp."); tb_property_add_immediate(xdomain_property_dir, "deviceid", 0x1); - tb_property_add_text(xdomain_property_dir, "deviceid", - utsname()->nodename); tb_property_add_immediate(xdomain_property_dir, "devicerv", 0x80000100); - ret = rebuild_property_block(); - if (ret) { - tb_property_free_dir(xdomain_property_dir); - xdomain_property_dir = NULL; - } - - return ret; + return 0; } void tb_xdomain_exit(void) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 5d41f85a744544191291b5f788260a1d096c9a30..ea66f8f385bae8b50b6accb250585db24ade1e5c 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -408,7 +408,7 @@ static ssize_t adsl_state_store(struct device *dev, case CXPOLL_STOPPING: /* abort stop request */ instance->poll_state = CXPOLL_POLLING; - /* fall through */ + fallthrough; case CXPOLL_POLLING: case CXPOLL_SHUTDOWN: /* don't start polling */ @@ -802,7 +802,7 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, case CXPOLL_STOPPING: /* abort stop request */ instance->poll_state = CXPOLL_POLLING; - /* fall through */ + fallthrough; case CXPOLL_POLLING: case CXPOLL_SHUTDOWN: /* don't start polling */ diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index e9fed9a8873771e326d7bc0e36a89ea66cad655a..786299892c7f46e8948825d194b91e433518c24b 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -570,7 +570,7 @@ MODULE_PARM_DESC(annex, #define LOAD_INTERNAL 0xA0 #define F8051_USBCS 0x7f92 -/** +/* * uea_send_modem_cmd - Send a command for pre-firmware devices. */ static int uea_send_modem_cmd(struct usb_device *usb, @@ -672,7 +672,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, uea_leaves(usb); } -/** +/* * uea_load_firmware - Load usb firmware for pre-firmware devices. */ static int uea_load_firmware(struct usb_device *usb, unsigned int ver) diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c index c39eee17c0e461441f2faf0fe7bdd7d5ff1052c9..39f2376663314936634e556c37d4ca8ff99b6eae 100644 --- a/drivers/usb/c67x00/c67x00-hcd.c +++ b/drivers/usb/c67x00/c67x00-hcd.c @@ -228,7 +228,7 @@ static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, * Main part of host controller driver */ -/** +/* * c67x00_hcd_irq * * This function is called from the interrupt handler in c67x00-drv.c @@ -260,7 +260,7 @@ static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg) } } -/** +/* * c67x00_hcd_start: Host controller start hook */ static int c67x00_hcd_start(struct usb_hcd *hcd) @@ -272,7 +272,7 @@ static int c67x00_hcd_start(struct usb_hcd *hcd) return 0; } -/** +/* * c67x00_hcd_stop: Host controller stop hook */ static void c67x00_hcd_stop(struct usb_hcd *hcd) diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c index e1fe3603140a85fe4fd99bf8695cd4f3f069e62c..7a214a3a6cc708d6829314b1ea47dec2c7e167f9 100644 --- a/drivers/usb/c67x00/c67x00-ll-hpi.c +++ b/drivers/usb/c67x00/c67x00-ll-hpi.c @@ -262,7 +262,7 @@ u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie) return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)); } -/** +/* * c67x00_ll_usb_clear_status - clear the USB status bits */ void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits) @@ -395,7 +395,7 @@ int c67x00_ll_reset(struct c67x00_device *dev) /* -------------------------------------------------------------------------- */ -/** +/* * c67x00_ll_write_mem_le16 - write into c67x00 memory * Only data is little endian, addr has cpu endianess. */ @@ -434,7 +434,7 @@ void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr, } } -/** +/* * c67x00_ll_read_mem_le16 - read from c67x00 memory * Only data is little endian, addr has cpu endianess. */ diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c index 9865750bc31e0aa9dee451d403d758f76ac20c0d..f7f6229082cad4a86d703e5beb545040bdeac256 100644 --- a/drivers/usb/c67x00/c67x00-sched.c +++ b/drivers/usb/c67x00/c67x00-sched.c @@ -23,7 +23,7 @@ /* -------------------------------------------------------------------------- */ -/** +/* * struct c67x00_ep_data: Host endpoint data structure */ struct c67x00_ep_data { @@ -34,7 +34,7 @@ struct c67x00_ep_data { u16 next_frame; /* For int/isoc transactions */ }; -/** +/* * struct c67x00_td * * Hardware parts are little endiannes, SW in CPU endianess. @@ -130,7 +130,7 @@ struct c67x00_urb_priv { /* -------------------------------------------------------------------------- */ -/** +/* * dbg_td - Dump the contents of the TD */ static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) @@ -161,7 +161,7 @@ static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00) return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK; } -/** +/* * frame_add * Software wraparound for framenumbers. */ @@ -170,7 +170,7 @@ static inline u16 frame_add(u16 a, u16 b) return (a + b) & HOST_FRAME_MASK; } -/** +/* * frame_after - is frame a after frame b */ static inline int frame_after(u16 a, u16 b) @@ -179,7 +179,7 @@ static inline int frame_after(u16 a, u16 b) (HOST_FRAME_MASK / 2); } -/** +/* * frame_after_eq - is frame a after or equal to frame b */ static inline int frame_after_eq(u16 a, u16 b) @@ -190,7 +190,7 @@ static inline int frame_after_eq(u16 a, u16 b) /* -------------------------------------------------------------------------- */ -/** +/* * c67x00_release_urb - remove link from all tds to this urb * Disconnects the urb from it's tds, so that it can be given back. * pre: urb->hcpriv != NULL @@ -557,7 +557,7 @@ static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb, /* -------------------------------------------------------------------------- */ -/** +/* * td_addr and buf_addr must be word aligned */ static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb, @@ -685,7 +685,7 @@ static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb) return 0; } -/** +/* * return 0 in case more bandwidth is available, else errorcode */ static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb) @@ -822,7 +822,7 @@ static void c67x00_fill_frame(struct c67x00_hcd *c67x00) /* -------------------------------------------------------------------------- */ -/** +/* * Get TD from C67X00 */ static inline void @@ -970,7 +970,7 @@ static void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td) /* -------------------------------------------------------------------------- */ -/** +/* * c67x00_check_td_list - handle tds which have been processed by the c67x00 * pre: current_td == 0 */ @@ -1045,7 +1045,7 @@ static inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00) return !c67x00_ll_husb_get_current_td(c67x00->sie); } -/** +/* * Send td to C67X00 */ static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td) @@ -1081,7 +1081,7 @@ static void c67x00_send_frame(struct c67x00_hcd *c67x00) /* -------------------------------------------------------------------------- */ -/** +/* * c67x00_do_work - Schedulers state machine */ static void c67x00_do_work(struct c67x00_hcd *c67x00) diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c index e701ab56b0a761c64f6af502fab6f4a2b33ad039..90e246601537c8cdb57c208bdb53723a1ec3e7fb 100644 --- a/drivers/usb/cdns3/cdns3-ti.c +++ b/drivers/usb/cdns3/cdns3-ti.c @@ -2,7 +2,7 @@ /** * cdns3-ti.c - TI specific Glue layer for Cadence USB Controller * - * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com */ #include <linux/bits.h> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 19bbb5b7e6b6c603e478d78a2fc7d1781255a59a..5c1586ec78241cb474cf55bfa381ebf854dea3a4 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -27,13 +27,6 @@ static int cdns3_idle_init(struct cdns3 *cdns); -static inline -struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) -{ - WARN_ON(!cdns->roles[cdns->role]); - return cdns->roles[cdns->role]; -} - static int cdns3_role_start(struct cdns3 *cdns, enum usb_role role) { int ret; @@ -93,7 +86,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns) struct device *dev = cdns->dev; enum usb_dr_mode best_dr_mode; enum usb_dr_mode dr_mode; - int ret = 0; + int ret; dr_mode = usb_get_dr_mode(dev); cdns->role = USB_ROLE_NONE; @@ -184,7 +177,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns) goto err; } - return ret; + return 0; err: cdns3_exit_roles(cdns); return ret; @@ -198,11 +191,17 @@ static int cdns3_core_init_role(struct cdns3 *cdns) */ static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns) { - enum usb_role role; + enum usb_role role = USB_ROLE_NONE; int id, vbus; - if (cdns->dr_mode != USB_DR_MODE_OTG) - goto not_otg; + if (cdns->dr_mode != USB_DR_MODE_OTG) { + if (cdns3_is_host(cdns)) + role = USB_ROLE_HOST; + if (cdns3_is_device(cdns)) + role = USB_ROLE_DEVICE; + + return role; + } id = cdns3_get_id(cdns); vbus = cdns3_get_vbus(cdns); @@ -239,14 +238,6 @@ static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns) dev_dbg(cdns->dev, "role %d -> %d\n", cdns->role, role); return role; - -not_otg: - if (cdns3_is_host(cdns)) - role = USB_ROLE_HOST; - if (cdns3_is_device(cdns)) - role = USB_ROLE_DEVICE; - - return role; } static int cdns3_idle_role_start(struct cdns3 *cdns) @@ -282,7 +273,7 @@ static int cdns3_idle_init(struct cdns3 *cdns) /** * cdns3_hw_role_switch - switch roles based on HW state - * @cdns3: controller + * @cdns: controller */ int cdns3_hw_role_switch(struct cdns3 *cdns) { @@ -320,7 +311,7 @@ int cdns3_hw_role_switch(struct cdns3 *cdns) /** * cdsn3_role_get - get current role of controller. * - * @dev: Pointer to device structure + * @sw: pointer to USB role switch structure * * Returns role */ @@ -334,8 +325,8 @@ static enum usb_role cdns3_role_get(struct usb_role_switch *sw) /** * cdns3_role_set - set current role of controller. * - * @dev: pointer to device object - * @role - the previous role + * @sw: pointer to USB role switch structure + * @role: the previous role * Handles below events: * - Role switch for dual-role devices * - USB_ROLE_GADGET <--> USB_ROLE_NONE for peripheral-only devices @@ -356,7 +347,6 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role) case USB_ROLE_HOST: break; default: - ret = -EPERM; goto pm_put; } } @@ -367,17 +357,14 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role) case USB_ROLE_DEVICE: break; default: - ret = -EPERM; goto pm_put; } } cdns3_role_stop(cdns); ret = cdns3_role_start(cdns, role); - if (ret) { + if (ret) dev_err(cdns->dev, "set role %d has failed\n", role); - ret = -EPERM; - } pm_put: pm_runtime_put_sync(cdns->dev); @@ -402,7 +389,7 @@ static int cdns3_probe(struct platform_device *pdev) ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) { dev_err(dev, "error setting dma mask: %d\n", ret); - return -ENODEV; + return ret; } cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); @@ -436,8 +423,7 @@ static int cdns3_probe(struct platform_device *pdev) if (cdns->dev_irq < 0) dev_err(dev, "couldn't get peripheral irq\n"); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dev"); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource_byname(pdev, "dev"); if (IS_ERR(regs)) return PTR_ERR(regs); cdns->dev_regs = regs; diff --git a/drivers/usb/cdns3/drd.c b/drivers/usb/cdns3/drd.c index 58089841ed52d0999d9dc3b2f22b7d1d927db2fd..6234bcd6158aac475df446ec9275238196e5ef16 100644 --- a/drivers/usb/cdns3/drd.c +++ b/drivers/usb/cdns3/drd.c @@ -29,7 +29,6 @@ */ int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) { - int ret = 0; u32 reg; switch (mode) { @@ -61,7 +60,7 @@ int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) return -EINVAL; } - return ret; + return 0; } int cdns3_get_id(struct cdns3 *cdns) @@ -84,25 +83,25 @@ int cdns3_get_vbus(struct cdns3 *cdns) return vbus; } -int cdns3_is_host(struct cdns3 *cdns) +bool cdns3_is_host(struct cdns3 *cdns) { if (cdns->dr_mode == USB_DR_MODE_HOST) - return 1; - else if (!cdns3_get_id(cdns)) - return 1; + return true; + else if (cdns3_get_id(cdns) == CDNS3_ID_HOST) + return true; - return 0; + return false; } -int cdns3_is_device(struct cdns3 *cdns) +bool cdns3_is_device(struct cdns3 *cdns) { if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL) - return 1; + return true; else if (cdns->dr_mode == USB_DR_MODE_OTG) - if (cdns3_get_id(cdns)) - return 1; + if (cdns3_get_id(cdns) == CDNS3_ID_PERIPHERAL) + return true; - return 0; + return false; } /** @@ -125,85 +124,97 @@ static void cdns3_otg_enable_irq(struct cdns3 *cdns) } /** - * cdns3_drd_switch_host - start/stop host - * @cdns: Pointer to controller context structure - * @on: 1 for start, 0 for stop + * cdns3_drd_host_on - start host. + * @cdns: Pointer to controller context structure. * - * Returns 0 on success otherwise negative errno + * Returns 0 on success otherwise negative errno. */ -int cdns3_drd_switch_host(struct cdns3 *cdns, int on) +int cdns3_drd_host_on(struct cdns3 *cdns) { - int ret, val; - u32 reg = OTGCMD_OTG_DIS; + u32 val; + int ret; - /* switch OTG core */ - if (on) { - writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd); - - dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n"); - ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val, - val & OTGSTS_XHCI_READY, - 1, 100000); - if (ret) { - dev_err(cdns->dev, "timeout waiting for xhci_ready\n"); - return ret; - } - } else { - writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | - OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, - &cdns->otg_regs->cmd); - /* Waiting till H_IDLE state.*/ - readl_poll_timeout_atomic(&cdns->otg_regs->state, val, - !(val & OTGSTATE_HOST_STATE_MASK), - 1, 2000000); - } + /* Enable host mode. */ + writel(OTGCMD_HOST_BUS_REQ | OTGCMD_OTG_DIS, + &cdns->otg_regs->cmd); - return 0; + dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n"); + ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val, + val & OTGSTS_XHCI_READY, 1, 100000); + + if (ret) + dev_err(cdns->dev, "timeout waiting for xhci_ready\n"); + + return ret; } /** - * cdns3_drd_switch_gadget - start/stop gadget - * @cdns: Pointer to controller context structure - * @on: 1 for start, 0 for stop + * cdns3_drd_host_off - stop host. + * @cdns: Pointer to controller context structure. + */ +void cdns3_drd_host_off(struct cdns3 *cdns) +{ + u32 val; + + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, + &cdns->otg_regs->cmd); + + /* Waiting till H_IDLE state.*/ + readl_poll_timeout_atomic(&cdns->otg_regs->state, val, + !(val & OTGSTATE_HOST_STATE_MASK), + 1, 2000000); +} + +/** + * cdns3_drd_gadget_on - start gadget. + * @cdns: Pointer to controller context structure. * * Returns 0 on success otherwise negative errno */ -int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) +int cdns3_drd_gadget_on(struct cdns3 *cdns) { int ret, val; u32 reg = OTGCMD_OTG_DIS; /* switch OTG core */ - if (on) { - writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd); + writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd); - dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n"); + dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n"); - ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val, - val & OTGSTS_DEV_READY, - 1, 100000); - if (ret) { - dev_err(cdns->dev, "timeout waiting for dev_ready\n"); - return ret; - } - } else { - /* - * driver should wait at least 10us after disabling Device - * before turning-off Device (DEV_BUS_DROP) - */ - usleep_range(20, 30); - writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | - OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, - &cdns->otg_regs->cmd); - /* Waiting till DEV_IDLE state.*/ - readl_poll_timeout_atomic(&cdns->otg_regs->state, val, - !(val & OTGSTATE_DEV_STATE_MASK), - 1, 2000000); + ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val, + val & OTGSTS_DEV_READY, + 1, 100000); + if (ret) { + dev_err(cdns->dev, "timeout waiting for dev_ready\n"); + return ret; } return 0; } +/** + * cdns3_drd_gadget_off - stop gadget. + * @cdns: Pointer to controller context structure. + */ +void cdns3_drd_gadget_off(struct cdns3 *cdns) +{ + u32 val; + + /* + * Driver should wait at least 10us after disabling Device + * before turning-off Device (DEV_BUS_DROP). + */ + usleep_range(20, 30); + writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP | + OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF, + &cdns->otg_regs->cmd); + /* Waiting till DEV_IDLE state.*/ + readl_poll_timeout_atomic(&cdns->otg_regs->state, val, + !(val & OTGSTATE_DEV_STATE_MASK), + 1, 2000000); +} + /** * cdns3_init_otg_mode - initialize drd controller * @cdns: Pointer to controller context structure @@ -212,7 +223,7 @@ int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) */ static int cdns3_init_otg_mode(struct cdns3 *cdns) { - int ret = 0; + int ret; cdns3_otg_disable_irq(cdns); /* clear all interrupts */ @@ -223,7 +234,8 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns) return ret; cdns3_otg_enable_irq(cdns); - return ret; + + return 0; } /** @@ -234,7 +246,7 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns) */ int cdns3_drd_update_mode(struct cdns3 *cdns) { - int ret = 0; + int ret; switch (cdns->dr_mode) { case USB_DR_MODE_PERIPHERAL: @@ -279,12 +291,12 @@ static irqreturn_t cdns3_drd_irq(int irq, void *data) u32 reg; if (cdns->dr_mode != USB_DR_MODE_OTG) - return ret; + return IRQ_NONE; reg = readl(&cdns->otg_regs->ivect); if (!reg) - return ret; + return IRQ_NONE; if (reg & OTGIEN_ID_CHANGE_INT) { dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n", @@ -307,8 +319,8 @@ static irqreturn_t cdns3_drd_irq(int irq, void *data) int cdns3_drd_init(struct cdns3 *cdns) { void __iomem *regs; - int ret = 0; u32 state; + int ret; regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res); if (IS_ERR(regs)) @@ -359,19 +371,18 @@ int cdns3_drd_init(struct cdns3 *cdns) cdns3_drd_thread_irq, IRQF_SHARED, dev_name(cdns->dev), cdns); - if (ret) { dev_err(cdns->dev, "couldn't get otg_irq\n"); return ret; } state = readl(&cdns->otg_regs->sts); - if (OTGSTS_OTG_NRDY(state) != 0) { + if (OTGSTS_OTG_NRDY(state)) { dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n"); return -ENODEV; } - return ret; + return 0; } int cdns3_drd_exit(struct cdns3 *cdns) diff --git a/drivers/usb/cdns3/drd.h b/drivers/usb/cdns3/drd.h index 04e01c4d23775755c4a54f904c7e5ef77dde40b6..7e7cf7fa2dd3d2680a00cbc545b40688f01a5c2b 100644 --- a/drivers/usb/cdns3/drd.h +++ b/drivers/usb/cdns3/drd.h @@ -153,15 +153,20 @@ struct cdns3_otg_common_regs { /* Only for CDNS3_CONTROLLER_V0 version */ #define OVERRIDE_IDPULLUP_V0 BIT(24) -int cdns3_is_host(struct cdns3 *cdns); -int cdns3_is_device(struct cdns3 *cdns); +#define CDNS3_ID_PERIPHERAL 1 +#define CDNS3_ID_HOST 0 + +bool cdns3_is_host(struct cdns3 *cdns); +bool cdns3_is_device(struct cdns3 *cdns); int cdns3_get_id(struct cdns3 *cdns); int cdns3_get_vbus(struct cdns3 *cdns); int cdns3_drd_init(struct cdns3 *cdns); int cdns3_drd_exit(struct cdns3 *cdns); int cdns3_drd_update_mode(struct cdns3 *cdns); -int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on); -int cdns3_drd_switch_host(struct cdns3 *cdns, int on); +int cdns3_drd_gadget_on(struct cdns3 *cdns); +void cdns3_drd_gadget_off(struct cdns3 *cdns); +int cdns3_drd_host_on(struct cdns3 *cdns); +void cdns3_drd_host_off(struct cdns3 *cdns); int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode); #endif /* __LINUX_CDNS3_DRD */ diff --git a/drivers/usb/cdns3/ep0.c b/drivers/usb/cdns3/ep0.c index 5aa69980e7ff535b527d2a082fa5f9d1c1e4cd2a..d9779abc65b2b79e3dd70889a9d786a0436269a4 100644 --- a/drivers/usb/cdns3/ep0.c +++ b/drivers/usb/cdns3/ep0.c @@ -29,6 +29,7 @@ static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = { * @length: data length * @erdy: set it to 1 when ERDY packet should be sent - * exit from flow control state + * @zlp: add zero length packet */ static void cdns3_ep0_run_transfer(struct cdns3_device *priv_dev, dma_addr_t dma_addr, @@ -122,8 +123,6 @@ static void cdns3_ep0_complete_setup(struct cdns3_device *priv_dev, priv_dev->ep0_stage = CDNS3_SETUP_STAGE; writel((send_erdy ? EP_CMD_ERDY : 0) | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); - - cdns3_allow_enable_l1(priv_dev, 1); } /** @@ -160,13 +159,12 @@ static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, if (result) return result; - if (config) { - cdns3_set_hw_configuration(priv_dev); - } else { + if (!config) { cdns3_hw_reset_eps_config(priv_dev); usb_gadget_set_state(&priv_dev->gadget, USB_STATE_ADDRESS); } + break; case USB_STATE_CONFIGURED: result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); @@ -227,7 +225,7 @@ static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev, /** * cdns3_req_ep0_get_status - Handling of GET_STATUS standard USB request * @priv_dev: extended gadget object - * @ctrl_req: pointer to received setup packet + * @ctrl: pointer to received setup packet * * Returns 0 if success, error code on error */ @@ -329,10 +327,10 @@ static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev, tmode >>= 8; switch (tmode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: cdns3_set_register_bit(&priv_dev->regs->usb_cmd, USB_CMD_STMODE | USB_STS_TMODE_SEL(tmode - 1)); @@ -401,7 +399,7 @@ static int cdns3_ep0_feature_handle_endpoint(struct cdns3_device *priv_dev, * Handling of GET/SET_FEATURE standard USB request * * @priv_dev: extended gadget object - * @ctrl_req: pointer to received setup packet + * @ctrl: pointer to received setup packet * @set: must be set to 1 for SET_FEATURE request * * Returns 0 if success, error code on error @@ -610,7 +608,7 @@ static bool cdns3_check_new_setup(struct cdns3_device *priv_dev) { u32 ep_sts_reg; - cdns3_select_ep(priv_dev, 0 | USB_DIR_OUT); + cdns3_select_ep(priv_dev, USB_DIR_OUT); ep_sts_reg = readl(&priv_dev->regs->ep_sts); return !!(ep_sts_reg & (EP_STS_SETUP | EP_STS_STPWAIT)); @@ -639,7 +637,6 @@ void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) if (priv_dev->wait_for_setup && ep_sts_reg & EP_STS_IOC) { priv_dev->wait_for_setup = 0; - cdns3_allow_enable_l1(priv_dev, 0); cdns3_ep0_setup_phase(priv_dev); } else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { priv_dev->ep0_data_dir = dir; @@ -654,6 +651,9 @@ void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) /** * cdns3_gadget_ep0_enable + * @ep: pointer to endpoint zero object + * @desc: pointer to usb endpoint descriptor + * * Function shouldn't be called by gadget driver, * endpoint 0 is allways active */ @@ -665,6 +665,8 @@ static int cdns3_gadget_ep0_enable(struct usb_ep *ep, /** * cdns3_gadget_ep0_disable + * @ep: pointer to endpoint zero object + * * Function shouldn't be called by gadget driver, * endpoint 0 is allways active */ @@ -701,7 +703,6 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep, struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); struct cdns3_device *priv_dev = priv_ep->cdns3_dev; unsigned long flags; - int erdy_sent = 0; int ret = 0; u8 zlp = 0; @@ -717,15 +718,8 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep, /* send STATUS stage. Should be called only for SET_CONFIGURATION */ if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) { cdns3_select_ep(priv_dev, 0x00); - - erdy_sent = !priv_dev->hw_configured_flag; cdns3_set_hw_configuration(priv_dev); - - if (!erdy_sent) - cdns3_ep0_complete_setup(priv_dev, 0, 1); - - cdns3_allow_enable_l1(priv_dev, 1); - + cdns3_ep0_complete_setup(priv_dev, 0, 1); request->actual = 0; priv_dev->status_completion_no_call = true; priv_dev->pending_status_request = request; @@ -860,7 +854,7 @@ void cdns3_ep0_config(struct cdns3_device *priv_dev) /** * cdns3_init_ep0 Initializes software endpoint 0 of gadget * @priv_dev: extended gadget object - * @ep_priv: extended endpoint object + * @priv_ep: extended endpoint object * * Returns 0 on success else error code. */ diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 5e24c2e57c0d8c85eea214e5be36fd9bd794ff44..dea649ee173baee1daa54ece02e7f4f28798d581 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -242,9 +242,10 @@ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) return -ENOMEM; priv_ep->alloc_ring_size = ring_size; - memset(priv_ep->trb_pool, 0, ring_size); } + memset(priv_ep->trb_pool, 0, ring_size); + priv_ep->num_trbs = num_trbs; if (!priv_ep->num) @@ -421,7 +422,7 @@ static int cdns3_start_all_request(struct cdns3_device *priv_dev, if ((priv_req->flags & REQUEST_INTERNAL) || (priv_ep->flags & EP_TDLCHK_EN) || priv_ep->use_streams) { - trace_printk("Blocking external request\n"); + dev_dbg(priv_dev->dev, "Blocking external request\n"); return ret; } } @@ -644,7 +645,7 @@ static void cdns3_wa2_remove_old_request(struct cdns3_endpoint *priv_ep) /** * cdns3_wa2_descmissing_packet - handles descriptor missing event. - * @priv_dev: extended gadget object + * @priv_ep: extended gadget object * * This function is used only for WA2. For more information see Work around 2 * description. @@ -1080,6 +1081,7 @@ static int cdns3_ep_run_stream_transfer(struct cdns3_endpoint *priv_ep, /** * cdns3_ep_run_transfer - start transfer on no-default endpoint hardware * @priv_ep: endpoint object + * @request: request object * * Returns zero on success or negative value on failure */ @@ -1314,7 +1316,6 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) return; writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf); - writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd); cdns3_set_register_bit(&priv_dev->regs->usb_conf, USB_CONF_U1EN | USB_CONF_U2EN); @@ -1331,6 +1332,8 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) cdns3_start_all_request(priv_dev, priv_ep); } } + + cdns3_allow_enable_l1(priv_dev, 1); } /** @@ -1809,8 +1812,8 @@ static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) struct cdns3_device *priv_dev = data; irqreturn_t ret = IRQ_NONE; unsigned long flags; - int bit; - u32 reg; + unsigned int bit; + unsigned long reg; spin_lock_irqsave(&priv_dev->lock, flags); @@ -1841,7 +1844,7 @@ static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) if (!reg) goto irqend; - for_each_set_bit(bit, (unsigned long *)®, + for_each_set_bit(bit, ®, sizeof(u32) * BITS_PER_BYTE) { cdns3_check_ep_interrupt_proceed(priv_dev->eps[bit]); ret = IRQ_HANDLED; @@ -2568,7 +2571,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, /** * __cdns3_gadget_ep_set_halt Sets stall on selected endpoint * Should be called after acquiring spin_lock and selecting ep - * @ep: endpoint object to set stall on. + * @priv_ep: endpoint object to set stall on. */ void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep) { @@ -2589,7 +2592,7 @@ void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep) /** * __cdns3_gadget_ep_clear_halt Clears stall on selected endpoint * Should be called after acquiring spin_lock and selecting ep - * @ep: endpoint object to clear stall on + * @priv_ep: endpoint object to clear stall on */ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep) { @@ -2814,7 +2817,7 @@ static int cdns3_gadget_udc_start(struct usb_gadget *gadget, dev_err(priv_dev->dev, "invalid maximum_speed parameter %d\n", max_speed); - /* fall through */ + fallthrough; case USB_SPEED_UNKNOWN: /* default to superspeed */ max_speed = USB_SPEED_SUPER; @@ -2890,7 +2893,7 @@ static void cdns3_free_all_eps(struct cdns3_device *priv_dev) /** * cdns3_init_eps Initializes software endpoints of gadget - * @cdns3: extended gadget object + * @priv_dev: extended gadget object * * Returns 0 on success, error code elsewhere */ @@ -3014,7 +3017,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns) kfree(priv_dev->zlp_buf); kfree(priv_dev); cdns->gadget_dev = NULL; - cdns3_drd_switch_gadget(cdns, 0); + cdns3_drd_gadget_off(cdns); } static int cdns3_gadget_start(struct cdns3 *cdns) @@ -3055,7 +3058,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns) default: dev_err(cdns->dev, "invalid maximum_speed parameter %d\n", max_speed); - /* fall through */ + fallthrough; case USB_SPEED_UNKNOWN: /* default to superspeed */ max_speed = USB_SPEED_SUPER; @@ -3145,7 +3148,7 @@ static int __cdns3_gadget_init(struct cdns3 *cdns) return ret; } - cdns3_drd_switch_gadget(cdns, 1); + cdns3_drd_gadget_on(cdns); pm_runtime_get_sync(cdns->dev); ret = cdns3_gadget_start(cdns); @@ -3202,7 +3205,7 @@ static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated) /** * cdns3_gadget_init - initialize device structure * - * cdns: cdns3 instance + * @cdns: cdns3 instance * * This function initializes the gadget. */ diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index ad788bf3fe4f6f8e9ac1865fd3d6c6ca518ba341..36c63d9ecd37fff83c8f40b8f262bf24dad5727d 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -19,7 +19,7 @@ static int __cdns3_host_init(struct cdns3 *cdns) struct platform_device *xhci; int ret; - cdns3_drd_switch_host(cdns, 1); + cdns3_drd_host_on(cdns); xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); if (!xhci) { @@ -53,7 +53,7 @@ static void cdns3_host_exit(struct cdns3 *cdns) { platform_device_unregister(cdns->host_dev); cdns->host_dev = NULL; - cdns3_drd_switch_host(cdns, 0); + cdns3_drd_host_off(cdns); } int cdns3_host_init(struct cdns3 *cdns) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 5ae16368a0c75a06588b0ae3fa97ac7a71d5e274..c39e2b615ac6d179c822250e7bc33b8c1b41f64b 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -462,6 +462,10 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (!IS_ERR(pdata.vbus_extcon.edev) || of_property_read_bool(np, "usb-role-switch")) data->usbmisc_data->ext_vbus = 1; + + /* usbmisc needs to know dr mode to choose wakeup setting */ + data->usbmisc_data->available_role = + ci_hdrc_query_available_role(data->ci_pdev); } ret = imx_usbmisc_init_post(data->usbmisc_data); diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 727d02b6dbd3192ccec2db8e0d76a3bf4fd1a50d..99f846119c00418eb3383f4bee91e8a864f9bd7e 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -25,6 +25,7 @@ struct imx_usbmisc_data { unsigned int ext_id:1; /* ID from exteranl event */ unsigned int ext_vbus:1; /* Vbus from exteranl event */ struct usb_phy *usb_phy; + enum usb_dr_mode available_role; /* runtime usb dr mode */ }; int imx_usbmisc_init(struct imx_usbmisc_data *data); diff --git a/drivers/usb/chipidea/ci_hdrc_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c index 49a61549cee678324429aca80433a5f07a68e156..d63479e1ad104ec9f0189c29044428a62f46265d 100644 --- a/drivers/usb/chipidea/ci_hdrc_pci.c +++ b/drivers/usb/chipidea/ci_hdrc_pci.c @@ -120,7 +120,7 @@ static void ci_hdrc_pci_remove(struct pci_dev *pdev) usb_phy_generic_unregister(ci->phy); } -/** +/* * PCI device table * PCI device structure * diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index bb133245beed5c1d21f33f74d21191c9a7794427..aa40e510b806ecb5b8ed3b30065b0c7cf3a162d1 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -155,6 +155,7 @@ u32 hw_read_intr_status(struct ci_hdrc *ci) /** * hw_port_test_set: writes port test mode (execute without interruption) + * @ci: the controller * @mode: new value * * This function returns an error code @@ -877,6 +878,33 @@ void ci_hdrc_remove_device(struct platform_device *pdev) } EXPORT_SYMBOL_GPL(ci_hdrc_remove_device); +/** + * ci_hdrc_query_available_role: get runtime available operation mode + * + * The glue layer can get current operation mode (host/peripheral/otg) + * This function should be called after ci core device has created. + * + * @pdev: the platform device of ci core. + * + * Return runtime usb_dr_mode. + */ +enum usb_dr_mode ci_hdrc_query_available_role(struct platform_device *pdev) +{ + struct ci_hdrc *ci = platform_get_drvdata(pdev); + + if (!ci) + return USB_DR_MODE_UNKNOWN; + if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) + return USB_DR_MODE_OTG; + else if (ci->roles[CI_ROLE_HOST]) + return USB_DR_MODE_HOST; + else if (ci->roles[CI_ROLE_GADGET]) + return USB_DR_MODE_PERIPHERAL; + else + return USB_DR_MODE_UNKNOWN; +} +EXPORT_SYMBOL_GPL(ci_hdrc_query_available_role); + static inline void ci_role_destroy(struct ci_hdrc *ci) { ci_hdrc_gadget_destroy(ci); diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index e0376ee646adff735be1da570869aae2e8e50f69..da5d18cf68406386d632910c3096d1d458055260 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -18,7 +18,7 @@ #include "bits.h" #include "otg.h" -/** +/* * ci_device_show: prints information about device capabilities and status */ static int ci_device_show(struct seq_file *s, void *data) @@ -47,7 +47,7 @@ static int ci_device_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(ci_device); -/** +/* * ci_port_test_show: reads port test mode */ static int ci_port_test_show(struct seq_file *s, void *data) @@ -67,7 +67,7 @@ static int ci_port_test_show(struct seq_file *s, void *data) return 0; } -/** +/* * ci_port_test_write: writes port test mode */ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf, @@ -115,7 +115,7 @@ static const struct file_operations ci_port_test_fops = { .release = single_release, }; -/** +/* * ci_qheads_show: DMA contents of all queue heads */ static int ci_qheads_show(struct seq_file *s, void *data) @@ -147,7 +147,7 @@ static int ci_qheads_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(ci_qheads); -/** +/* * ci_requests_show: DMA contents of all requests currently queued (all endpts) */ static int ci_requests_show(struct seq_file *s, void *data) diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index be63924ea82efff1ae8e122ae8d3f1a6c67fee91..d3aada3ce7ec2ac6a419751ebcd7ac74a47cfb07 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -23,6 +23,7 @@ /** * hw_read_otgsc returns otgsc register bits value. + * @ci: the controller * @mask: bitfield mask */ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) @@ -75,6 +76,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) /** * hw_write_otgsc updates target bits of OTGSC register. + * @ci: the controller * @mask: bitfield mask * @data: to be written */ @@ -229,7 +231,7 @@ static void ci_otg_work(struct work_struct *work) /** * ci_hdrc_otg_init - initialize otg struct - * ci: the controller + * @ci: the controller */ int ci_hdrc_otg_init(struct ci_hdrc *ci) { @@ -248,7 +250,7 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci) /** * ci_hdrc_otg_destroy - destroy otg struct - * ci: the controller + * @ci: the controller */ void ci_hdrc_otg_destroy(struct ci_hdrc *ci) { diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index db0cfde0cc3cb08eb7574a21f7cc0449b8a2d53d..60ea932afe2b8892e2f6296bc782c40d09fd1d4a 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -72,6 +72,7 @@ static inline int ep_to_bit(struct ci_hdrc *ci, int n) /** * hw_device_state: enables/disables interrupts (execute without interruption) + * @ci: the controller * @dma: 0 => disable, !0 => enable and set dma engine * * This function returns an error code @@ -91,6 +92,7 @@ static int hw_device_state(struct ci_hdrc *ci, u32 dma) /** * hw_ep_flush: flush endpoint fifo (execute without interruption) + * @ci: the controller * @num: endpoint number * @dir: endpoint direction * @@ -112,6 +114,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir) /** * hw_ep_disable: disables endpoint (execute without interruption) + * @ci: the controller * @num: endpoint number * @dir: endpoint direction * @@ -126,6 +129,7 @@ static int hw_ep_disable(struct ci_hdrc *ci, int num, int dir) /** * hw_ep_enable: enables endpoint (execute without interruption) + * @ci: the controller * @num: endpoint number * @dir: endpoint direction * @type: endpoint type @@ -161,6 +165,7 @@ static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type) /** * hw_ep_get_halt: return endpoint halt status + * @ci: the controller * @num: endpoint number * @dir: endpoint direction * @@ -175,6 +180,7 @@ static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir) /** * hw_ep_prime: primes endpoint (execute without interruption) + * @ci: the controller * @num: endpoint number * @dir: endpoint direction * @is_ctrl: true if control endpoint @@ -205,6 +211,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl) /** * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute * without interruption) + * @ci: the controller * @num: endpoint number * @dir: endpoint direction * @value: true => stall, false => unstall @@ -231,6 +238,7 @@ static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value) /** * hw_is_port_high_speed: test if port is high speed + * @ci: the controller * * This function returns true if high speed port */ @@ -243,6 +251,7 @@ static int hw_port_is_high_speed(struct ci_hdrc *ci) /** * hw_test_and_clear_complete: test & clear complete status (execute without * interruption) + * @ci: the controller * @n: endpoint number * * This function returns complete status @@ -256,6 +265,7 @@ static int hw_test_and_clear_complete(struct ci_hdrc *ci, int n) /** * hw_test_and_clear_intr_active: test & clear active interrupts (execute * without interruption) + * @ci: the controller * * This function returns active interrutps */ @@ -270,6 +280,7 @@ static u32 hw_test_and_clear_intr_active(struct ci_hdrc *ci) /** * hw_test_and_clear_setup_guard: test & clear setup guard (execute without * interruption) + * @ci: the controller * * This function returns guard value */ @@ -281,6 +292,7 @@ static int hw_test_and_clear_setup_guard(struct ci_hdrc *ci) /** * hw_test_and_set_setup_guard: test & set setup guard (execute without * interruption) + * @ci: the controller * * This function returns guard value */ @@ -291,6 +303,7 @@ static int hw_test_and_set_setup_guard(struct ci_hdrc *ci) /** * hw_usb_set_address: configures USB address (execute without interruption) + * @ci: the controller * @value: new USB address * * This function explicitly sets the address, without the "USBADRA" (advance) @@ -305,6 +318,7 @@ static void hw_usb_set_address(struct ci_hdrc *ci, u8 value) /** * hw_usb_reset: restart device after a bus reset (execute without * interruption) + * @ci: the controller * * This function returns an error code */ @@ -473,9 +487,10 @@ static void ci_add_buffer_entry(struct td_node *node, struct scatterlist *s) int empty_td_slot_index = (CI_MAX_BUF_SIZE - node->td_remaining_size) / CI_HDRC_PAGE_SIZE; int i; + u32 token; - node->ptr->token += - cpu_to_le32(sg_dma_len(s) << __ffs(TD_TOTAL_BYTES)); + token = le32_to_cpu(node->ptr->token) + (sg_dma_len(s) << __ffs(TD_TOTAL_BYTES)); + node->ptr->token = cpu_to_le32(token); for (i = empty_td_slot_index; i < TD_PAGE_COUNT; i++) { u32 page = (u32) sg_dma_address(s) + @@ -610,7 +625,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) return ret; } -/* +/** * free_pending_td: remove a pending request for the endpoint * @hwep: endpoint */ @@ -636,8 +651,8 @@ static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep, /** * _hardware_dequeue: handles a request at hardware level - * @gadget: gadget - * @hwep: endpoint + * @hwep: endpoint + * @hwreq: request * * This function returns an error code */ @@ -1215,11 +1230,11 @@ __acquires(ci->lock) case USB_DEVICE_TEST_MODE: tmode = le16_to_cpu(req.wIndex) >> 8; switch (tmode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: + case USB_TEST_FORCE_ENABLE: ci->test_mode = tmode; err = isr_setup_status_phase( ci); @@ -1316,7 +1331,7 @@ __acquires(ci->lock) /****************************************************************************** * ENDPT block *****************************************************************************/ -/** +/* * ep_enable: configure endpoint, making it usable * * Check usb_ep_enable() at "usb_gadget.h" for details @@ -1384,7 +1399,7 @@ static int ep_enable(struct usb_ep *ep, return retval; } -/** +/* * ep_disable: endpoint is no longer usable * * Check usb_ep_disable() at "usb_gadget.h" for details @@ -1424,7 +1439,7 @@ static int ep_disable(struct usb_ep *ep) return retval; } -/** +/* * ep_alloc_request: allocate a request object to use with this endpoint * * Check usb_ep_alloc_request() at "usb_gadget.h" for details @@ -1445,7 +1460,7 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) return (hwreq == NULL) ? NULL : &hwreq->req; } -/** +/* * ep_free_request: frees a request object * * Check usb_ep_free_request() at "usb_gadget.h" for details @@ -1478,7 +1493,7 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req) spin_unlock_irqrestore(hwep->lock, flags); } -/** +/* * ep_queue: queues (submits) an I/O request to an endpoint * * Check usb_ep_queue()* at usb_gadget.h" for details @@ -1503,7 +1518,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, return retval; } -/** +/* * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint * * Check usb_ep_dequeue() at "usb_gadget.h" for details @@ -1547,7 +1562,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) return 0; } -/** +/* * ep_set_halt: sets the endpoint halt feature * * Check usb_ep_set_halt() at "usb_gadget.h" for details @@ -1557,7 +1572,7 @@ static int ep_set_halt(struct usb_ep *ep, int value) return _ep_set_halt(ep, value, true); } -/** +/* * ep_set_wedge: sets the halt feature and ignores clear requests * * Check usb_ep_set_wedge() at "usb_gadget.h" for details @@ -1577,7 +1592,7 @@ static int ep_set_wedge(struct usb_ep *ep) return usb_ep_set_halt(ep); } -/** +/* * ep_fifo_flush: flushes contents of a fifo * * Check usb_ep_fifo_flush() at "usb_gadget.h" for details @@ -1603,7 +1618,7 @@ static void ep_fifo_flush(struct usb_ep *ep) spin_unlock_irqrestore(hwep->lock, flags); } -/** +/* * Endpoint-specific part of the API to the USB controller hardware * Check "usb_gadget.h" for details */ @@ -1622,7 +1637,7 @@ static const struct usb_ep_ops usb_ep_ops = { /****************************************************************************** * GADGET block *****************************************************************************/ -/** +/* * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded */ static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active) @@ -1772,7 +1787,7 @@ static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget, return NULL; } -/** +/* * Device operations part of the API to the USB controller hardware, * which don't involve endpoints (or i/o) * Check "usb_gadget.h" for details @@ -1924,7 +1939,7 @@ static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci) mutex_unlock(&ci->fsm.lock); } -/** +/* * ci_udc_stop: unregister a gadget driver */ static int ci_udc_stop(struct usb_gadget *gadget) @@ -1955,7 +1970,7 @@ static int ci_udc_stop(struct usb_gadget *gadget) /****************************************************************************** * BUS block *****************************************************************************/ -/** +/* * udc_irq: ci interrupt handler * * This function returns IRQ_HANDLED if the IRQ has been handled @@ -2086,7 +2101,7 @@ static int udc_start(struct ci_hdrc *ci) return retval; } -/** +/* * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC * * No interrupts active, the IRQ has been released @@ -2136,7 +2151,7 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci) /** * ci_hdrc_gadget_init - initialize device related bits - * ci: the controller + * @ci: the controller * * This function initializes the gadget, if the device is "device capable". */ diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index f136876cb4a308005c56216f059160d3cfe3a6e3..322e4de6b24af096877360107e96297c1b267cb2 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -367,10 +367,10 @@ static u32 usbmisc_wakeup_setting(struct imx_usbmisc_data *data) { u32 wakeup_setting = MX6_USB_OTG_WAKEUP_BITS; - if (data->ext_id) + if (data->ext_id || data->available_role != USB_DR_MODE_OTG) wakeup_setting &= ~MX6_BM_ID_WAKEUP; - if (data->ext_vbus) + if (data->ext_vbus || data->available_role == USB_DR_MODE_HOST) wakeup_setting &= ~MX6_BM_VBUS_WAKEUP; return wakeup_setting; @@ -789,7 +789,7 @@ static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data) return 0; } -/** +/* * Whole charger detection process: * 1. OPMODE override to be non-driving * 2. Data contact check diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index e3db6fbeadef84214c3ba91666a21dc33ff3aecb..7f5de956a2fc864b3101b506f7379d92aaa45d6b 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -940,7 +940,8 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) * @intf: usb interface the subdriver will associate with * @ep: interrupt endpoint to monitor for notifications * @bufsize: maximum message size to support for read/write - * + * @manage_power: call-back invoked during open and release to + * manage the device's power * Create WDM usb class character device and associate it with intf * without binding, allowing another driver to manage the interface. * diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index ffc9c6fdd7e1d64126e88cad23c2954218c5f2c1..b222b777e6a43c6ba8fa3bddd9f3928e9b20106b 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ -/** +/* * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver * * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany @@ -2282,7 +2282,7 @@ static void usbtmc_interrupt(struct urb *urb) case -EOVERFLOW: dev_err(dev, "overflow with length %d, actual length is %d\n", data->iin_wMaxPacketSize, urb->actual_length); - /* fall through */ + fallthrough; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: diff --git a/drivers/usb/common/Kconfig b/drivers/usb/common/Kconfig index d611477aae4143e0fcef28f5de1902820789667f..5e8a04e3dd3c896ed3a9a4d309d8963202247e74 100644 --- a/drivers/usb/common/Kconfig +++ b/drivers/usb/common/Kconfig @@ -40,6 +40,7 @@ config USB_CONN_GPIO tristate "USB GPIO Based Connection Detection Driver" depends on GPIOLIB select USB_ROLE_SWITCH + select POWER_SUPPLY help The driver supports USB role switch between host and device via GPIO based USB cable detection, used typically if an input GPIO is used diff --git a/drivers/usb/common/debug.c b/drivers/usb/common/debug.c index 92a986aeaa5d606399bfa651f69d9b12fb0178bb..ba849c7bc5c7f155ee3420be2d556052f2aaa733 100644 --- a/drivers/usb/common/debug.c +++ b/drivers/usb/common/debug.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * Common USB debugging functions * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -53,15 +53,15 @@ static const char *usb_decode_device_feature(u16 wValue) static const char *usb_decode_test_mode(u16 wIndex) { switch (wIndex) { - case TEST_J: + case USB_TEST_J: return ": TEST_J"; - case TEST_K: + case USB_TEST_K: return ": TEST_K"; - case TEST_SE0_NAK: + case USB_TEST_SE0_NAK: return ": TEST_SE0_NAK"; - case TEST_PACKET: + case USB_TEST_PACKET: return ": TEST_PACKET"; - case TEST_FORCE_EN: + case USB_TEST_FORCE_ENABLE: return ": TEST_FORCE_EN"; default: return ": UNKNOWN"; @@ -207,7 +207,7 @@ static void usb_decode_set_isoch_delay(__u8 wValue, char *str, size_t size) snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", wValue); } -/** +/* * usb_decode_ctrl - returns a string representation of ctrl request */ const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType, diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 9a2ab6751a23c504177fbac78cc7e95cdb21a1ae..a18d7c4222ddfedb62c3e1605190239601c1a1d5 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * ulpi.c - USB ULPI PHY bus * * Copyright (C) 2015 Intel Corporation @@ -143,6 +143,7 @@ static const struct device_type ulpi_dev_type = { /** * ulpi_register_driver - register a driver with the ULPI bus * @drv: driver being registered + * @module: ends up being THIS_MODULE * * Registers a driver with the ULPI bus. */ @@ -290,7 +291,7 @@ EXPORT_SYMBOL_GPL(ulpi_register_interface); /** * ulpi_unregister_interface - unregister ULPI interface - * @intrf: struct ulpi_interface + * @ulpi: struct ulpi_interface * * Unregisters a ULPI device and it's interface that was created with * ulpi_create_interface(). diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index ed204cbb63ea19719c4a72c13dd28987dcc26f1c..7b3a21360d7ca1be93ea2161fbc77c26ddbd132b 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -17,6 +17,7 @@ #include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/power_supply.h> #include <linux/regulator/consumer.h> #include <linux/usb/role.h> @@ -38,9 +39,12 @@ struct usb_conn_info { struct gpio_desc *vbus_gpiod; int id_irq; int vbus_irq; + + struct power_supply_desc desc; + struct power_supply *charger; }; -/** +/* * "DEVICE" = VBUS and "HOST" = !ID, so we have: * Both "DEVICE" and "HOST" can't be set as active at the same time * so if "HOST" is active (i.e. ID is 0) we keep "DEVICE" inactive @@ -104,6 +108,8 @@ static void usb_conn_detect_cable(struct work_struct *work) dev_dbg(info->dev, "vbus regulator is %s\n", regulator_is_enabled(info->vbus) ? "enabled" : "disabled"); + + power_supply_changed(info->charger); } static void usb_conn_queue_dwork(struct usb_conn_info *info, @@ -121,10 +127,35 @@ static irqreturn_t usb_conn_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static enum power_supply_property usb_charger_properties[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static int usb_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct usb_conn_info *info = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = info->last_role == USB_ROLE_DEVICE; + break; + default: + return -EINVAL; + } + + return 0; +} + static int usb_conn_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct power_supply_desc *desc; struct usb_conn_info *info; + struct power_supply_config cfg = { + .of_node = dev->of_node, + }; int ret = 0; info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); @@ -203,6 +234,20 @@ static int usb_conn_probe(struct platform_device *pdev) } } + desc = &info->desc; + desc->name = "usb-charger"; + desc->properties = usb_charger_properties; + desc->num_properties = ARRAY_SIZE(usb_charger_properties); + desc->get_property = usb_charger_get_property; + desc->type = POWER_SUPPLY_TYPE_USB; + cfg.drv_data = info; + + info->charger = devm_power_supply_register(dev, desc, &cfg); + if (IS_ERR(info->charger)) { + dev_err(dev, "Unable to register charger\n"); + return PTR_ERR(info->charger); + } + platform_set_drvdata(pdev, info); /* Perform initial detection */ diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index ecaacc8ed31185324fa6c8e6e5281ceedf66064b..dfacc478a8fc20673e5ecdd90d3bfa2fa316c2bf 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -55,18 +55,18 @@ config USB_OTG Select this only if your board has Mini-AB/Micro-AB connector. -config USB_OTG_WHITELIST +config USB_OTG_PRODUCTLIST bool "Rely on OTG and EH Targeted Peripherals List" depends on USB help - If you say Y here, the "otg_whitelist.h" file will be used as a - product whitelist, so USB peripherals not listed there will be + If you say Y here, the "otg_productlist.h" file will be used as a + product list, so USB peripherals not listed there will be rejected during enumeration. This behavior is required by the USB OTG and EH specification for all devices not on your product's "Targeted Peripherals List". "Embedded Hosts" are likewise allowed to support only a limited number of peripherals. -config USB_OTG_BLACKLIST_HUB +config USB_OTG_DISABLE_EXTERNAL_HUB bool "Disable external hubs" depends on USB_OTG || EXPERT help diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index b7918f6954344321412f550e262b6183c0d2a292..562a730befdac64d8049c9b30bd6ce0e291f2af2 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -298,10 +298,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, goto skip_to_next_endpoint_or_interface_descriptor; } - /* Ignore blacklisted endpoints */ - if (udev->quirks & USB_QUIRK_ENDPOINT_BLACKLIST) { - if (usb_endpoint_is_blacklisted(udev, ifp, d)) { - dev_warn(ddev, "config %d interface %d altsetting %d has a blacklisted endpoint with address 0x%X, skipping\n", + /* Ignore some endpoints */ + if (udev->quirks & USB_QUIRK_ENDPOINT_IGNORE) { + if (usb_endpoint_is_ignored(udev, ifp, d)) { + dev_warn(ddev, "config %d interface %d altsetting %d has an ignored endpoint with address 0x%X, skipping\n", cfgno, inum, asnum, d->bEndpointAddress); goto skip_to_next_endpoint_or_interface_descriptor; @@ -427,7 +427,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, i = maxp & (BIT(12) | BIT(11)); maxp &= ~i; } - /* fallthrough */ + fallthrough; default: maxpacket_maxes = high_speed_maxpacket_maxes; break; diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 94b6fa6e585e71653a6a4d2103ba50f2043f10b0..696b2b692b8307632dfd7b11d4d774383cbff5e4 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -133,6 +133,10 @@ static const struct class_info clas_info[] = { {USB_CLASS_CSCID, "scard"}, {USB_CLASS_CONTENT_SEC, "c-sec"}, {USB_CLASS_VIDEO, "video"}, + {USB_CLASS_PERSONAL_HEALTHCARE, "perhc"}, + {USB_CLASS_AUDIO_VIDEO, "av"}, + {USB_CLASS_BILLBOARD, "blbrd"}, + {USB_CLASS_USB_TYPE_C_BRIDGE, "bridg"}, {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"}, {USB_CLASS_MISC, "misc"}, {USB_CLASS_APP_SPEC, "app."}, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 96d4507d988ac01949a9e89d1c4568d71b07ba17..e96a858a12185bac3d5aa5e5b8d1b7caa6c3e38c 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1102,22 +1102,20 @@ static int usbdev_release(struct inode *inode, struct file *file) return 0; } -static int proc_control(struct usb_dev_state *ps, void __user *arg) +static int do_proc_control(struct usb_dev_state *ps, + struct usbdevfs_ctrltransfer *ctrl) { struct usb_device *dev = ps->dev; - struct usbdevfs_ctrltransfer ctrl; unsigned int tmo; unsigned char *tbuf; unsigned wLength; int i, pipe, ret; - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest, - ctrl.wIndex); + ret = check_ctrlrecip(ps, ctrl->bRequestType, ctrl->bRequest, + ctrl->wIndex); if (ret) return ret; - wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ + wLength = ctrl->wLength; /* To suppress 64k PAGE_SIZE warning */ if (wLength > PAGE_SIZE) return -EINVAL; ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) + @@ -1129,52 +1127,52 @@ static int proc_control(struct usb_dev_state *ps, void __user *arg) ret = -ENOMEM; goto done; } - tmo = ctrl.timeout; + tmo = ctrl->timeout; snoop(&dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " "wIndex=%04x wLength=%04x\n", - ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, - ctrl.wIndex, ctrl.wLength); - if (ctrl.bRequestType & 0x80) { + ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, + ctrl->wIndex, ctrl->wLength); + if (ctrl->bRequestType & 0x80) { pipe = usb_rcvctrlpipe(dev, 0); - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); + snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT, NULL, 0); usb_unlock_device(dev); - i = usb_control_msg(dev, pipe, ctrl.bRequest, - ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, - tbuf, ctrl.wLength, tmo); + i = usb_control_msg(dev, pipe, ctrl->bRequest, + ctrl->bRequestType, ctrl->wValue, ctrl->wIndex, + tbuf, ctrl->wLength, tmo); usb_lock_device(dev); snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, tbuf, max(i, 0)); - if ((i > 0) && ctrl.wLength) { - if (copy_to_user(ctrl.data, tbuf, i)) { + if ((i > 0) && ctrl->wLength) { + if (copy_to_user(ctrl->data, tbuf, i)) { ret = -EFAULT; goto done; } } } else { - if (ctrl.wLength) { - if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { + if (ctrl->wLength) { + if (copy_from_user(tbuf, ctrl->data, ctrl->wLength)) { ret = -EFAULT; goto done; } } pipe = usb_sndctrlpipe(dev, 0); - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, - tbuf, ctrl.wLength); + snoop_urb(dev, NULL, pipe, ctrl->wLength, tmo, SUBMIT, + tbuf, ctrl->wLength); usb_unlock_device(dev); - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, - ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, - tbuf, ctrl.wLength, tmo); + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl->bRequest, + ctrl->bRequestType, ctrl->wValue, ctrl->wIndex, + tbuf, ctrl->wLength, tmo); usb_lock_device(dev); snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0); } if (i < 0 && i != -EPIPE) { dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " "failed cmd %s rqt %u rq %u len %u ret %d\n", - current->comm, ctrl.bRequestType, ctrl.bRequest, - ctrl.wLength, i); + current->comm, ctrl->bRequestType, ctrl->bRequest, + ctrl->wLength, i); } ret = i; done: @@ -1184,30 +1182,37 @@ static int proc_control(struct usb_dev_state *ps, void __user *arg) return ret; } -static int proc_bulk(struct usb_dev_state *ps, void __user *arg) +static int proc_control(struct usb_dev_state *ps, void __user *arg) +{ + struct usbdevfs_ctrltransfer ctrl; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; + return do_proc_control(ps, &ctrl); +} + +static int do_proc_bulk(struct usb_dev_state *ps, + struct usbdevfs_bulktransfer *bulk) { struct usb_device *dev = ps->dev; - struct usbdevfs_bulktransfer bulk; unsigned int tmo, len1, pipe; int len2; unsigned char *tbuf; int i, ret; - if (copy_from_user(&bulk, arg, sizeof(bulk))) - return -EFAULT; - ret = findintfep(ps->dev, bulk.ep); + ret = findintfep(ps->dev, bulk->ep); if (ret < 0) return ret; ret = checkintf(ps, ret); if (ret) return ret; - if (bulk.ep & USB_DIR_IN) - pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); + if (bulk->ep & USB_DIR_IN) + pipe = usb_rcvbulkpipe(dev, bulk->ep & 0x7f); else - pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); - if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) + pipe = usb_sndbulkpipe(dev, bulk->ep & 0x7f); + if (!usb_maxpacket(dev, pipe, !(bulk->ep & USB_DIR_IN))) return -EINVAL; - len1 = bulk.len; + len1 = bulk->len; if (len1 >= (INT_MAX - sizeof(struct urb))) return -EINVAL; ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); @@ -1218,8 +1223,8 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) ret = -ENOMEM; goto done; } - tmo = bulk.timeout; - if (bulk.ep & 0x80) { + tmo = bulk->timeout; + if (bulk->ep & 0x80) { snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); usb_unlock_device(dev); @@ -1228,14 +1233,14 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2); if (!i && len2) { - if (copy_to_user(bulk.data, tbuf, len2)) { + if (copy_to_user(bulk->data, tbuf, len2)) { ret = -EFAULT; goto done; } } } else { if (len1) { - if (copy_from_user(tbuf, bulk.data, len1)) { + if (copy_from_user(tbuf, bulk->data, len1)) { ret = -EFAULT; goto done; } @@ -1254,6 +1259,15 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) return ret; } +static int proc_bulk(struct usb_dev_state *ps, void __user *arg) +{ + struct usbdevfs_bulktransfer bulk; + + if (copy_from_user(&bulk, arg, sizeof(bulk))) + return -EFAULT; + return do_proc_bulk(ps, &bulk); +} + static void check_reset_of_active_ep(struct usb_device *udev, unsigned int epnum, char *ioctl_name) { @@ -2013,33 +2027,31 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg) static int proc_control_compat(struct usb_dev_state *ps, struct usbdevfs_ctrltransfer32 __user *p32) { - struct usbdevfs_ctrltransfer __user *p; - __u32 udata; - p = compat_alloc_user_space(sizeof(*p)); - if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || - get_user(udata, &p32->data) || - put_user(compat_ptr(udata), &p->data)) + struct usbdevfs_ctrltransfer ctrl; + u32 udata; + + if (copy_from_user(&ctrl, p32, sizeof(*p32) - sizeof(compat_caddr_t)) || + get_user(udata, &p32->data)) return -EFAULT; - return proc_control(ps, p); + ctrl.data = compat_ptr(udata); + return do_proc_control(ps, &ctrl); } static int proc_bulk_compat(struct usb_dev_state *ps, struct usbdevfs_bulktransfer32 __user *p32) { - struct usbdevfs_bulktransfer __user *p; - compat_uint_t n; + struct usbdevfs_bulktransfer bulk; compat_caddr_t addr; - p = compat_alloc_user_space(sizeof(*p)); - - if (get_user(n, &p32->ep) || put_user(n, &p->ep) || - get_user(n, &p32->len) || put_user(n, &p->len) || - get_user(n, &p32->timeout) || put_user(n, &p->timeout) || - get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) + if (get_user(bulk.ep, &p32->ep) || + get_user(bulk.len, &p32->len) || + get_user(bulk.timeout, &p32->timeout) || + get_user(addr, &p32->data)) return -EFAULT; - - return proc_bulk(ps, p); + bulk.data = compat_ptr(addr); + return do_proc_bulk(ps, &bulk); } + static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg) { struct usbdevfs_disconnectsignal32 ds; diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 4626227a6dd223c037907dc999412486d8b581bd..b6f2d4b447546ed5a44366bfbc7e375f09ba761c 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -205,8 +205,6 @@ static int __check_usb_generic(struct device_driver *drv, void *data) udrv = to_usb_device_driver(drv); if (udrv == &usb_generic_driver) return 0; - if (!udrv->id_table) - return 0; return usb_device_match_id(udev, udrv->id_table) != NULL; } diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 1547aa6e5314c2a8983a7f503735c3c0a4251852..4dc443aaef5c624526624b178b57e73318efd3cc 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -194,20 +194,21 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id, * make sure irq setup is not touched for xhci in generic hcd code */ if ((driver->flags & HCD_MASK) < HCD_USB3) { - if (!dev->irq) { + retval = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSI); + if (retval < 0) { dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); retval = -ENODEV; goto disable_pci; } - hcd_irq = dev->irq; + hcd_irq = pci_irq_vector(dev, 0); } hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); if (!hcd) { retval = -ENOMEM; - goto disable_pci; + goto free_irq_vectors; } hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) && @@ -286,6 +287,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id, put_hcd: usb_put_hcd(hcd); +free_irq_vectors: + if ((driver->flags & HCD_MASK) < HCD_USB3) + pci_free_irq_vectors(dev); disable_pci: pci_disable_device(dev); dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); @@ -343,6 +347,8 @@ void usb_hcd_pci_remove(struct pci_dev *dev) up_read(&companions_rwsem); } usb_put_hcd(hcd); + if ((hcd->driver->flags & HCD_MASK) < HCD_USB3) + pci_free_irq_vectors(dev); pci_disable_device(dev); } EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); @@ -454,7 +460,7 @@ static int suspend_common(struct device *dev, bool do_wakeup) * synchronized here. */ if (!hcd->msix_enabled) - synchronize_irq(pci_dev->irq); + synchronize_irq(pci_irq_vector(pci_dev, 0)); /* Downstream ports from this root hub should already be quiesced, so * there will be no DMA activity. Now we can shut down the upstream diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index de624c47e1906e6b8415e2de9f8189974eb804da..a33b849e8beb8ce0b35e776283405e7bdda37833 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -564,7 +564,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) case DeviceRequest | USB_REQ_GET_CONFIGURATION: tbuf[0] = 1; len = 1; - /* FALLTHROUGH */ + fallthrough; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: break; case DeviceRequest | USB_REQ_GET_DESCRIPTOR: @@ -633,7 +633,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) case DeviceRequest | USB_REQ_GET_INTERFACE: tbuf[0] = 0; len = 1; - /* FALLTHROUGH */ + fallthrough; case DeviceOutRequest | USB_REQ_SET_INTERFACE: break; case DeviceOutRequest | USB_REQ_SET_ADDRESS: @@ -651,7 +651,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) tbuf[0] = 0; tbuf[1] = 0; len = 2; - /* FALLTHROUGH */ + fallthrough; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: case EndpointOutRequest | USB_REQ_SET_FEATURE: dev_dbg (hcd->self.controller, "no endpoint features yet\n"); @@ -2726,7 +2726,7 @@ int usb_add_hcd(struct usb_hcd *hcd, case HCD_USB32: rhdev->rx_lanes = 2; rhdev->tx_lanes = 2; - /* fall through */ + fallthrough; case HCD_USB31: rhdev->speed = USB_SPEED_SUPER_PLUS; break; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b1e14beaac5f76a075562a3c5bc1fbd2e3e3aba3..052d5accfe9b2bc077e0b877efdce60a2aafd95b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -35,7 +35,7 @@ #include <asm/byteorder.h> #include "hub.h" -#include "otg_whitelist.h" +#include "otg_productlist.h" #define USB_VENDOR_GENESYS_LOGIC 0x05e3 #define USB_VENDOR_SMSC 0x0424 @@ -1834,7 +1834,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) return -E2BIG; } -#ifdef CONFIG_USB_OTG_BLACKLIST_HUB +#ifdef CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB if (hdev->parent) { dev_warn(&intf->dev, "ignoring external hub\n"); return -ENODEV; @@ -2403,7 +2403,7 @@ static int usb_enumerate_device(struct usb_device *udev) if (err < 0) return err; - if (IS_ENABLED(CONFIG_USB_OTG_WHITELIST) && hcd->tpl_support && + if (IS_ENABLED(CONFIG_USB_OTG_PRODUCTLIST) && hcd->tpl_support && !is_targeted(udev)) { /* Maybe it can talk to us, though we can't talk to it. * (Includes HNP test device.) @@ -4698,7 +4698,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, r = 0; break; } - /* FALL THROUGH */ + fallthrough; default: if (r == 0) r = -EPROTO; diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index c12ac56606c3f681fe8cebe0357a8284ec405f25..ba371a24ff781b45848e27f2b89b53938adde58d 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -34,7 +34,7 @@ struct usbport_trig_port { * Helpers ***************************************/ -/** +/* * usbport_trig_usb_dev_observed - Check if dev is connected to observed port */ static bool usbport_trig_usb_dev_observed(struct usbport_trig_data *usbport_data, @@ -64,7 +64,7 @@ static int usbport_trig_usb_dev_check(struct usb_device *usb_dev, void *data) return 0; } -/** +/* * usbport_trig_update_count - Recalculate amount of connected matching devices */ static void usbport_trig_update_count(struct usbport_trig_data *usbport_data) @@ -123,7 +123,7 @@ static const struct attribute_group ports_group = { * Adding & removing ports ***************************************/ -/** +/* * usbport_trig_port_observed - Check if port should be observed */ static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data, diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index 651708d8c9083b99df235dddc3eddde12b9e5188..617e92569b2c7c39d24f928e3e2e00721dc43d7b 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -45,7 +45,7 @@ EXPORT_SYMBOL_GPL(usb_of_get_device_node); * * Determine whether a USB device has a so called combined node which is * shared with its sole interface. This is the case if and only if the device - * has a node and its decriptors report the following: + * has a node and its descriptors report the following: * * 1) bDeviceClass is 0 or 9, and * 2) bNumConfigurations is 1, and diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_productlist.h similarity index 90% rename from drivers/usb/core/otg_whitelist.h rename to drivers/usb/core/otg_productlist.h index fdd4897401e2786f08a1dbfb9a60b21367e12fe7..db67df29fb2b10325c86bb04e8b4effa7a140765 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_productlist.h @@ -1,18 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0+ */ -/* - * drivers/usb/core/otg_whitelist.h - * - * Copyright (C) 2004 Texas Instruments - */ +/* Copyright (C) 2004 Texas Instruments */ /* - * This OTG and Embedded Host Whitelist is "Targeted Peripheral List". + * This OTG and Embedded Host list is "Targeted Peripheral List". * It should mostly use of USB_DEVICE() or USB_DEVICE_VER() entries.. * * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! */ -static struct usb_device_id whitelist_table[] = { +static struct usb_device_id productlist_table[] = { /* hubs are optional in OTG, but very handy ... */ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, @@ -44,7 +40,7 @@ static struct usb_device_id whitelist_table[] = { static int is_targeted(struct usb_device *dev) { - struct usb_device_id *id = whitelist_table; + struct usb_device_id *id = productlist_table; /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && @@ -59,7 +55,7 @@ static int is_targeted(struct usb_device *dev) /* NOTE: can't use usb_match_id() since interface caches * aren't set up yet. this is cut/paste from that code. */ - for (id = whitelist_table; id->match_flags; id++) { + for (id = productlist_table; id->match_flags; id++) { if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) continue; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index e0b77674869ce6de9ec0a45f7982f7a460104b7b..7c1198f80c2316e48acdcbdefe9a3b64bcb5d096 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -25,17 +25,23 @@ static unsigned int quirk_count; static char quirks_param[128]; -static int quirks_param_set(const char *val, const struct kernel_param *kp) +static int quirks_param_set(const char *value, const struct kernel_param *kp) { - char *p, *field; + char *val, *p, *field; u16 vid, pid; u32 flags; size_t i; int err; + val = kstrdup(value, GFP_KERNEL); + if (!val) + return -ENOMEM; + err = param_set_copystring(val, kp); - if (err) + if (err) { + kfree(val); return err; + } mutex_lock(&quirk_mutex); @@ -60,10 +66,11 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp) if (!quirk_list) { quirk_count = 0; mutex_unlock(&quirk_mutex); + kfree(val); return -ENOMEM; } - for (i = 0, p = (char *)val; p && *p;) { + for (i = 0, p = val; p && *p;) { /* Each entry consists of VID:PID:flags */ field = strsep(&p, ":"); if (!field) @@ -144,6 +151,7 @@ static int quirks_param_set(const char *val, const struct kernel_param *kp) unlock: mutex_unlock(&quirk_mutex); + kfree(val); return 0; } @@ -360,7 +368,7 @@ static const struct usb_device_id usb_quirk_list[] = { /* Sound Devices USBPre2 */ { USB_DEVICE(0x0926, 0x0202), .driver_info = - USB_QUIRK_ENDPOINT_BLACKLIST }, + USB_QUIRK_ENDPOINT_IGNORE }, /* Keytouch QWERTY Panel keyboard */ { USB_DEVICE(0x0926, 0x3333), .driver_info = @@ -494,24 +502,24 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = { }; /* - * Entries for blacklisted endpoints that should be ignored when parsing - * configuration descriptors. + * Entries for endpoints that should be ignored when parsing configuration + * descriptors. * - * Matched for devices with USB_QUIRK_ENDPOINT_BLACKLIST. + * Matched for devices with USB_QUIRK_ENDPOINT_IGNORE. */ -static const struct usb_device_id usb_endpoint_blacklist[] = { +static const struct usb_device_id usb_endpoint_ignore[] = { { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 }, { } }; -bool usb_endpoint_is_blacklisted(struct usb_device *udev, - struct usb_host_interface *intf, - struct usb_endpoint_descriptor *epd) +bool usb_endpoint_is_ignored(struct usb_device *udev, + struct usb_host_interface *intf, + struct usb_endpoint_descriptor *epd) { const struct usb_device_id *id; unsigned int address; - for (id = usb_endpoint_blacklist; id->match_flags; ++id) { + for (id = usb_endpoint_ignore; id->match_flags; ++id) { if (!usb_match_device(udev, id)) continue; diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index da923ec176122210705bb67cda9c81cecf83b3f9..7bc23469f4e4e69ea73dc7beb334d3678916a1de 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -486,7 +486,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) case USB_ENDPOINT_XFER_INT: if (is_out) allowed |= URB_ZERO_PACKET; - /* FALLTHROUGH */ + fallthrough; default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; @@ -519,7 +519,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if ((urb->interval < 6) && (xfertype == USB_ENDPOINT_XFER_INT)) return -EINVAL; - /* fall through */ + fallthrough; default: if (urb->interval <= 0) return -EINVAL; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index f16c26dc079d7949fa3c610f2521c832386e3f1e..bafc113f2b3ef3db133e8c8ab2faa1d0278768a4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -19,9 +19,8 @@ * just a collection of helper routines that implement the * generic USB things that the real drivers can use.. * - * Think of this as a "USB library" rather than anything else. - * It should be considered a slave, with no callbacks. Callbacks - * are evil. + * Think of this as a "USB library" rather than anything else, + * with no callbacks. Callbacks are evil. */ #include <linux/module.h> diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 19e4c550bc733dd9b9dafc03c88b6da6f0404717..98e7d1ee63dc39c26bb9b33fb5932e5e0406ac7d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -37,7 +37,7 @@ extern void usb_authorize_interface(struct usb_interface *); extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_interface_quirks(struct usb_device *udev); extern void usb_release_quirk_list(void); -extern bool usb_endpoint_is_blacklisted(struct usb_device *udev, +extern bool usb_endpoint_is_ignored(struct usb_device *udev, struct usb_host_interface *intf, struct usb_endpoint_descriptor *epd); extern int usb_remove_device(struct usb_device *udev); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 132d687f1590db8d7e2df011f78589b70ae886c1..9deff0400a92280e6200737269589b76d6e45fc9 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -1036,7 +1036,7 @@ struct dwc2_hregs_backup { * @fifo_mem: Total internal RAM for FIFOs (bytes) * @fifo_map: Each bit intend for concrete fifo. If that bit is set, * then that fifo is used - * @gadget: Represents a usb slave device + * @gadget: Represents a usb gadget device * @connected: Used in slave mode. True if device connected with host * @eps_in: The IN endpoints being supplied to the gadget framework * @eps_out: The OUT endpoints being supplied to the gadget framework diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 3a0dcbfbc82721f0823acfa1b57298d3c67c5ac9..aaafd463d72a3befb9978fdc424166a27c8d8d61 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -37,15 +37,15 @@ static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t return -EFAULT; if (!strncmp(buf, "test_j", 6)) - testmode = TEST_J; + testmode = USB_TEST_J; else if (!strncmp(buf, "test_k", 6)) - testmode = TEST_K; + testmode = USB_TEST_K; else if (!strncmp(buf, "test_se0_nak", 12)) - testmode = TEST_SE0_NAK; + testmode = USB_TEST_SE0_NAK; else if (!strncmp(buf, "test_packet", 11)) - testmode = TEST_PACKET; + testmode = USB_TEST_PACKET; else if (!strncmp(buf, "test_force_enable", 17)) - testmode = TEST_FORCE_EN; + testmode = USB_TEST_FORCE_ENABLE; else testmode = 0; @@ -78,19 +78,19 @@ static int testmode_show(struct seq_file *s, void *unused) case 0: seq_puts(s, "no test\n"); break; - case TEST_J: + case USB_TEST_J: seq_puts(s, "test_j\n"); break; - case TEST_K: + case USB_TEST_K: seq_puts(s, "test_k\n"); break; - case TEST_SE0_NAK: + case USB_TEST_SE0_NAK: seq_puts(s, "test_se0_nak\n"); break; - case TEST_PACKET: + case USB_TEST_PACKET: seq_puts(s, "test_packet\n"); break; - case TEST_FORCE_EN: + case USB_TEST_FORCE_ENABLE: seq_puts(s, "test_force_enable\n"); break; default: diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 7faf5f8c056d40fd111b8adb807dbafababfbb85..5b9d23991c99dd2b6fa242f49ab8d322e4c341a7 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -260,6 +260,7 @@ static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) gintsts2 = dwc2_readl(hsotg, GINTSTS2); gintmsk2 = dwc2_readl(hsotg, GINTMSK2); + gintsts2 &= gintmsk2; if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); @@ -882,11 +883,10 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, struct dwc2_dma_desc *desc; struct dwc2_hsotg *hsotg = hs_ep->parent; u32 index; - u32 maxsize = 0; u32 mask = 0; u8 pid = 0; - maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); + dwc2_gadget_get_desc_params(hs_ep, &mask); index = hs_ep->next_desc; desc = &hs_ep->desc_list[index]; @@ -1561,11 +1561,11 @@ int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) dctl &= ~DCTL_TSTCTL_MASK; switch (testmode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: + case USB_TEST_FORCE_ENABLE: dctl |= testmode << DCTL_TSTCTL_SHIFT; break; default: @@ -2978,10 +2978,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); u32 ints; - u32 ctrl; ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); - ctrl = dwc2_readl(hsotg, epctl_reg); /* Clear endpoint interrupts */ dwc2_writel(hsotg, ints, epint_reg); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index b90f858af9608951dafd00ff1fd9843988acac6e..e9ac215b9663396712e50e3c7cb71edf0947306c 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3628,7 +3628,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); if (windex != hsotg->otg_port) goto error; - if (hsotg->params.power_down == 2) + if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_HIBERNATION) dwc2_enter_hibernation(hsotg, 1); else dwc2_port_suspend(hsotg, windex); @@ -3646,7 +3646,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, break; case USB_PORT_FEAT_RESET: - if (hsotg->params.power_down == 2 && + if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_HIBERNATION && hsotg->hibernated) dwc2_exit_hibernation(hsotg, 0, 1, 1); hprt0 = dwc2_read_hprt0(hsotg); diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index ce736d67c7c34ee9aa9696255132cbcab7eba6aa..8f9d061c4d5fa641185e5bcf114af7625ecb085b 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -68,14 +68,14 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; p->change_speed_quirk = true; - p->power_down = false; + p->power_down = DWC2_POWER_DOWN_PARAM_NONE; } static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg) { struct dwc2_core_params *p = &hsotg->params; - p->power_down = 0; + p->power_down = DWC2_POWER_DOWN_PARAM_NONE; p->phy_utmi_width = 8; } @@ -89,7 +89,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) p->host_perio_tx_fifo_size = 256; p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; - p->power_down = 0; + p->power_down = DWC2_POWER_DOWN_PARAM_NONE; } static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) @@ -319,11 +319,11 @@ static void dwc2_set_param_power_down(struct dwc2_hsotg *hsotg) int val; if (hsotg->hw_params.hibernation) - val = 2; + val = DWC2_POWER_DOWN_PARAM_HIBERNATION; else if (hsotg->hw_params.power_optimized) - val = 1; + val = DWC2_POWER_DOWN_PARAM_PARTIAL; else - val = 0; + val = DWC2_POWER_DOWN_PARAM_NONE; hsotg->params.power_down = val; } diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index cb8ddbd537187de004e2acc1a0f2885debb667ef..db9fd4bd1a38cd9647401e8961d6e0bb3650d96c 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -582,6 +582,7 @@ static int dwc2_driver_probe(struct platform_device *dev) if (hsotg->gadget_enabled) { retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget); if (retval) { + hsotg->gadget.udc = NULL; dwc2_hsotg_remove(hsotg); goto error_init; } @@ -593,7 +594,8 @@ static int dwc2_driver_probe(struct platform_device *dev) if (hsotg->params.activate_stm_id_vb_detection) regulator_disable(hsotg->usb33d); error: - dwc2_lowlevel_hw_disable(hsotg); + if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) + dwc2_lowlevel_hw_disable(hsotg); return retval; } diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 25c686a752b0fc3c5fc97f56dc4d8f597866ad8d..422aea24afcd1ffbc8cccdb802acb81632601c23 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -2,7 +2,7 @@ /** * core.c - DesignWare USB3 DRD Controller Core file * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 013f42a2b5dcc652cd70ef2e0b4b9ce664eecce9..2f04b3e42bf1c2b983bd72f41e3d27a33652d523 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -2,7 +2,7 @@ /* * core.h - DesignWare USB3 DRD Core Header * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index d8f600e0e88fbf6b7041760f9ceb007093bc94bb..3d16dac4e5cc352ba9597cddc4fcad75d025777b 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -2,7 +2,7 @@ /** * debug.h - DesignWare USB3 DRD Controller Debug Header * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 6d9de334e46ad0479ec25725bcb1d02a103611b1..2c7b6dd79cdfed350c6d321e5702e7eff8abe3d2 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -2,7 +2,7 @@ /** * debugfs.c - DesignWare USB3 DRD Controller DebugFS file * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -466,19 +466,19 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) case 0: seq_printf(s, "no test\n"); break; - case TEST_J: + case USB_TEST_J: seq_printf(s, "test_j\n"); break; - case TEST_K: + case USB_TEST_K: seq_printf(s, "test_k\n"); break; - case TEST_SE0_NAK: + case USB_TEST_SE0_NAK: seq_printf(s, "test_se0_nak\n"); break; - case TEST_PACKET: + case USB_TEST_PACKET: seq_printf(s, "test_packet\n"); break; - case TEST_FORCE_EN: + case USB_TEST_FORCE_ENABLE: seq_printf(s, "test_force_enable\n"); break; default: @@ -506,15 +506,15 @@ static ssize_t dwc3_testmode_write(struct file *file, return -EFAULT; if (!strncmp(buf, "test_j", 6)) - testmode = TEST_J; + testmode = USB_TEST_J; else if (!strncmp(buf, "test_k", 6)) - testmode = TEST_K; + testmode = USB_TEST_K; else if (!strncmp(buf, "test_se0_nak", 12)) - testmode = TEST_SE0_NAK; + testmode = USB_TEST_SE0_NAK; else if (!strncmp(buf, "test_packet", 11)) - testmode = TEST_PACKET; + testmode = USB_TEST_PACKET; else if (!strncmp(buf, "test_force_enable", 17)) - testmode = TEST_FORCE_EN; + testmode = USB_TEST_FORCE_ENABLE; else testmode = 0; diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 2e483448d6959927edea713df82495e86f5bb4a1..3e1c1aacf002b50d2423ba195ec69bb80b088993 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * drd.c - DesignWare USB3 DRD Controller Dual-role support * - * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com * * Authors: Roger Quadros <rogerq@ti.com> */ diff --git a/drivers/usb/dwc3/dwc3-haps.c b/drivers/usb/dwc3/dwc3-haps.c index 3cecbf1694526eed989ccbd0b39d2988d2697564..55b4a901168e8c46d5f71f3055c4690345ba29f5 100644 --- a/drivers/usb/dwc3/dwc3-haps.c +++ b/drivers/usb/dwc3/dwc3-haps.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * dwc3-haps.c - Synopsys HAPS PCI Specific glue layer * * Copyright (C) 2018 Synopsys, Inc. diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 6505f7bd69e25d62bb73d463c89f442dccd246a1..9a99253d5ba3be3a428c04ce491fed06e1003c2c 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -2,7 +2,7 @@ /** * dwc3-keystone.c - Keystone Specific Glue layer * - * Copyright (C) 2010-2013 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2013 Texas Instruments Incorporated - https://www.ti.com * * Author: WingMan Kwok <w-kwok2@ti.com> */ diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 1f7f4d88ed9d8d1227fde3ce460b3bfe4fc5abf6..88b75b5a039c949ba63b195ff80acc34a43649e6 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -737,13 +737,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) goto err_disable_clks; } - ret = reset_control_reset(priv->reset); + ret = reset_control_deassert(priv->reset); if (ret) - goto err_disable_clks; + goto err_assert_reset; ret = dwc3_meson_g12a_get_phys(priv); if (ret) - goto err_disable_clks; + goto err_assert_reset; ret = priv->drvdata->setup_regmaps(priv, base); if (ret) @@ -752,7 +752,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) if (priv->vbus) { ret = regulator_enable(priv->vbus); if (ret) - goto err_disable_clks; + goto err_assert_reset; } /* Get dr_mode */ @@ -765,13 +765,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) ret = priv->drvdata->usb_init(priv); if (ret) - goto err_disable_clks; + goto err_assert_reset; /* Init PHYs */ for (i = 0 ; i < PHY_COUNT ; ++i) { ret = phy_init(priv->phys[i]); if (ret) - goto err_disable_clks; + goto err_assert_reset; } /* Set PHY Power */ @@ -809,6 +809,9 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) for (i = 0 ; i < PHY_COUNT ; ++i) phy_exit(priv->phys[i]); +err_assert_reset: + reset_control_assert(priv->reset); + err_disable_clks: clk_bulk_disable_unprepare(priv->drvdata->num_clks, priv->drvdata->clks); diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index 8852fbfdead4e7a75a68c958532af2e49a569a78..7df11501293548e4cfe8a1330c54ff8746e0cd69 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * dwc3-of-simple.c - OF glue layer for simple integrations * - * Copyright (c) 2015 Texas Instruments Incorporated - http://www.ti.com + * Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com * * Author: Felipe Balbi <balbi@ti.com> * diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 8c3de2d258bf7d780edf70737a967b7a281f5317..3db17806e92e7df6c132bb0c71027eb8346748dd 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * dwc3-omap.c - OMAP Specific Glue layer * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -457,8 +457,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) int ret; int irq; - u32 reg; - void __iomem *base; if (!node) { @@ -503,9 +501,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) dwc3_omap_map_offset(omap); dwc3_omap_set_utmi_mode(omap); - /* check the DMA Status */ - reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); - ret = dwc3_omap_extcon_register(omap); if (ret < 0) goto err1; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 139474c3e77b1c8693ac284114159af9a22ae702..f5a61f57c74f0005ef3ddd0f54289f2916e3fcfd 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -2,7 +2,7 @@ /** * dwc3-pci.c - PCI Specific glue layer * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 1dfd024cd06b11ff2a0409acff192890d7754bef..e1e78e9824b16eb11e95f516e21ef7dfb75a6bc3 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -540,16 +540,6 @@ static int dwc3_qcom_of_register_core(struct platform_device *pdev) return 0; } -static const struct dwc3_acpi_pdata sdm845_acpi_pdata = { - .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET, - .qscratch_base_size = SDM845_QSCRATCH_SIZE, - .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE, - .hs_phy_irq_index = 1, - .dp_hs_phy_irq_index = 4, - .dm_hs_phy_irq_index = 3, - .ss_phy_irq_index = 2 -}; - static int dwc3_qcom_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -758,11 +748,23 @@ static const struct of_device_id dwc3_qcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); +#ifdef CONFIG_ACPI +static const struct dwc3_acpi_pdata sdm845_acpi_pdata = { + .qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET, + .qscratch_base_size = SDM845_QSCRATCH_SIZE, + .dwc3_core_base_size = SDM845_DWC3_CORE_SIZE, + .hs_phy_irq_index = 1, + .dp_hs_phy_irq_index = 4, + .dm_hs_phy_irq_index = 3, + .ss_phy_irq_index = 2 +}; + static const struct acpi_device_id dwc3_qcom_acpi_match[] = { { "QCOM2430", (unsigned long)&sdm845_acpi_pdata }, { }, }; MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match); +#endif static struct platform_driver dwc3_qcom_driver = { .probe = dwc3_qcom_probe, diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index c682420f25ca97b747d3c0be6ccf0293c6cfcc77..e733be84054597fb15063ffb2d3ca7452e196d02 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -206,8 +206,8 @@ static int st_dwc3_probe(struct platform_device *pdev) if (!dwc3_data) return -ENOMEM; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg-glue"); - dwc3_data->glue_base = devm_ioremap_resource(dev, res); + dwc3_data->glue_base = + devm_platform_ioremap_resource_byname(pdev, "reg-glue"); if (IS_ERR(dwc3_data->glue_base)) return PTR_ERR(dwc3_data->glue_base); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 6dee4dabc0a435f72e18527e0d05814284d278dc..59f2e8c31bd1bf94c0b483979ee39b01a45acb84 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -2,7 +2,7 @@ /* * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -425,11 +425,11 @@ static int dwc3_ep0_handle_test(struct dwc3 *dwc, enum usb_device_state state, return -EINVAL; switch (wIndex >> 8) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: + case USB_TEST_FORCE_ENABLE: dwc->test_mode_nr = wIndex >> 8; dwc->test_mode = true; break; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 80c3ef134e41d3b8d0e5b6b3a0080992ee8ea883..e44bfc3b5096d987dd74f9ff0c14a273862c6568 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2,7 +2,7 @@ /* * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -46,11 +46,11 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) reg &= ~DWC3_DCTL_TSTCTRL_MASK; switch (mode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: + case USB_TEST_FORCE_ENABLE: reg |= mode << 1; break; default: @@ -1403,7 +1403,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) * Check if we can start isoc transfer on the next interval or * 4 uframes in the future with BIT[15:14] as dep->combo_num */ - test_frame_number = dep->frame_number & 0x3fff; + test_frame_number = dep->frame_number & DWC3_FRNUMBER_MASK; test_frame_number |= dep->combo_num << 14; test_frame_number += max_t(u32, 4, dep->interval); @@ -1450,7 +1450,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) else if (test0 && test1) dep->combo_num = 0; - dep->frame_number &= 0x3fff; + dep->frame_number &= DWC3_FRNUMBER_MASK; dep->frame_number |= dep->combo_num << 14; dep->frame_number += max_t(u32, 4, dep->interval); @@ -1463,6 +1463,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) { + const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; struct dwc3 *dwc = dep->dwc; int ret; int i; @@ -1480,6 +1481,27 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) return dwc3_gadget_start_isoc_quirk(dep); } + if (desc->bInterval <= 14 && + dwc->gadget.speed >= USB_SPEED_HIGH) { + u32 frame = __dwc3_gadget_get_frame(dwc); + bool rollover = frame < + (dep->frame_number & DWC3_FRNUMBER_MASK); + + /* + * frame_number is set from XferNotReady and may be already + * out of date. DSTS only provides the lower 14 bit of the + * current frame number. So add the upper two bits of + * frame_number and handle a possible rollover. + * This will provide the correct frame_number unless more than + * rollover has happened since XferNotReady. + */ + + dep->frame_number = (dep->frame_number & ~DWC3_FRNUMBER_MASK) | + frame; + if (rollover) + dep->frame_number += BIT(14); + } + for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) { dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1); @@ -2716,7 +2738,9 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep, if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) goto out; - if (status == -EXDEV && list_empty(&dep->started_list)) + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + list_empty(&dep->started_list) && + (list_empty(&dep->pending_list) || status == -EXDEV)) dwc3_stop_active_transfer(dep, true, true); else if (dwc3_gadget_ep_should_continue(dep)) if (__dwc3_gadget_kick_transfer(dep) == 0) diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 24dca38720225ddc49d817488a1342a118dc9c8b..bd85eb7fa9ef84eecafbdb8dc70606f4bcba40c7 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -2,7 +2,7 @@ /* * gadget.h - DesignWare USB3 DRD Gadget Header * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> @@ -54,6 +54,8 @@ struct dwc3; /* U2 Device exit Latency */ #define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */ +/* Frame/Microframe Number Mask */ +#define DWC3_FRNUMBER_MASK 0x3fff /* -------------------------------------------------------------------------- */ #define to_dwc3_request(r) (container_of(r, struct dwc3_request, request)) diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index bef1c1ac20677c1b3701a8c4ed6526cfa6d00cd1..e195176580de1f52cd5c2a49ede2f69caf000045 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -2,7 +2,7 @@ /* * host.c - DesignWare USB3 DRD Controller Host Glue * - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, */ diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 9bbe5d4bf076ac5c4399ef5b4e44811f7c79b2ab..76b73b116862625839c24ea078b901608d308b8c 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -2,7 +2,7 @@ /** * io.h - DesignWare USB3 DRD IO Header * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010-2011 Texas Instruments Incorporated - https://www.ti.com * * Authors: Felipe Balbi <balbi@ti.com>, * Sebastian Andrzej Siewior <bigeasy@linutronix.de> diff --git a/drivers/usb/dwc3/trace.c b/drivers/usb/dwc3/trace.c index f8886f3f3c9ed23407cbb23002dd79d03a329551..1b45a9723eeb7f3ff305f2466066a5da3f8657d6 100644 --- a/drivers/usb/dwc3/trace.c +++ b/drivers/usb/dwc3/trace.c @@ -2,7 +2,7 @@ /** * trace.c - DesignWare USB3 DRD Controller Trace Support * - * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com * * Author: Felipe Balbi <balbi@ti.com> */ diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 4c4fc6c41d9b4193cec869a6a569fe02492abf3a..da1be01637c8d826c1cdb7794d9ff077b7356776 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -2,7 +2,7 @@ /** * trace.h - DesignWare USB3 DRD Controller Trace Support * - * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com * * Author: Felipe Balbi <balbi@ti.com> */ diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c index f62b5f3c2d67dbf85be78473a388a3093a941986..e6e6176386a4b4942fc28382c22abcfad7ce8d11 100644 --- a/drivers/usb/dwc3/ulpi.c +++ b/drivers/usb/dwc3/ulpi.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * ulpi.c - DesignWare USB3 Controller's ULPI PHY interface * * Copyright (C) 2015 Intel Corporation diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 775cf70cfb3ed3f82a1e821b0d1bf78886043bed..b075dbfad730fb2099840dc74a63adeb289f20d4 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -912,7 +912,7 @@ int __init early_dbgp_init(char *s) static void early_dbgp_write(struct console *con, const char *str, u32 n) { - int chunk, ret; + int chunk; char buf[DBGP_MAX_PACKET]; int use_cr = 0; u32 cmd, ctrl; @@ -951,8 +951,8 @@ static void early_dbgp_write(struct console *con, const char *str, u32 n) buf[chunk] = *str; } if (chunk > 0) { - ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, - dbgp_endpoint_out, buf, chunk); + dbgp_bulk_write(USB_DEBUG_DEVNUM, + dbgp_endpoint_out, buf, chunk); } } if (unlikely(reset_run)) { diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 04ba11fff0edcd2b178b30385a73e2b84b8214a7..c0507767a8e34f124dbfcf297dfdf714bf5e2ace 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * xhci-dbc.c - xHCI debug capability early driver * * Copyright (C) 2016 Intel Corporation @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/kthread.h> +#include <linux/usb/xhci-dbgp.h> #include "../host/xhci.h" #include "xhci-dbc.h" diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c6db0a0a340c9345eeda98d71c357dc7cbdb206d..7e47e6223089cb42c2df61f00a17f0205ffecf24 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -19,8 +19,8 @@ menuconfig USB_GADGET select USB_COMMON select NLS help - USB is a master/slave protocol, organized with one master - host (such as a PC) controlling up to 127 peripheral devices. + USB is a host/device protocol, organized with one host (such as a + PC) controlling up to 127 peripheral devices. The USB hardware is asymmetric, which makes it easier to set up: you can't connect a "to-the-host" connector to a peripheral. diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5c1eb96a5c5713e0d0397659b582a811b0dcc9b7..05b176c82cc522b7416b0379915af615b3eac4ec 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -72,17 +72,17 @@ function_descriptors(struct usb_function *f, descriptors = f->ssp_descriptors; if (descriptors) break; - /* FALLTHROUGH */ + fallthrough; case USB_SPEED_SUPER: descriptors = f->ss_descriptors; if (descriptors) break; - /* FALLTHROUGH */ + fallthrough; case USB_SPEED_HIGH: descriptors = f->hs_descriptors; if (descriptors) break; - /* FALLTHROUGH */ + fallthrough; default: descriptors = f->fs_descriptors; } @@ -170,20 +170,20 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g, want_comp_desc = 1; break; } - /* fall through */ + fallthrough; case USB_SPEED_SUPER: if (gadget_is_superspeed(g)) { speed_desc = f->ss_descriptors; want_comp_desc = 1; break; } - /* fall through */ + fallthrough; case USB_SPEED_HIGH: if (gadget_is_dualspeed(g)) { speed_desc = f->hs_descriptors; break; } - /* fall through */ + fallthrough; default: speed_desc = f->fs_descriptors; } @@ -237,7 +237,7 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g, case USB_ENDPOINT_XFER_ISOC: /* mult: bits 1:0 of bmAttributes */ _ep->mult = (comp_desc->bmAttributes & 0x3) + 1; - /* fall through */ + fallthrough; case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_INT: _ep->maxburst = comp_desc->bMaxBurst + 1; @@ -1085,7 +1085,7 @@ static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) while (*sp) { s = *sp; language = cpu_to_le16(s->language); - for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { + for (tmp = buf; *tmp && tmp < &buf[USB_MAX_STRING_LEN]; tmp++) { if (*tmp == language) goto repeat; } @@ -1160,7 +1160,7 @@ static int get_string(struct usb_composite_dev *cdev, collect_langs(sp, s->wData); } - for (len = 0; len <= 126 && s->wData[len]; len++) + for (len = 0; len <= USB_MAX_STRING_LEN && s->wData[len]; len++) continue; if (!len) return -EINVAL; @@ -1697,7 +1697,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!gadget_is_dualspeed(gadget) || gadget->speed >= USB_SPEED_SUPER) break; - /* FALLTHROUGH */ + fallthrough; case USB_DT_CONFIG: value = config_desc(cdev, w_value); if (value >= 0) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 9dc06a4e1b307822726e2e4b0f8f81e05777efdc..56051bb9734983d643ff809007b7c8c5862ae758 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -103,7 +103,7 @@ static int usb_string_copy(const char *s, char **s_copy) char *str; char *copy = *s_copy; ret = strlen(s); - if (ret > 126) + if (ret > USB_MAX_STRING_LEN) return -EOVERFLOW; str = kstrdup(s, GFP_KERNEL); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 490d353d5fdecff95cdf8d7429436928b8cf32aa..046f770a76dae1cd0d40cb028ae950bd797287d2 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2352,7 +2352,7 @@ static int __must_check ffs_do_os_descs(unsigned count, return _len - len; } -/** +/* * Validate contents of the buffer from userspace related to OS descriptors. */ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, @@ -2726,7 +2726,7 @@ static void __ffs_event_add(struct ffs_data *ffs, switch (type) { case FUNCTIONFS_RESUME: rem_type2 = FUNCTIONFS_SUSPEND; - /* FALL THROUGH */ + fallthrough; case FUNCTIONFS_SUSPEND: case FUNCTIONFS_SETUP: rem_type1 = type; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index df671acdd464b7e9c323ebfbadc0fefd9e37acfd..1125f4715830de1e5e201001e042f758a7ac395e 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -477,7 +477,7 @@ static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) break; default: ERROR(cdev, "Set report failed %d\n", req->status); - /* FALLTHROUGH */ + fallthrough; case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 950d2a85f098e1532ae3744759a3c2d410b3d991..331c951d72dc994ab4f16f4ee9d1c095f046dae6 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2039,7 +2039,7 @@ static int do_scsi_command(struct fsg_common *common) case RELEASE: case RESERVE: case SEND_DIAGNOSTIC: - /* Fall through */ + fallthrough; default: unknown_cmnd: diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c index d7f6cc51b7ece7abc93d63fa5931887c052c4c43..0b468f5d55bc5df968de2ab142ddcc2c8d50c3aa 100644 --- a/drivers/usb/gadget/function/f_phonet.c +++ b/drivers/usb/gadget/function/f_phonet.c @@ -212,7 +212,7 @@ static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req) case -ESHUTDOWN: /* disconnected */ case -ECONNRESET: /* disabled */ dev->stats.tx_aborted_errors++; - /* fall through */ + fallthrough; default: dev->stats.tx_errors++; } @@ -360,7 +360,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) /* Do resubmit in these cases: */ case -EOVERFLOW: /* request buffer overflow */ dev->stats.rx_over_errors++; - /* fall through */ + fallthrough; default: dev->stats.rx_errors++; break; diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 9c7ed2539ff7727c64427d76a681a063c82937b7..68697f596066c6037e811511dd242e5959be18e2 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -285,7 +285,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) /* data overrun */ case -EOVERFLOW: - /* FALLTHROUGH */ + fallthrough; default: DBG(dev, "rx status %d\n", status); @@ -304,7 +304,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) switch (req->status) { default: VDBG(dev, "tx err %d\n", req->status); - /* FALLTHROUGH */ + fallthrough; case -ECONNRESET: /* unlink */ case -ESHUTDOWN: /* disconnect etc */ break; @@ -338,6 +338,11 @@ printer_open(struct inode *inode, struct file *fd) spin_lock_irqsave(&dev->lock, flags); + if (dev->interface < 0) { + spin_unlock_irqrestore(&dev->lock, flags); + return -ENODEV; + } + if (!dev->printer_cdev_open) { dev->printer_cdev_open = 1; fd->private_data = dev; @@ -430,6 +435,12 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) mutex_lock(&dev->lock_printer_io); spin_lock_irqsave(&dev->lock, flags); + if (dev->interface < 0) { + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + return -ENODEV; + } + /* We will use this flag later to check if a printer reset happened * after we turn interrupts back on. */ @@ -561,6 +572,12 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) mutex_lock(&dev->lock_printer_io); spin_lock_irqsave(&dev->lock, flags); + if (dev->interface < 0) { + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + return -ENODEV; + } + /* Check if a printer reset happens while we have interrupts on */ dev->reset_printer = 0; @@ -667,6 +684,13 @@ printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) inode_lock(inode); spin_lock_irqsave(&dev->lock, flags); + + if (dev->interface < 0) { + spin_unlock_irqrestore(&dev->lock, flags); + inode_unlock(inode); + return -ENODEV; + } + tx_list_empty = (likely(list_empty(&dev->tx_reqs))); spin_unlock_irqrestore(&dev->lock, flags); @@ -689,6 +713,13 @@ printer_poll(struct file *fd, poll_table *wait) mutex_lock(&dev->lock_printer_io); spin_lock_irqsave(&dev->lock, flags); + + if (dev->interface < 0) { + spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock_printer_io); + return EPOLLERR | EPOLLHUP; + } + setup_rx_reqs(dev); spin_unlock_irqrestore(&dev->lock, flags); mutex_unlock(&dev->lock_printer_io); @@ -722,6 +753,11 @@ printer_ioctl(struct file *fd, unsigned int code, unsigned long arg) spin_lock_irqsave(&dev->lock, flags); + if (dev->interface < 0) { + spin_unlock_irqrestore(&dev->lock, flags); + return -ENODEV; + } + switch (code) { case GADGET_GET_PRINTER_STATUS: status = (int)dev->printer_status; @@ -919,7 +955,7 @@ static bool gprinter_req_match(struct usb_function *f, if (!w_value && !w_length && !(USB_DIR_IN & ctrl->bRequestType)) break; - /* fall through */ + fallthrough; default: return false; } diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 0d8e4a364ca6e0d54d01fc644c4907287b88646c..9534c8ab62a8e4c7bcd4e8e47b2e87c501582f13 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -426,7 +426,7 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) DBG(cdev, "RNDIS %s response error %d, %d/%d\n", ep->name, status, req->actual, req->length); - /* FALLTHROUGH */ + fallthrough; case 0: if (ep != rndis->notify) break; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index eaf556ceac32b741f054c3cde8f044df72f06228..d94b814328c8bfb447e14947e5b4e34a97d4f31f 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1150,7 +1150,7 @@ static int usbg_submit_command(struct f_uas *fu, default: pr_debug_once("Unsupported prio_attr: %02x.\n", cmd_iu->prio_attr); - /* fall through */ + fallthrough; case UAS_SIMPLE_TAG: cmd->prio_attr = TCM_SIMPLE_TAG; break; diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index db2d4980cb3549b51e187a1bd5788d52f2120e49..3633df6d7610f04e1d6b1142e9d8c2223900d806 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -215,10 +215,7 @@ static struct uac2_ac_header_descriptor ac_hdr_desc = { .bDescriptorSubtype = UAC_MS_HEADER, .bcdADC = cpu_to_le16(0x200), .bCategory = UAC2_FUNCTION_IO_BOX, - .wTotalLength = cpu_to_le16(sizeof in_clk_src_desc - + sizeof out_clk_src_desc + sizeof usb_out_it_desc - + sizeof io_in_it_desc + sizeof usb_in_ot_desc - + sizeof io_out_ot_desc), + /* .wTotalLength = DYNAMIC */ .bmControls = 0, }; @@ -501,7 +498,7 @@ static void setup_descriptor(struct f_uac2_opts *opts) as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; iad_desc.bInterfaceCount = 1; - ac_hdr_desc.wTotalLength = 0; + ac_hdr_desc.wTotalLength = cpu_to_le16(sizeof(ac_hdr_desc)); if (EPIN_EN(opts)) { u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index fbe96ef1ac7a42dd2bac48a37b1a95e9801172d2..c3cc6bd14e615a26bfaaa938938e4d0859814978 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -321,7 +321,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req) /* data overrun */ case -EOVERFLOW: dev->net->stats.rx_over_errors++; - /* FALLTHROUGH */ + fallthrough; default: dev->net->stats.rx_errors++; @@ -444,7 +444,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req) default: dev->net->stats.tx_errors++; VDBG(dev, "tx err %d\n", req->status); - /* FALLTHROUGH */ + fallthrough; case -ECONNRESET: /* unlink */ case -ESHUTDOWN: /* disconnect etc */ dev_kfree_skb_any(skb); @@ -730,7 +730,7 @@ static struct device_type gadget_type = { .name = "gadget", }; -/** +/* * gether_setup_name - initialize one ethernet-over-usb link * @g: gadget to associated with these links * @ethaddr: NULL, or a buffer in which the ethernet address of the @@ -1012,7 +1012,7 @@ int gether_get_ifname(struct net_device *net, char *name, int len) } EXPORT_SYMBOL_GPL(gether_get_ifname); -/** +/* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep * diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 3cfc6e2eba71a475eec8b81821069fd791e48c22..127ecc2b431766730a2989d39495fc492178f70c 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -386,7 +386,7 @@ static void gs_rx_push(struct work_struct *work) /* presumably a transient fault */ pr_warn("ttyGS%d: unexpected RX status %d\n", port->port_num, req->status); - /* FALLTHROUGH */ + fallthrough; case 0: /* normal completion */ break; @@ -472,7 +472,7 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) /* presumably a transient fault */ pr_warn("%s: unexpected %s status %d\n", __func__, ep->name, req->status); - /* FALL THROUGH */ + fallthrough; case 0: /* normal completion */ gs_start_tx(port); @@ -527,7 +527,7 @@ static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head, /** * gs_start_io - start USB I/O streams - * @dev: encapsulates endpoints to use + * @port: port to use * Context: holding port_lock; port_tty and port_usb are non-null * * We only start I/O when something is connected to both sides of @@ -871,7 +871,7 @@ static void gs_console_complete_out(struct usb_ep *ep, struct usb_request *req) default: pr_warn("%s: unexpected %s status %d\n", __func__, ep->name, req->status); - /* fall through */ + fallthrough; case 0: /* normal completion */ spin_lock(&cons->lock); diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h index cadb76eecbc7a870888cd1f33e983704baa7c73b..102a7323a1fd344e490acdc4440a9fd94c96cdc9 100644 --- a/drivers/usb/gadget/function/u_serial.h +++ b/drivers/usb/gadget/function/u_serial.h @@ -12,7 +12,7 @@ #include <linux/usb/composite.h> #include <linux/usb/cdc.h> -#define MAX_U_SERIAL_PORTS 4 +#define MAX_U_SERIAL_PORTS 8 struct f_serial_opts { struct usb_function_instance func_inst; diff --git a/drivers/usb/gadget/function/u_uac1_legacy.c b/drivers/usb/gadget/function/u_uac1_legacy.c index 5393e5c37a4ba68d36952fabc1bacbb2e9fcb3b3..60ae8b2d3f6a2f78f71b3d624ff15f18f66df493 100644 --- a/drivers/usb/gadget/function/u_uac1_legacy.c +++ b/drivers/usb/gadget/function/u_uac1_legacy.c @@ -23,7 +23,7 @@ /*-------------------------------------------------------------------------*/ -/** +/* * Some ALSA internal helper functions */ static int snd_interval_refine_set(struct snd_interval *i, unsigned int val) @@ -86,7 +86,7 @@ static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, } /*-------------------------------------------------------------------------*/ -/** +/* * Set default hardware params */ static int playback_default_hw_params(struct gaudio_snd_dev *snd) @@ -146,7 +146,7 @@ static int playback_default_hw_params(struct gaudio_snd_dev *snd) return 0; } -/** +/* * Playback audio buffer data by ALSA PCM device */ size_t u_audio_playback(struct gaudio *card, void *buf, size_t count) @@ -189,7 +189,7 @@ int u_audio_get_playback_rate(struct gaudio *card) return card->playback.rate; } -/** +/* * Open ALSA PCM and control device files * Initial the PCM or control device */ @@ -250,7 +250,7 @@ static int gaudio_open_snd_dev(struct gaudio *card) return 0; } -/** +/* * Close ALSA PCM and control device files */ static int gaudio_close_snd_dev(struct gaudio *gau) @@ -275,7 +275,7 @@ static int gaudio_close_snd_dev(struct gaudio *gau) return 0; } -/** +/* * gaudio_setup - setup ALSA interface and preparing for USB transfer * * This sets up PCM, mixer or MIDI ALSA devices fore USB gadget using. @@ -294,7 +294,7 @@ int gaudio_setup(struct gaudio *card) } -/** +/* * gaudio_cleanup - remove ALSA device interface * * This is called to free all resources allocated by @gaudio_setup(). diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 9ee0bfe7bcdaeac2b6377894adf05b64813b7c2d..1b430b36d0a6be6042732c586446129c09a823a5 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -312,7 +312,7 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata, bool is_write) case STATE_EP_READY: /* not configured yet */ if (is_write) return 0; - // FALLTHRU + fallthrough; case STATE_EP_UNBOUND: /* clean disconnect */ break; // case STATE_EP_DISABLED: /* "can't happen" */ @@ -1084,7 +1084,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) case GADGETFS_DISCONNECT: if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; - // FALL THROUGH + fallthrough; case GADGETFS_CONNECT: dev->ev_next = 0; break; @@ -1381,7 +1381,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) make_qualifier (dev); break; case USB_DT_OTHER_SPEED_CONFIG: - // FALLTHROUGH case USB_DT_CONFIG: value = config_buf (dev, w_value >> 8, @@ -1718,7 +1717,7 @@ gadgetfs_suspend (struct usb_gadget *gadget) case STATE_DEV_UNCONNECTED: next_event (dev, GADGETFS_SUSPEND); ep0_readable (dev); - /* FALLTHROUGH */ + fallthrough; default: break; } diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 978c1a34a9320e8da4f17b9e701c15a744804bb4..2e15f9a32ce9fd14a72a30fd3e2e6de9196263bc 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -62,7 +62,6 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); #define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX static char manufacturer_nokia[] = "Nokia"; -static const char product_nokia[] = NOKIA_LONG_NAME; static const char description_nokia[] = "PC-Suite Configuration"; static struct usb_string strings_dev[] = { diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 57858f0c2b6c99e8d0632dc10f5d148aa835d97a..2cd389575084b7a64b170dd18cfb6a13fbcdb01c 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -21,7 +21,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); #define DRIVER_VERSION "2015 FEB 17" static const char shortname [] = "printer"; -static const char driver_desc [] = DRIVER_DESC; #include "u_printer.h" diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c index 6e84b44c8a3bca144886203e2f745e4057043dc8..23312a07efb4941cd1b10bf9a1734a3815379de6 100644 --- a/drivers/usb/gadget/legacy/zero.c +++ b/drivers/usb/gadget/legacy/zero.c @@ -11,8 +11,8 @@ * can write a hardware-agnostic gadget driver running inside a USB device. * Some hardware details are visible, but don't affect most of the driver. * - * Use it with the Linux host/master side "usbtest" driver to get a basic - * functional test of your device-side usb stack, or with "usb-skeleton". + * Use it with the Linux host side "usbtest" driver to get a basic functional + * test of your device-side usb stack, or with "usb-skeleton". * * It supports two similar configurations. One sinks whatever the usb host * writes, and in return sources zeroes. The other loops whatever the host diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 3a7179e90f4e8f432534bbb0e53596d57f9a7aa2..1a12aab208b465d32cbf2b4d80de61c1a54cc14a 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -474,7 +474,7 @@ config USB_DUMMY_HCD help This host controller driver emulates USB, looping all data transfer requests back to a USB "gadget driver" in the same host. The host - side is the master; the gadget side is the slave. Gadget drivers + side is the controller; the gadget side is the device. Gadget drivers can be high, full, or low speed; and they have access to endpoints like those from NET2280, PXA2xx, or SA1100 hardware. diff --git a/drivers/usb/gadget/udc/amd5536udc.h b/drivers/usb/gadget/udc/amd5536udc.h index 0262383f8c79ce699a4f7d6131663ef7642a46e6..3296f3fcee486918c470064e7dc54ef3b670e06c 100644 --- a/drivers/usb/gadget/udc/amd5536udc.h +++ b/drivers/usb/gadget/udc/amd5536udc.h @@ -2,7 +2,7 @@ /* * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller * - * Copyright (C) 2007 AMD (http://www.amd.com) + * Copyright (C) 2007 AMD (https://www.amd.com) * Author: Thomas Dahlmann */ diff --git a/drivers/usb/gadget/udc/amd5536udc_pci.c b/drivers/usb/gadget/udc/amd5536udc_pci.c index 80685e4306f314e909448306975d9a9c05cbd75b..8d387e0e4d91fca0512ea98cfbd21d069e8dcec9 100644 --- a/drivers/usb/gadget/udc/amd5536udc_pci.c +++ b/drivers/usb/gadget/udc/amd5536udc_pci.c @@ -2,7 +2,7 @@ /* * amd5536udc_pci.c -- AMD 5536 UDC high/full speed USB device controller * - * Copyright (C) 2005-2007 AMD (http://www.amd.com) + * Copyright (C) 2005-2007 AMD (https://www.amd.com) * Author: Thomas Dahlmann */ @@ -49,7 +49,6 @@ static struct udc *udc; /* description */ -static const char mod_desc[] = UDC_MOD_DESCRIPTION; static const char name[] = "amd5536udc-pci"; /* Reset all pci context */ diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 9342a3d24963934326df7db62aee7135d4182d15..fa6793065c7c986e47ebf9335afa7a9004615617 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1028,6 +1028,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) return 0; } +static int atmel_usba_pullup(struct usb_gadget *gadget, int is_on); static int atmel_usba_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); static int atmel_usba_stop(struct usb_gadget *gadget); @@ -1101,6 +1102,7 @@ static const struct usb_gadget_ops usba_udc_ops = { .get_frame = usba_udc_get_frame, .wakeup = usba_udc_wakeup, .set_selfpowered = usba_udc_set_selfpowered, + .pullup = atmel_usba_pullup, .udc_start = atmel_usba_start, .udc_stop = atmel_usba_stop, .match_ep = atmel_usba_match_ep, @@ -1957,6 +1959,24 @@ static irqreturn_t usba_vbus_irq_thread(int irq, void *devid) return IRQ_HANDLED; } +static int atmel_usba_pullup(struct usb_gadget *gadget, int is_on) +{ + struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&udc->lock, flags); + ctrl = usba_readl(udc, CTRL); + if (is_on) + ctrl &= ~USBA_DETACH; + else + ctrl |= USBA_DETACH; + usba_writel(udc, CTRL, ctrl); + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + static int atmel_usba_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { @@ -2097,7 +2117,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; const struct of_device_id *match; - struct device_node *pp; int i, ret; struct usba_ep *eps, *ep; const struct usba_udc_config *udc_config; @@ -2122,7 +2141,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, GPIOD_IN); if (fifo_mode == 0) { - pp = NULL; udc->num_ep = udc_config->num_ep; udc->configured_ep = 1; } else { @@ -2138,7 +2156,6 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, INIT_LIST_HEAD(&eps[0].ep.ep_list); - pp = NULL; i = 0; while (i < udc->num_ep) { const struct usba_ep_config *ep_cfg = &udc_config->config[i]; diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 54501814dc3fd9b5e35a978f807fbc095531de50..feaec00a3c169bf4a39e441d2a0cf3bdb658e9de 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -266,8 +266,8 @@ struct bcm63xx_req { * @pd: Platform data (board/port info). * @usbd_clk: Clock descriptor for the USB device block. * @usbh_clk: Clock descriptor for the USB host block. - * @gadget: USB slave device. - * @driver: Driver for USB slave devices. + * @gadget: USB device. + * @driver: Driver for USB device. * @usbd_regs: Base address of the USBD/USB20D block. * @iudma_regs: Base address of the USBD's associated IUDMA block. * @bep: Array of endpoints, including ep0. @@ -1744,7 +1744,7 @@ static void bcm63xx_ep0_process(struct work_struct *w) /** * bcm63xx_udc_get_frame - Read current SOF frame number from the HW. - * @gadget: USB slave device. + * @gadget: USB device. */ static int bcm63xx_udc_get_frame(struct usb_gadget *gadget) { @@ -1756,7 +1756,7 @@ static int bcm63xx_udc_get_frame(struct usb_gadget *gadget) /** * bcm63xx_udc_pullup - Enable/disable pullup on D+ line. - * @gadget: USB slave device. + * @gadget: USB device. * @is_on: 0 to disable pullup, 1 to enable. * * See notes in bcm63xx_select_pullup(). @@ -1805,8 +1805,8 @@ static int bcm63xx_udc_pullup(struct usb_gadget *gadget, int is_on) /** * bcm63xx_udc_start - Start the controller. - * @gadget: USB slave device. - * @driver: Driver for USB slave devices. + * @gadget: USB device. + * @driver: Driver for USB device. */ static int bcm63xx_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) @@ -1842,8 +1842,8 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget, /** * bcm63xx_udc_stop - Shut down the controller. - * @gadget: USB slave device. - * @driver: Driver for USB slave devices. + * @gadget: USB device. + * @driver: Driver for USB device. */ static int bcm63xx_udc_stop(struct usb_gadget *gadget) { diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index 6e1e881dc51e22eb362c09208aadafd57d550593..ac75e25c3b6ab4a79cbbbac360f6b19f535719b2 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -44,7 +44,7 @@ #define NUM_SR_ENTRIES 64 /* Num of bds per table */ -#define NUM_BDS_PER_TABLE 32 +#define NUM_BDS_PER_TABLE 64 /* Num of tables in bd list for control,bulk and Int ep */ #define NUM_TABLES 2 diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 02a3a774670b1682619fdd58de3aa4e9d5615bc0..5ff36525044ef0814da99dad60d0ff917ad060bd 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -12,6 +12,7 @@ #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/iopoll.h> #include <linux/ioport.h> #include <linux/io.h> #include <linux/list.h> @@ -29,24 +30,19 @@ #include "bdc_dbg.h" /* Poll till controller status is not OIP */ -static int poll_oip(struct bdc *bdc, int usec) +static int poll_oip(struct bdc *bdc, u32 usec) { u32 status; - /* Poll till STS!= OIP */ - while (usec) { - status = bdc_readl(bdc->regs, BDC_BDCSC); - if (BDC_CSTS(status) != BDC_OIP) { - dev_dbg(bdc->dev, - "poll_oip complete status=%d", - BDC_CSTS(status)); - return 0; - } - udelay(10); - usec -= 10; - } - dev_err(bdc->dev, "Err: operation timedout BDCSC: 0x%08x\n", status); + int ret; - return -ETIMEDOUT; + ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status, + (BDC_CSTS(status) != BDC_OIP), 10, usec); + if (ret) + dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status); + else + dev_dbg(bdc->dev, "%s complete status=%d", __func__, BDC_CSTS(status)); + + return ret; } /* Stop the BDC controller */ @@ -282,6 +278,7 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit) * in that case reinit is passed as 1 */ if (reinit) { + int i; /* Enable interrupts */ temp = bdc_readl(bdc->regs, BDC_BDCSC); temp |= BDC_GIE; @@ -291,6 +288,13 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit) /* Initialize SRR to 0 */ memset(bdc->srr.sr_bds, 0, NUM_SR_ENTRIES * sizeof(struct bdc_bd)); + /* + * clear ep flags to avoid post disconnect stops/deconfigs but + * not during S2 exit + */ + if (!bdc->gadget.speed) + for (i = 1; i < bdc->num_eps; ++i) + bdc->bdc_ep_array[i]->flags = 0; } else { /* One time initiaization only */ /* Enable status report function pointers */ @@ -489,11 +493,9 @@ static int bdc_probe(struct platform_device *pdev) dev_dbg(dev, "%s()\n", __func__); - clk = devm_clk_get(dev, "sw_usbd"); - if (IS_ERR(clk)) { - dev_info(dev, "Clock not found in Device Tree\n"); - clk = NULL; - } + clk = devm_clk_get_optional(dev, "sw_usbd"); + if (IS_ERR(clk)) + return PTR_ERR(clk); ret = clk_prepare_enable(clk); if (ret) { @@ -599,9 +601,14 @@ static int bdc_remove(struct platform_device *pdev) static int bdc_suspend(struct device *dev) { struct bdc *bdc = dev_get_drvdata(dev); + int ret; - clk_disable_unprepare(bdc->clk); - return 0; + /* Halt the controller */ + ret = bdc_stop(bdc); + if (!ret) + clk_disable_unprepare(bdc->clk); + + return ret; } static int bdc_resume(struct device *dev) @@ -629,7 +636,7 @@ static SIMPLE_DEV_PM_OPS(bdc_pm_ops, bdc_suspend, bdc_resume); static const struct of_device_id bdc_of_match[] = { - { .compatible = "brcm,bdc-v0.16" }, + { .compatible = "brcm,bdc-udc-v2" }, { .compatible = "brcm,bdc" }, { /* sentinel */ } }; diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index d49c6dc1082dc980b47620a63fb28e35f5780c67..fafdc9fdb4a50a539d340906b42c30aab877279f 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -615,7 +615,6 @@ int bdc_ep_enable(struct bdc_ep *ep) } bdc_dbg_bd_list(bdc, ep); /* only for ep0: config ep is called for ep0 from connect event */ - ep->flags |= BDC_EP_ENABLED; if (ep->ep_num == 1) return ret; @@ -759,10 +758,13 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) __func__, ep->name, start_bdi, end_bdi); dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n", ep, (void *)ep->usb_ep.desc); - /* Stop the ep to see where the HW is ? */ - ret = bdc_stop_ep(bdc, ep->ep_num); - /* if there is an issue with stopping ep, then no need to go further */ - if (ret) + /* if still connected, stop the ep to see where the HW is ? */ + if (!(bdc_readl(bdc->regs, BDC_USPC) & BDC_PST_MASK)) { + ret = bdc_stop_ep(bdc, ep->ep_num); + /* if there is an issue, then no need to go further */ + if (ret) + return 0; + } else return 0; /* @@ -927,11 +929,11 @@ static int bdc_set_test_mode(struct bdc *bdc) usb2_pm &= ~BDC_PTC_MASK; dev_dbg(bdc->dev, "%s\n", __func__); switch (bdc->test_mode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: + case USB_TEST_J: + case USB_TEST_K: + case USB_TEST_SE0_NAK: + case USB_TEST_PACKET: + case USB_TEST_FORCE_ENABLE: usb2_pm |= bdc->test_mode << 28; break; default: @@ -1911,7 +1913,9 @@ static int bdc_gadget_ep_disable(struct usb_ep *_ep) __func__, ep->name, ep->flags); if (!(ep->flags & BDC_EP_ENABLED)) { - dev_warn(bdc->dev, "%s is already disabled\n", ep->name); + if (bdc->gadget.speed != USB_SPEED_UNKNOWN) + dev_warn(bdc->dev, "%s is already disabled\n", + ep->name); return 0; } spin_lock_irqsave(&bdc->lock, flags); diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 2e28dde8376f62be368c9ff6832b8b29dd405e4b..4f82bcd31fd3f662201e96b7a1647bced1af692e 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * udc.c - Core UDC Framework * * Copyright (C) 2010 Texas Instruments @@ -23,11 +23,11 @@ /** * struct usb_udc - describes one usb device controller - * @driver - the gadget driver pointer. For use by the class code - * @dev - the child device to the actual controller - * @gadget - the gadget. For use by the class code - * @list - for use by the udc class driver - * @vbus - for udcs who care about vbus status, this value is real vbus status; + * @driver: the gadget driver pointer. For use by the class code + * @dev: the child device to the actual controller + * @gadget: the gadget. For use by the class code + * @list: for use by the udc class driver + * @vbus: for udcs who care about vbus status, this value is real vbus status; * for udcs who do not care about vbus status, this value is always true * * This represents the internal data structure which is used by the UDC-class @@ -85,7 +85,7 @@ EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit); * for interrupt transfers as well as bulk, but it likely couldn't be used * for iso transfers or for endpoint 14. some endpoints are fully * configurable, with more generic names like "ep-a". (remember that for - * USB, "in" means "towards the USB master".) + * USB, "in" means "towards the USB host".) * * This routine must be called in process context. * @@ -891,6 +891,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); /** * usb_gadget_giveback_request - give the request back to the gadget layer + * @ep: the endpoint to be used with with the request + * @req: the request being given back + * * Context: in_interrupt() * * This is called by device controller drivers in order to return the @@ -1084,8 +1087,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc) /** * usb_gadget_udc_stop - tells usb device controller we don't need it anymore - * @gadget: The device we want to stop activity - * @driver: The driver to unbind from @gadget + * @udc: The UDC to be stopped * * This call is issued by the UDC Class driver after calling * gadget driver's unbind() method. @@ -1228,6 +1230,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, return 0; err_del_udc: + flush_work(&gadget->work); device_del(&udc->dev); err_unlist_udc: diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 0eeaead5acea307f2e3e940ebe059c00807a5c9a..53a227217f1cbc8ba42792af3721423941950412 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -14,7 +14,7 @@ * Linux-USB host controller driver. USB traffic is simulated; there's * no need for USB hardware. Use this with two other drivers: * - * - Gadget driver, responding to requests (slave); + * - Gadget driver, responding to requests (device); * - Host-side device driver, as already familiar in Linux. * * Having this all in one kernel can help some stages of development, @@ -261,7 +261,7 @@ struct dummy { spinlock_t lock; /* - * SLAVE/GADGET side support + * DEVICE/GADGET side support */ struct dummy_ep ep[DUMMY_ENDPOINTS]; int address; @@ -276,7 +276,7 @@ struct dummy { unsigned pullup:1; /* - * MASTER/HOST side support + * HOST side support */ struct dummy_hcd *hs_hcd; struct dummy_hcd *ss_hcd; @@ -323,7 +323,7 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev) /*-------------------------------------------------------------------------*/ -/* SLAVE/GADGET SIDE UTILITY ROUTINES */ +/* DEVICE/GADGET SIDE UTILITY ROUTINES */ /* called with spinlock held */ static void nuke(struct dummy *dum, struct dummy_ep *ep) @@ -486,7 +486,7 @@ static void set_link_state(struct dummy_hcd *dum_hcd) /*-------------------------------------------------------------------------*/ -/* SLAVE/GADGET SIDE DRIVER +/* DEVICE/GADGET SIDE DRIVER * * This only tracks gadget state. All the work is done when the host * side tries some (emulated) i/o operation. Real device controller @@ -567,12 +567,12 @@ static int dummy_enable(struct usb_ep *_ep, if (max <= 1024) break; /* save a return statement */ - /* fall through */ + fallthrough; case USB_SPEED_FULL: if (max <= 64) break; /* save a return statement */ - /* fall through */ + fallthrough; default: if (max <= 8) break; @@ -590,7 +590,7 @@ static int dummy_enable(struct usb_ep *_ep, if (max <= 1024) break; /* save a return statement */ - /* fall through */ + fallthrough; case USB_SPEED_FULL: if (max <= 1023) break; @@ -957,7 +957,7 @@ static DEVICE_ATTR_RO(function); * hardware can be built with discrete components, so the gadget API doesn't * require that assumption. * - * For this emulator, it might be convenient to create a usb slave device + * For this emulator, it might be convenient to create a usb device * for each driver that registers: just add to a big root hub. */ @@ -981,7 +981,7 @@ static int dummy_udc_start(struct usb_gadget *g, } /* - * SLAVE side init ... the layer above hardware, which + * DEVICE side init ... the layer above hardware, which * can't enumerate without help from the driver we're binding. */ @@ -1151,7 +1151,7 @@ static unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc) return index; } -/* MASTER/HOST SIDE DRIVER +/* HOST SIDE DRIVER * * this uses the hcd framework to hook up to host side drivers. * its root hub will only have one device, otherwise it acts like @@ -1581,7 +1581,7 @@ static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address) /** * handle_control_request() - handles all control transfers - * @dum: pointer to dummy (the_controller) + * @dum_hcd: pointer to dummy (the_controller) * @urb: the urb request to handle * @setup: pointer to the setup data for a USB device control * request @@ -1943,7 +1943,7 @@ static void dummy_timer(struct timer_list *t) * this almost certainly polls too fast. */ limit = max(limit, periodic_bytes(dum, ep)); - /* FALLTHROUGH */ + fallthrough; default: treat_control_like_bulk: @@ -2252,7 +2252,7 @@ static int dummy_hub_control( "supported for USB 2.0 roothub\n"); goto error; } - /* FALLS THROUGH */ + fallthrough; case USB_PORT_FEAT_RESET: /* if it's already enabled, disable */ if (hcd->speed == HCD_USB3) { @@ -2276,7 +2276,7 @@ static int dummy_hub_control( * interval? Is it still 50msec as for HS? */ dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); - /* FALLS THROUGH */ + fallthrough; default: if (hcd->speed == HCD_USB3) { if ((dum_hcd->port_status & @@ -2451,8 +2451,8 @@ static int dummy_start(struct usb_hcd *hcd) struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); /* - * MASTER side init ... we emulate a root hub that'll only ever - * talk to one device (the slave side). Also appears in sysfs, + * HOST side init ... we emulate a root hub that'll only ever + * talk to one device (the gadget side). Also appears in sysfs, * just like more familiar pci-based HCDs. */ if (!usb_hcd_is_primary_hcd(hcd)) diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 91dcb1995c27d935811671b0c5b27738942e233b..25c1d6ab5adb457d4af5904dca7e3ff6b299a28b 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -125,11 +125,14 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) max = get_unaligned_le16(&desc->wMaxPacketSize); switch (max) { case 64: - mode++; /* fall through */ + mode++; + fallthrough; case 32: - mode++; /* fall through */ + mode++; + fallthrough; case 16: - mode++; /* fall through */ + mode++; + fallthrough; case 8: mode <<= 3; break; diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index 7419889ebe9ab029592610b20684e31951149edd..f8f3aa52383bb03bff64917b0c7b76bd9b6269d5 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -8,7 +8,7 @@ * GRLIB VHDL IP core library. * * Full documentation of the GRUSBDC core can be found here: - * http://www.gaisler.com/products/grlib/grip.pdf + * https://www.gaisler.com/products/grlib/grip.pdf * * Contributors: * - Andreas Larsson <andreas@gaisler.com> @@ -912,9 +912,9 @@ static int gr_device_request(struct gr_udc *dev, u8 type, u8 request, return gr_ep0_respond_empty(dev); case USB_DEVICE_TEST_MODE: - /* The hardware does not support TEST_FORCE_EN */ + /* The hardware does not support USB_TEST_FORCE_ENABLE */ test = index >> 8; - if (test >= TEST_J && test <= TEST_PACKET) { + if (test >= USB_TEST_J && test <= USB_TEST_PACKET) { dev->test_mode = test; return gr_ep0_respond(dev, NULL, 0, gr_ep0_testmode_complete); diff --git a/drivers/usb/gadget/udc/gr_udc.h b/drivers/usb/gadget/udc/gr_udc.h index 417ad2aa2cc738342fdf5e8058acaa79d4f7338d..ac5b3f65adb5845f77c30721fc48d7a81f4003f6 100644 --- a/drivers/usb/gadget/udc/gr_udc.h +++ b/drivers/usb/gadget/udc/gr_udc.h @@ -8,7 +8,7 @@ * GRLIB VHDL IP core library. * * Full documentation of the GRUSBDC core can be found here: - * http://www.gaisler.com/products/grlib/grip.pdf + * https://www.gaisler.com/products/grlib/grip.pdf * * Contributors: * - Andreas Larsson <andreas@gaisler.com> diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 4a112670cc6c4b39e3ef5d8b28760dfa7be05713..e8a4637a9a1733e5b74560ba20a727f93a95c929 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -2986,7 +2986,7 @@ static void lpc32xx_rmwkup_chg(int remote_wakup_enable) /* Enable or disable USB remote wakeup */ } -struct lpc32xx_usbd_cfg lpc32xx_usbddata = { +static struct lpc32xx_usbd_cfg lpc32xx_usbddata = { .vbus_drv_pol = 0, .conn_chgb = &lpc32xx_usbd_conn_chg, .susp_chgb = &lpc32xx_usbd_susp_chg, diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c index 23f33946d80c4c85f6070fc51fe4612f665a7410..35179543c32724b0c645526b854cc3c6a352ae6b 100644 --- a/drivers/usb/gadget/udc/max3420_udc.c +++ b/drivers/usb/gadget/udc/max3420_udc.c @@ -7,7 +7,7 @@ * * Based on: * o MAX3420E datasheet - * http://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf + * https://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf * o MAX342{0,1}E Programming Guides * https://pdfserv.maximintegrated.com/en/an/AN3598.pdf * https://pdfserv.maximintegrated.com/en/an/AN3785.pdf @@ -623,7 +623,6 @@ static void max3420_set_clear_feature(struct max3420_udc *udc) static void max3420_handle_setup(struct max3420_udc *udc) { struct usb_ctrlrequest setup; - u8 addr; spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8); @@ -647,7 +646,7 @@ static void max3420_handle_setup(struct max3420_udc *udc) USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { break; } - addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1); + spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1); dev_dbg(udc->dev, "Assigned Address=%d\n", udc->setup.wValue); return; case USB_REQ_CLEAR_FEATURE: diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 5bb0568b934e136365fad691219a78ce2c003592..5486f5a708681a5919faa61abae10a6893a45688 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -32,7 +32,6 @@ #define DRIVER_DESC "Marvell PXA USB3.0 Device Controller driver" static const char driver_name[] = "mv_u3d"; -static const char driver_desc[] = DRIVER_DESC; static void mv_u3d_nuke(struct mv_u3d_ep *ep, int status); static void mv_u3d_stop_activity(struct mv_u3d *u3d, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 80a1b52c656e0ae049ddf2c327291699a665b247..0fb4ef464321d135f7d81df9e8b2a7ad3291c7a2 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -53,7 +53,6 @@ static DECLARE_COMPLETION(release_done); static const char driver_name[] = "mv_udc"; -static const char driver_desc[] = DRIVER_DESC; static void nuke(struct mv_ep *ep, int status); static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver); @@ -1502,7 +1501,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) static void mv_udc_testmode(struct mv_udc *udc, u16 index) { - if (index <= TEST_FORCE_EN) { + if (index <= USB_TEST_FORCE_ENABLE) { udc->test_mode = index; if (udc_prime_status(udc, EP_DIR_IN, 0, true)) ep0_stall(udc); diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 928057b206f1be946a4a93819ab1d906d5a15a1b..44d1ea2307bbe638d6be9f85a57cc08e7df49213 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1688,7 +1688,7 @@ net2272_set_test_mode(struct net2272 *dev, int mode) net2272_write(dev, USBTEST, mode); /* load test packet */ - if (mode == TEST_PACKET) { + if (mode == USB_TEST_PACKET) { /* switch to 8 bit mode */ net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) & ~(1 << DATA_WIDTH)); @@ -2370,6 +2370,8 @@ net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) err: while (--i >= 0) { + if (i == 1) + continue; /* BAR1 unused */ iounmap(mem_mapped_addr[i]); release_mem_region(pci_resource_start(pdev, i), pci_resource_len(pdev, i)); diff --git a/drivers/usb/gadget/udc/net2272.h b/drivers/usb/gadget/udc/net2272.h index 8e644627992d64c19f02d5be42037858baf887a6..87d0ab9ffeeb2e8f56eba58f16cf228f2d407b97 100644 --- a/drivers/usb/gadget/udc/net2272.h +++ b/drivers/usb/gadget/udc/net2272.h @@ -105,11 +105,6 @@ #define USBTEST 0x32 #define TEST_MODE_SELECT 0 #define NORMAL_OPERATION 0 -#define TEST_J 1 -#define TEST_K 2 -#define TEST_SE0_NAK 3 -#define TEST_PACKET 4 -#define TEST_FORCE_ENABLE 5 #define XCVRDIAG 0x33 #define FORCE_FULL_SPEED 2 #define FORCE_HIGH_SPEED 3 diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 5eff85eeaa5a0969f2bb6533636267d16834e241..7530bd9a08c43329dc393893c0b2db93210dcbcb 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -3781,8 +3781,10 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; done: - if (dev) + if (dev) { net2280_remove(pdev); + kfree(dev); + } return retval; } diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index 4139da8856516c3ecdd87167149b11b06a06f039..494da00398d7cb460f89dcee771fea5ea1336cfa 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2831,7 +2831,7 @@ static int omap_udc_probe(struct platform_device *pdev) type = "integrated"; break; } - /* FALL THROUGH */ + fallthrough; case 3: case 11: case 16: @@ -2848,7 +2848,7 @@ static int omap_udc_probe(struct platform_device *pdev) case 14: /* transceiverless */ if (cpu_is_omap1710()) goto bad_on_1710; - /* FALL THROUGH */ + fallthrough; case 13: case 15: type = "no"; diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 3344fb8c4181103269d36705561e2bf3014f4551..8afc31d94b0e4a9b5945cb3f162cd580ab5ef5d9 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -229,8 +229,7 @@ struct pch_udc_data_dma_desc { * for control data * @status: Status * @reserved: Reserved - * @data12: First setup word - * @data34: Second setup word + * @request: Control Request */ struct pch_udc_stp_dma_desc { u32 status; @@ -304,8 +303,8 @@ struct pch_udc_ep { * for detecting VBUS * @port: gpio port number * @intr: gpio interrupt number - * @irq_work_fall Structure for WorkQueue - * @irq_work_rise Structure for WorkQueue + * @irq_work_fall: Structure for WorkQueue + * @irq_work_rise: Structure for WorkQueue */ struct pch_vbus_gpio_data { int port; @@ -475,7 +474,7 @@ static void pch_udc_csr_busy(struct pch_udc_dev *dev) * pch_udc_write_csr() - Write the command and status registers. * @dev: Reference to pch_udc_dev structure * @val: value to be written to CSR register - * @addr: address of CSR register + * @ep: end-point number */ static void pch_udc_write_csr(struct pch_udc_dev *dev, unsigned long val, unsigned int ep) @@ -490,7 +489,7 @@ static void pch_udc_write_csr(struct pch_udc_dev *dev, unsigned long val, /** * pch_udc_read_csr() - Read the command and status registers. * @dev: Reference to pch_udc_dev structure - * @addr: address of CSR register + * @ep: end-point number * * Return codes: content of CSR register */ @@ -656,6 +655,7 @@ static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep, * pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint * @ep: Reference to structure of type pch_udc_ep_regs * @buf_size: The buffer word size + * @ep_in: EP is IN */ static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep, u32 buf_size, u32 ep_in) @@ -968,7 +968,8 @@ static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir) /** * pch_udc_ep_enable() - This api enables endpoint - * @regs: Reference to structure pch_udc_ep_regs + * @ep: reference to structure of type pch_udc_ep_regs + * @cfg: current configuration information * @desc: endpoint descriptor */ static void pch_udc_ep_enable(struct pch_udc_ep *ep, @@ -1004,7 +1005,7 @@ static void pch_udc_ep_enable(struct pch_udc_ep *ep, /** * pch_udc_ep_disable() - This api disables endpoint - * @regs: Reference to structure pch_udc_ep_regs + * @ep: reference to structure of type pch_udc_ep_regs */ static void pch_udc_ep_disable(struct pch_udc_ep *ep) { @@ -1024,7 +1025,7 @@ static void pch_udc_ep_disable(struct pch_udc_ep *ep) /** * pch_udc_wait_ep_stall() - Wait EP stall. - * @dev: Reference to pch_udc_dev structure + * @ep: reference to structure of type pch_udc_ep_regs */ static void pch_udc_wait_ep_stall(struct pch_udc_ep *ep) { @@ -1331,7 +1332,7 @@ static void pch_vbus_gpio_work_rise(struct work_struct *irq_work) /** * pch_vbus_gpio_irq() - IRQ handler for GPIO interrupt for changing VBUS * @irq: Interrupt request number - * @dev: Reference to the device structure + * @data: Reference to the device structure * * Return codes: * 0: Success @@ -1354,8 +1355,8 @@ static irqreturn_t pch_vbus_gpio_irq(int irq, void *data) /** * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS. - * @dev: Reference to the driver structure - * @vbus_gpio Number of GPIO port to detect gpio + * @dev: Reference to the driver structure + * @vbus_gpio_port: Number of GPIO port to detect gpio * * Return codes: * 0: Success @@ -1499,8 +1500,8 @@ static void empty_req_queue(struct pch_udc_ep *ep) /** * pch_udc_free_dma_chain() - This function frees the DMA chain created * for the request - * @dev Reference to the driver structure - * @req Reference to the request to be freed + * @dev: Reference to the driver structure + * @req: Reference to the request to be freed * * Return codes: * 0: Success @@ -1707,7 +1708,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, /** * pch_udc_pcd_ep_disable() - This API disables endpoint and is called * from gadget driver - * @usbep Reference to the USB endpoint structure + * @usbep: Reference to the USB endpoint structure * * Return codes: * 0: Success @@ -1996,7 +1997,6 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) * pch_udc_pcd_set_wedge() - This function Sets or clear the endpoint * halt feature * @usbep: Reference to the USB endpoint structure - * @halt: Specifies whether to set or clear the feature * * Return codes: * 0: Success @@ -2750,7 +2750,7 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr) /** * pch_udc_isr() - This function handles interrupts from the PCH USB Device * @irq: Interrupt request number - * @dev: Reference to the device structure + * @pdev: Reference to the device structure */ static irqreturn_t pch_udc_isr(int irq, void *pdev) { @@ -2900,7 +2900,7 @@ static int pch_udc_pcd_init(struct pch_udc_dev *dev) /** * init_dma_pools() - create dma pools during initialization - * @pdev: reference to struct pci_dev + * @dev: reference to struct pci_dev */ static int init_dma_pools(struct pch_udc_dev *dev) { diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 78902d13fc275eee5456e9b059035a747afcbcbc..cfaeca457fa72b4fc23ddd7e53aa4915a7fb6db8 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -386,7 +386,7 @@ static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask) /** * ep_write_UDCCSR - set bits in UDCCSR - * @udc: udc device + * @ep: udc endpoint * @mask: bits to set in UDCCR * * Sets bits in UDCCSR (UDCCSR0 and UDCCSR*). @@ -472,7 +472,7 @@ static int epout_has_pkt(struct pxa_ep *ep) /** * set_ep0state - Set ep0 automata state - * @dev: udc device + * @udc: udc device * @state: state */ static void set_ep0state(struct pxa_udc *udc, int state) @@ -498,7 +498,6 @@ static void ep0_idle(struct pxa_udc *dev) /** * inc_ep_stats_reqs - Update ep stats counts * @ep: physical endpoint - * @req: usb request * @is_in: ep direction (USB_DIR_IN or 0) * */ @@ -1473,7 +1472,6 @@ static void udc_disable(struct pxa_udc *udc); * Context: any * * The UDC should be enabled if : - * - the pullup resistor is connected * - and a gadget driver is bound * - and vbus is sensed (or no vbus sense is available) @@ -1688,7 +1686,7 @@ static void udc_init_data(struct pxa_udc *dev) /** * udc_enable - Enables the udc device - * @dev: udc device + * @udc: udc device * * Enables the udc device : enables clocks, udc interrupts, control endpoint * interrupts, sets usb as UDC client and setups endpoints. @@ -1732,8 +1730,8 @@ static void udc_enable(struct pxa_udc *udc) /** * pxa27x_start - Register gadget driver + * @g: gadget * @driver: gadget driver - * @bind: bind function * * When a driver is successfully registered, it will receive control requests * including set_configuration(), which enables non-control requests. Then @@ -1775,7 +1773,6 @@ static int pxa27x_udc_start(struct usb_gadget *g, /** * stop_activity - Stops udc endpoints * @udc: udc device - * @driver: gadget driver * * Disables all udc endpoints (even control endpoint), report disconnect to * the gadget user. @@ -1792,7 +1789,7 @@ static void stop_activity(struct pxa_udc *udc) /** * pxa27x_udc_stop - Unregister the gadget driver - * @driver: gadget driver + * @g: gadget * * Returns 0 if no error, -ENODEV, -EINVAL otherwise */ @@ -2349,7 +2346,7 @@ MODULE_DEVICE_TABLE(of, udc_pxa_dt_ids); /** * pxa_udc_probe - probes the udc device - * @_dev: platform device + * @pdev: platform device * * Perform basic init : allocates udc clock, creates sysfs files, requests * irq. diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 537094b485bf4f1d095ad4d12781fc1747298e69..896c1a016d550e0482ab9bb7cff75fc00d37de7c 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1827,10 +1827,8 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r) static int r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, struct platform_device *pdev) { - struct resource *res; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac"); - r8a66597->sudmac_reg = devm_ioremap_resource(&pdev->dev, res); + r8a66597->sudmac_reg = + devm_platform_ioremap_resource_byname(pdev, "sudmac"); return PTR_ERR_OR_ZERO(r8a66597->sudmac_reg); } diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 80002d97b59d82e788ce1c378b877661fb999cff..bc2e8eb737c3166280a929306719b87154ea5cf0 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -308,7 +308,7 @@ static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, switch (idx) { default: idx = 0; - /* fall through */ + fallthrough; case 0: fifo_reg = S3C2410_UDC_EP0_FIFO_REG; break; @@ -413,7 +413,7 @@ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, switch (idx) { default: idx = 0; - /* fall through */ + fallthrough; case 0: fifo_reg = S3C2410_UDC_EP0_FIFO_REG; break; diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index e76f1a50b0fc951f3c8d574dd5a192d26139c109..6c726d2e1788e1d6045feb3c73ac8cc50dbf2169 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -2,7 +2,7 @@ /* * amd5536.c -- AMD 5536 UDC high/full speed USB device controller * - * Copyright (C) 2005-2007 AMD (http://www.amd.com) + * Copyright (C) 2005-2007 AMD (https://www.amd.com) * Author: Thomas Dahlmann */ diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index bbe1a04686dabf91d7c4f537ab58061417c6241a..d6ff68c06911f269ef109d659785fc4cd78c3a6b 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -2742,7 +2742,7 @@ static void tegra_xudc_handle_transfer_event(struct tegra_xudc *xudc, ep_wait_for_stopped(xudc, ep_index); ep->enq_ptr = ep->deq_ptr; tegra_xudc_ep_nuke(ep, -EIO); - /* FALLTHROUGH */ + fallthrough; case TRB_CMPL_CODE_STREAM_NUMP_ERROR: case TRB_CMPL_CODE_CTRL_DIR_ERR: case TRB_CMPL_CODE_INVALID_STREAM_TYPE_ERR: @@ -3750,15 +3750,12 @@ static int tegra_xudc_probe(struct platform_device *pdev) return PTR_ERR(xudc->base); xudc->phys_base = res->start; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fpci"); - xudc->fpci = devm_ioremap_resource(&pdev->dev, res); + xudc->fpci = devm_platform_ioremap_resource_byname(pdev, "fpci"); if (IS_ERR(xudc->fpci)) return PTR_ERR(xudc->fpci); if (xudc->soc->has_ipfs) { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "ipfs"); - xudc->ipfs = devm_ioremap_resource(&pdev->dev, res); + xudc->ipfs = devm_platform_ioremap_resource_byname(pdev, "ipfs"); if (IS_ERR(xudc->ipfs)) return PTR_ERR(xudc->ipfs); } diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 709553bdb23397a2a7647f85b53dbf854bb9853c..d5e9d20c097d205054378fb79796296b969d4043 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2097,9 +2097,9 @@ static int xudc_probe(struct platform_device *pdev) /* Check for IP endianness */ udc->write_fn = xudc_write32_be; udc->read_fn = xudc_read32_be; - udc->write_fn(udc->addr, XUSB_TESTMODE_OFFSET, TEST_J); + udc->write_fn(udc->addr, XUSB_TESTMODE_OFFSET, USB_TEST_J); if ((udc->read_fn(udc->addr + XUSB_TESTMODE_OFFSET)) - != TEST_J) { + != USB_TEST_J) { udc->write_fn = xudc_write32; udc->read_fn = xudc_read32; } diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 119505fac777681a6c9a9b06ff3fbdec02e68cb1..75f6f99f8173ed7b9cfd2859e93ea3c777f4c67e 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -55,9 +55,9 @@ usb_gadget_get_string (const struct usb_gadget_strings *table, int id, u8 *buf) return -EINVAL; /* string descriptors have length, tag, then UTF16-LE text */ - len = min ((size_t) 126, strlen (s->s)); + len = min((size_t)USB_MAX_STRING_LEN, strlen(s->s)); len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN, - (wchar_t *) &buf[2], 126); + (wchar_t *) &buf[2], USB_MAX_STRING_LEN); if (len < 0) return -EINVAL; buf [0] = (len + 1) * 2; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1cb3004ea7b2b3aa1d50957dad935d96ea19977a..ab12c4bf0ef1f968e67fdf4380d89cba8b2715e9 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -44,10 +44,10 @@ config USB_XHCI_PCI default y config USB_XHCI_PCI_RENESAS - tristate "Support for additional Renesas xHCI controller with firwmare" + tristate "Support for additional Renesas xHCI controller with firmware" help Say 'Y' to enable the support for the Renesas xHCI controller with - firwmare. Make sure you have the firwmare for the device and + firmware. Make sure you have the firwmare for the device and installed on your system for this device to work. If unsure, say 'N'. diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 652fa29beb273cd0006fcec5c639020c95c60f0c..b1b777f33521ecae9e59495da8582aa3b3b7adb7 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -168,7 +168,7 @@ static void bcma_hcd_init_chip_mips(struct bcma_device *dev) } } -/** +/* * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM * * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced @@ -261,7 +261,7 @@ static void bcma_hcd_usb20_ns_init_hc(struct bcma_device *dev) usleep_range(1000, 2000); } -/** +/* * bcma_hcd_usb20_ns_init - Initialize Northstar USB 2.0 controller */ static int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 7619cfb068836e6a95722caae82ae9f670976a03..0b7f1edd9eec4435c572d22ea627063b5eee6a5e 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -823,7 +823,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) break; case 0: /* illegal reserved capability */ cap = 0; - /* FALLTHROUGH */ + fallthrough; default: /* unknown */ break; } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 9e9c232e896fa073eb17a83c2bd090c914d1f5da..1e8b59ab22729cb65b8cdec5fe56d18a181ca916 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -234,7 +234,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, break; case FSL_USB2_PHY_UTMI_WIDE: portsc |= PORT_PTS_PTW; - /* fall through */ + fallthrough; case FSL_USB2_PHY_UTMI: /* Presence of this node "has_fsl_erratum_a006918" * in device-tree is used to stop USB controller @@ -244,7 +244,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, dev_warn(dev, "USB PHY clock invalid\n"); return -EINVAL; } - /* fall through */ + fallthrough; case FSL_USB2_PHY_UTMI_DUAL: /* PHY_CLK_VALID bit is de-featured from all controller * versions below 2.4 and is to be checked only for @@ -683,7 +683,7 @@ static const struct ehci_driver_overrides ehci_fsl_overrides __initconst = { /** * fsl_ehci_drv_remove - shutdown processing for FSL-based HCDs - * @dev: USB Host Controller being removed + * @pdev: USB Host Controller being removed * Context: !in_interrupt() * * Reverses the effect of usb_hcd_fsl_probe(). diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index cf2b7ae93b7e907efb339c0f9bcd962259ce1ba1..6257be4110ca26e5a4ab0a77e06b8b666c978a6e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -982,7 +982,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) start_unlink_async(ehci, qh); else start_unlink_intr(ehci, qh); - /* FALL THROUGH */ + fallthrough; case QH_STATE_COMPLETING: /* already in unlinking */ case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: @@ -999,7 +999,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) qh_destroy(ehci, qh); break; } - /* fall through */ + fallthrough; default: /* caller was supposed to have unlinked any requests; * that's not our job. just leak this memory. diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index fc125b3d06e7da76913b3009e732f0ce81d0bf75..8771a2ed69268fa49bb1907d8d4b0ac503d333e4 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -24,7 +24,6 @@ #include <linux/slab.h> #include <linux/usb/ulpi.h> #include <linux/pm_runtime.h> -#include <linux/gpio.h> #include <linux/clk.h> #include <linux/usb.h> #include <linux/usb/hcd.h> @@ -78,6 +77,7 @@ static const struct ehci_driver_overrides ehci_omap_overrides __initconst = { /** * ehci_hcd_omap_probe - initialize TI-based HCDs + * @pdev: Pointer to this platform device's information * * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index af3c1b9b38b22fd307112c253931a30636127a0b..71ec3025686fe13aafba203369dd5d3698fa2162 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -124,8 +124,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) case 0x005b: /* CK804 */ case 0x00d8: /* CK8 */ case 0x00e8: /* CK8S */ - if (pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(31)) < 0) + if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(31)) < 0) ehci_warn(ehci, "can't enable NVidia " "workaround for >2GB RAM\n"); break; diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index e9a49007cce4a0d3bd57ebf1dff72a75007563f3..006c4f6188a52cc3d177eeea0180035dc4bdf807 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -475,11 +475,13 @@ static const struct of_device_id vt8500_ehci_ids[] = { }; MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); +#ifdef CONFIG_ACPI static const struct acpi_device_id ehci_acpi_match[] = { { "PNP0D20", 0 }, /* EHCI controller without debug */ { } }; MODULE_DEVICE_TABLE(acpi, ehci_acpi_match); +#endif static const struct platform_device_id ehci_platform_table[] = { { "ehci-platform", 0 }, diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 8a5c9b3ebe1e74e982ff49060e48f1938049bf1b..a826715ae9bdfa3e4857c3ea09dc12b6e4708b82 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -874,7 +874,7 @@ qh_make ( switch (urb->dev->speed) { case USB_SPEED_LOW: info1 |= QH_LOW_SPEED; - /* FALL THROUGH */ + fallthrough; case USB_SPEED_FULL: /* EPS 0 means "full" */ diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index da7b00a6110b5a50f58d9eac13bd639ea3fbfde8..847979f265b102eea7c26f7e0bbfa9f67c5bfc26 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -2475,7 +2475,7 @@ static void scan_isoc(struct ehci_hcd *ehci) ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n", type, frame, q.ptr); /* BUG(); */ - /* FALL THROUGH */ + fallthrough; case Q_TYPE_QH: case Q_TYPE_FSTN: /* End of the iTDs and siTDs */ diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index 5c423f240a1f0782961c02a49918688df5289620..a45ede80edfcd175ff499535af95803f50fb9f45 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -701,7 +701,6 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) u32 data_len = urb->transfer_buffer_length; int urb_state = 0; int toggle = 0; - struct td *td; u8 *data; u16 cnt = 0; @@ -770,7 +769,7 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) usb_endpoint_maxp(&urb->ep->desc)) == 0)) urb_state = US_BULK0; while (data_len > 4096) { - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, cnt ? USB_TD_TOGGLE_CARRY : @@ -781,7 +780,7 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) cnt++; } - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, cnt ? USB_TD_TOGGLE_CARRY : toggle, data, data_len, 0, 0, true); @@ -789,7 +788,7 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) if (urb->transfer_flags & URB_ZERO_PACKET && cnt < urb_priv->num_of_tds) { - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, USB_TD_TOGGLE_CARRY, NULL, 0, 0, 0, true); @@ -798,7 +797,7 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) break; case FHCI_TF_INTR: urb->start_frame = get_frame_num(fhci) + 1; - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, USB_TD_TOGGLE_DATA0, data, data_len, urb->interval, urb->start_frame, true); @@ -808,12 +807,12 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) ed->max_pkt_size = usb_endpoint_maxp(&urb->ep->desc); /* setup stage */ - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true); /* data stage */ if (data_len > 0) { - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, USB_TD_TOGGLE_DATA1, data, data_len, 0, 0, @@ -822,12 +821,12 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) /* status stage */ if (data_len > 0) - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, (usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT), USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); else - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_IN, USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); @@ -844,7 +843,7 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) */ frame += cnt * urb->interval; frame &= 0x07ff; - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, + fhci_td_fill(fhci, urb, urb_priv, ed, cnt, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, USB_TD_TOGGLE_DATA0, diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c index f3308ce2504389851f2591b2d90a4451ecfcc50f..d98fd9e1af0bcc825b812b55820881a1e2483a82 100644 --- a/drivers/usb/host/fhci-tds.c +++ b/drivers/usb/host/fhci-tds.c @@ -467,17 +467,15 @@ u32 fhci_host_transaction(struct fhci_usb *usb, /* Reset the Tx BD ring */ void fhci_flush_bds(struct fhci_usb *usb) { - u16 extra_data; u16 td_status; - u32 buf; struct usb_td __iomem *td; struct endpoint *ep = usb->ep0; td = ep->td_base; while (1) { td_status = in_be16(&td->status); - buf = in_be32(&td->buf_ptr); - extra_data = in_be16(&td->extra); + in_be32(&td->buf_ptr); + in_be16(&td->extra); /* if the TD is not empty - we'll confirm it as Timeout */ if (td_status & TD_R) @@ -524,7 +522,6 @@ void fhci_flush_actual_frame(struct fhci_usb *usb) { u8 mode; u16 tb_ptr; - u16 extra_data; u16 td_status; u32 buf_ptr; struct usb_td __iomem *td; @@ -538,7 +535,7 @@ void fhci_flush_actual_frame(struct fhci_usb *usb) td = cpm_muram_addr(tb_ptr); td_status = in_be16(&td->status); buf_ptr = in_be32(&td->buf_ptr); - extra_data = in_be16(&td->extra); + in_be16(&td->extra); do { if (td_status & TD_R) { out_be16(&td->status, (td_status & ~TD_R) | TD_TO); @@ -552,7 +549,7 @@ void fhci_flush_actual_frame(struct fhci_usb *usb) td = next_bd(ep->td_base, td, td_status); td_status = in_be16(&td->status); buf_ptr = in_be32(&td->buf_ptr); - extra_data = in_be16(&td->extra); + in_be16(&td->extra); } while ((td_status & TD_R) || buf_ptr); fhci_td_transaction_confirm(usb); diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index f967adf2d8dfcfe8dcc140c946845125c12e4972..194df82824716f1102d20a6d23cd36deb6a23b91 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -2807,7 +2807,7 @@ static struct fotg210_qh *qh_make(struct fotg210_hcd *fotg210, struct urb *urb, switch (urb->dev->speed) { case USB_SPEED_LOW: info1 |= QH_LOW_SPEED; - /* FALL THROUGH */ + fallthrough; case USB_SPEED_FULL: /* EPS 0 means "full" */ @@ -4634,7 +4634,7 @@ static inline int scan_frame_queue(struct fotg210_hcd *fotg210, unsigned frame, default: fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n", type, frame, q.ptr); - /* FALL THROUGH */ + fallthrough; case Q_TYPE_QH: case Q_TYPE_FSTN: /* End of the iTDs and siTDs */ @@ -5010,7 +5010,6 @@ static int fotg210_run(struct usb_hcd *hcd) { struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); u32 temp; - u32 hcc_params; hcd->uses_new_polling = 1; @@ -5033,7 +5032,7 @@ static int fotg210_run(struct usb_hcd *hcd) * Scsi_Host.highmem_io, and so forth. It's readonly to all * host side drivers though. */ - hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params); + fotg210_readl(fotg210, &fotg210->caps->hcc_params); /* * Philips, Intel, and maybe others need CMD_RUN before the @@ -5412,7 +5411,7 @@ static void fotg210_endpoint_disable(struct usb_hcd *hcd, */ if (tmp) start_unlink_async(fotg210, qh); - /* FALL THROUGH */ + fallthrough; case QH_STATE_UNLINK: /* wait for hw to finish? */ case QH_STATE_UNLINK_WAIT: idle_timeout: @@ -5426,7 +5425,7 @@ static void fotg210_endpoint_disable(struct usb_hcd *hcd, qh_destroy(fotg210, qh); break; } - /* fall through */ + fallthrough; default: /* caller was supposed to have unlinked any requests; * that's not our job. just leak this memory. @@ -5558,7 +5557,7 @@ static void fotg210_init(struct fotg210_hcd *fotg210) iowrite32(value, &fotg210->regs->otgcsr); } -/** +/* * fotg210_hcd_probe - initialize faraday FOTG210 HCDs * * Allocates basic resources for this USB host controller, and @@ -5657,7 +5656,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev) return retval; } -/** +/* * fotg210_hcd_remove - shutdown processing for EHCI HCDs * @dev: USB Host Controller being removed * diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 5835f9966204626fbf5f29c769c233249a7b96bf..b2716cb724719eb1e19eb3c9a63dd4de100f5395 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -224,7 +224,7 @@ static void setup_etd_dword0(struct imx21 *imx21, ((u32) maxpacket << DW0_MAXPKTSIZ)); } -/** +/* * Copy buffer to data controller data memory. * We cannot use memcpy_toio() because the hardware requires 32bit writes */ diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 4a3a2852523f276261d7a87ecadfefd5cedc09cf..2cecb36d241b4911550410e6ce3e4daea0d8ad3f 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -1748,7 +1748,7 @@ static int isp1362_bus_suspend(struct usb_hcd *hcd) isp1362_hcd->hc_control &= ~OHCI_CTRL_HCFS; isp1362_hcd->hc_control |= OHCI_USB_RESET; isp1362_write_reg32(isp1362_hcd, HCCONTROL, isp1362_hcd->hc_control); - /* FALL THROUGH */ + fallthrough; case OHCI_USB_RESET: status = -EBUSY; pr_warn("%s: needs reinit!\n", __func__); diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h index 4c49688a069d1d5d8167696c6f3e91ede28fa3b2..9bbfcc3fdd3ccc6bc9fa8503402260728f046db2 100644 --- a/drivers/usb/host/isp1362.h +++ b/drivers/usb/host/isp1362.h @@ -56,7 +56,7 @@ typedef const unsigned char isp1362_reg_t; #define ISP1362_REG_NO(r) (r) #define ISP1362_REG(name, addr, width, rw) \ -static isp1362_reg_t ISP1362_REG_##name = addr +static isp1362_reg_t __maybe_unused ISP1362_REG_##name = addr #define REG_ACCESS_TEST(r) do {} while (0) #define REG_WIDTH_TEST(r, w) do {} while (0) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 8819f502b6a683dfd523bc8de226407a06d77d19..0894f6caccb2cd95e04edc16d848ecd6779e0124 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -11,9 +11,9 @@ * * Based on: * o MAX3421E datasheet - * http://datasheets.maximintegrated.com/en/ds/MAX3421E.pdf + * https://datasheets.maximintegrated.com/en/ds/MAX3421E.pdf * o MAX3421E Programming Guide - * http://www.hdl.co.jp/ftpdata/utl-001/AN3785.pdf + * https://www.hdl.co.jp/ftpdata/utl-001/AN3785.pdf * o gadget/dummy_hcd.c * For USB HCD implementation. * o Arduino MAX3421 driver @@ -317,7 +317,7 @@ static const int hrsl_to_error[] = { }; /* - * See http://www.beyondlogic.org/usbnutshell/usb4.shtml#Control for a + * See https://www.beyondlogic.org/usbnutshell/usb4.shtml#Control for a * reasonable overview of how control transfers use the the IN/OUT * tokens. */ @@ -925,7 +925,7 @@ max3421_handle_error(struct usb_hcd *hcd, u8 hrsl) spi_wr8(hcd, MAX3421_REG_HCTL, BIT(sndtog + MAX3421_HCTL_SNDTOG0_BIT)); } - /* FALL THROUGH */ + fallthrough; case MAX3421_HRSL_BADBC: /* bad byte count */ case MAX3421_HRSL_PIDERR: /* received PID is corrupted */ case MAX3421_HRSL_PKTERR: /* packet error (stuff, EOP) */ @@ -1715,7 +1715,7 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index, dev_dbg(hcd->self.controller, "power-off\n"); max3421_gpout_set_value(hcd, pdata->vbus_gpout, !pdata->vbus_active_level); - /* FALLS THROUGH */ + fallthrough; default: max3421_hcd->port_status &= ~(1 << value); } @@ -1768,7 +1768,7 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index, break; case USB_PORT_FEAT_RESET: max3421_reset_port(hcd); - /* FALLS THROUGH */ + fallthrough; default: if ((max3421_hcd->port_status & USB_PORT_STAT_POWER) != 0) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index b635c6a1b1a91d43b430f22bd6ee4969dc8fcc93..0487a4b0501eca5c65b9405afe7b0f628d2015d7 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -153,7 +153,7 @@ static struct regmap *at91_dt_syscon_sfr(void) /* always called with process context; sleeping is OK */ -/** +/* * usb_hcd_at91_probe - initialize AT91-based HCDs * Context: !in_interrupt() * @@ -244,9 +244,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, /* may be called with controller, bus, and devices active */ -/** +/* * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs - * @dev: USB Host Controller being removed * Context: !in_interrupt() * * Reverses the effect of usb_hcd_at91_probe(), first invoking diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 4de91653a2c7bbd9b4b92935f92a4db7a4aeb370..dd37e77dae0014731a692d58e5070f98c1ffbe07 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -16,7 +16,7 @@ * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller * interfaces (though some non-x86 Intel chips use it). It supports * smarter hardware than UHCI. A download link for the spec available - * through the http://www.usb.org website. + * through the https://www.usb.org website. * * This file is licenced under the GPL. */ @@ -385,7 +385,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) ed_free (ohci, ed); break; } - /* fall through */ + fallthrough; default: /* caller was supposed to have unlinked any requests; * that's not our job. can't recover; must leak ed. @@ -1051,7 +1051,7 @@ int ohci_restart(struct ohci_hcd *ohci) ed->ed_next = ohci->ed_rm_list; ed->ed_prev = NULL; ohci->ed_rm_list = ed; - /* FALLTHROUGH */ + fallthrough; case ED_UNLINK: break; default: diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 634f3c7bf7748085758635ffe86108c948e0d08e..44504c1751e0450e309abb1338cc97df0556f26d 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -58,7 +58,7 @@ __acquires(ohci->lock) ohci->hc_control |= OHCI_USB_RESET; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); - /* FALL THROUGH */ + fallthrough; case OHCI_USB_RESET: status = -EBUSY; ohci_dbg (ohci, "needs reinit!\n"); diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index d8d35d45645627f40abc2a0bc2b714562178c88c..9ccdf2c216b513f7af5fc34c688dfeed88e17f51 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -18,7 +18,7 @@ #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/jiffies.h> #include <linux/kernel.h> @@ -53,38 +53,29 @@ #define DRIVER_DESC "OHCI OMAP driver" -#ifdef CONFIG_TPS65010 -#include <linux/mfd/tps65010.h> -#else - -#define LOW 0 -#define HIGH 1 - -#define GPIO1 1 - -static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) -{ - return 0; -} - -#endif - -static struct clk *usb_host_ck; -static struct clk *usb_dc_ck; +struct ohci_omap_priv { + struct clk *usb_host_ck; + struct clk *usb_dc_ck; + struct gpio_desc *power; + struct gpio_desc *overcurrent; +}; static const char hcd_name[] = "ohci-omap"; static struct hc_driver __read_mostly ohci_omap_hc_driver; -static void omap_ohci_clock_power(int on) +#define hcd_to_ohci_omap_priv(h) \ + ((struct ohci_omap_priv *)hcd_to_ohci(h)->priv) + +static void omap_ohci_clock_power(struct ohci_omap_priv *priv, int on) { if (on) { - clk_enable(usb_dc_ck); - clk_enable(usb_host_ck); + clk_enable(priv->usb_dc_ck); + clk_enable(priv->usb_host_ck); /* guesstimate for T5 == 1x 32K clock + APLL lock time */ udelay(100); } else { - clk_disable(usb_host_ck); - clk_disable(usb_dc_ck); + clk_disable(priv->usb_host_ck); + clk_disable(priv->usb_dc_ck); } } @@ -92,22 +83,22 @@ static void omap_ohci_clock_power(int on) * Board specific gang-switched transceiver power on/off. * NOTE: OSK supplies power from DC, not battery. */ -static int omap_ohci_transceiver_power(int on) +static int omap_ohci_transceiver_power(struct ohci_omap_priv *priv, int on) { if (on) { if (machine_is_omap_innovator() && cpu_is_omap1510()) __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) - tps65010_set_gpio_out_value(GPIO1, LOW); + else if (priv->power) + gpiod_set_value(priv->power, 0); } else { if (machine_is_omap_innovator() && cpu_is_omap1510()) __raw_writeb(__raw_readb(INNOVATOR_FPGA_CAM_USB_CONTROL) & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) - tps65010_set_gpio_out_value(GPIO1, HIGH); + else if (priv->power) + gpiod_set_value(priv->power, 1); } return 0; @@ -196,6 +187,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct omap_usb_config *config = dev_get_platdata(hcd->self.controller); + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); int need_transceiver = (config->otg != 0); int ret; @@ -235,7 +227,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) } #endif - omap_ohci_clock_power(1); + omap_ohci_clock_power(priv, 1); if (cpu_is_omap15xx()) { omap_1510_local_bus_power(1); @@ -266,8 +258,6 @@ static int ohci_omap_reset(struct usb_hcd *hcd) /* gpio9 for overcurrent detction */ omap_cfg_reg(W8_1610_GPIO9); - gpio_request(9, "OHCI overcurrent"); - gpio_direction_input(9); /* for paranoia's sake: disable USB.PUEN */ omap_cfg_reg(W4_USB_HIGHZ); @@ -281,7 +271,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) } /* FIXME hub_wq hub requests should manage power switching */ - omap_ohci_transceiver_power(1); + omap_ohci_transceiver_power(priv, 1); /* board init will have already handled HMC and mux setup. * any external transceiver should already be initialized @@ -305,6 +295,7 @@ static int ohci_hcd_omap_probe(struct platform_device *pdev) { int retval, irq; struct usb_hcd *hcd = 0; + struct ohci_omap_priv *priv; if (pdev->num_resources != 2) { dev_err(&pdev->dev, "invalid num_resources: %i\n", @@ -318,34 +309,58 @@ static int ohci_hcd_omap_probe(struct platform_device *pdev) return -ENODEV; } - usb_host_ck = clk_get(&pdev->dev, "usb_hhc_ck"); - if (IS_ERR(usb_host_ck)) - return PTR_ERR(usb_host_ck); + hcd = usb_create_hcd(&ohci_omap_hc_driver, &pdev->dev, + dev_name(&pdev->dev)); + if (!hcd) + return -ENOMEM; - if (!cpu_is_omap15xx()) - usb_dc_ck = clk_get(&pdev->dev, "usb_dc_ck"); - else - usb_dc_ck = clk_get(&pdev->dev, "lb_ck"); + hcd->rsrc_start = pdev->resource[0].start; + hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; + priv = hcd_to_ohci_omap_priv(hcd); - if (IS_ERR(usb_dc_ck)) { - clk_put(usb_host_ck); - return PTR_ERR(usb_dc_ck); + /* Obtain two optional GPIO lines */ + priv->power = devm_gpiod_get_optional(&pdev->dev, "power", GPIOD_ASIS); + if (IS_ERR(priv->power)) { + retval = PTR_ERR(priv->power); + goto err_put_hcd; } + if (priv->power) + gpiod_set_consumer_name(priv->power, "OHCI power"); + /* + * This "overcurrent" GPIO line isn't really used in the code, + * but has a designated hardware function. + * TODO: implement proper overcurrent handling. + */ + priv->overcurrent = devm_gpiod_get_optional(&pdev->dev, "overcurrent", + GPIOD_IN); + if (IS_ERR(priv->overcurrent)) { + retval = PTR_ERR(priv->overcurrent); + goto err_put_hcd; + } + if (priv->overcurrent) + gpiod_set_consumer_name(priv->overcurrent, "OHCI overcurrent"); - hcd = usb_create_hcd(&ohci_omap_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err0; + priv->usb_host_ck = clk_get(&pdev->dev, "usb_hhc_ck"); + if (IS_ERR(priv->usb_host_ck)) { + retval = PTR_ERR(priv->usb_host_ck); + goto err_put_hcd; + } + + if (!cpu_is_omap15xx()) + priv->usb_dc_ck = clk_get(&pdev->dev, "usb_dc_ck"); + else + priv->usb_dc_ck = clk_get(&pdev->dev, "lb_ck"); + + if (IS_ERR(priv->usb_dc_ck)) { + retval = PTR_ERR(priv->usb_dc_ck); + goto err_put_host_ck; } - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_dbg(&pdev->dev, "request_mem_region failed\n"); retval = -EBUSY; - goto err1; + goto err_put_dc_ck; } hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); @@ -370,11 +385,12 @@ static int ohci_hcd_omap_probe(struct platform_device *pdev) iounmap(hcd->regs); err2: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: +err_put_dc_ck: + clk_put(priv->usb_dc_ck); +err_put_host_ck: + clk_put(priv->usb_host_ck); +err_put_hcd: usb_put_hcd(hcd); -err0: - clk_put(usb_dc_ck); - clk_put(usb_host_ck); return retval; } @@ -393,21 +409,20 @@ static int ohci_hcd_omap_probe(struct platform_device *pdev) static int ohci_hcd_omap_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); dev_dbg(hcd->self.controller, "stopping USB Controller\n"); usb_remove_hcd(hcd); - omap_ohci_clock_power(0); + omap_ohci_clock_power(priv, 0); if (!IS_ERR_OR_NULL(hcd->usb_phy)) { (void) otg_set_host(hcd->usb_phy->otg, 0); usb_put_phy(hcd->usb_phy); } - if (machine_is_omap_osk()) - gpio_free(9); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + clk_put(priv->usb_dc_ck); + clk_put(priv->usb_host_ck); usb_put_hcd(hcd); - clk_put(usb_dc_ck); - clk_put(usb_host_ck); return 0; } @@ -419,6 +434,7 @@ static int ohci_omap_suspend(struct platform_device *pdev, pm_message_t message) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); bool do_wakeup = device_may_wakeup(&pdev->dev); int ret; @@ -430,7 +446,7 @@ static int ohci_omap_suspend(struct platform_device *pdev, pm_message_t message) if (ret) return ret; - omap_ohci_clock_power(0); + omap_ohci_clock_power(priv, 0); return ret; } @@ -438,12 +454,13 @@ static int ohci_omap_resume(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct ohci_omap_priv *priv = hcd_to_ohci_omap_priv(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; - omap_ohci_clock_power(1); + omap_ohci_clock_power(priv, 1); ohci_resume(hcd, false); return 0; } @@ -470,7 +487,8 @@ static struct platform_driver ohci_hcd_omap_driver = { static const struct ohci_driver_overrides omap_overrides __initconst = { .product_desc = "OMAP OHCI", - .reset = ohci_omap_reset + .reset = ohci_omap_reset, + .extra_priv_size = sizeof(struct ohci_omap_priv), }; static int __init ohci_omap_init(void) diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 585222af24ff9076a401eaf219a85c3dc7715213..41efe927d8f3f5ec4cfcdd7fd20e43fc09408b2f 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -232,10 +232,6 @@ static const struct pci_device_id ohci_pci_quirks[] = { .driver_data = (unsigned long)ohci_quirk_qemu, }, - /* FIXME for some of the early AMD 760 southbridges, OHCI - * won't work at all. blacklist them. - */ - {}, }; diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 4ccb85a67bb3c65bcf3d12e393e0838d4e30ada1..3b445312beea3a80ffff90db00179b3079abe00d 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -647,7 +647,7 @@ static void td_submit_urb ( /* ... and periodic urbs have extra accounting */ periodic = ohci_to_hcd(ohci)->self.bandwidth_int_reqs++ == 0 && ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0; - /* FALLTHROUGH */ + fallthrough; case PIPE_BULK: info = is_out ? TD_T_TOGGLE | TD_CC | TD_DP_OUT @@ -879,11 +879,11 @@ static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) case TD_DATAUNDERRUN: if ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0) break; - /* fallthrough */ + fallthrough; case TD_CC_STALL: if (usb_pipecontrol (urb->pipe)) break; - /* fallthrough */ + fallthrough; default: ohci_dbg (ohci, "urb %p path %s ep%d%s %08x cc %d --> status %d\n", diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index d961097c90f0ea4fd0642e0a089aa9c7b81509ea..de5e570c58baeb72c40b28c32325eb108c165ed5 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -343,7 +343,7 @@ ohci_hcd_s3c2410_remove(struct platform_device *dev) return 0; } -/** +/* * ohci_hcd_s3c2410_probe - initialize S3C2410-based HCDs * Context: !in_interrupt() * diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index fb6f5e9ae5c620e54aa85c2542339314f634d10e..7f857bad9e95bd5382375e4dafcec00065db567a 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -97,13 +97,13 @@ static void tmio_stop_hc(struct platform_device *dev) switch (ohci->num_ports) { default: dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports); - /* fall through */ + fallthrough; case 3: pm |= CCR_PM_USBPW3; - /* fall through */ + fallthrough; case 2: pm |= CCR_PM_USBPW2; - /* fall through */ + fallthrough; case 1: pm |= CCR_PM_USBPW1; } diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index b85a39588f9d9eec1aa87b2526bdeaaf8e5346cc..aac6285b37f80d3465eb7ee6453c5d2dc52a59b2 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -162,7 +162,7 @@ struct td { /* map OHCI TD status codes (CC) to errno values */ -static const int cc_to_error [16] = { +static const int __maybe_unused cc_to_error [16] = { /* No Error */ 0, /* CRC Error */ -EILSEQ, /* Bit Stuff */ -EPROTO, diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 120666a0d5901dd24ab6edc93af419098770b646..cfa7dd2cc7d36507fcc9e72a238f612b1d66a997 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -1858,7 +1858,7 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu, switch (urb->dev->speed) { case USB_SPEED_LOW: info1 |= (1 << 12); /* EPS "low" */ - /* FALL THROUGH */ + fallthrough; case USB_SPEED_FULL: /* EPS 0 means "full" */ @@ -2037,16 +2037,15 @@ static struct ehci_qh *qh_append_tds(struct oxu_hcd *oxu, static int submit_async(struct oxu_hcd *oxu, struct urb *urb, struct list_head *qtd_list, gfp_t mem_flags) { - struct ehci_qtd *qtd; - int epnum; + int epnum = urb->ep->desc.bEndpointAddress; unsigned long flags; struct ehci_qh *qh = NULL; int rc = 0; +#ifdef OXU_URB_TRACE + struct ehci_qtd *qtd; qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list); - epnum = urb->ep->desc.bEndpointAddress; -#ifdef OXU_URB_TRACE oxu_dbg(oxu, "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", __func__, urb->dev->devpath, urb, epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", @@ -3378,7 +3377,7 @@ static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) switch (qh->qh_state) { case QH_STATE_LINKED: intr_deschedule(oxu, qh); - /* FALL THROUGH */ + fallthrough; case QH_STATE_IDLE: qh_completions(oxu, qh); break; @@ -3450,7 +3449,7 @@ static void oxu_endpoint_disable(struct usb_hcd *hcd, if (!tmp) goto nogood; unlink_async(oxu, qh); - /* FALL THROUGH */ + fallthrough; case QH_STATE_UNLINK: /* wait for hw to finish? */ idle_timeout: spin_unlock_irqrestore(&oxu->lock, flags); @@ -3461,7 +3460,7 @@ static void oxu_endpoint_disable(struct usb_hcd *hcd, qh_put(qh); break; } - /* fall through */ + fallthrough; default: nogood: /* caller was supposed to have unlinked any requests; diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 0b949acfa2589cc3be5f7d81f7e88cd3ab1b2401..b8961c0381cfd4fe87eca833834dfd65d0eac786 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -1133,7 +1133,7 @@ void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) } EXPORT_SYMBOL_GPL(usb_disable_xhci_ports); -/** +/* * PCI Quirks for xHCI. * * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS. diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 0c03ac6b021379b1a076eed75360759aba28526c..63719cdf6a4e61f85fd9c0546950d41a490ad054 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -475,16 +475,14 @@ static void pipe_stop(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe) static void clear_all_buffer(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe) { - u16 tmp; - if (!pipe || pipe->info.pipenum == 0) return; pipe_stop(r8a66597, pipe); r8a66597_bset(r8a66597, ACLRM, pipe->pipectr); - tmp = r8a66597_read(r8a66597, pipe->pipectr); - tmp = r8a66597_read(r8a66597, pipe->pipectr); - tmp = r8a66597_read(r8a66597, pipe->pipectr); + r8a66597_read(r8a66597, pipe->pipectr); + r8a66597_read(r8a66597, pipe->pipectr); + r8a66597_read(r8a66597, pipe->pipectr); r8a66597_bclr(r8a66597, ACLRM, pipe->pipectr); } diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 93e2cca5262d16ffbdc7c96586cff3d1eb397924..fcc5ac5ce8b10b7b61fe6937d4b4d1505950d46d 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * xhci-dbgcap.c - xHCI debug capability support * * Copyright (C) 2017 Intel Corporation @@ -14,24 +14,27 @@ #include "xhci-trace.h" #include "xhci-dbgcap.h" -static inline void * -dbc_dma_alloc_coherent(struct xhci_hcd *xhci, size_t size, - dma_addr_t *dma_handle, gfp_t flags) +static void dbc_free_ctx(struct device *dev, struct xhci_container_ctx *ctx) { - void *vaddr; - - vaddr = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, - size, dma_handle, flags); - return vaddr; + if (!ctx) + return; + dma_free_coherent(dev, ctx->size, ctx->bytes, ctx->dma); + kfree(ctx); } -static inline void -dbc_dma_free_coherent(struct xhci_hcd *xhci, size_t size, - void *cpu_addr, dma_addr_t dma_handle) +/* we use only one segment for DbC rings */ +static void dbc_ring_free(struct device *dev, struct xhci_ring *ring) { - if (cpu_addr) - dma_free_coherent(xhci_to_hcd(xhci)->self.sysdev, - size, cpu_addr, dma_handle); + if (!ring) + return; + + if (ring->first_seg && ring->first_seg->trbs) { + dma_free_coherent(dev, TRB_SEGMENT_SIZE, + ring->first_seg->trbs, + ring->first_seg->dma); + kfree(ring->first_seg); + } + kfree(ring); } static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings) @@ -83,16 +86,14 @@ static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings) return string_length; } -static void xhci_dbc_init_contexts(struct xhci_hcd *xhci, u32 string_length) +static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length) { - struct xhci_dbc *dbc; struct dbc_info_context *info; struct xhci_ep_ctx *ep_ctx; u32 dev_info; dma_addr_t deq, dma; unsigned int max_burst; - dbc = xhci->dbc; if (!dbc) return; @@ -121,7 +122,7 @@ static void xhci_dbc_init_contexts(struct xhci_hcd *xhci, u32 string_length) ep_ctx->deq = cpu_to_le64(deq | dbc->ring_in->cycle_state); /* Set DbC context and info registers: */ - xhci_write_64(xhci, dbc->ctx->dma, &dbc->regs->dccp); + lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp); dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL); writel(dev_info, &dbc->regs->devinfo1); @@ -134,10 +135,8 @@ static void xhci_dbc_giveback(struct dbc_request *req, int status) __releases(&dbc->lock) __acquires(&dbc->lock) { - struct dbc_ep *dep = req->dep; - struct xhci_dbc *dbc = dep->dbc; - struct xhci_hcd *xhci = dbc->xhci; - struct device *dev = xhci_to_hcd(dbc->xhci)->self.sysdev; + struct xhci_dbc *dbc = req->dbc; + struct device *dev = dbc->dev; list_del_init(&req->list_pending); req->trb_dma = 0; @@ -151,11 +150,11 @@ static void xhci_dbc_giveback(struct dbc_request *req, int status) dma_unmap_single(dev, req->dma, req->length, - dbc_ep_dma_direction(dep)); + dbc_ep_dma_direction(req)); /* Give back the transfer request: */ spin_unlock(&dbc->lock); - req->complete(xhci, req); + req->complete(dbc, req); spin_lock(&dbc->lock); } @@ -187,18 +186,25 @@ static void xhci_dbc_flush_requests(struct xhci_dbc *dbc) } struct dbc_request * -dbc_alloc_request(struct dbc_ep *dep, gfp_t gfp_flags) +dbc_alloc_request(struct xhci_dbc *dbc, unsigned int direction, gfp_t flags) { struct dbc_request *req; - req = kzalloc(sizeof(*req), gfp_flags); + if (direction != BULK_IN && + direction != BULK_OUT) + return NULL; + + if (!dbc) + return NULL; + + req = kzalloc(sizeof(*req), flags); if (!req) return NULL; - req->dep = dep; + req->dbc = dbc; INIT_LIST_HEAD(&req->list_pending); INIT_LIST_HEAD(&req->list_pool); - req->direction = dep->direction; + req->direction = direction; trace_xhci_dbc_alloc_request(req); @@ -206,7 +212,7 @@ dbc_alloc_request(struct dbc_ep *dep, gfp_t gfp_flags) } void -dbc_free_request(struct dbc_ep *dep, struct dbc_request *req) +dbc_free_request(struct dbc_request *req) { trace_xhci_dbc_free_request(req); @@ -242,7 +248,7 @@ static int xhci_dbc_queue_bulk_tx(struct dbc_ep *dep, u64 addr; union xhci_trb *trb; unsigned int num_trbs; - struct xhci_dbc *dbc = dep->dbc; + struct xhci_dbc *dbc = req->dbc; struct xhci_ring *ring = dep->ring; u32 length, control, cycle; @@ -286,14 +292,12 @@ static int xhci_dbc_queue_bulk_tx(struct dbc_ep *dep, } static int -dbc_ep_do_queue(struct dbc_ep *dep, struct dbc_request *req) +dbc_ep_do_queue(struct dbc_request *req) { int ret; - struct device *dev; - struct xhci_dbc *dbc = dep->dbc; - struct xhci_hcd *xhci = dbc->xhci; - - dev = xhci_to_hcd(xhci)->self.sysdev; + struct xhci_dbc *dbc = req->dbc; + struct device *dev = dbc->dev; + struct dbc_ep *dep = &dbc->eps[req->direction]; if (!req->length || !req->buf) return -EINVAL; @@ -306,13 +310,13 @@ dbc_ep_do_queue(struct dbc_ep *dep, struct dbc_request *req) req->length, dbc_ep_dma_direction(dep)); if (dma_mapping_error(dev, req->dma)) { - xhci_err(xhci, "failed to map buffer\n"); + dev_err(dbc->dev, "failed to map buffer\n"); return -EFAULT; } ret = xhci_dbc_queue_bulk_tx(dep, req); if (ret) { - xhci_err(xhci, "failed to queue trbs\n"); + dev_err(dbc->dev, "failed to queue trbs\n"); dma_unmap_single(dev, req->dma, req->length, @@ -325,16 +329,22 @@ dbc_ep_do_queue(struct dbc_ep *dep, struct dbc_request *req) return 0; } -int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req, - gfp_t gfp_flags) +int dbc_ep_queue(struct dbc_request *req) { unsigned long flags; - struct xhci_dbc *dbc = dep->dbc; + struct xhci_dbc *dbc = req->dbc; int ret = -ESHUTDOWN; + if (!dbc) + return -ENODEV; + + if (req->direction != BULK_IN && + req->direction != BULK_OUT) + return -EINVAL; + spin_lock_irqsave(&dbc->lock, flags); if (dbc->state == DS_CONFIGURED) - ret = dbc_ep_do_queue(dep, req); + ret = dbc_ep_do_queue(req); spin_unlock_irqrestore(&dbc->lock, flags); mod_delayed_work(system_wq, &dbc->event_work, 0); @@ -344,10 +354,9 @@ int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req, return ret; } -static inline void xhci_dbc_do_eps_init(struct xhci_hcd *xhci, bool direction) +static inline void xhci_dbc_do_eps_init(struct xhci_dbc *dbc, bool direction) { struct dbc_ep *dep; - struct xhci_dbc *dbc = xhci->dbc; dep = &dbc->eps[direction]; dep->dbc = dbc; @@ -357,125 +366,205 @@ static inline void xhci_dbc_do_eps_init(struct xhci_hcd *xhci, bool direction) INIT_LIST_HEAD(&dep->list_pending); } -static void xhci_dbc_eps_init(struct xhci_hcd *xhci) +static void xhci_dbc_eps_init(struct xhci_dbc *dbc) { - xhci_dbc_do_eps_init(xhci, BULK_OUT); - xhci_dbc_do_eps_init(xhci, BULK_IN); + xhci_dbc_do_eps_init(dbc, BULK_OUT); + xhci_dbc_do_eps_init(dbc, BULK_IN); } -static void xhci_dbc_eps_exit(struct xhci_hcd *xhci) +static void xhci_dbc_eps_exit(struct xhci_dbc *dbc) { - struct xhci_dbc *dbc = xhci->dbc; - memset(dbc->eps, 0, sizeof(struct dbc_ep) * ARRAY_SIZE(dbc->eps)); } -static int xhci_dbc_mem_init(struct xhci_hcd *xhci, gfp_t flags) +static int dbc_erst_alloc(struct device *dev, struct xhci_ring *evt_ring, + struct xhci_erst *erst, gfp_t flags) +{ + erst->entries = dma_alloc_coherent(dev, sizeof(struct xhci_erst_entry), + &erst->erst_dma_addr, flags); + if (!erst->entries) + return -ENOMEM; + + erst->num_entries = 1; + erst->entries[0].seg_addr = cpu_to_le64(evt_ring->first_seg->dma); + erst->entries[0].seg_size = cpu_to_le32(TRBS_PER_SEGMENT); + erst->entries[0].rsvd = 0; + return 0; +} + +static void dbc_erst_free(struct device *dev, struct xhci_erst *erst) +{ + if (erst->entries) + dma_free_coherent(dev, sizeof(struct xhci_erst_entry), + erst->entries, erst->erst_dma_addr); + erst->entries = NULL; +} + +static struct xhci_container_ctx * +dbc_alloc_ctx(struct device *dev, gfp_t flags) +{ + struct xhci_container_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), flags); + if (!ctx) + return NULL; + + /* xhci 7.6.9, all three contexts; info, ep-out and ep-in. Each 64 bytes*/ + ctx->size = 3 * DBC_CONTEXT_SIZE; + ctx->bytes = dma_alloc_coherent(dev, ctx->size, &ctx->dma, flags); + if (!ctx->bytes) { + kfree(ctx); + return NULL; + } + return ctx; +} + +static struct xhci_ring * +xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags) +{ + struct xhci_ring *ring; + struct xhci_segment *seg; + dma_addr_t dma; + + ring = kzalloc(sizeof(*ring), flags); + if (!ring) + return NULL; + + ring->num_segs = 1; + ring->type = type; + + seg = kzalloc(sizeof(*seg), flags); + if (!seg) + goto seg_fail; + + ring->first_seg = seg; + ring->last_seg = seg; + seg->next = seg; + + seg->trbs = dma_alloc_coherent(dev, TRB_SEGMENT_SIZE, &dma, flags); + if (!seg->trbs) + goto dma_fail; + + seg->dma = dma; + + /* Only event ring does not use link TRB */ + if (type != TYPE_EVENT) { + union xhci_trb *trb = &seg->trbs[TRBS_PER_SEGMENT - 1]; + + trb->link.segment_ptr = cpu_to_le64(dma); + trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK)); + } + INIT_LIST_HEAD(&ring->td_list); + xhci_initialize_ring_info(ring, 1); + return ring; +dma_fail: + kfree(seg); +seg_fail: + kfree(ring); + return NULL; +} + +static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags) { int ret; dma_addr_t deq; u32 string_length; - struct xhci_dbc *dbc = xhci->dbc; + struct device *dev = dbc->dev; /* Allocate various rings for events and transfers: */ - dbc->ring_evt = xhci_ring_alloc(xhci, 1, 1, TYPE_EVENT, 0, flags); + dbc->ring_evt = xhci_dbc_ring_alloc(dev, TYPE_EVENT, flags); if (!dbc->ring_evt) goto evt_fail; - dbc->ring_in = xhci_ring_alloc(xhci, 1, 1, TYPE_BULK, 0, flags); + dbc->ring_in = xhci_dbc_ring_alloc(dev, TYPE_BULK, flags); if (!dbc->ring_in) goto in_fail; - dbc->ring_out = xhci_ring_alloc(xhci, 1, 1, TYPE_BULK, 0, flags); + dbc->ring_out = xhci_dbc_ring_alloc(dev, TYPE_BULK, flags); if (!dbc->ring_out) goto out_fail; /* Allocate and populate ERST: */ - ret = xhci_alloc_erst(xhci, dbc->ring_evt, &dbc->erst, flags); + ret = dbc_erst_alloc(dev, dbc->ring_evt, &dbc->erst, flags); if (ret) goto erst_fail; /* Allocate context data structure: */ - dbc->ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); + dbc->ctx = dbc_alloc_ctx(dev, flags); /* was sysdev, and is still */ if (!dbc->ctx) goto ctx_fail; /* Allocate the string table: */ dbc->string_size = sizeof(struct dbc_str_descs); - dbc->string = dbc_dma_alloc_coherent(xhci, - dbc->string_size, - &dbc->string_dma, - flags); + dbc->string = dma_alloc_coherent(dev, dbc->string_size, + &dbc->string_dma, flags); if (!dbc->string) goto string_fail; /* Setup ERST register: */ writel(dbc->erst.erst_size, &dbc->regs->ersts); - xhci_write_64(xhci, dbc->erst.erst_dma_addr, &dbc->regs->erstba); + + lo_hi_writeq(dbc->erst.erst_dma_addr, &dbc->regs->erstba); deq = xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg, dbc->ring_evt->dequeue); - xhci_write_64(xhci, deq, &dbc->regs->erdp); + lo_hi_writeq(deq, &dbc->regs->erdp); /* Setup strings and contexts: */ string_length = xhci_dbc_populate_strings(dbc->string); - xhci_dbc_init_contexts(xhci, string_length); + xhci_dbc_init_contexts(dbc, string_length); - xhci_dbc_eps_init(xhci); + xhci_dbc_eps_init(dbc); dbc->state = DS_INITIALIZED; return 0; string_fail: - xhci_free_container_ctx(xhci, dbc->ctx); + dbc_free_ctx(dev, dbc->ctx); dbc->ctx = NULL; ctx_fail: - xhci_free_erst(xhci, &dbc->erst); + dbc_erst_free(dev, &dbc->erst); erst_fail: - xhci_ring_free(xhci, dbc->ring_out); + dbc_ring_free(dev, dbc->ring_out); dbc->ring_out = NULL; out_fail: - xhci_ring_free(xhci, dbc->ring_in); + dbc_ring_free(dev, dbc->ring_in); dbc->ring_in = NULL; in_fail: - xhci_ring_free(xhci, dbc->ring_evt); + dbc_ring_free(dev, dbc->ring_evt); dbc->ring_evt = NULL; evt_fail: return -ENOMEM; } -static void xhci_dbc_mem_cleanup(struct xhci_hcd *xhci) +static void xhci_dbc_mem_cleanup(struct xhci_dbc *dbc) { - struct xhci_dbc *dbc = xhci->dbc; - if (!dbc) return; - xhci_dbc_eps_exit(xhci); + xhci_dbc_eps_exit(dbc); if (dbc->string) { - dbc_dma_free_coherent(xhci, - dbc->string_size, - dbc->string, dbc->string_dma); + dma_free_coherent(dbc->dev, dbc->string_size, + dbc->string, dbc->string_dma); dbc->string = NULL; } - xhci_free_container_ctx(xhci, dbc->ctx); + dbc_free_ctx(dbc->dev, dbc->ctx); dbc->ctx = NULL; - xhci_free_erst(xhci, &dbc->erst); - xhci_ring_free(xhci, dbc->ring_out); - xhci_ring_free(xhci, dbc->ring_in); - xhci_ring_free(xhci, dbc->ring_evt); + dbc_erst_free(dbc->dev, &dbc->erst); + dbc_ring_free(dbc->dev, dbc->ring_out); + dbc_ring_free(dbc->dev, dbc->ring_in); + dbc_ring_free(dbc->dev, dbc->ring_evt); dbc->ring_in = NULL; dbc->ring_out = NULL; dbc->ring_evt = NULL; } -static int xhci_do_dbc_start(struct xhci_hcd *xhci) +static int xhci_do_dbc_start(struct xhci_dbc *dbc) { int ret; u32 ctrl; - struct xhci_dbc *dbc = xhci->dbc; if (dbc->state != DS_DISABLED) return -EINVAL; @@ -487,7 +576,7 @@ static int xhci_do_dbc_start(struct xhci_hcd *xhci) if (ret) return ret; - ret = xhci_dbc_mem_init(xhci, GFP_ATOMIC); + ret = xhci_dbc_mem_init(dbc, GFP_ATOMIC); if (ret) return ret; @@ -505,10 +594,8 @@ static int xhci_do_dbc_start(struct xhci_hcd *xhci) return 0; } -static int xhci_do_dbc_stop(struct xhci_hcd *xhci) +static int xhci_do_dbc_stop(struct xhci_dbc *dbc) { - struct xhci_dbc *dbc = xhci->dbc; - if (dbc->state == DS_DISABLED) return -1; @@ -518,76 +605,81 @@ static int xhci_do_dbc_stop(struct xhci_hcd *xhci) return 0; } -static int xhci_dbc_start(struct xhci_hcd *xhci) +static int xhci_dbc_start(struct xhci_dbc *dbc) { int ret; unsigned long flags; - struct xhci_dbc *dbc = xhci->dbc; WARN_ON(!dbc); - pm_runtime_get_sync(xhci_to_hcd(xhci)->self.controller); + pm_runtime_get_sync(dbc->dev); /* note this was self.controller */ spin_lock_irqsave(&dbc->lock, flags); - ret = xhci_do_dbc_start(xhci); + ret = xhci_do_dbc_start(dbc); spin_unlock_irqrestore(&dbc->lock, flags); if (ret) { - pm_runtime_put(xhci_to_hcd(xhci)->self.controller); + pm_runtime_put(dbc->dev); /* note this was self.controller */ return ret; } return mod_delayed_work(system_wq, &dbc->event_work, 1); } -static void xhci_dbc_stop(struct xhci_hcd *xhci) +static void xhci_dbc_stop(struct xhci_dbc *dbc) { int ret; unsigned long flags; - struct xhci_dbc *dbc = xhci->dbc; - struct dbc_port *port = &dbc->port; WARN_ON(!dbc); - cancel_delayed_work_sync(&dbc->event_work); + switch (dbc->state) { + case DS_DISABLED: + return; + case DS_CONFIGURED: + case DS_STALLED: + if (dbc->driver->disconnect) + dbc->driver->disconnect(dbc); + break; + default: + break; + } - if (port->registered) - xhci_dbc_tty_unregister_device(xhci); + cancel_delayed_work_sync(&dbc->event_work); spin_lock_irqsave(&dbc->lock, flags); - ret = xhci_do_dbc_stop(xhci); + ret = xhci_do_dbc_stop(dbc); spin_unlock_irqrestore(&dbc->lock, flags); if (!ret) { - xhci_dbc_mem_cleanup(xhci); - pm_runtime_put_sync(xhci_to_hcd(xhci)->self.controller); + xhci_dbc_mem_cleanup(dbc); + pm_runtime_put_sync(dbc->dev); /* note, was self.controller */ } } static void -dbc_handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) +dbc_handle_port_status(struct xhci_dbc *dbc, union xhci_trb *event) { u32 portsc; - struct xhci_dbc *dbc = xhci->dbc; portsc = readl(&dbc->regs->portsc); if (portsc & DBC_PORTSC_CONN_CHANGE) - xhci_info(xhci, "DbC port connect change\n"); + dev_info(dbc->dev, "DbC port connect change\n"); if (portsc & DBC_PORTSC_RESET_CHANGE) - xhci_info(xhci, "DbC port reset change\n"); + dev_info(dbc->dev, "DbC port reset change\n"); if (portsc & DBC_PORTSC_LINK_CHANGE) - xhci_info(xhci, "DbC port link status change\n"); + dev_info(dbc->dev, "DbC port link status change\n"); if (portsc & DBC_PORTSC_CONFIG_CHANGE) - xhci_info(xhci, "DbC config error change\n"); + dev_info(dbc->dev, "DbC config error change\n"); /* Port reset change bit will be cleared in other place: */ writel(portsc & ~DBC_PORTSC_RESET_CHANGE, &dbc->regs->portsc); } -static void dbc_handle_xfer_event(struct xhci_hcd *xhci, union xhci_trb *event) +static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event) { struct dbc_ep *dep; struct xhci_ring *ring; @@ -601,7 +693,7 @@ static void dbc_handle_xfer_event(struct xhci_hcd *xhci, union xhci_trb *event) remain_length = EVENT_TRB_LEN(le32_to_cpu(event->generic.field[2])); ep_id = TRB_TO_EP_ID(le32_to_cpu(event->generic.field[3])); dep = (ep_id == EPID_OUT) ? - get_out_ep(xhci) : get_in_ep(xhci); + get_out_ep(dbc) : get_in_ep(dbc); ring = dep->ring; switch (comp_code) { @@ -615,11 +707,11 @@ static void dbc_handle_xfer_event(struct xhci_hcd *xhci, union xhci_trb *event) case COMP_BABBLE_DETECTED_ERROR: case COMP_USB_TRANSACTION_ERROR: case COMP_STALL_ERROR: - xhci_warn(xhci, "tx error %d detected\n", comp_code); + dev_warn(dbc->dev, "tx error %d detected\n", comp_code); status = -comp_code; break; default: - xhci_err(xhci, "unknown tx error %d\n", comp_code); + dev_err(dbc->dev, "unknown tx error %d\n", comp_code); status = -comp_code; break; } @@ -633,7 +725,7 @@ static void dbc_handle_xfer_event(struct xhci_hcd *xhci, union xhci_trb *event) } if (!req) { - xhci_warn(xhci, "no matched request\n"); + dev_warn(dbc->dev, "no matched request\n"); return; } @@ -644,13 +736,23 @@ static void dbc_handle_xfer_event(struct xhci_hcd *xhci, union xhci_trb *event) xhci_dbc_giveback(req, status); } +static void inc_evt_deq(struct xhci_ring *ring) +{ + /* If on the last TRB of the segment go back to the beginning */ + if (ring->dequeue == &ring->deq_seg->trbs[TRBS_PER_SEGMENT - 1]) { + ring->cycle_state ^= 1; + ring->dequeue = ring->deq_seg->trbs; + return; + } + ring->dequeue++; +} + static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) { dma_addr_t deq; struct dbc_ep *dep; union xhci_trb *evt; u32 ctrl, portsc; - struct xhci_hcd *xhci = dbc->xhci; bool update_erdp = false; /* DbC state machine: */ @@ -663,7 +765,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) portsc = readl(&dbc->regs->portsc); if (portsc & DBC_PORTSC_CONN_STATUS) { dbc->state = DS_CONNECTED; - xhci_info(xhci, "DbC connected\n"); + dev_info(dbc->dev, "DbC connected\n"); } return EVT_DONE; @@ -671,7 +773,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) ctrl = readl(&dbc->regs->control); if (ctrl & DBC_CTRL_DBC_RUN) { dbc->state = DS_CONFIGURED; - xhci_info(xhci, "DbC configured\n"); + dev_info(dbc->dev, "DbC configured\n"); portsc = readl(&dbc->regs->portsc); writel(portsc, &dbc->regs->portsc); return EVT_GSER; @@ -683,7 +785,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) portsc = readl(&dbc->regs->portsc); if (!(portsc & DBC_PORTSC_PORT_ENABLED) && !(portsc & DBC_PORTSC_CONN_STATUS)) { - xhci_info(xhci, "DbC cable unplugged\n"); + dev_info(dbc->dev, "DbC cable unplugged\n"); dbc->state = DS_ENABLED; xhci_dbc_flush_requests(dbc); @@ -692,7 +794,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) /* Handle debug port reset event: */ if (portsc & DBC_PORTSC_RESET_CHANGE) { - xhci_info(xhci, "DbC port reset\n"); + dev_info(dbc->dev, "DbC port reset\n"); writel(portsc, &dbc->regs->portsc); dbc->state = DS_ENABLED; xhci_dbc_flush_requests(dbc); @@ -704,16 +806,16 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) ctrl = readl(&dbc->regs->control); if ((ctrl & DBC_CTRL_HALT_IN_TR) || (ctrl & DBC_CTRL_HALT_OUT_TR)) { - xhci_info(xhci, "DbC Endpoint stall\n"); + dev_info(dbc->dev, "DbC Endpoint stall\n"); dbc->state = DS_STALLED; if (ctrl & DBC_CTRL_HALT_IN_TR) { - dep = get_in_ep(xhci); + dep = get_in_ep(dbc); xhci_dbc_flush_endpoint_requests(dep); } if (ctrl & DBC_CTRL_HALT_OUT_TR) { - dep = get_out_ep(xhci); + dep = get_out_ep(dbc); xhci_dbc_flush_endpoint_requests(dep); } @@ -738,7 +840,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) return EVT_DONE; default: - xhci_err(xhci, "Unknown DbC state %d\n", dbc->state); + dev_err(dbc->dev, "Unknown DbC state %d\n", dbc->state); break; } @@ -756,16 +858,17 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) switch (le32_to_cpu(evt->event_cmd.flags) & TRB_TYPE_BITMASK) { case TRB_TYPE(TRB_PORT_STATUS): - dbc_handle_port_status(xhci, evt); + dbc_handle_port_status(dbc, evt); break; case TRB_TYPE(TRB_TRANSFER): - dbc_handle_xfer_event(xhci, evt); + dbc_handle_xfer_event(dbc, evt); break; default: break; } - inc_deq(xhci, dbc->ring_evt); + inc_evt_deq(dbc->ring_evt); + evt = dbc->ring_evt->dequeue; update_erdp = true; } @@ -774,7 +877,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) if (update_erdp) { deq = xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg, dbc->ring_evt->dequeue); - xhci_write_64(xhci, deq, &dbc->regs->erdp); + lo_hi_writeq(deq, &dbc->regs->erdp); } return EVT_DONE; @@ -782,14 +885,11 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) static void xhci_dbc_handle_events(struct work_struct *work) { - int ret; enum evtreturn evtr; struct xhci_dbc *dbc; unsigned long flags; - struct xhci_hcd *xhci; dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work); - xhci = dbc->xhci; spin_lock_irqsave(&dbc->lock, flags); evtr = xhci_dbc_do_handle_events(dbc); @@ -797,21 +897,17 @@ static void xhci_dbc_handle_events(struct work_struct *work) switch (evtr) { case EVT_GSER: - ret = xhci_dbc_tty_register_device(xhci); - if (ret) { - xhci_err(xhci, "failed to alloc tty device\n"); - break; - } - - xhci_info(xhci, "DbC now attached to /dev/ttyDBC0\n"); + if (dbc->driver->configure) + dbc->driver->configure(dbc); break; case EVT_DISC: - xhci_dbc_tty_unregister_device(xhci); + if (dbc->driver->disconnect) + dbc->driver->disconnect(dbc); break; case EVT_DONE: break; default: - xhci_info(xhci, "stop handling dbc events\n"); + dev_info(dbc->dev, "stop handling dbc events\n"); return; } @@ -864,6 +960,7 @@ static int xhci_do_dbc_init(struct xhci_hcd *xhci) spin_unlock_irqrestore(&xhci->lock, flags); dbc->xhci = xhci; + dbc->dev = xhci_to_hcd(xhci)->self.sysdev; INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events); spin_lock_init(&dbc->lock); @@ -912,13 +1009,15 @@ static ssize_t dbc_store(struct device *dev, const char *buf, size_t count) { struct xhci_hcd *xhci; + struct xhci_dbc *dbc; xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; if (!strncmp(buf, "enable", 6)) - xhci_dbc_start(xhci); + xhci_dbc_start(dbc); else if (!strncmp(buf, "disable", 7)) - xhci_dbc_stop(xhci); + xhci_dbc_stop(dbc); else return -EINVAL; @@ -936,7 +1035,7 @@ int xhci_dbc_init(struct xhci_hcd *xhci) if (ret) goto init_err3; - ret = xhci_dbc_tty_register_driver(xhci); + ret = xhci_dbc_tty_probe(xhci); if (ret) goto init_err2; @@ -947,7 +1046,7 @@ int xhci_dbc_init(struct xhci_hcd *xhci) return 0; init_err1: - xhci_dbc_tty_unregister_driver(); + xhci_dbc_tty_remove(xhci->dbc); init_err2: xhci_do_dbc_exit(xhci); init_err3: @@ -962,8 +1061,8 @@ void xhci_dbc_exit(struct xhci_hcd *xhci) return; device_remove_file(dev, &dev_attr_dbc); - xhci_dbc_tty_unregister_driver(); - xhci_dbc_stop(xhci); + xhci_dbc_tty_remove(xhci->dbc); + xhci_dbc_stop(xhci->dbc); xhci_do_dbc_exit(xhci); } @@ -978,7 +1077,7 @@ int xhci_dbc_suspend(struct xhci_hcd *xhci) if (dbc->state == DS_CONFIGURED) dbc->resume_required = 1; - xhci_dbc_stop(xhci); + xhci_dbc_stop(dbc); return 0; } @@ -993,7 +1092,7 @@ int xhci_dbc_resume(struct xhci_hcd *xhci) if (dbc->resume_required) { dbc->resume_required = 0; - xhci_dbc_start(xhci); + xhci_dbc_start(dbc); } return ret; diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index ce0c6072bd48870a0f6ed86e924dc7a2237d3bb9..c70b78d504eb5428d7c7910d315c145d47573262 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -84,28 +84,11 @@ enum dbc_state { DS_STALLED, }; -struct dbc_request { - void *buf; - unsigned int length; - dma_addr_t dma; - void (*complete)(struct xhci_hcd *xhci, - struct dbc_request *req); - struct list_head list_pool; - int status; - unsigned int actual; - - struct dbc_ep *dep; - struct list_head list_pending; - dma_addr_t trb_dma; - union xhci_trb *trb; - unsigned direction:1; -}; - struct dbc_ep { struct xhci_dbc *dbc; struct list_head list_pending; struct xhci_ring *ring; - unsigned direction:1; + unsigned int direction:1; }; #define DBC_QUEUE_SIZE 16 @@ -127,12 +110,16 @@ struct dbc_port { struct kfifo write_fifo; bool registered; - struct dbc_ep *in; - struct dbc_ep *out; +}; + +struct dbc_driver { + int (*configure)(struct xhci_dbc *dbc); + void (*disconnect)(struct xhci_dbc *dbc); }; struct xhci_dbc { spinlock_t lock; /* device access */ + struct device *dev; struct xhci_hcd *xhci; struct dbc_regs __iomem *regs; struct xhci_ring *ring_evt; @@ -150,7 +137,25 @@ struct xhci_dbc { unsigned resume_required:1; struct dbc_ep eps[2]; - struct dbc_port port; + const struct dbc_driver *driver; + void *priv; +}; + +struct dbc_request { + void *buf; + unsigned int length; + dma_addr_t dma; + void (*complete)(struct xhci_dbc *dbc, + struct dbc_request *req); + struct list_head list_pool; + int status; + unsigned int actual; + + struct xhci_dbc *dbc; + struct list_head list_pending; + dma_addr_t trb_dma; + union xhci_trb *trb; + unsigned direction:1; }; #define dbc_bulkout_ctx(d) \ @@ -178,30 +183,26 @@ enum evtreturn { EVT_DISC, }; -static inline struct dbc_ep *get_in_ep(struct xhci_hcd *xhci) +static inline struct dbc_ep *get_in_ep(struct xhci_dbc *dbc) { - struct xhci_dbc *dbc = xhci->dbc; - return &dbc->eps[BULK_IN]; } -static inline struct dbc_ep *get_out_ep(struct xhci_hcd *xhci) +static inline struct dbc_ep *get_out_ep(struct xhci_dbc *dbc) { - struct xhci_dbc *dbc = xhci->dbc; - return &dbc->eps[BULK_OUT]; } #ifdef CONFIG_USB_XHCI_DBGCAP int xhci_dbc_init(struct xhci_hcd *xhci); void xhci_dbc_exit(struct xhci_hcd *xhci); -int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci); -void xhci_dbc_tty_unregister_driver(void); -int xhci_dbc_tty_register_device(struct xhci_hcd *xhci); -void xhci_dbc_tty_unregister_device(struct xhci_hcd *xhci); -struct dbc_request *dbc_alloc_request(struct dbc_ep *dep, gfp_t gfp_flags); -void dbc_free_request(struct dbc_ep *dep, struct dbc_request *req); -int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req, gfp_t gfp_flags); +int xhci_dbc_tty_probe(struct xhci_hcd *xhci); +void xhci_dbc_tty_remove(struct xhci_dbc *dbc); +struct dbc_request *dbc_alloc_request(struct xhci_dbc *dbc, + unsigned int direction, + gfp_t flags); +void dbc_free_request(struct dbc_request *req); +int dbc_ep_queue(struct dbc_request *req); #ifdef CONFIG_PM int xhci_dbc_suspend(struct xhci_hcd *xhci); int xhci_dbc_resume(struct xhci_hcd *xhci); diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index be726c791323af16c066ea642aeee359474bce4c..b8918f73a432ebe4d0eb21f5388407b6cdde6ef7 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * xhci-dbgtty.c - tty glue for xHCI debug capability * * Copyright (C) 2017 Intel Corporation @@ -14,6 +14,16 @@ #include "xhci.h" #include "xhci-dbgcap.h" +static int dbc_tty_init(void); +static void dbc_tty_exit(void); + +static struct tty_driver *dbc_tty_driver; + +static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc) +{ + return dbc->priv; +} + static unsigned int dbc_send_packet(struct dbc_port *port, char *packet, unsigned int size) { @@ -48,7 +58,7 @@ static int dbc_start_tx(struct dbc_port *port) list_del(&req->list_pool); spin_unlock(&port->port_lock); - status = dbc_ep_queue(port->out, req, GFP_ATOMIC); + status = dbc_ep_queue(req); spin_lock(&port->port_lock); if (status) { @@ -80,7 +90,7 @@ static void dbc_start_rx(struct dbc_port *port) req->length = DBC_MAX_PACKET; spin_unlock(&port->port_lock); - status = dbc_ep_queue(port->in, req, GFP_ATOMIC); + status = dbc_ep_queue(req); spin_lock(&port->port_lock); if (status) { @@ -91,11 +101,10 @@ static void dbc_start_rx(struct dbc_port *port) } static void -dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req) +dbc_read_complete(struct xhci_dbc *dbc, struct dbc_request *req) { unsigned long flags; - struct xhci_dbc *dbc = xhci->dbc; - struct dbc_port *port = &dbc->port; + struct dbc_port *port = dbc_to_port(dbc); spin_lock_irqsave(&port->port_lock, flags); list_add_tail(&req->list_pool, &port->read_queue); @@ -103,11 +112,10 @@ dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req) spin_unlock_irqrestore(&port->port_lock, flags); } -static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req) +static void dbc_write_complete(struct xhci_dbc *dbc, struct dbc_request *req) { unsigned long flags; - struct xhci_dbc *dbc = xhci->dbc; - struct dbc_port *port = &dbc->port; + struct dbc_port *port = dbc_to_port(dbc); spin_lock_irqsave(&port->port_lock, flags); list_add(&req->list_pool, &port->write_pool); @@ -118,35 +126,36 @@ static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req) case -ESHUTDOWN: break; default: - xhci_warn(xhci, "unexpected write complete status %d\n", + dev_warn(dbc->dev, "unexpected write complete status %d\n", req->status); break; } spin_unlock_irqrestore(&port->port_lock, flags); } -static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req) +static void xhci_dbc_free_req(struct dbc_request *req) { kfree(req->buf); - dbc_free_request(dep, req); + dbc_free_request(req); } static int -xhci_dbc_alloc_requests(struct dbc_ep *dep, struct list_head *head, - void (*fn)(struct xhci_hcd *, struct dbc_request *)) +xhci_dbc_alloc_requests(struct xhci_dbc *dbc, unsigned int direction, + struct list_head *head, + void (*fn)(struct xhci_dbc *, struct dbc_request *)) { int i; struct dbc_request *req; for (i = 0; i < DBC_QUEUE_SIZE; i++) { - req = dbc_alloc_request(dep, GFP_KERNEL); + req = dbc_alloc_request(dbc, direction, GFP_KERNEL); if (!req) break; req->length = DBC_MAX_PACKET; req->buf = kmalloc(req->length, GFP_KERNEL); if (!req->buf) { - dbc_free_request(dep, req); + dbc_free_request(req); break; } @@ -158,14 +167,14 @@ xhci_dbc_alloc_requests(struct dbc_ep *dep, struct list_head *head, } static void -xhci_dbc_free_requests(struct dbc_ep *dep, struct list_head *head) +xhci_dbc_free_requests(struct list_head *head) { struct dbc_request *req; while (!list_empty(head)) { req = list_entry(head->next, struct dbc_request, list_pool); list_del(&req->list_pool); - xhci_dbc_free_req(dep, req); + xhci_dbc_free_req(req); } } @@ -279,55 +288,6 @@ static const struct tty_operations dbc_tty_ops = { .unthrottle = dbc_tty_unthrottle, }; -static struct tty_driver *dbc_tty_driver; - -int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci) -{ - int status; - struct xhci_dbc *dbc = xhci->dbc; - - dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV); - if (IS_ERR(dbc_tty_driver)) { - status = PTR_ERR(dbc_tty_driver); - dbc_tty_driver = NULL; - return status; - } - - dbc_tty_driver->driver_name = "dbc_serial"; - dbc_tty_driver->name = "ttyDBC"; - - dbc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - dbc_tty_driver->subtype = SERIAL_TYPE_NORMAL; - dbc_tty_driver->init_termios = tty_std_termios; - dbc_tty_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - dbc_tty_driver->init_termios.c_ispeed = 9600; - dbc_tty_driver->init_termios.c_ospeed = 9600; - dbc_tty_driver->driver_state = &dbc->port; - - tty_set_operations(dbc_tty_driver, &dbc_tty_ops); - - status = tty_register_driver(dbc_tty_driver); - if (status) { - xhci_err(xhci, - "can't register dbc tty driver, err %d\n", status); - put_tty_driver(dbc_tty_driver); - dbc_tty_driver = NULL; - } - - return status; -} - -void xhci_dbc_tty_unregister_driver(void) -{ - if (dbc_tty_driver) { - tty_unregister_driver(dbc_tty_driver); - put_tty_driver(dbc_tty_driver); - dbc_tty_driver = NULL; - } -} - static void dbc_rx_push(unsigned long _port) { struct dbc_request *req; @@ -418,7 +378,7 @@ static const struct tty_port_operations dbc_port_ops = { }; static void -xhci_dbc_tty_init_port(struct xhci_hcd *xhci, struct dbc_port *port) +xhci_dbc_tty_init_port(struct xhci_dbc *dbc, struct dbc_port *port) { tty_port_init(&port->port); spin_lock_init(&port->port_lock); @@ -427,8 +387,6 @@ xhci_dbc_tty_init_port(struct xhci_hcd *xhci, struct dbc_port *port) INIT_LIST_HEAD(&port->read_queue); INIT_LIST_HEAD(&port->write_pool); - port->in = get_in_ep(xhci); - port->out = get_out_ep(xhci); port->port.ops = &dbc_port_ops; port->n_read = 0; } @@ -440,14 +398,16 @@ xhci_dbc_tty_exit_port(struct dbc_port *port) tty_port_destroy(&port->port); } -int xhci_dbc_tty_register_device(struct xhci_hcd *xhci) +static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc) { int ret; struct device *tty_dev; - struct xhci_dbc *dbc = xhci->dbc; - struct dbc_port *port = &dbc->port; + struct dbc_port *port = dbc_to_port(dbc); + + if (port->registered) + return -EBUSY; - xhci_dbc_tty_init_port(xhci, port); + xhci_dbc_tty_init_port(dbc, port); tty_dev = tty_port_register_device(&port->port, dbc_tty_driver, 0, NULL); if (IS_ERR(tty_dev)) { @@ -459,12 +419,12 @@ int xhci_dbc_tty_register_device(struct xhci_hcd *xhci) if (ret) goto buf_alloc_fail; - ret = xhci_dbc_alloc_requests(port->in, &port->read_pool, + ret = xhci_dbc_alloc_requests(dbc, BULK_IN, &port->read_pool, dbc_read_complete); if (ret) goto request_fail; - ret = xhci_dbc_alloc_requests(port->out, &port->write_pool, + ret = xhci_dbc_alloc_requests(dbc, BULK_OUT, &port->write_pool, dbc_write_complete); if (ret) goto request_fail; @@ -474,8 +434,8 @@ int xhci_dbc_tty_register_device(struct xhci_hcd *xhci) return 0; request_fail: - xhci_dbc_free_requests(port->in, &port->read_pool); - xhci_dbc_free_requests(port->out, &port->write_pool); + xhci_dbc_free_requests(&port->read_pool); + xhci_dbc_free_requests(&port->write_pool); kfifo_free(&port->write_fifo); buf_alloc_fail: @@ -484,22 +444,113 @@ int xhci_dbc_tty_register_device(struct xhci_hcd *xhci) register_fail: xhci_dbc_tty_exit_port(port); - xhci_err(xhci, "can't register tty port, err %d\n", ret); + dev_err(dbc->dev, "can't register tty port, err %d\n", ret); return ret; } -void xhci_dbc_tty_unregister_device(struct xhci_hcd *xhci) +static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc) { - struct xhci_dbc *dbc = xhci->dbc; - struct dbc_port *port = &dbc->port; + struct dbc_port *port = dbc_to_port(dbc); + if (!port->registered) + return; tty_unregister_device(dbc_tty_driver, 0); xhci_dbc_tty_exit_port(port); port->registered = false; kfifo_free(&port->write_fifo); - xhci_dbc_free_requests(get_out_ep(xhci), &port->read_pool); - xhci_dbc_free_requests(get_out_ep(xhci), &port->read_queue); - xhci_dbc_free_requests(get_in_ep(xhci), &port->write_pool); + xhci_dbc_free_requests(&port->read_pool); + xhci_dbc_free_requests(&port->read_queue); + xhci_dbc_free_requests(&port->write_pool); +} + +static const struct dbc_driver dbc_driver = { + .configure = xhci_dbc_tty_register_device, + .disconnect = xhci_dbc_tty_unregister_device, +}; + +int xhci_dbc_tty_probe(struct xhci_hcd *xhci) +{ + struct xhci_dbc *dbc = xhci->dbc; + struct dbc_port *port; + int status; + + /* dbc_tty_init will be called by module init() in the future */ + status = dbc_tty_init(); + if (status) + return status; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) { + status = -ENOMEM; + goto out; + } + + dbc->driver = &dbc_driver; + dbc->priv = port; + + + dbc_tty_driver->driver_state = port; + + return 0; +out: + /* dbc_tty_exit will be called by module_exit() in the future */ + dbc_tty_exit(); + return status; +} + +/* + * undo what probe did, assume dbc is stopped already. + * we also assume tty_unregister_device() is called before this + */ +void xhci_dbc_tty_remove(struct xhci_dbc *dbc) +{ + struct dbc_port *port = dbc_to_port(dbc); + + dbc->driver = NULL; + dbc->priv = NULL; + kfree(port); + + /* dbc_tty_exit will be called by module_exit() in the future */ + dbc_tty_exit(); +} + +static int dbc_tty_init(void) +{ + int ret; + + dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(dbc_tty_driver)) + return PTR_ERR(dbc_tty_driver); + + dbc_tty_driver->driver_name = "dbc_serial"; + dbc_tty_driver->name = "ttyDBC"; + + dbc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + dbc_tty_driver->subtype = SERIAL_TYPE_NORMAL; + dbc_tty_driver->init_termios = tty_std_termios; + dbc_tty_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + dbc_tty_driver->init_termios.c_ispeed = 9600; + dbc_tty_driver->init_termios.c_ospeed = 9600; + + tty_set_operations(dbc_tty_driver, &dbc_tty_ops); + + ret = tty_register_driver(dbc_tty_driver); + if (ret) { + pr_err("Can't register dbc tty driver\n"); + put_tty_driver(dbc_tty_driver); + } + return ret; +} + +static void dbc_tty_exit(void) +{ + if (dbc_tty_driver) { + tty_unregister_driver(dbc_tty_driver); + put_tty_driver(dbc_tty_driver); + dbc_tty_driver = NULL; + } } diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 76c3f29562d2b9d2e3263f3d3dc1b45b92728140..92e25a62fdb5b7fc8c76656345ab62b0841a95ef 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -110,6 +110,7 @@ static void xhci_debugfs_free_regset(struct xhci_regset *regset) kfree(regset); } +__printf(6, 7) static void xhci_debugfs_regset(struct xhci_hcd *xhci, u32 base, const struct debugfs_reg32 *regs, size_t nregs, struct dentry *parent, diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index f37316d2c8fa4ff056ebe142c6422cbcf4d98416..c3554e37e09f3db3e936bbdf53360125ceea9b54 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -612,7 +612,7 @@ static void xhci_port_set_test_mode(struct xhci_hcd *xhci, temp |= test_mode << PORT_TEST_MODE_SHIFT; writel(temp, port->addr + PORTPMSC); xhci->test_mode = test_mode; - if (test_mode == TEST_FORCE_EN) + if (test_mode == USB_TEST_FORCE_ENABLE) xhci_start(xhci); } @@ -666,7 +666,7 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci) xhci_err(xhci, "Not in test mode, do nothing.\n"); return 0; } - if (xhci->test_mode == TEST_FORCE_EN && + if (xhci->test_mode == USB_TEST_FORCE_ENABLE && !(xhci->xhc_state & XHCI_STATE_HALTED)) { retval = xhci_halt(xhci); if (retval) @@ -1241,7 +1241,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = readl(ports[wIndex]->addr); /* Disable port */ if (link_state == USB_SS_PORT_LS_SS_DISABLED) { - xhci_dbg(xhci, "Disable port %d\n", wIndex); + xhci_dbg(xhci, "Disable port %d-%d\n", + hcd->self.busnum, wIndex + 1); temp = xhci_port_state_to_neutral(temp); /* * Clear all change bits, so that we get a new @@ -1257,7 +1258,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* Put link in RxDetect (enable port) */ if (link_state == USB_SS_PORT_LS_RX_DETECT) { - xhci_dbg(xhci, "Enable port %d\n", wIndex); + xhci_dbg(xhci, "Enable port %d-%d\n", + hcd->self.busnum, wIndex + 1); xhci_set_link_state(xhci, ports[wIndex], link_state); temp = readl(ports[wIndex]->addr); @@ -1289,8 +1291,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; } - xhci_dbg(xhci, "Enable compliance mode transition for port %d\n", - wIndex); + xhci_dbg(xhci, "Enable compliance mode transition for port %d-%d\n", + hcd->self.busnum, wIndex + 1); xhci_set_link_state(xhci, ports[wIndex], link_state); @@ -1304,8 +1306,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } /* Can't set port link state above '3' (U3) */ if (link_state > USB_SS_PORT_LS_U3) { - xhci_warn(xhci, "Cannot set port %d link state %d\n", - wIndex, link_state); + xhci_warn(xhci, "Cannot set port %d-%d link state %d\n", + hcd->self.busnum, wIndex + 1, + link_state); goto error; } @@ -1340,8 +1343,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, spin_unlock_irqrestore(&xhci->lock, flags); if (!wait_for_completion_timeout(&bus_state->u3exit_done[wIndex], msecs_to_jiffies(100))) - xhci_dbg(xhci, "missing U0 port change event for port %d\n", - wIndex); + xhci_dbg(xhci, "missing U0 port change event for port %d-%d\n", + hcd->self.busnum, wIndex + 1); spin_lock_irqsave(&xhci->lock, flags); temp = readl(ports[wIndex]->addr); break; @@ -1386,15 +1389,15 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, writel(temp, ports[wIndex]->addr); temp = readl(ports[wIndex]->addr); - xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); + xhci_dbg(xhci, "set port reset, actual port %d-%d status = 0x%x\n", + hcd->self.busnum, wIndex + 1, temp); break; case USB_PORT_FEAT_REMOTE_WAKE_MASK: xhci_set_remote_wake_mask(xhci, ports[wIndex], wake_mask); temp = readl(ports[wIndex]->addr); - xhci_dbg(xhci, "set port remote wake mask, " - "actual port %d status = 0x%x\n", - wIndex, temp); + xhci_dbg(xhci, "set port remote wake mask, actual port %d-%d status = 0x%x\n", + hcd->self.busnum, wIndex + 1, temp); break; case USB_PORT_FEAT_BH_PORT_RESET: temp |= PORT_WR; @@ -1421,7 +1424,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* 4.19.6 Port Test Modes (USB2 Test Mode) */ if (hcd->speed != HCD_USB2) goto error; - if (test_mode > TEST_FORCE_EN || test_mode < TEST_J) + if (test_mode > USB_TEST_FORCE_ENABLE || + test_mode < USB_TEST_J) goto error; retval = xhci_enter_test_mode(xhci, test_mode, wIndex, &flags); @@ -1634,8 +1638,8 @@ int xhci_bus_suspend(struct usb_hcd *hcd) spin_unlock_irqrestore(&xhci->lock, flags); msleep(XHCI_PORT_POLLING_LFPS_TIME); spin_lock_irqsave(&xhci->lock, flags); - xhci_dbg(xhci, "port %d polling in bus suspend, waiting\n", - port_index); + xhci_dbg(xhci, "port %d-%d polling in bus suspend, waiting\n", + hcd->self.busnum, port_index + 1); goto retry; } /* bail out if port detected a over-current condition */ @@ -1653,7 +1657,8 @@ int xhci_bus_suspend(struct usb_hcd *hcd) xhci_dbg(xhci, "Bus suspend bailout, port connect change\n"); return -EBUSY; } - xhci_dbg(xhci, "port %d not suspended\n", port_index); + xhci_dbg(xhci, "port %d-%d not suspended\n", + hcd->self.busnum, port_index + 1); t2 &= ~PORT_PLS_MASK; t2 |= PORT_LINK_STROBE | XDEV_U3; set_bit(port_index, &bus_state->bus_suspended); @@ -1783,7 +1788,8 @@ int xhci_bus_resume(struct usb_hcd *hcd) if ((xhci->quirks & XHCI_MISSING_CAS) && (hcd->speed >= HCD_USB3) && xhci_port_missing_cas_quirk(ports[port_index])) { - xhci_dbg(xhci, "reset stuck port %d\n", port_index); + xhci_dbg(xhci, "reset stuck port %d-%d\n", + hcd->self.busnum, port_index + 1); clear_bit(port_index, &bus_state->bus_suspended); continue; } @@ -1830,8 +1836,8 @@ int xhci_bus_resume(struct usb_hcd *hcd) sret = xhci_handshake(ports[port_index]->addr, PORT_PLC, PORT_PLC, 10 * 1000); if (sret) { - xhci_warn(xhci, "port %d resume PLC timeout\n", - port_index); + xhci_warn(xhci, "port %d-%d resume PLC timeout\n", + hcd->self.busnum, port_index + 1); continue; } xhci_test_and_clear_bit(xhci, ports[port_index], PORT_PLC); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 9764122c9cdf2d9baa8271a4cd927dc8d99efb2d..696fad50b478b22564d917c5dcfc17a553e48bbb 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -96,8 +96,9 @@ static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, * DMA address of the next segment. The caller needs to set any Link TRB * related flags, such as End TRB, Toggle Cycle, and no snoop. */ -static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, - struct xhci_segment *next, enum xhci_ring_type type) +static void xhci_link_segments(struct xhci_segment *prev, + struct xhci_segment *next, + enum xhci_ring_type type, bool chain_links) { u32 val; @@ -112,11 +113,7 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control); val &= ~TRB_TYPE_BITMASK; val |= TRB_TYPE(TRB_LINK); - /* Always set the chain bit with 0.95 hardware */ - /* Set chain bit for isoc rings on AMD 0.96 host */ - if (xhci_link_trb_quirk(xhci) || - (type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))) + if (chain_links) val |= TRB_CHAIN; prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); } @@ -131,13 +128,19 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_segs) { struct xhci_segment *next; + bool chain_links; if (!ring || !first || !last) return; + /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */ + chain_links = !!(xhci_link_trb_quirk(xhci) || + (ring->type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST))); + next = ring->enq_seg->next; - xhci_link_segments(xhci, ring->enq_seg, first, ring->type); - xhci_link_segments(xhci, last, next, ring->type); + xhci_link_segments(ring->enq_seg, first, ring->type, chain_links); + xhci_link_segments(last, next, ring->type, chain_links); ring->num_segs += num_segs; ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs; @@ -290,8 +293,8 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) kfree(ring); } -static void xhci_initialize_ring_info(struct xhci_ring *ring, - unsigned int cycle_state) +void xhci_initialize_ring_info(struct xhci_ring *ring, + unsigned int cycle_state) { /* The ring is empty, so the enqueue pointer == dequeue pointer */ ring->enqueue = ring->first_seg->trbs; @@ -321,6 +324,12 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) { struct xhci_segment *prev; + bool chain_links; + + /* Set chain bit for 0.95 hosts, and for isoc rings on AMD 0.96 host */ + chain_links = !!(xhci_link_trb_quirk(xhci) || + (type == TYPE_ISOC && + (xhci->quirks & XHCI_AMD_0x96_HOST))); prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags); if (!prev) @@ -341,18 +350,18 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, } return -ENOMEM; } - xhci_link_segments(xhci, prev, next, type); + xhci_link_segments(prev, next, type, chain_links); prev = next; num_segs--; } - xhci_link_segments(xhci, prev, *first, type); + xhci_link_segments(prev, *first, type, chain_links); *last = prev; return 0; } -/** +/* * Create a new ring with zero or more segments. * * Link each segment together into a ring. diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 9234c82e70e413a7ad3ef4dcea0834f11da55ea7..3feaafebfe5817a6f2822b44af90558f01a1331f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -57,7 +57,10 @@ #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba #define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb #define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc +#define PCI_DEVICE_ID_ASMEDIA_1042_XHCI 0x1042 #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142 +#define PCI_DEVICE_ID_ASMEDIA_1142_XHCI 0x1242 +#define PCI_DEVICE_ID_ASMEDIA_2142_XHCI 0x2142 static const char hcd_name[] = "xhci_hcd"; @@ -260,13 +263,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_LPM_SUPPORT; if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && - pdev->device == 0x1042) + pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) xhci->quirks |= XHCI_BROKEN_STREAMS; if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && - pdev->device == 0x1142) + pdev->device == PCI_DEVICE_ID_ASMEDIA_1042A_XHCI) xhci->quirks |= XHCI_TRUST_TX_LENGTH; if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && - pdev->device == 0x2142) + (pdev->device == PCI_DEVICE_ID_ASMEDIA_1142_XHCI || + pdev->device == PCI_DEVICE_ID_ASMEDIA_2142_XHCI)) xhci->quirks |= XHCI_NO_64BIT_SUPPORT; if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index f6b4089bfc4a5122fdf9dc21e96966758d3cee2d..3057cfc76d6a7041de8f0f5e9c41dd5e47b267a4 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -2,7 +2,7 @@ /* * xhci-plat.c - xHCI host controller driver platform Bus Glue. * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> * * A lot of code borrowed from the Linux xHCI driver. @@ -454,12 +454,14 @@ static const struct dev_pm_ops xhci_plat_pm_ops = { NULL) }; +#ifdef CONFIG_ACPI static const struct acpi_device_id usb_xhci_acpi_match[] = { /* XHCI-compliant USB Controller */ { "PNP0D10", }, { } }; MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); +#endif static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index ee6bf01775bba1a61d91c86b3eae27d85c7e16b2..014d79334f50e1de0390c287b8144a4e0f583fb4 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1853,11 +1853,7 @@ static const char * const tegra124_supply_names[] = { "avddio-pex", "dvddio-pex", "avdd-usb", - "avdd-pll-utmip", - "avdd-pll-erefe", - "avdd-usb-ss-pll", "hvdd-usb-ss", - "hvdd-usb-ss-pll-e", }; static const struct tegra_xusb_phy_type tegra124_phy_types[] = { @@ -1931,10 +1927,6 @@ static const char * const tegra210_supply_names[] = { "dvddio-pex", "hvddio-pex", "avdd-usb", - "avdd-pll-utmip", - "avdd-pll-uerefe", - "dvdd-pex-pll", - "hvdd-pex-pll-e", }; static const struct tegra_xusb_phy_type tegra210_phy_types[] = { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ed468eed299c5c0de6724f8f48ca2b8fb3bfc667..3c41b14ecce720280bb1c37b8493407aff73dd6a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1271,7 +1271,7 @@ static int xhci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); } -/** +/* * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and * HCDs. Find the index for an endpoint given its descriptor. Use the return * value to right shift 1 for the bitmask. diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c295e8a7f5ae08a3269a2402bf71a6b2f73e7e4a..ea1754f185a2271570d01e77d3e4ce92b86418c0 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2015,6 +2015,8 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_ring *evt_ring, struct xhci_erst *erst, gfp_t flags); +void xhci_initialize_ring_info(struct xhci_ring *ring, + unsigned int cycle_state); void xhci_free_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); void xhci_free_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 2388674042a918c195c0c7143cd975879cb0ef69..fc0e22cc6fda4c13ba5c0dcd4fb50b36f9904c9f 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -880,7 +880,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s return -EIO; } mdc800->pic_len=-1; - /* fall through */ + fallthrough; case 0x09: /* Download Thumbnail */ mdc800->download_left=answersize+64; diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c index 579a21bd70adb117c13d3a030c22fb6d3e209845..dd74ab7a2f9ce438f1c71e7773cfc714006f94e0 100644 --- a/drivers/usb/isp1760/isp1760-hcd.c +++ b/drivers/usb/isp1760/isp1760-hcd.c @@ -788,11 +788,11 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, mem_reads8(hcd->regs, qtd->payload_addr, qtd->data_buffer, qtd->actual_length); - /* Fall through */ + fallthrough; case OUT_PID: qtd->urb->actual_length += qtd->actual_length; - /* Fall through */ + fallthrough; case SETUP_PID: break; } diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4e48f8eed16829124b5223ef98b725c1375ca0db..6818ea689cd913bf63afef95ddaa7fcee1c2644d 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -78,7 +78,7 @@ config USB_CYPRESS_CY7C63 driver supports the pre-programmed devices (incl. firmware) by AK Modul-Bus Computer GmbH. - Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html + Please see: https://www.ak-modul-bus.de/stat/mikrocontroller.html To compile this driver as a module, choose M here: the module will be called cypress_cy7c63. @@ -106,7 +106,7 @@ config USB_IDMOUSE This driver creates an entry "/dev/idmouseX" or "/dev/usb/idmouseX", which can be used by, e.g.,"cat /dev/idmouse0 > fingerprint.pnm". - See also <http://www.fs.tum.de/~echtler/idmouse/>. + See also <https://www.fs.tum.de/~echtler/idmouse/>. config USB_FTDI_ELAN tristate "Elan PCMCIA CardBus Adapter USB Client" diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index d8d157c4c271d32e44eb923bccef4dba6cd4192f..a7eefe11f31aab79cce4e4ece8a02feaac969a25 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -109,7 +109,7 @@ static inline void adu_debug_data(struct device *dev, const char *function, function, size, size, data); } -/** +/* * adu_abort_transfers * aborts transfers and frees associated data structures */ @@ -642,7 +642,7 @@ static struct usb_class_driver adu_class = { .minor_base = ADU_MINOR_BASE, }; -/** +/* * adu_probe * * Called by the usb core when a new device is connected that it thinks @@ -753,7 +753,7 @@ static int adu_probe(struct usb_interface *interface, return retval; } -/** +/* * adu_disconnect * * Called by the usb core when the device is removed from the system. diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index ba1eaabc779698f50b94f47409095aa75e47a763..36fed1a0966633cfb226917c67aae1384ee204c5 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -89,7 +89,7 @@ static void appledisplay_complete(struct urb *urb) dev_err(dev, "OVERFLOW with data length %d, actual length is %d\n", ACD_URB_BUFFER_LEN, pdata->urb->actual_length); - /* fall through */ + fallthrough; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: @@ -305,8 +305,7 @@ static int appledisplay_probe(struct usb_interface *iface, if (pdata->urb) { usb_kill_urb(pdata->urb); cancel_delayed_work_sync(&pdata->work); - if (pdata->urbdata) - usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, + usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, pdata->urbdata, pdata->urb->transfer_dma); usb_free_urb(pdata->urb); } diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c index 7895d61e733b4c920b59b4cb41e051afa3faed7c..2752e1f4f4d0774aeab07c1987bc0743e603f5c7 100644 --- a/drivers/usb/misc/ehset.c +++ b/drivers/usb/misc/ehset.c @@ -33,28 +33,28 @@ static int ehset_probe(struct usb_interface *intf, ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_TEST, - (TEST_SE0_NAK << 8) | portnum, + (USB_TEST_SE0_NAK << 8) | portnum, NULL, 0, 1000); break; case TEST_J_PID: ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_TEST, - (TEST_J << 8) | portnum, + (USB_TEST_J << 8) | portnum, NULL, 0, 1000); break; case TEST_K_PID: ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_TEST, - (TEST_K << 8) | portnum, + (USB_TEST_K << 8) | portnum, NULL, 0, 1000); break; case TEST_PACKET_PID: ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, USB_PORT_FEAT_TEST, - (TEST_PACKET << 8) | portnum, + (USB_TEST_PACKET << 8) | portnum, NULL, 0, 1000); break; case TEST_HS_HOST_PORT_SUSPEND_RESUME: diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index dce20301e367a617277d1ae0f2489f220c4f9ee4..70ec296815268cd2d8e9f984fc93727fd454a3fb 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -2,14 +2,15 @@ /* * Native support for the I/O-Warrior USB devices * - * Copyright (c) 2003-2005 Code Mercenaries GmbH - * written by Christian Lucht <lucht@codemercs.com> + * Copyright (c) 2003-2005, 2020 Code Mercenaries GmbH + * written by Christian Lucht <lucht@codemercs.com> and + * Christoph Jung <jung@codemercs.com> * * based on * usb-skeleton.c by Greg Kroah-Hartman <greg@kroah.com> * brlvger.c by Stephane Dalton <sdalton@videotron.ca> - * and St�hane Doyon <s.doyon@videotron.ca> + * and Stephane Doyon <s.doyon@videotron.ca> * * Released under the GPLv2. */ @@ -244,7 +245,7 @@ static void iowarrior_write_callback(struct urb *urb) wake_up_interruptible(&dev->write_wait); } -/** +/* * iowarrior_delete */ static inline void iowarrior_delete(struct iowarrior *dev) @@ -271,7 +272,7 @@ static int read_index(struct iowarrior *dev) return (read_idx == intr_idx ? -1 : read_idx); } -/** +/* * iowarrior_read */ static ssize_t iowarrior_read(struct file *file, char __user *buffer, @@ -475,7 +476,7 @@ static ssize_t iowarrior_write(struct file *file, return retval; } -/** +/* * iowarrior_ioctl */ static long iowarrior_ioctl(struct file *file, unsigned int cmd, @@ -592,7 +593,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, return retval; } -/** +/* * iowarrior_open */ static int iowarrior_open(struct inode *inode, struct file *file) @@ -640,7 +641,7 @@ static int iowarrior_open(struct inode *inode, struct file *file) return retval; } -/** +/* * iowarrior_release */ static int iowarrior_release(struct inode *inode, struct file *file) @@ -742,7 +743,7 @@ static struct usb_class_driver iowarrior_class = { /*---------------------------------*/ /* probe and disconnect functions */ /*---------------------------------*/ -/** +/* * iowarrior_probe * * Called by the usb core when a new device is connected that it thinks @@ -802,14 +803,28 @@ static int iowarrior_probe(struct usb_interface *interface, /* we have to check the report_size often, so remember it in the endianness suitable for our machine */ dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); - if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && - ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) || - (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) || - (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) || - (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) || - (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100))) - /* IOWarrior56 has wMaxPacketSize different from report size */ - dev->report_size = 7; + + /* + * Some devices need the report size to be different than the + * endpoint size. + */ + if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { + switch (dev->product_id) { + case USB_DEVICE_ID_CODEMERCS_IOW56: + case USB_DEVICE_ID_CODEMERCS_IOW56AM: + dev->report_size = 7; + break; + + case USB_DEVICE_ID_CODEMERCS_IOW28: + case USB_DEVICE_ID_CODEMERCS_IOW28L: + dev->report_size = 4; + break; + + case USB_DEVICE_ID_CODEMERCS_IOW100: + dev->report_size = 13; + break; + } + } /* create the urb and buffer for reading */ dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -870,7 +885,7 @@ static int iowarrior_probe(struct usb_interface *interface, return retval; } -/** +/* * iowarrior_disconnect * * Called by the usb core when the device is removed from the system. diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 8f86b4ebca898b32e572cba6006ca01ab414b2ea..670e4d91e9cae09e66e154dfa69e66f79b2f63a0 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0+ -/** +/* * Generic USB driver for report based interrupt in/out devices * like LD Didactic's USB devices. LD Didactic's USB devices are * HID devices which do not use HID report definitons (they use @@ -184,7 +184,7 @@ struct ld_usb { static struct usb_driver ld_usb_driver; -/** +/* * ld_usb_abort_transfers * aborts transfers and frees associated data structures */ @@ -199,7 +199,7 @@ static void ld_usb_abort_transfers(struct ld_usb *dev) usb_kill_urb(dev->interrupt_out_urb); } -/** +/* * ld_usb_delete */ static void ld_usb_delete(struct ld_usb *dev) @@ -213,7 +213,7 @@ static void ld_usb_delete(struct ld_usb *dev) kfree(dev); } -/** +/* * ld_usb_interrupt_in_callback */ static void ld_usb_interrupt_in_callback(struct urb *urb) @@ -274,7 +274,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) wake_up_interruptible(&dev->read_wait); } -/** +/* * ld_usb_interrupt_out_callback */ static void ld_usb_interrupt_out_callback(struct urb *urb) @@ -294,7 +294,7 @@ static void ld_usb_interrupt_out_callback(struct urb *urb) wake_up_interruptible(&dev->write_wait); } -/** +/* * ld_usb_open */ static int ld_usb_open(struct inode *inode, struct file *file) @@ -365,7 +365,7 @@ static int ld_usb_open(struct inode *inode, struct file *file) return retval; } -/** +/* * ld_usb_release */ static int ld_usb_release(struct inode *inode, struct file *file) @@ -407,7 +407,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) return retval; } -/** +/* * ld_usb_poll */ static __poll_t ld_usb_poll(struct file *file, poll_table *wait) @@ -431,7 +431,7 @@ static __poll_t ld_usb_poll(struct file *file, poll_table *wait) return mask; } -/** +/* * ld_usb_read */ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, @@ -518,7 +518,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, return retval; } -/** +/* * ld_usb_write */ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, @@ -641,7 +641,7 @@ static struct usb_class_driver ld_usb_class = { .minor_base = USB_LD_MINOR_BASE, }; -/** +/* * ld_usb_probe * * Called by the usb core when a new device is connected that it thinks @@ -745,7 +745,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * return retval; } -/** +/* * ld_usb_disconnect * * Called by the usb core when the device is removed from the system. diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index ab4b98b04115849a52c97ae39cc2531c21567fc1..f922544056de4f071d8240af10b70e37ddc7b1c0 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -271,7 +271,7 @@ static struct usb_driver tower_driver = { }; -/** +/* * lego_usb_tower_debug_data */ static inline void lego_usb_tower_debug_data(struct device *dev, @@ -283,7 +283,7 @@ static inline void lego_usb_tower_debug_data(struct device *dev, } -/** +/* * tower_delete */ static inline void tower_delete(struct lego_usb_tower *dev) @@ -299,7 +299,7 @@ static inline void tower_delete(struct lego_usb_tower *dev) } -/** +/* * tower_open */ static int tower_open(struct inode *inode, struct file *file) @@ -398,7 +398,7 @@ static int tower_open(struct inode *inode, struct file *file) return retval; } -/** +/* * tower_release */ static int tower_release(struct inode *inode, struct file *file) @@ -440,7 +440,7 @@ static int tower_release(struct inode *inode, struct file *file) return retval; } -/** +/* * tower_check_for_read_packet * * To get correct semantics for signals and non-blocking I/O @@ -461,7 +461,7 @@ static void tower_check_for_read_packet(struct lego_usb_tower *dev) } -/** +/* * tower_poll */ static __poll_t tower_poll(struct file *file, poll_table *wait) @@ -487,7 +487,7 @@ static __poll_t tower_poll(struct file *file, poll_table *wait) } -/** +/* * tower_llseek */ static loff_t tower_llseek(struct file *file, loff_t off, int whence) @@ -496,7 +496,7 @@ static loff_t tower_llseek(struct file *file, loff_t off, int whence) } -/** +/* * tower_read */ static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) @@ -580,7 +580,7 @@ static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, } -/** +/* * tower_write */ static ssize_t tower_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) @@ -662,7 +662,7 @@ static ssize_t tower_write(struct file *file, const char __user *buffer, size_t } -/** +/* * tower_interrupt_in_callback */ static void tower_interrupt_in_callback(struct urb *urb) @@ -717,7 +717,7 @@ static void tower_interrupt_in_callback(struct urb *urb) } -/** +/* * tower_interrupt_out_callback */ static void tower_interrupt_out_callback(struct urb *urb) @@ -742,7 +742,7 @@ static void tower_interrupt_out_callback(struct urb *urb) } -/** +/* * tower_probe * * Called by the usb core when a new device is connected that it thinks @@ -854,7 +854,7 @@ static int tower_probe(struct usb_interface *interface, const struct usb_device_ } -/** +/* * tower_disconnect * * Called by the usb core when the device is removed from the system. diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index fc8a5da4a07c9adeb8d4f447e9d323a6519d6c15..f08de33d9ff383475b18908115a09248e157d164 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -761,7 +761,7 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, u8 swap8, fromkern = kernbuffer ? 1 : 0; u16 swap16; u32 swap32, flag = (length >> 28) & 1; - char buf[4]; + u8 buf[4]; /* if neither kernbuffer not userbuffer are given, assume * data in obuf @@ -1283,7 +1283,7 @@ int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data); } -int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, +int sisusb_copy_memory(struct sisusb_usb_data *sisusb, u8 *src, u32 dest, int length) { size_t dummy; @@ -1307,7 +1307,7 @@ static int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, #ifdef SISUSBENDIANTEST static void sisusb_testreadwrite(struct sisusb_usb_data *sisusb) { - static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; + static u8 srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; char destbuffer[10]; int i, j; @@ -2340,7 +2340,7 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) } } else if (sisusb->scrbuf) { - ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf, + ret |= sisusb_copy_memory(sisusb, (u8 *)sisusb->scrbuf, sisusb->vrambase, sisusb->scrbuf_size); } diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index cd0155310fead19f02d97d510acd1844a6597643..15e62a2e9b1b3fcd67b764ac5c736ec52c28af74 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -509,7 +509,7 @@ sisusbcon_switch(struct vc_data *c) /* Restore the screen contents */ memcpy((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, length); - sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_copy_memory(sisusb, (u8 *)c->vc_origin, sisusb_haddr(sisusb, c, 0, 0), length); mutex_unlock(&sisusb->lock); @@ -615,7 +615,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) sisusbcon_memsetw((u16 *)c->vc_origin, c->vc_video_erase_char, c->vc_screenbuf_size); - sisusb_copy_memory(sisusb, (char *)c->vc_origin, + sisusb_copy_memory(sisusb, (u8 *)c->vc_origin, sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); sisusb->con_blanked = 1; @@ -897,18 +897,18 @@ sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b, if (copyall) sisusb_copy_memory(sisusb, - (char *)c->vc_origin, + (u8 *)c->vc_origin, sisusb_haddr(sisusb, c, 0, 0), c->vc_screenbuf_size); else if (dir == SM_UP) sisusb_copy_memory(sisusb, - (char *)c->vc_origin + c->vc_screenbuf_size - delta, + (u8 *)c->vc_origin + c->vc_screenbuf_size - delta, sisusb_haddr(sisusb, c, 0, 0) + c->vc_screenbuf_size - delta, delta); else sisusb_copy_memory(sisusb, - (char *)c->vc_origin, + (u8 *)c->vc_origin, sisusb_haddr(sisusb, c, 0, 0), delta); @@ -1226,7 +1226,7 @@ sisusbcon_font_set(struct vc_data *c, struct console_font *font, sisusb->font_backup = vmalloc(array_size(charcount, 32)); if (sisusb->font_backup) { - memcpy(sisusb->font_backup, font->data, charcount * 32); + memcpy(sisusb->font_backup, font->data, array_size(charcount, 32)); sisusb->font_backup_size = charcount; sisusb->font_backup_height = font->height; sisusb->font_backup_512 = (charcount == 512) ? 1 : 0; diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 66f6ab5acd974a26c75fba75ef08bc17dc300b3c..7c11198d5dda0db3d0bcbdf01d91acfca578b5e2 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -45,6 +45,7 @@ #include "sisusb.h" #include "sisusb_init.h" +#include "sisusb_tables.h" /*********************************************/ /* POINTER INITIALIZATION */ diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index aa33bc81ee5269a99c5c9105109c8ff157270a9a..b5cd77ae941d7853eb78b95c09483ee34bb0727d 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h @@ -147,668 +147,6 @@ #define SIS_VIDEO_PLAYBACK 0x02 - 0x30 #define SIS_CRT2_PORT_04 0x04 - 0x30 -/* Mode numbers */ -static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f }; -static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 }; -static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 }; -static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c }; -static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e }; -static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 }; -static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 }; -static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 }; -static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 }; -static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 }; -static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 }; -static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e }; -static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 }; -static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f }; -static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 }; -static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 }; -static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 }; -static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b }; -static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 }; -static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 }; -static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 }; - -static const unsigned char SiS_MDA_DAC[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F -}; - -static const unsigned char SiS_CGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F -}; - -static const unsigned char SiS_EGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, - 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, - 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, - 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, - 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, - 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, - 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F -}; - -static const unsigned char SiS_VGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, - 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, - 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, - 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, - 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, - 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, - 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, - 0x0B, 0x0C, 0x0D, 0x0F, 0x10 -}; - -static const struct SiS_St SiSUSB_SModeIDTable[] = { - {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, - {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -}; - -static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = { - {640, 400}, - {640, 350}, - {720, 400}, - {720, 350}, - {640, 480} -}; - -static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { - {320, 200, 8, 8}, /* 0x00 */ - {320, 240, 8, 8}, /* 0x01 */ - {320, 400, 8, 8}, /* 0x02 */ - {400, 300, 8, 8}, /* 0x03 */ - {512, 384, 8, 8}, /* 0x04 */ - {640, 400, 8, 16}, /* 0x05 */ - {640, 480, 8, 16}, /* 0x06 */ - {800, 600, 8, 16}, /* 0x07 */ - {1024, 768, 8, 16}, /* 0x08 */ - {1280, 1024, 8, 16}, /* 0x09 */ - {1600, 1200, 8, 16}, /* 0x0a */ - {1920, 1440, 8, 16}, /* 0x0b */ - {2048, 1536, 8, 16}, /* 0x0c */ - {720, 480, 8, 16}, /* 0x0d */ - {720, 576, 8, 16}, /* 0x0e */ - {1280, 960, 8, 16}, /* 0x0f */ - {800, 480, 8, 16}, /* 0x10 */ - {1024, 576, 8, 16}, /* 0x11 */ - {1280, 720, 8, 16}, /* 0x12 */ - {856, 480, 8, 16}, /* 0x13 */ - {1280, 768, 8, 16}, /* 0x14 */ - {1400, 1050, 8, 16}, /* 0x15 */ - {1152, 864, 8, 16}, /* 0x16 */ - {848, 480, 8, 16}, /* 0x17 */ - {1360, 768, 8, 16}, /* 0x18 */ - {1024, 600, 8, 16}, /* 0x19 */ - {1152, 768, 8, 16}, /* 0x1a */ - {768, 576, 8, 16}, /* 0x1b */ - {1360, 1024, 8, 16}, /* 0x1c */ - {1680, 1050, 8, 16}, /* 0x1d */ - {1280, 800, 8, 16}, /* 0x1e */ - {1920, 1080, 8, 16}, /* 0x1f */ - {960, 540, 8, 16}, /* 0x20 */ - {960, 600, 8, 16} /* 0x21 */ -}; - -static const struct SiS_StandTable SiSUSB_StandTable[] = { - /* MD_3_400 - mode 0x03 - 400 */ - { - 0x50, 0x18, 0x10, 0x1000, - {0x00, 0x03, 0x00, 0x02}, - 0x67, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x0c, 0x00, 0x0f, 0x08}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} - }, - /* Generic for VGA and higher */ - { - 0x00, 0x00, 0x00, 0x0000, - {0x01, 0x0f, 0x00, 0x0e}, - 0x23, - {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x01, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} - } -}; - -static const struct SiS_Ext SiSUSB_EModeIDTable[] = { - {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ - {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ - {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ - {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ - {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ - {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ - {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ - {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ - {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ - {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ - {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ - {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ - {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ - {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ - {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ - {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ - {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ - {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ - {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ - {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ - {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ - {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ - {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ - {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ - {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ - {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ - {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ - {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ - {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ - {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ - {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ - {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ - {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ - {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ - {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ - {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ - {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ - {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ - {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ - {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ - {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ - {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ - {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ - {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, - -1}, - {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, - -1}, - {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ - {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, - -1}, - {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, - -1}, - {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ - {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ - {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ - {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ - {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, - -1}, - {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, - -1}, - {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ - {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, - -1}, - {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, - -1}, - {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ - {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, - -1}, - {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, - -1}, - {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ - {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, - -1}, - {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, - -1}, - {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} -}; - -static const struct SiS_Ext2 SiSUSB_RefIndex[] = { - {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ - {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ - {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ - {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ - {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ - {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ - {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ - {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ - {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ - {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ - {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ - {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ - {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ - {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ - {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ - {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ - {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ - {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ - {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ - {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ - {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ - {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ - {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ - {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ - {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ - {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ - {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ - {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ - {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ - {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ - {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ - {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ - {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ - {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ - {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ - {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ - {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ - {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ - {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ - {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ - {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ - {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ - {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ - {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ - {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ - {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ - {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ - {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ - {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ - {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ - {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ - {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ - {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ - {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ - {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} -}; - -static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { - {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, - 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, - 0x00}}, /* 0x0 */ - {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, - 0x00}}, /* 0x1 */ - {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, - 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, - 0x01}}, /* 0x2 */ - {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, - 0x01}}, /* 0x3 */ - {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, - 0x00}}, /* 0x4 */ - {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, - 0x00}}, /* 0x5 */ - {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, - 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, - 0x00}}, /* 0x6 */ - {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, - 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, - 0x00}}, /* 0x7 */ - {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, - 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, - 0x00}}, /* 0x8 */ - {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, - 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, - 0x61}}, /* 0x9 */ - {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, - 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, - 0x61}}, /* 0xa */ - {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, - 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, - 0x61}}, /* 0xb */ - {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, - 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, - 0x00}}, /* 0xc */ - {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, - 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, - 0x01}}, /* 0xd */ - {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, - 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, - 0x01}}, /* 0xe */ - {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, - 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, - 0x01}}, /* 0xf */ - {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, - 0x01}}, /* 0x10 */ - {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, - 0x01}}, /* 0x11 */ - {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, - 0x61}}, /* 0x12 */ - {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, - 0x61}}, /* 0x13 */ - {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, - 0x61}}, /* 0x14 */ - {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, - 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, - 0x00}}, /* 0x15 */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, - 0x01}}, /* 0x16 */ - {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, - 0x01}}, /* 0x17 */ - {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, - 0x01}}, /* 0x18 */ - {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, - 0x01}}, /* 0x19 */ - {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, - 0x62}}, /* 0x1a */ - {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, - 0x62}}, /* 0x1b */ - {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, - 0x00}}, /* 0x1c */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, - 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, - 0x01}}, /* 0x1d */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, - 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, - 0x01}}, /* 0x1e */ - {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, - 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, - 0x01}}, /* 0x1f */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x20 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x21 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x22 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x23 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x24 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x25 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x26 */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x27 */ - {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, - 0x63}}, /* 0x28 */ - {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, - 0x63}}, /* 0x29 */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x2a */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x2b */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x2c */ - {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x2d */ - {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x2e */ - {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x2f */ - {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, - 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x30 */ - {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, - 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, - 0x00}}, /* 0x31 */ - {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, - 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, - 0x01}}, /* 0x32 */ - {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, - 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, - 0x01}}, /* 0x33 */ - {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, - 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, - 0x01}}, /* 0x34 */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, - 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, - 0x01}}, /* 0x35 */ - {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, - 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, - 0x01}}, /* 0x36 */ - {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, - 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, - 0x01}}, /* 0x37 */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, - 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, - 0x01}}, /* 0x38 */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, - 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, - 0x01}}, /* 0x39 */ - {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, - 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, - 0x01}}, /* 0x3a */ - {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, - 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, - 0x01}}, /* 0x3b */ - {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, - 0x00}}, /* 0x3c */ - {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, - 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, - 0x41}}, /* 0x3d */ - {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, - 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, - 0x00}}, /* 0x3e */ - {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, - 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, - 0x00}}, /* 0x3f */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, - 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, - 0x01}}, /* 0x40 */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, - 0x01}}, /* 0x41 */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, - 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, - 0x01}}, /* 0x42 */ - {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, - 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, - 0x00}}, /* 0x43 */ - {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, - 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, - 0x01}}, /* 0x44 */ - {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, - 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, - 0x00}}, /* 0x45 */ - {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, - 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, - 0x00}}, /* 0x46 */ - {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, - 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, - 0x00}}, /* 0x47 */ - {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, - 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, - 0x00}}, /* 0x48 */ - {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, - 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, - 0x01}}, /* 0x49 */ - {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, - 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, - 0x01}}, /* 0x4a */ - {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, - 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, - 0x00}}, /* 0x4b */ - {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, - 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, - 0x01}}, /* 0x4c */ - {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, - 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, - 0x41}}, - {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, - 0x00}}, /* 0x4e */ - {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, - 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, - 0x21}}, /* 0x4f */ - {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, - 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, - 0x20}}, /* 0x50 */ - {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, - 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, - 0x61}}, /* 0x51 */ - {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, - 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, - 0x41}}, /* 0x52 */ - {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, - 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, - 0x01}}, /* 0x53 */ - {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, - 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, - 0x41}} /* 0x54 */ -}; - -static const struct SiS_VCLKData SiSUSB_VCLKData[] = { - {0x1b, 0xe1, 25}, /* 0x00 */ - {0x4e, 0xe4, 28}, /* 0x01 */ - {0x57, 0xe4, 31}, /* 0x02 */ - {0xc3, 0xc8, 36}, /* 0x03 */ - {0x42, 0xe2, 40}, /* 0x04 */ - {0xfe, 0xcd, 43}, /* 0x05 */ - {0x5d, 0xc4, 44}, /* 0x06 */ - {0x52, 0xe2, 49}, /* 0x07 */ - {0x53, 0xe2, 50}, /* 0x08 */ - {0x74, 0x67, 52}, /* 0x09 */ - {0x6d, 0x66, 56}, /* 0x0a */ - {0x5a, 0x64, 65}, /* 0x0b */ - {0x46, 0x44, 67}, /* 0x0c */ - {0xb1, 0x46, 68}, /* 0x0d */ - {0xd3, 0x4a, 72}, /* 0x0e */ - {0x29, 0x61, 75}, /* 0x0f */ - {0x6e, 0x46, 76}, /* 0x10 */ - {0x2b, 0x61, 78}, /* 0x11 */ - {0x31, 0x42, 79}, /* 0x12 */ - {0xab, 0x44, 83}, /* 0x13 */ - {0x46, 0x25, 84}, /* 0x14 */ - {0x78, 0x29, 86}, /* 0x15 */ - {0x62, 0x44, 94}, /* 0x16 */ - {0x2b, 0x41, 104}, /* 0x17 */ - {0x3a, 0x23, 105}, /* 0x18 */ - {0x70, 0x44, 108}, /* 0x19 */ - {0x3c, 0x23, 109}, /* 0x1a */ - {0x5e, 0x43, 113}, /* 0x1b */ - {0xbc, 0x44, 116}, /* 0x1c */ - {0xe0, 0x46, 132}, /* 0x1d */ - {0x54, 0x42, 135}, /* 0x1e */ - {0xea, 0x2a, 139}, /* 0x1f */ - {0x41, 0x22, 157}, /* 0x20 */ - {0x70, 0x24, 162}, /* 0x21 */ - {0x30, 0x21, 175}, /* 0x22 */ - {0x4e, 0x22, 189}, /* 0x23 */ - {0xde, 0x26, 194}, /* 0x24 */ - {0x62, 0x06, 202}, /* 0x25 */ - {0x3f, 0x03, 229}, /* 0x26 */ - {0xb8, 0x06, 234}, /* 0x27 */ - {0x34, 0x02, 253}, /* 0x28 */ - {0x58, 0x04, 255}, /* 0x29 */ - {0x24, 0x01, 265}, /* 0x2a */ - {0x9b, 0x02, 267}, /* 0x2b */ - {0x70, 0x05, 270}, /* 0x2c */ - {0x25, 0x01, 272}, /* 0x2d */ - {0x9c, 0x02, 277}, /* 0x2e */ - {0x27, 0x01, 286}, /* 0x2f */ - {0x3c, 0x02, 291}, /* 0x30 */ - {0xef, 0x0a, 292}, /* 0x31 */ - {0xf6, 0x0a, 310}, /* 0x32 */ - {0x95, 0x01, 315}, /* 0x33 */ - {0xf0, 0x09, 324}, /* 0x34 */ - {0xfe, 0x0a, 331}, /* 0x35 */ - {0xf3, 0x09, 332}, /* 0x36 */ - {0xea, 0x08, 340}, /* 0x37 */ - {0xe8, 0x07, 376}, /* 0x38 */ - {0xde, 0x06, 389}, /* 0x39 */ - {0x52, 0x2a, 54}, /* 0x3a 301 TV */ - {0x52, 0x6a, 27}, /* 0x3b 301 TV */ - {0x62, 0x24, 70}, /* 0x3c 301 TV */ - {0x62, 0x64, 70}, /* 0x3d 301 TV */ - {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ - {0x20, 0x26, 33}, /* 0x3f 301 TV */ - {0x31, 0xc2, 39}, /* 0x40 */ - {0x60, 0x36, 30}, /* 0x41 Chrontel */ - {0x40, 0x4a, 28}, /* 0x42 Chrontel */ - {0x9f, 0x46, 44}, /* 0x43 Chrontel */ - {0x97, 0x2c, 26}, /* 0x44 */ - {0x44, 0xe4, 25}, /* 0x45 Chrontel */ - {0x7e, 0x32, 47}, /* 0x46 Chrontel */ - {0x8a, 0x24, 31}, /* 0x47 Chrontel */ - {0x97, 0x2c, 26}, /* 0x48 Chrontel */ - {0xce, 0x3c, 39}, /* 0x49 */ - {0x52, 0x4a, 36}, /* 0x4a Chrontel */ - {0x34, 0x61, 95}, /* 0x4b */ - {0x78, 0x27, 108}, /* 0x4c - was 102 */ - {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ - {0x41, 0x4e, 21}, /* 0x4e */ - {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ - {0x19, 0x42, 42}, /* 0x50 */ - {0x54, 0x46, 58}, /* 0x51 Chrontel */ - {0x25, 0x42, 61}, /* 0x52 */ - {0x44, 0x44, 66}, /* 0x53 Chrontel */ - {0x3a, 0x62, 70}, /* 0x54 Chrontel */ - {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ - {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ - {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ - {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ - {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ - {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ - {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ - {0x45, 0x25, 83}, /* 0x5c 1280x800 */ - {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ - {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ - {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ - {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ - {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ - {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ - {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ - {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ - {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ - {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ - {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ - {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ - {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ - {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ - {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ - {0x45, 0x25, 83}, /* 0x6c 1280x800 */ - {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ - {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ - {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ - {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ - {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ -}; - int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); @@ -828,7 +166,7 @@ extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, u32 port, void sisusb_delete(struct kref *kref); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); -int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, +int sisusb_copy_memory(struct sisusb_usb_data *sisusb, u8 *src, u32 dest, int length); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, diff --git a/drivers/usb/misc/sisusbvga/sisusb_tables.h b/drivers/usb/misc/sisusbvga/sisusb_tables.h new file mode 100644 index 0000000000000000000000000000000000000000..56972f1ec2806945405661cbe86c076195ef3fb9 --- /dev/null +++ b/drivers/usb/misc/sisusbvga/sisusb_tables.h @@ -0,0 +1,688 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* $XFree86$ */ +/* $XdotOrg$ */ +/* + * Data tables for init.c + * + * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria + * + * If distributed as part of the Linux kernel, the following license terms + * apply: + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation; either version 2 of the named License, + * * or any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program; if not, write to the Free Software + * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * Otherwise, the following license terms apply: + * + * * Redistribution and use in source and binary forms, with or without + * * modification, are permitted provided that the following conditions + * * are met: + * * 1) Redistributions of source code must retain the above copyright + * * notice, this list of conditions and the following disclaimer. + * * 2) Redistributions in binary form must reproduce the above copyright + * * notice, this list of conditions and the following disclaimer in the + * * documentation and/or other materials provided with the distribution. + * * 3) The name of the author may not be used to endorse or promote products + * * derived from this software without specific prior written permission. + * * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Thomas Winischhofer <thomas@winischhofer.net> + * + */ + +#ifndef _SISUSB_TABLES_H_ +#define _SISUSB_TABLES_H_ + +static const unsigned char SiS_MDA_DAC[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F +}; + +static const unsigned char SiS_CGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F +}; + +static const unsigned char SiS_EGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, + 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, + 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, + 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, + 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, + 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, + 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F +}; + +static const unsigned char SiS_VGA_DAC[] = { + 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, + 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, + 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, + 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, + 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, + 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, + 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, + 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, + 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, + 0x0B, 0x0C, 0x0D, 0x0F, 0x10 +}; + +static const struct SiS_St SiSUSB_SModeIDTable[] = { + {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, + {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { + {320, 200, 8, 8}, /* 0x00 */ + {320, 240, 8, 8}, /* 0x01 */ + {320, 400, 8, 8}, /* 0x02 */ + {400, 300, 8, 8}, /* 0x03 */ + {512, 384, 8, 8}, /* 0x04 */ + {640, 400, 8, 16}, /* 0x05 */ + {640, 480, 8, 16}, /* 0x06 */ + {800, 600, 8, 16}, /* 0x07 */ + {1024, 768, 8, 16}, /* 0x08 */ + {1280, 1024, 8, 16}, /* 0x09 */ + {1600, 1200, 8, 16}, /* 0x0a */ + {1920, 1440, 8, 16}, /* 0x0b */ + {2048, 1536, 8, 16}, /* 0x0c */ + {720, 480, 8, 16}, /* 0x0d */ + {720, 576, 8, 16}, /* 0x0e */ + {1280, 960, 8, 16}, /* 0x0f */ + {800, 480, 8, 16}, /* 0x10 */ + {1024, 576, 8, 16}, /* 0x11 */ + {1280, 720, 8, 16}, /* 0x12 */ + {856, 480, 8, 16}, /* 0x13 */ + {1280, 768, 8, 16}, /* 0x14 */ + {1400, 1050, 8, 16}, /* 0x15 */ + {1152, 864, 8, 16}, /* 0x16 */ + {848, 480, 8, 16}, /* 0x17 */ + {1360, 768, 8, 16}, /* 0x18 */ + {1024, 600, 8, 16}, /* 0x19 */ + {1152, 768, 8, 16}, /* 0x1a */ + {768, 576, 8, 16}, /* 0x1b */ + {1360, 1024, 8, 16}, /* 0x1c */ + {1680, 1050, 8, 16}, /* 0x1d */ + {1280, 800, 8, 16}, /* 0x1e */ + {1920, 1080, 8, 16}, /* 0x1f */ + {960, 540, 8, 16}, /* 0x20 */ + {960, 600, 8, 16} /* 0x21 */ +}; + +static const struct SiS_StandTable SiSUSB_StandTable[] = { + /* MD_3_400 - mode 0x03 - 400 */ + { + 0x50, 0x18, 0x10, 0x1000, + {0x00, 0x03, 0x00, 0x02}, + 0x67, + {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x0c, 0x00, 0x0f, 0x08}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} + }, + /* Generic for VGA and higher */ + { + 0x00, 0x00, 0x00, 0x0000, + {0x01, 0x0f, 0x00, 0x0e}, + 0x23, + {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, + 0xff}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x01, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} + } +}; + +static const struct SiS_Ext SiSUSB_EModeIDTable[] = { + {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ + {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ + {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ + {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ + {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ + {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ + {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ + {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ + {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ + {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ + {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ + {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ + {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ + {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ + {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ + {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ + {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ + {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ + {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ + {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ + {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ + {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ + {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ + {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ + {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ + {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ + {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ + {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ + {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ + {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ + {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ + {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ + {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ + {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ + {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ + {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ + {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ + {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ + {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ + {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ + {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ + {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ + {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ + {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, + -1}, + {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ + {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, + -1}, + {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ + {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ + {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ + {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ + {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, + -1}, + {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ + {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, + -1}, + {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ + {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, + -1}, + {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ + {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, + -1}, + {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} +}; + +static const struct SiS_Ext2 SiSUSB_RefIndex[] = { + {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ + {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ + {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ + {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ + {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ + {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ + {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ + {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ + {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ + {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ + {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ + {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ + {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ + {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ + {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ + {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ + {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ + {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ + {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ + {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ + {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ + {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ + {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ + {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ + {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ + {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ + {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ + {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ + {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ + {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ + {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ + {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ + {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ + {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ + {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ + {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ + {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ + {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ + {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ + {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ + {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ + {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ + {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ + {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ + {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ + {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ + {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ + {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ + {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ + {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ + {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ + {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ + {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ + {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ + {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} +}; + +static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, + 0x00}}, /* 0x0 */ + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x1 */ + {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, + 0x01}}, /* 0x2 */ + {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, + 0x01}}, /* 0x3 */ + {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, + 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, + 0x00}}, /* 0x4 */ + {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, + 0x00}}, /* 0x5 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, + 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, + 0x00}}, /* 0x6 */ + {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, + 0x00}}, /* 0x7 */ + {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x00}}, /* 0x8 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, + 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, + 0x61}}, /* 0x9 */ + {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, + 0x61}}, /* 0xa */ + {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, + 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, + 0x61}}, /* 0xb */ + {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, + 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, + 0x00}}, /* 0xc */ + {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, + 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, + 0x01}}, /* 0xd */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, + 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, + 0x01}}, /* 0xe */ + {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, + 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, + 0x01}}, /* 0xf */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, + 0x01}}, /* 0x10 */ + {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, + 0x01}}, /* 0x11 */ + {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, + 0x61}}, /* 0x12 */ + {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, + 0x61}}, /* 0x13 */ + {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, + 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, + 0x61}}, /* 0x14 */ + {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, + 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, + 0x00}}, /* 0x15 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x16 */ + {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x17 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, + 0x01}}, /* 0x18 */ + {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, + 0x01}}, /* 0x19 */ + {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1a */ + {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, + 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, + 0x62}}, /* 0x1b */ + {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, + 0x00}}, /* 0x1c */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1d */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1e */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, + 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, + 0x01}}, /* 0x1f */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x20 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x21 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x22 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x23 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x24 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x25 */ + {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, + 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, + 0x00}}, /* 0x26 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x27 */ + {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x28 */ + {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, + 0x63}}, /* 0x29 */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2a */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2b */ + {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, + 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, + 0x00}}, /* 0x2c */ + {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2d */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2e */ + {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, + 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x2f */ + {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, + 0x44}}, /* 0x30 */ + {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, + 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, + 0x00}}, /* 0x31 */ + {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, + 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, + 0x01}}, /* 0x32 */ + {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, + 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, + 0x01}}, /* 0x33 */ + {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, + 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, + 0x01}}, /* 0x34 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, + 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, + 0x01}}, /* 0x35 */ + {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, + 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x36 */ + {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, + 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, + 0x01}}, /* 0x37 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x38 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, + 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, + 0x01}}, /* 0x39 */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, + 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, + 0x01}}, /* 0x3a */ + {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, + 0x01}}, /* 0x3b */ + {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, + 0x00}}, /* 0x3c */ + {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, /* 0x3d */ + {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, + 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, + 0x00}}, /* 0x3e */ + {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, + 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x3f */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, + 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, + 0x01}}, /* 0x40 */ + {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, + 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, + 0x01}}, /* 0x41 */ + {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, + 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, + 0x01}}, /* 0x42 */ + {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, + 0x00}}, /* 0x43 */ + {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, + 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, + 0x01}}, /* 0x44 */ + {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x45 */ + {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, + 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, + 0x00}}, /* 0x46 */ + {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, + 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, + 0x00}}, /* 0x47 */ + {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, + 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, + 0x00}}, /* 0x48 */ + {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, + 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, + 0x01}}, /* 0x49 */ + {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, + 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, + 0x01}}, /* 0x4a */ + {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, + 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, + 0x00}}, /* 0x4b */ + {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, + 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, + 0x01}}, /* 0x4c */ + {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, + 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, + 0x41}}, + {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, + 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, + 0x00}}, /* 0x4e */ + {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, + 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, + 0x21}}, /* 0x4f */ + {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, + 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, + 0x20}}, /* 0x50 */ + {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, + 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, + 0x61}}, /* 0x51 */ + {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, + 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, + 0x41}}, /* 0x52 */ + {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, + 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, + 0x01}}, /* 0x53 */ + {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, + 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, + 0x41}} /* 0x54 */ +}; + +static const struct SiS_VCLKData SiSUSB_VCLKData[] = { + {0x1b, 0xe1, 25}, /* 0x00 */ + {0x4e, 0xe4, 28}, /* 0x01 */ + {0x57, 0xe4, 31}, /* 0x02 */ + {0xc3, 0xc8, 36}, /* 0x03 */ + {0x42, 0xe2, 40}, /* 0x04 */ + {0xfe, 0xcd, 43}, /* 0x05 */ + {0x5d, 0xc4, 44}, /* 0x06 */ + {0x52, 0xe2, 49}, /* 0x07 */ + {0x53, 0xe2, 50}, /* 0x08 */ + {0x74, 0x67, 52}, /* 0x09 */ + {0x6d, 0x66, 56}, /* 0x0a */ + {0x5a, 0x64, 65}, /* 0x0b */ + {0x46, 0x44, 67}, /* 0x0c */ + {0xb1, 0x46, 68}, /* 0x0d */ + {0xd3, 0x4a, 72}, /* 0x0e */ + {0x29, 0x61, 75}, /* 0x0f */ + {0x6e, 0x46, 76}, /* 0x10 */ + {0x2b, 0x61, 78}, /* 0x11 */ + {0x31, 0x42, 79}, /* 0x12 */ + {0xab, 0x44, 83}, /* 0x13 */ + {0x46, 0x25, 84}, /* 0x14 */ + {0x78, 0x29, 86}, /* 0x15 */ + {0x62, 0x44, 94}, /* 0x16 */ + {0x2b, 0x41, 104}, /* 0x17 */ + {0x3a, 0x23, 105}, /* 0x18 */ + {0x70, 0x44, 108}, /* 0x19 */ + {0x3c, 0x23, 109}, /* 0x1a */ + {0x5e, 0x43, 113}, /* 0x1b */ + {0xbc, 0x44, 116}, /* 0x1c */ + {0xe0, 0x46, 132}, /* 0x1d */ + {0x54, 0x42, 135}, /* 0x1e */ + {0xea, 0x2a, 139}, /* 0x1f */ + {0x41, 0x22, 157}, /* 0x20 */ + {0x70, 0x24, 162}, /* 0x21 */ + {0x30, 0x21, 175}, /* 0x22 */ + {0x4e, 0x22, 189}, /* 0x23 */ + {0xde, 0x26, 194}, /* 0x24 */ + {0x62, 0x06, 202}, /* 0x25 */ + {0x3f, 0x03, 229}, /* 0x26 */ + {0xb8, 0x06, 234}, /* 0x27 */ + {0x34, 0x02, 253}, /* 0x28 */ + {0x58, 0x04, 255}, /* 0x29 */ + {0x24, 0x01, 265}, /* 0x2a */ + {0x9b, 0x02, 267}, /* 0x2b */ + {0x70, 0x05, 270}, /* 0x2c */ + {0x25, 0x01, 272}, /* 0x2d */ + {0x9c, 0x02, 277}, /* 0x2e */ + {0x27, 0x01, 286}, /* 0x2f */ + {0x3c, 0x02, 291}, /* 0x30 */ + {0xef, 0x0a, 292}, /* 0x31 */ + {0xf6, 0x0a, 310}, /* 0x32 */ + {0x95, 0x01, 315}, /* 0x33 */ + {0xf0, 0x09, 324}, /* 0x34 */ + {0xfe, 0x0a, 331}, /* 0x35 */ + {0xf3, 0x09, 332}, /* 0x36 */ + {0xea, 0x08, 340}, /* 0x37 */ + {0xe8, 0x07, 376}, /* 0x38 */ + {0xde, 0x06, 389}, /* 0x39 */ + {0x52, 0x2a, 54}, /* 0x3a 301 TV */ + {0x52, 0x6a, 27}, /* 0x3b 301 TV */ + {0x62, 0x24, 70}, /* 0x3c 301 TV */ + {0x62, 0x64, 70}, /* 0x3d 301 TV */ + {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ + {0x20, 0x26, 33}, /* 0x3f 301 TV */ + {0x31, 0xc2, 39}, /* 0x40 */ + {0x60, 0x36, 30}, /* 0x41 Chrontel */ + {0x40, 0x4a, 28}, /* 0x42 Chrontel */ + {0x9f, 0x46, 44}, /* 0x43 Chrontel */ + {0x97, 0x2c, 26}, /* 0x44 */ + {0x44, 0xe4, 25}, /* 0x45 Chrontel */ + {0x7e, 0x32, 47}, /* 0x46 Chrontel */ + {0x8a, 0x24, 31}, /* 0x47 Chrontel */ + {0x97, 0x2c, 26}, /* 0x48 Chrontel */ + {0xce, 0x3c, 39}, /* 0x49 */ + {0x52, 0x4a, 36}, /* 0x4a Chrontel */ + {0x34, 0x61, 95}, /* 0x4b */ + {0x78, 0x27, 108}, /* 0x4c - was 102 */ + {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ + {0x41, 0x4e, 21}, /* 0x4e */ + {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ + {0x19, 0x42, 42}, /* 0x50 */ + {0x54, 0x46, 58}, /* 0x51 Chrontel */ + {0x25, 0x42, 61}, /* 0x52 */ + {0x44, 0x44, 66}, /* 0x53 Chrontel */ + {0x3a, 0x62, 70}, /* 0x54 Chrontel */ + {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ + {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ + {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ + {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ + {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ + {0x45, 0x25, 83}, /* 0x5c 1280x800 */ + {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ + {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ + {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ + {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ + {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ + {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ + {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ + {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ + {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ + {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ + {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ + {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ + {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ + {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ + {0x45, 0x25, 83}, /* 0x6c 1280x800 */ + {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ + {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ + {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ + {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ + {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ +}; + +#endif diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index bae88893ee8e3111afe706ceddda7d9f92fe00e9..150090ee4ec1ab888b7c8c42e062780abfed37f4 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -182,7 +182,7 @@ get_endpoints(struct usbtest_dev *dev, struct usb_interface *intf) case USB_ENDPOINT_XFER_ISOC: if (dev->info->iso) endpoint_update(edi, &iso_in, &iso_out, e); - /* FALLTHROUGH */ + fallthrough; default: continue; } @@ -364,7 +364,7 @@ static void simple_fill_buf(struct urb *urb) switch (pattern) { default: - /* FALLTHROUGH */ + fallthrough; case 0: memset(buf, 0, len); break; @@ -681,7 +681,7 @@ static int get_altsetting(struct usbtest_dev *dev) return dev->buf[0]; case 0: retval = -ERANGE; - /* FALLTHROUGH */ + fallthrough; default: return retval; } @@ -1951,7 +1951,7 @@ static void complicated_callback(struct urb *urb) dev_err(&ctx->dev->intf->dev, "resubmit err %d\n", status); - /* FALLTHROUGH */ + fallthrough; case -ENODEV: /* disconnected */ case -ESHUTDOWN: /* endpoint disabled */ ctx->submit_error = 1; @@ -2043,7 +2043,7 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, unsigned i; unsigned long packets = 0; int status = 0; - struct urb *urbs[MAX_SGLEN]; + struct urb **urbs; if (!param->sglen || param->iterations > UINT_MAX / param->sglen) return -EINVAL; @@ -2051,6 +2051,10 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, if (param->sglen > MAX_SGLEN) return -EINVAL; + urbs = kcalloc(param->sglen, sizeof(*urbs), GFP_KERNEL); + if (!urbs) + return -ENOMEM; + memset(&context, 0, sizeof(context)); context.count = param->iterations * param->sglen; context.dev = dev; @@ -2137,6 +2141,8 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, else if (context.errors > (context.is_iso ? context.packet_count / 10 : 0)) status = -EIO; + + kfree(urbs); return status; fail: @@ -2144,6 +2150,8 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, if (urbs[i]) simple_free_urb(urbs[i]); } + + kfree(urbs); return status; } diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index be0505b8b5d4e5515996faf25ef7485e978c9248..6e7d34e7fec4338c479d570dd977e01f51049f17 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -472,7 +472,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, break; case CMD_SET: data++; - /* FALL THROUGH */ + fallthrough; case '0' ... '9': set = 1; c = c2 = simple_strtoull(data, NULL, 0); diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index d49db92ab26c44c5ab2c1671d31601f1c172efb7..71f4f02c05c6d919f5ea5a22a841131055d6d013 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -293,8 +293,6 @@ struct mtu3_ep { const struct usb_endpoint_descriptor *desc; int flags; - u8 wedged; - u8 busy; }; struct mtu3_request { @@ -348,7 +346,8 @@ struct mtu3 { struct usb_gadget_driver *gadget_driver; struct mtu3_request ep0_req; u8 setup_buf[EP0_RESPONSE_BUF]; - u32 max_speed; + enum usb_device_speed max_speed; + enum usb_device_speed speed; unsigned is_active:1; unsigned may_wakeup:1; @@ -433,6 +432,7 @@ void mtu3_ep0_setup(struct mtu3 *mtu); void mtu3_start(struct mtu3 *mtu); void mtu3_stop(struct mtu3 *mtu); void mtu3_dev_on_off(struct mtu3 *mtu, int is_on); +void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed); int mtu3_gadget_setup(struct mtu3 *mtu); void mtu3_gadget_cleanup(struct mtu3 *mtu); diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index 9dd02160cca97e9242aac125d104df80cd72e3e3..b3b4599375668aa862040b483b0b8be960ab8605 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -131,8 +131,12 @@ static void mtu3_device_disable(struct mtu3 *mtu) mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN); - if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) + if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) { mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); + if (mtu->is_u3_ip) + mtu3_clrbits(ibase, SSUSB_U3_CTRL(0), + SSUSB_U3_PORT_DUAL_MODE); + } mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); } @@ -147,17 +151,6 @@ static void mtu3_device_reset(struct mtu3 *mtu) mtu3_clrbits(ibase, U3D_SSUSB_DEV_RST_CTRL, SSUSB_DEV_SW_RST); } -/* disable all interrupts */ -static void mtu3_intr_disable(struct mtu3 *mtu) -{ - void __iomem *mbase = mtu->mac_base; - - /* Disable level 1 interrupts */ - mtu3_writel(mbase, U3D_LV1IECR, ~0x0); - /* Disable endpoint interrupts */ - mtu3_writel(mbase, U3D_EPIECR, ~0x0); -} - static void mtu3_intr_status_clear(struct mtu3 *mtu) { void __iomem *mbase = mtu->mac_base; @@ -170,6 +163,18 @@ static void mtu3_intr_status_clear(struct mtu3 *mtu) mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0); /* Clear speed change interrupt status */ mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0); + /* Clear QMU interrupt status */ + mtu3_writel(mbase, U3D_QISAR0, ~0x0); +} + +/* disable all interrupts */ +static void mtu3_intr_disable(struct mtu3 *mtu) +{ + /* Disable level 1 interrupts */ + mtu3_writel(mtu->mac_base, U3D_LV1IECR, ~0x0); + /* Disable endpoint interrupts */ + mtu3_writel(mtu->mac_base, U3D_EPIECR, ~0x0); + mtu3_intr_status_clear(mtu); } /* enable system global interrupt */ @@ -202,6 +207,69 @@ static void mtu3_intr_enable(struct mtu3 *mtu) mtu3_writel(mbase, U3D_DEV_LINK_INTR_ENABLE, SSUSB_DEV_SPEED_CHG_INTR); } +void mtu3_set_speed(struct mtu3 *mtu, enum usb_device_speed speed) +{ + void __iomem *mbase = mtu->mac_base; + + if (speed > mtu->max_speed) + speed = mtu->max_speed; + + switch (speed) { + case USB_SPEED_FULL: + /* disable U3 SS function */ + mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN); + /* disable HS function */ + mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); + break; + case USB_SPEED_HIGH: + mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN); + /* HS/FS detected by HW */ + mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); + break; + case USB_SPEED_SUPER: + mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0), + SSUSB_U3_PORT_SSP_SPEED); + break; + case USB_SPEED_SUPER_PLUS: + mtu3_setbits(mtu->ippc_base, SSUSB_U3_CTRL(0), + SSUSB_U3_PORT_SSP_SPEED); + break; + default: + dev_err(mtu->dev, "invalid speed: %s\n", + usb_speed_string(speed)); + return; + } + + mtu->speed = speed; + dev_dbg(mtu->dev, "set speed: %s\n", usb_speed_string(speed)); +} + +/* CSR registers will be reset to default value if port is disabled */ +static void mtu3_csr_init(struct mtu3 *mtu) +{ + void __iomem *mbase = mtu->mac_base; + + if (mtu->is_u3_ip) { + /* disable LGO_U1/U2 by default */ + mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL, + SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE); + /* enable accept LGO_U1/U2 link command from host */ + mtu3_setbits(mbase, U3D_LINK_POWER_CONTROL, + SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE); + /* device responses to u3_exit from host automatically */ + mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN); + /* automatically build U2 link when U3 detect fail */ + mtu3_setbits(mbase, U3D_USB2_TEST_MODE, U2U3_AUTO_SWITCH); + /* auto clear SOFT_CONN when clear USB3_EN if work as HS */ + mtu3_setbits(mbase, U3D_U3U2_SWITCH_CTRL, SOFTCON_CLR_AUTO_EN); + } + + /* delay about 0.1us from detecting reset to send chirp-K */ + mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK); + /* enable automatical HWRW from L1 */ + mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE); +} + /* reset: u2 - data toggle, u3 - SeqN, flow control status etc */ static void mtu3_ep_reset(struct mtu3_ep *mep) { @@ -249,13 +317,13 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set) void mtu3_dev_on_off(struct mtu3 *mtu, int is_on) { - if (mtu->is_u3_ip && mtu->max_speed >= USB_SPEED_SUPER) + if (mtu->is_u3_ip && mtu->speed >= USB_SPEED_SUPER) mtu3_ss_func_set(mtu, is_on); else mtu3_hs_softconn_set(mtu, is_on); dev_info(mtu->dev, "gadget (%s) pullup D%s\n", - usb_speed_string(mtu->max_speed), is_on ? "+" : "-"); + usb_speed_string(mtu->speed), is_on ? "+" : "-"); } void mtu3_start(struct mtu3 *mtu) @@ -267,13 +335,8 @@ void mtu3_start(struct mtu3 *mtu) mtu3_clrbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); - /* - * When disable U2 port, USB2_CSR's register will be reset to - * default value after re-enable it again(HS is enabled by default). - * So if force mac to work as FS, disable HS function. - */ - if (mtu->max_speed == USB_SPEED_FULL) - mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); + mtu3_csr_init(mtu); + mtu3_set_speed(mtu, mtu->speed); /* Initialize the default interrupts */ mtu3_intr_enable(mtu); @@ -288,7 +351,6 @@ void mtu3_stop(struct mtu3 *mtu) dev_dbg(mtu->dev, "%s\n", __func__); mtu3_intr_disable(mtu); - mtu3_intr_status_clear(mtu); if (mtu->softconnect) mtu3_dev_on_off(mtu, 0); @@ -545,66 +607,19 @@ static void mtu3_mem_free(struct mtu3 *mtu) kfree(mtu->ep_array); } -static void mtu3_set_speed(struct mtu3 *mtu) -{ - void __iomem *mbase = mtu->mac_base; - - if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH)) - mtu->max_speed = USB_SPEED_HIGH; - - if (mtu->max_speed == USB_SPEED_FULL) { - /* disable U3 SS function */ - mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN); - /* disable HS function */ - mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); - } else if (mtu->max_speed == USB_SPEED_HIGH) { - mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN); - /* HS/FS detected by HW */ - mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE); - } else if (mtu->max_speed == USB_SPEED_SUPER) { - mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0), - SSUSB_U3_PORT_SSP_SPEED); - } - - dev_info(mtu->dev, "max_speed: %s\n", - usb_speed_string(mtu->max_speed)); -} - static void mtu3_regs_init(struct mtu3 *mtu) { - void __iomem *mbase = mtu->mac_base; /* be sure interrupts are disabled before registration of ISR */ mtu3_intr_disable(mtu); - mtu3_intr_status_clear(mtu); - - if (mtu->is_u3_ip) { - /* disable LGO_U1/U2 by default */ - mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL, - SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE); - /* enable accept LGO_U1/U2 link command from host */ - mtu3_setbits(mbase, U3D_LINK_POWER_CONTROL, - SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE); - /* device responses to u3_exit from host automatically */ - mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN); - /* automatically build U2 link when U3 detect fail */ - mtu3_setbits(mbase, U3D_USB2_TEST_MODE, U2U3_AUTO_SWITCH); - /* auto clear SOFT_CONN when clear USB3_EN if work as HS */ - mtu3_setbits(mbase, U3D_U3U2_SWITCH_CTRL, SOFTCON_CLR_AUTO_EN); - } - mtu3_set_speed(mtu); + mtu3_csr_init(mtu); - /* delay about 0.1us from detecting reset to send chirp-K */ - mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK); /* U2/U3 detected by HW */ mtu3_writel(mbase, U3D_DEVICE_CONF, 0); /* vbus detected by HW */ mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON); - /* enable automatical HWRW from L1 */ - mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE); - /* use new QMU format when HW version >= 0x1003 */ if (mtu->gen2cp) mtu3_writel(mbase, U3D_QFCR, ~0x0); @@ -759,6 +774,34 @@ static irqreturn_t mtu3_irq(int irq, void *data) return IRQ_HANDLED; } +static void mtu3_check_params(struct mtu3 *mtu) +{ + /* check the max_speed parameter */ + switch (mtu->max_speed) { + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + case USB_SPEED_SUPER_PLUS: + break; + default: + dev_err(mtu->dev, "invalid max_speed: %s\n", + usb_speed_string(mtu->max_speed)); + fallthrough; + case USB_SPEED_UNKNOWN: + /* default as SSP */ + mtu->max_speed = USB_SPEED_SUPER_PLUS; + break; + } + + if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH)) + mtu->max_speed = USB_SPEED_HIGH; + + mtu->speed = mtu->max_speed; + + dev_info(mtu->dev, "max_speed: %s\n", + usb_speed_string(mtu->max_speed)); +} + static int mtu3_hw_init(struct mtu3 *mtu) { u32 value; @@ -774,6 +817,8 @@ static int mtu3_hw_init(struct mtu3 *mtu) dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version, mtu->is_u3_ip ? "U3" : "U2"); + mtu3_check_params(mtu); + mtu3_device_reset(mtu); ret = mtu3_device_enable(mtu); @@ -797,7 +842,7 @@ static void mtu3_hw_exit(struct mtu3 *mtu) mtu3_mem_free(mtu); } -/** +/* * we set 32-bit DMA mask by default, here check whether the controller * supports 36-bit DMA or not, if it does, set 36-bit DMA mask. */ @@ -828,7 +873,6 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) struct device *dev = ssusb->dev; struct platform_device *pdev = to_platform_device(dev); struct mtu3 *mtu = NULL; - struct resource *res; int ret = -ENOMEM; mtu = devm_kzalloc(dev, sizeof(struct mtu3), GFP_KERNEL); @@ -840,8 +884,7 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) return mtu->irq; dev_info(dev, "irq %d\n", mtu->irq); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac"); - mtu->mac_base = devm_ioremap_resource(dev, res); + mtu->mac_base = devm_platform_ioremap_resource_byname(pdev, "mac"); if (IS_ERR(mtu->mac_base)) { dev_err(dev, "error mapping memory for dev mac\n"); return PTR_ERR(mtu->mac_base); @@ -855,23 +898,6 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) mtu->ssusb = ssusb; mtu->max_speed = usb_get_maximum_speed(dev); - /* check the max_speed parameter */ - switch (mtu->max_speed) { - case USB_SPEED_FULL: - case USB_SPEED_HIGH: - case USB_SPEED_SUPER: - case USB_SPEED_SUPER_PLUS: - break; - default: - dev_err(dev, "invalid max_speed: %s\n", - usb_speed_string(mtu->max_speed)); - /* fall through */ - case USB_SPEED_UNKNOWN: - /* default as SSP */ - mtu->max_speed = USB_SPEED_SUPER_PLUS; - break; - } - dev_dbg(dev, "mac_base=0x%p, ippc_base=0x%p\n", mtu->mac_base, mtu->ippc_base); diff --git a/drivers/usb/mtu3/mtu3_debug.h b/drivers/usb/mtu3/mtu3_debug.h index fb6b28277c9b1fd65ea83f1a330c27c0c38c617d..3084c46017c37ef9ecc4600355ab358f77c03695 100644 --- a/drivers/usb/mtu3/mtu3_debug.h +++ b/drivers/usb/mtu3/mtu3_debug.h @@ -12,6 +12,8 @@ #include <linux/debugfs.h> +struct ssusb_mtk; + #define MTU3_DEBUGFS_NAME_LEN 32 struct mtu3_regset { diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index f93732e53fd890c72dbdaf70b7580ac0b5ce85e6..1de5c9a1d20a1b885601523d8c019f8de497b2fa 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -15,17 +15,12 @@ void mtu3_req_complete(struct mtu3_ep *mep, __releases(mep->mtu->lock) __acquires(mep->mtu->lock) { - struct mtu3_request *mreq; - struct mtu3 *mtu; - int busy = mep->busy; + struct mtu3_request *mreq = to_mtu3_request(req); + struct mtu3 *mtu = mreq->mtu; - mreq = to_mtu3_request(req); list_del(&mreq->list); - if (mreq->request.status == -EINPROGRESS) - mreq->request.status = status; - - mtu = mreq->mtu; - mep->busy = 1; + if (req->status == -EINPROGRESS) + req->status = status; trace_mtu3_req_complete(mreq); spin_unlock(&mtu->lock); @@ -34,20 +29,17 @@ __acquires(mep->mtu->lock) if (mep->epnum) usb_gadget_unmap_request(&mtu->g, req, mep->is_in); - dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n", mep->name, - req, req->status, mreq->request.actual, mreq->request.length); - - usb_gadget_giveback_request(&mep->ep, &mreq->request); + dev_dbg(mtu->dev, "%s complete req: %p, sts %d, %d/%d\n", + mep->name, req, req->status, req->actual, req->length); + usb_gadget_giveback_request(&mep->ep, req); spin_lock(&mtu->lock); - mep->busy = busy; } static void nuke(struct mtu3_ep *mep, const int status) { struct mtu3_request *mreq = NULL; - mep->busy = 1; if (list_empty(&mep->req_list)) return; @@ -195,9 +187,7 @@ static int mtu3_gadget_ep_enable(struct usb_ep *ep, if (ret) goto error; - mep->busy = 0; - mep->wedged = 0; - mep->flags |= MTU3_EP_ENABLED; + mep->flags = MTU3_EP_ENABLED; mtu->active_ep++; error: @@ -225,7 +215,7 @@ static int mtu3_gadget_ep_disable(struct usb_ep *ep) spin_lock_irqsave(&mtu->lock, flags); mtu3_ep_disable(mep); - mep->flags &= ~MTU3_EP_ENABLED; + mep->flags = 0; mtu->active_ep--; spin_unlock_irqrestore(&(mtu->lock), flags); @@ -263,23 +253,15 @@ void mtu3_free_request(struct usb_ep *ep, struct usb_request *req) static int mtu3_gadget_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { - struct mtu3_ep *mep; - struct mtu3_request *mreq; - struct mtu3 *mtu; + struct mtu3_ep *mep = to_mtu3_ep(ep); + struct mtu3_request *mreq = to_mtu3_request(req); + struct mtu3 *mtu = mep->mtu; unsigned long flags; int ret = 0; - if (!ep || !req) - return -EINVAL; - if (!req->buf) return -ENODATA; - mep = to_mtu3_ep(ep); - mtu = mep->mtu; - mreq = to_mtu3_request(req); - mreq->mtu = mtu; - if (mreq->mep != mep) return -EINVAL; @@ -303,6 +285,7 @@ static int mtu3_gadget_queue(struct usb_ep *ep, return -ESHUTDOWN; } + mreq->mtu = mtu; mreq->request.actual = 0; mreq->request.status = -EINPROGRESS; @@ -335,11 +318,11 @@ static int mtu3_gadget_dequeue(struct usb_ep *ep, struct usb_request *req) struct mtu3_ep *mep = to_mtu3_ep(ep); struct mtu3_request *mreq = to_mtu3_request(req); struct mtu3_request *r; + struct mtu3 *mtu = mep->mtu; unsigned long flags; int ret = 0; - struct mtu3 *mtu = mep->mtu; - if (!ep || !req || mreq->mep != mep) + if (mreq->mep != mep) return -EINVAL; dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req); @@ -379,9 +362,6 @@ static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value) unsigned long flags; int ret = 0; - if (!ep) - return -EINVAL; - dev_dbg(mtu->dev, "%s : %s...", __func__, ep->name); spin_lock_irqsave(&mtu->lock, flags); @@ -405,7 +385,7 @@ static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value) goto done; } } else { - mep->wedged = 0; + mep->flags &= ~MTU3_EP_WEDGE; } dev_dbg(mtu->dev, "%s %s stall\n", ep->name, value ? "set" : "clear"); @@ -424,10 +404,7 @@ static int mtu3_gadget_ep_set_wedge(struct usb_ep *ep) { struct mtu3_ep *mep = to_mtu3_ep(ep); - if (!ep) - return -EINVAL; - - mep->wedged = 1; + mep->flags |= MTU3_EP_WEDGE; return usb_ep_set_halt(ep); } @@ -590,6 +567,19 @@ static int mtu3_gadget_stop(struct usb_gadget *g) return 0; } +static void +mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed) +{ + struct mtu3 *mtu = gadget_to_mtu3(g); + unsigned long flags; + + dev_dbg(mtu->dev, "%s %s\n", __func__, usb_speed_string(speed)); + + spin_lock_irqsave(&mtu->lock, flags); + mtu3_set_speed(mtu, speed); + spin_unlock_irqrestore(&mtu->lock, flags); +} + static const struct usb_gadget_ops mtu3_gadget_ops = { .get_frame = mtu3_gadget_get_frame, .wakeup = mtu3_gadget_wakeup, @@ -597,6 +587,7 @@ static const struct usb_gadget_ops mtu3_gadget_ops = { .pullup = mtu3_gadget_pullup, .udc_start = mtu3_gadget_start, .udc_stop = mtu3_gadget_stop, + .udc_set_speed = mtu3_gadget_set_speed, }; static void mtu3_state_reset(struct mtu3 *mtu) @@ -672,8 +663,6 @@ static void mtu3_gadget_init_eps(struct mtu3 *mtu) int mtu3_gadget_setup(struct mtu3 *mtu) { - int ret; - mtu->g.ops = &mtu3_gadget_ops; mtu->g.max_speed = mtu->max_speed; mtu->g.speed = USB_SPEED_UNKNOWN; @@ -684,11 +673,7 @@ int mtu3_gadget_setup(struct mtu3 *mtu) mtu3_gadget_init_eps(mtu); - ret = usb_add_gadget_udc(mtu->dev, &mtu->g); - if (ret) - dev_err(mtu->dev, "failed to register udc\n"); - - return ret; + return usb_add_gadget_udc(mtu->dev, &mtu->g); } void mtu3_gadget_cleanup(struct mtu3 *mtu) diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 2be182bd793a9f025dba76f6cfc44e5dfea89b5b..0ca47212f1ec1825d4e1fe5a57deebfce55f7e4c 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -278,20 +278,20 @@ static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup) u32 value; switch (le16_to_cpu(setup->wIndex) >> 8) { - case TEST_J: - dev_dbg(mtu->dev, "TEST_J\n"); + case USB_TEST_J: + dev_dbg(mtu->dev, "USB_TEST_J\n"); mtu->test_mode_nr = TEST_J_MODE; break; - case TEST_K: - dev_dbg(mtu->dev, "TEST_K\n"); + case USB_TEST_K: + dev_dbg(mtu->dev, "USB_TEST_K\n"); mtu->test_mode_nr = TEST_K_MODE; break; - case TEST_SE0_NAK: - dev_dbg(mtu->dev, "TEST_SE0_NAK\n"); + case USB_TEST_SE0_NAK: + dev_dbg(mtu->dev, "USB_TEST_SE0_NAK\n"); mtu->test_mode_nr = TEST_SE0_NAK_MODE; break; - case TEST_PACKET: - dev_dbg(mtu->dev, "TEST_PACKET\n"); + case USB_TEST_PACKET: + dev_dbg(mtu->dev, "USB_TEST_PACKET\n"); mtu->test_mode_nr = TEST_PACKET_MODE; break; default: @@ -417,7 +417,7 @@ static int ep0_handle_feature(struct mtu3 *mtu, handled = 1; /* ignore request if endpoint is wedged */ - if (mep->wedged) + if (mep->flags & MTU3_EP_WEDGE) break; mtu3_ep_stall_set(mep, set); diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index bf34f784f84bba18fd5349a10a5101ccd77ab188..072db1f6470ef9a38361ec03773b55ff050e0bb1 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h @@ -134,7 +134,7 @@ #define TX_W1C_BITS (~(TX_SENTSTALL)) /* U3D_TX1CSR1 */ -#define TX_MAX_PKT_G2(x) (((x) & 0x7f) << 24) +#define TX_MAX_PKT_G2(x) (((x) & 0xff) << 24) #define TX_MULT_G2(x) (((x) & 0x7) << 21) #define TX_MULT_OG(x) (((x) & 0x3) << 22) #define TX_MAX_PKT_OG(x) (((x) & 0x3f) << 16) @@ -173,7 +173,7 @@ #define RX_W1C_BITS (~(RX_SENTSTALL | RX_RXPKTRDY)) /* U3D_RX1CSR1 */ -#define RX_MAX_PKT_G2(x) (((x) & 0x7f) << 24) +#define RX_MAX_PKT_G2(x) (((x) & 0xff) << 24) #define RX_MULT_G2(x) (((x) & 0x7) << 21) #define RX_MULT_OG(x) (((x) & 0x3) << 22) #define RX_MAX_PKT_OG(x) (((x) & 0x3f) << 16) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 9c256ea3cdf5c10a7f433d34aae4766a43cf175e..d44d5417438dc15db796ae545d24213c9611b05c 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -216,7 +216,6 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) struct device_node *node = pdev->dev.of_node; struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; struct device *dev = &pdev->dev; - struct resource *res; int i; int ret; @@ -263,8 +262,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) } } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ippc"); - ssusb->ippc_base = devm_ioremap_resource(dev, res); + ssusb->ippc_base = devm_platform_ioremap_resource_byname(pdev, "ippc"); if (IS_ERR(ssusb->ippc_base)) return PTR_ERR(ssusb->ippc_base); diff --git a/drivers/usb/mtu3/mtu3_trace.c b/drivers/usb/mtu3/mtu3_trace.c index 4f5e7857ec312f43d8e1da562fbb4e9e52dba538..d17ddb87cdcf2ac71f35ab5e5b3e174ca3485d0f 100644 --- a/drivers/usb/mtu3/mtu3_trace.c +++ b/drivers/usb/mtu3/mtu3_trace.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * mtu3_trace.c - trace support * * Copyright (C) 2019 MediaTek Inc. @@ -8,6 +8,7 @@ */ #define CREATE_TRACE_POINTS +#include "mtu3_debug.h" #include "mtu3_trace.h" void mtu3_dbg_trace(struct device *dev, const char *fmt, ...) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 3b0d1c20ebe67bf737e23882e4127906fc6c9515..8de143807c1aec12692923da04c455f3e99d953a 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -113,7 +113,7 @@ config USB_MUSB_JZ4740 depends on OF depends on MIPS || COMPILE_TEST depends on USB_MUSB_GADGET - depends on USB=n || USB_OTG_BLACKLIST_HUB + depends on USB=n || USB_OTG_DISABLE_EXTERNAL_HUB select USB_ROLE_SWITCH config USB_MUSB_MEDIATEK diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 384a8039a7fd5d59aeeb4c5ae0466ab6626d2329..5a56a03996b1df9d68d3a1b5d59492256e8b52a9 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1637,8 +1637,8 @@ static int musb_core_init(u16 musb_type, struct musb *musb) musb->is_multipoint = 0; type = ""; if (IS_ENABLED(CONFIG_USB) && - !IS_ENABLED(CONFIG_USB_OTG_BLACKLIST_HUB)) { - pr_err("%s: kernel must blacklist external hubs\n", + !IS_ENABLED(CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB)) { + pr_err("%s: kernel must disable external hubs, please fix the configuration\n", musb_driver_name); } } diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 88923175f71e58b5c03d66cb43e04ffe9cb74671..19556c1a8ae878b8f49a2bf6f972dc343420bb2e 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -36,7 +36,7 @@ static const struct of_device_id musb_dsps_of_match[]; -/** +/* * DSPS musb wrapper register offset. * FIXME: This should be expanded to have all the wrapper registers from TI DSPS * musb ips. @@ -96,7 +96,7 @@ struct dsps_context { u32 rx_mode; }; -/** +/* * DSPS glue structure. */ struct dsps_glue { @@ -162,7 +162,7 @@ static void dsps_mod_timer_optional(struct dsps_glue *glue) #define USBSS_IRQ_PD_COMP (1 << 2) -/** +/* * dsps_musb_enable - enable interrupts */ static void dsps_musb_enable(struct musb *musb) @@ -188,7 +188,7 @@ static void dsps_musb_enable(struct musb *musb) dsps_mod_timer(glue, -1); } -/** +/* * dsps_musb_disable - disable HDRC and flush interrupts */ static void dsps_musb_disable(struct musb *musb) @@ -429,12 +429,10 @@ static int dsps_musb_init(struct musb *musb) struct platform_device *parent = to_platform_device(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base; - struct resource *r; u32 rev, val; int ret; - r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); - reg_base = devm_ioremap_resource(dev, r); + reg_base = devm_platform_ioremap_resource_byname(parent, "control"); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); musb->ctrl_base = reg_base; diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 91a5027b5c1f97d522c7beed568f2ac39e74ea86..0ae3e0be043ed2496f8000b3de4d33e7441fcefb 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -311,27 +311,23 @@ __acquires(musb->lock) goto stall; switch (ctrlrequest->wIndex >> 8) { - case 1: - pr_debug("TEST_J\n"); - /* TEST_J */ + case USB_TEST_J: + pr_debug("USB_TEST_J\n"); musb->test_mode_nr = MUSB_TEST_J; break; - case 2: - /* TEST_K */ - pr_debug("TEST_K\n"); + case USB_TEST_K: + pr_debug("USB_TEST_K\n"); musb->test_mode_nr = MUSB_TEST_K; break; - case 3: - /* TEST_SE0_NAK */ - pr_debug("TEST_SE0_NAK\n"); + case USB_TEST_SE0_NAK: + pr_debug("USB_TEST_SE0_NAK\n"); musb->test_mode_nr = MUSB_TEST_SE0_NAK; break; - case 4: - /* TEST_PACKET */ - pr_debug("TEST_PACKET\n"); + case USB_TEST_PACKET: + pr_debug("USB_TEST_PACKET\n"); musb->test_mode_nr = MUSB_TEST_PACKET; break; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 32336571f05cff8c80265d7d21097ec7fa7aa4d3..4804d4d85c1540110e0ac201870683465590f9fc 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -97,7 +97,6 @@ static inline void musb_host_tx(struct musb *musb, u8 epnum) {} static inline void musb_host_rx(struct musb *musb, u8 epnum) {} static inline void musb_root_disconnect(struct musb *musb) {} static inline void musb_host_resume_root_hub(struct musb *musb) {} -static inline void musb_host_poll_rh_status(struct musb *musb) {} static inline void musb_host_poke_root_hub(struct musb *musb) {} static inline int musb_port_suspend(struct musb *musb, bool do_suspend) { diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index a84ec27c4c128ba8cf78660f1e88ef8a5c02f57a..cb7ae297a3af009376c7b45357fc8ad0750e38f2 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -385,25 +385,25 @@ int musb_hub_control( wIndex >>= 8; switch (wIndex) { - case 1: - pr_debug("TEST_J\n"); + case USB_TEST_J: + pr_debug("USB_TEST_J\n"); temp = MUSB_TEST_J; break; - case 2: - pr_debug("TEST_K\n"); + case USB_TEST_K: + pr_debug("USB_TEST_K\n"); temp = MUSB_TEST_K; break; - case 3: - pr_debug("TEST_SE0_NAK\n"); + case USB_TEST_SE0_NAK: + pr_debug("USB_TEST_SE0_NAK\n"); temp = MUSB_TEST_SE0_NAK; break; - case 4: - pr_debug("TEST_PACKET\n"); + case USB_TEST_PACKET: + pr_debug("USB_TEST_PACKET\n"); temp = MUSB_TEST_PACKET; musb_load_testpacket(musb); break; - case 5: - pr_debug("TEST_FORCE_ENABLE\n"); + case USB_TEST_FORCE_ENABLE: + pr_debug("USB_TEST_FORCE_ENABLE\n"); temp = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS; diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 4b3fa78995cf2ff189b64458d9243e8181800076..ef4787cd3d37b80b6f88cb7f70b943d7d968b7d7 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -185,11 +185,11 @@ config USB_ULPI_VIEWPORT controllers with a viewport register (e.g. Chipidea/ARC controllers). config JZ4770_PHY - tristate "Ingenic JZ4770 Transceiver Driver" + tristate "Ingenic SoCs Transceiver Driver" depends on MIPS || COMPILE_TEST select USB_PHY help This driver provides PHY support for the USB controller found - on the JZ4770 SoC from Ingenic. + on the JZ-series and X-series SoCs from Ingenic. endmenu diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 20c0f082bf9c07a8ff7665a5d2abef03d0e70221..aa4a3140394b760a38e04fce2109fdc0d3b5ad26 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -331,7 +331,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab, switch (lsts) { case USB_LINK_ACA_RID_B_8505: event = UX500_MUSB_RIDB; - /* Fall through */ + fallthrough; case USB_LINK_NOT_CONFIGURED_8505: case USB_LINK_RESERVED0_8505: case USB_LINK_RESERVED1_8505: @@ -352,7 +352,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab, case USB_LINK_ACA_RID_C_NM_8505: event = UX500_MUSB_RIDC; - /* Fall through */ + fallthrough; case USB_LINK_STD_HOST_NC_8505: case USB_LINK_STD_HOST_C_NS_8505: case USB_LINK_STD_HOST_C_S_8505: @@ -371,7 +371,7 @@ static int ab8505_usb_link_status_update(struct ab8500_usb *ab, case USB_LINK_ACA_RID_A_8505: case USB_LINK_ACA_DOCK_CHGR_8505: event = UX500_MUSB_RIDA; - /* Fall through */ + fallthrough; case USB_LINK_HM_IDGND_8505: if (ab->mode == USB_IDLE) { ab->mode = USB_HOST; @@ -444,7 +444,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, switch (lsts) { case USB_LINK_ACA_RID_B_8500: event = UX500_MUSB_RIDB; - /* Fall through */ + fallthrough; case USB_LINK_NOT_CONFIGURED_8500: case USB_LINK_NOT_VALID_LINK_8500: ab->mode = USB_IDLE; @@ -461,7 +461,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, case USB_LINK_ACA_RID_C_HS_8500: case USB_LINK_ACA_RID_C_HS_CHIRP_8500: event = UX500_MUSB_RIDC; - /* Fall through */ + fallthrough; case USB_LINK_STD_HOST_NC_8500: case USB_LINK_STD_HOST_C_NS_8500: case USB_LINK_STD_HOST_C_S_8500: @@ -481,7 +481,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab, case USB_LINK_ACA_RID_A_8500: event = UX500_MUSB_RIDA; - /* Fall through */ + fallthrough; case USB_LINK_HM_IDGND_8500: if (ab->mode == USB_IDLE) { ab->mode = USB_HOST; diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index d16dfc320faa8930a97d6feb285f9b2431264378..97e6603c7149527a93cc3ddbc0287e6a7f3d0016 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -149,7 +149,6 @@ EXPORT_SYMBOL_GPL(am335x_get_phy_control); static int am335x_control_usb_probe(struct platform_device *pdev) { - struct resource *res; struct am335x_control_usb *ctrl_usb; const struct of_device_id *of_id; const struct phy_control *phy_ctrl; @@ -166,13 +165,11 @@ static int am335x_control_usb_probe(struct platform_device *pdev) ctrl_usb->dev = &pdev->dev; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); - ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res); + ctrl_usb->phy_reg = devm_platform_ioremap_resource_byname(pdev, "phy_ctrl"); if (IS_ERR(ctrl_usb->phy_reg)) return PTR_ERR(ctrl_usb->phy_reg); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wakeup"); - ctrl_usb->wkup = devm_ioremap_resource(&pdev->dev, res); + ctrl_usb->wkup = devm_platform_ioremap_resource_byname(pdev, "wakeup"); if (IS_ERR(ctrl_usb->wkup)) return PTR_ERR(ctrl_usb->wkup); diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index b451f4695f3f07d5c9f649edc1fb9ab6a093ed53..f34c9437a182cce14d3c81a89ef2c9bad9ee593a 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -911,10 +911,10 @@ int usb_otg_start(struct platform_device *pdev) break; case FSL_USB2_PHY_UTMI_WIDE: temp |= PORTSC_PTW_16BIT; - /* fall through */ + fallthrough; case FSL_USB2_PHY_UTMI: temp |= PORTSC_PTS_UTMI; - /* fall through */ + fallthrough; default: break; } @@ -957,159 +957,6 @@ int usb_otg_start(struct platform_device *pdev) return 0; } -/* - * state file in sysfs - */ -static ssize_t show_fsl_usb2_otg_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct otg_fsm *fsm = &fsl_otg_dev->fsm; - char *next = buf; - unsigned size = PAGE_SIZE; - int t; - - mutex_lock(&fsm->lock); - - /* basic driver infomation */ - t = scnprintf(next, size, - DRIVER_DESC "\n" "fsl_usb2_otg version: %s\n\n", - DRIVER_VERSION); - size -= t; - next += t; - - /* Registers */ - t = scnprintf(next, size, - "OTGSC: 0x%08x\n" - "PORTSC: 0x%08x\n" - "USBMODE: 0x%08x\n" - "USBCMD: 0x%08x\n" - "USBSTS: 0x%08x\n" - "USBINTR: 0x%08x\n", - fsl_readl(&usb_dr_regs->otgsc), - fsl_readl(&usb_dr_regs->portsc), - fsl_readl(&usb_dr_regs->usbmode), - fsl_readl(&usb_dr_regs->usbcmd), - fsl_readl(&usb_dr_regs->usbsts), - fsl_readl(&usb_dr_regs->usbintr)); - size -= t; - next += t; - - /* State */ - t = scnprintf(next, size, - "OTG state: %s\n\n", - usb_otg_state_string(fsl_otg_dev->phy.otg->state)); - size -= t; - next += t; - - /* State Machine Variables */ - t = scnprintf(next, size, - "a_bus_req: %d\n" - "b_bus_req: %d\n" - "a_bus_resume: %d\n" - "a_bus_suspend: %d\n" - "a_conn: %d\n" - "a_sess_vld: %d\n" - "a_srp_det: %d\n" - "a_vbus_vld: %d\n" - "b_bus_resume: %d\n" - "b_bus_suspend: %d\n" - "b_conn: %d\n" - "b_se0_srp: %d\n" - "b_ssend_srp: %d\n" - "b_sess_vld: %d\n" - "id: %d\n", - fsm->a_bus_req, - fsm->b_bus_req, - fsm->a_bus_resume, - fsm->a_bus_suspend, - fsm->a_conn, - fsm->a_sess_vld, - fsm->a_srp_det, - fsm->a_vbus_vld, - fsm->b_bus_resume, - fsm->b_bus_suspend, - fsm->b_conn, - fsm->b_se0_srp, - fsm->b_ssend_srp, - fsm->b_sess_vld, - fsm->id); - size -= t; - next += t; - - mutex_unlock(&fsm->lock); - - return PAGE_SIZE - size; -} - -static DEVICE_ATTR(fsl_usb2_otg_state, S_IRUGO, show_fsl_usb2_otg_state, NULL); - -static struct attribute *fsl_otg_attrs[] = { - &dev_attr_fsl_usb2_otg_state.attr, - NULL, -}; -ATTRIBUTE_GROUPS(fsl_otg); - -/* Char driver interface to control some OTG input */ - -/* - * Handle some ioctl command, such as get otg - * status and set host suspend - */ -static long fsl_otg_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - u32 retval = 0; - - switch (cmd) { - case GET_OTG_STATUS: - retval = fsl_otg_dev->host_working; - break; - - case SET_A_SUSPEND_REQ: - fsl_otg_dev->fsm.a_suspend_req_inf = arg; - break; - - case SET_A_BUS_DROP: - fsl_otg_dev->fsm.a_bus_drop = arg; - break; - - case SET_A_BUS_REQ: - fsl_otg_dev->fsm.a_bus_req = arg; - break; - - case SET_B_BUS_REQ: - fsl_otg_dev->fsm.b_bus_req = arg; - break; - - default: - break; - } - - otg_statemachine(&fsl_otg_dev->fsm); - - return retval; -} - -static int fsl_otg_open(struct inode *inode, struct file *file) -{ - return 0; -} - -static int fsl_otg_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static const struct file_operations otg_fops = { - .owner = THIS_MODULE, - .llseek = NULL, - .read = NULL, - .write = NULL, - .unlocked_ioctl = fsl_otg_ioctl, - .open = fsl_otg_open, - .release = fsl_otg_release, -}; - static int fsl_otg_probe(struct platform_device *pdev) { int ret; @@ -1131,12 +978,6 @@ static int fsl_otg_probe(struct platform_device *pdev) return ret; } - ret = register_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME, &otg_fops); - if (ret) { - dev_err(&pdev->dev, "unable to register FSL OTG device\n"); - return ret; - } - return ret; } @@ -1153,8 +994,6 @@ static int fsl_otg_remove(struct platform_device *pdev) kfree(fsl_otg_dev->phy.otg); kfree(fsl_otg_dev); - unregister_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME); - if (pdata->exit) pdata->exit(pdev); @@ -1167,7 +1006,6 @@ struct platform_driver fsl_otg_driver = { .driver = { .name = driver_name, .owner = THIS_MODULE, - .dev_groups = fsl_otg_groups, }, }; diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h index fbcc28ad9964979e7e856cedf1b9b4aea95d4059..d70341ae5a926b54fd883cf184946f138bdbb489 100644 --- a/drivers/usb/phy/phy-fsl-usb.h +++ b/drivers/usb/phy/phy-fsl-usb.h @@ -371,21 +371,7 @@ struct fsl_otg_config { u8 otg_port; }; -/* For SRP and HNP handle */ -#define FSL_OTG_MAJOR 240 #define FSL_OTG_NAME "fsl-usb2-otg" -/* Command to OTG driver ioctl */ -#define OTG_IOCTL_MAGIC FSL_OTG_MAJOR -/* if otg work as host, it should return 1, otherwise return 0 */ -#define GET_OTG_STATUS _IOR(OTG_IOCTL_MAGIC, 1, int) -#define SET_A_SUSPEND_REQ _IOW(OTG_IOCTL_MAGIC, 2, int) -#define SET_A_BUS_DROP _IOW(OTG_IOCTL_MAGIC, 3, int) -#define SET_A_BUS_REQ _IOW(OTG_IOCTL_MAGIC, 4, int) -#define SET_B_BUS_REQ _IOW(OTG_IOCTL_MAGIC, 5, int) -#define GET_A_SUSPEND_REQ _IOR(OTG_IOCTL_MAGIC, 6, int) -#define GET_A_BUS_DROP _IOR(OTG_IOCTL_MAGIC, 7, int) -#define GET_A_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 8, int) -#define GET_B_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 9, int) void fsl_otg_add_timer(struct otg_fsm *fsm, void *timer); void fsl_otg_del_timer(struct otg_fsm *fsm, void *timer); diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 7041ba030052c47c30f4baa46424b56eb66a2d17..4a6462c92ef2c39c7a1485c7a67d08e52fd78cc3 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -581,11 +581,11 @@ static void otg_update_isp(struct isp1301 *isp) /* HNP failed for some reason (A_AIDL_BDIS timeout) */ notresponding(isp); - /* FALLTHROUGH */ + fallthrough; case OTG_STATE_A_VBUS_ERR: isp->phy.otg->state = OTG_STATE_A_WAIT_VFALL; pr_debug(" --> a_wait_vfall\n"); - /* FALLTHROUGH */ + fallthrough; case OTG_STATE_A_WAIT_VFALL: /* FIXME usbcore thinks port power is still on ... */ clr |= OTG1_VBUS_DRV; @@ -595,7 +595,7 @@ static void otg_update_isp(struct isp1301 *isp) isp->phy.otg->state = OTG_STATE_A_WAIT_VRISE; pr_debug(" --> a_wait_vrise\n"); } - /* FALLTHROUGH */ + fallthrough; default: toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV); } @@ -945,10 +945,10 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) switch (state) { case OTG_STATE_B_IDLE: a_idle(isp, "idle"); - /* FALLTHROUGH */ + fallthrough; case OTG_STATE_A_IDLE: enable_vbus_source(isp); - /* FALLTHROUGH */ + fallthrough; case OTG_STATE_A_WAIT_VRISE: /* we skip over OTG_STATE_A_WAIT_BCON, since * the HC will transition to A_HOST (or @@ -1032,12 +1032,12 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) OTG1_DP_PULLUP); dump_regs(isp, __func__); #endif - /* FALLTHROUGH */ + fallthrough; case OTG_STATE_B_SRP_INIT: b_idle(isp, __func__); l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; omap_writel(l, OTG_CTRL); - /* FALLTHROUGH */ + fallthrough; case OTG_STATE_B_IDLE: if (otg->gadget && (isp_bstat & OTG_B_SESS_VLD)) { #ifdef CONFIG_USB_OTG diff --git a/drivers/usb/phy/phy-jz4770.c b/drivers/usb/phy/phy-jz4770.c index 8f62dc2a90ff9ef8d9579a4af2779cba75ab8c74..d4ee3cb721ea8cac0352d0aab0342fa9a7190460 100644 --- a/drivers/usb/phy/phy-jz4770.c +++ b/drivers/usb/phy/phy-jz4770.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Ingenic JZ4770 USB PHY driver + * Ingenic SoCs USB PHY driver * Copyright (c) Paul Cercueil <paul@crapouillou.net> + * Copyright (c) æ¼†é¹æŒ¯ (Qi Pengzhen) <aric.pzqi@ingenic.com> + * Copyright (c) å‘¨ç°æ° (Zhou Yanjie) <zhouyanjie@wanyeetech.com> */ #include <linux/clk.h> @@ -12,66 +14,95 @@ #include <linux/usb/otg.h> #include <linux/usb/phy.h> -#define REG_USBPCR_OFFSET 0x00 -#define REG_USBRDT_OFFSET 0x04 -#define REG_USBVBFIL_OFFSET 0x08 -#define REG_USBPCR1_OFFSET 0x0c - -/* USBPCR */ -#define USBPCR_USB_MODE BIT(31) -#define USBPCR_AVLD_REG BIT(30) -#define USBPCR_INCRM BIT(27) -#define USBPCR_CLK12_EN BIT(26) -#define USBPCR_COMMONONN BIT(25) -#define USBPCR_VBUSVLDEXT BIT(24) -#define USBPCR_VBUSVLDEXTSEL BIT(23) -#define USBPCR_POR BIT(22) -#define USBPCR_SIDDQ BIT(21) -#define USBPCR_OTG_DISABLE BIT(20) -#define USBPCR_TXPREEMPHTUNE BIT(6) +/* OTGPHY register offsets */ +#define REG_USBPCR_OFFSET 0x00 +#define REG_USBRDT_OFFSET 0x04 +#define REG_USBVBFIL_OFFSET 0x08 +#define REG_USBPCR1_OFFSET 0x0c + +/* bits within the USBPCR register */ +#define USBPCR_USB_MODE BIT(31) +#define USBPCR_AVLD_REG BIT(30) +#define USBPCR_COMMONONN BIT(25) +#define USBPCR_VBUSVLDEXT BIT(24) +#define USBPCR_VBUSVLDEXTSEL BIT(23) +#define USBPCR_POR BIT(22) +#define USBPCR_SIDDQ BIT(21) +#define USBPCR_OTG_DISABLE BIT(20) +#define USBPCR_TXPREEMPHTUNE BIT(6) #define USBPCR_IDPULLUP_LSB 28 -#define USBPCR_IDPULLUP_MASK GENMASK(29, USBPCR_IDPULLUP_LSB) -#define USBPCR_IDPULLUP_ALWAYS (3 << USBPCR_IDPULLUP_LSB) -#define USBPCR_IDPULLUP_SUSPEND (1 << USBPCR_IDPULLUP_LSB) -#define USBPCR_IDPULLUP_OTG (0 << USBPCR_IDPULLUP_LSB) +#define USBPCR_IDPULLUP_MASK GENMASK(29, USBPCR_IDPULLUP_LSB) +#define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_LSB) +#define USBPCR_IDPULLUP_SUSPEND (0x1 << USBPCR_IDPULLUP_LSB) +#define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_LSB) -#define USBPCR_COMPDISTUNE_LSB 17 -#define USBPCR_COMPDISTUNE_MASK GENMASK(19, USBPCR_COMPDISTUNE_LSB) -#define USBPCR_COMPDISTUNE_DFT 4 +#define USBPCR_COMPDISTUNE_LSB 17 +#define USBPCR_COMPDISTUNE_MASK GENMASK(19, USBPCR_COMPDISTUNE_LSB) +#define USBPCR_COMPDISTUNE_DFT (0x4 << USBPCR_COMPDISTUNE_LSB) -#define USBPCR_OTGTUNE_LSB 14 -#define USBPCR_OTGTUNE_MASK GENMASK(16, USBPCR_OTGTUNE_LSB) -#define USBPCR_OTGTUNE_DFT 4 +#define USBPCR_OTGTUNE_LSB 14 +#define USBPCR_OTGTUNE_MASK GENMASK(16, USBPCR_OTGTUNE_LSB) +#define USBPCR_OTGTUNE_DFT (0x4 << USBPCR_OTGTUNE_LSB) #define USBPCR_SQRXTUNE_LSB 11 -#define USBPCR_SQRXTUNE_MASK GENMASK(13, USBPCR_SQRXTUNE_LSB) -#define USBPCR_SQRXTUNE_DFT 3 - -#define USBPCR_TXFSLSTUNE_LSB 7 -#define USBPCR_TXFSLSTUNE_MASK GENMASK(10, USBPCR_TXFSLSTUNE_LSB) -#define USBPCR_TXFSLSTUNE_DFT 3 - -#define USBPCR_TXRISETUNE_LSB 4 -#define USBPCR_TXRISETUNE_MASK GENMASK(5, USBPCR_TXRISETUNE_LSB) -#define USBPCR_TXRISETUNE_DFT 3 - -#define USBPCR_TXVREFTUNE_LSB 0 -#define USBPCR_TXVREFTUNE_MASK GENMASK(3, USBPCR_TXVREFTUNE_LSB) -#define USBPCR_TXVREFTUNE_DFT 5 - -/* USBRDT */ -#define USBRDT_VBFIL_LD_EN BIT(25) -#define USBRDT_IDDIG_EN BIT(24) -#define USBRDT_IDDIG_REG BIT(23) +#define USBPCR_SQRXTUNE_MASK GENMASK(13, USBPCR_SQRXTUNE_LSB) +#define USBPCR_SQRXTUNE_DCR_20PCT (0x7 << USBPCR_SQRXTUNE_LSB) +#define USBPCR_SQRXTUNE_DFT (0x3 << USBPCR_SQRXTUNE_LSB) + +#define USBPCR_TXFSLSTUNE_LSB 7 +#define USBPCR_TXFSLSTUNE_MASK GENMASK(10, USBPCR_TXFSLSTUNE_LSB) +#define USBPCR_TXFSLSTUNE_DCR_50PPT (0xf << USBPCR_TXFSLSTUNE_LSB) +#define USBPCR_TXFSLSTUNE_DCR_25PPT (0x7 << USBPCR_TXFSLSTUNE_LSB) +#define USBPCR_TXFSLSTUNE_DFT (0x3 << USBPCR_TXFSLSTUNE_LSB) +#define USBPCR_TXFSLSTUNE_INC_25PPT (0x1 << USBPCR_TXFSLSTUNE_LSB) +#define USBPCR_TXFSLSTUNE_INC_50PPT (0x0 << USBPCR_TXFSLSTUNE_LSB) + +#define USBPCR_TXHSXVTUNE_LSB 4 +#define USBPCR_TXHSXVTUNE_MASK GENMASK(5, USBPCR_TXHSXVTUNE_LSB) +#define USBPCR_TXHSXVTUNE_DFT (0x3 << USBPCR_TXHSXVTUNE_LSB) +#define USBPCR_TXHSXVTUNE_DCR_15MV (0x1 << USBPCR_TXHSXVTUNE_LSB) + +#define USBPCR_TXRISETUNE_LSB 4 +#define USBPCR_TXRISETUNE_MASK GENMASK(5, USBPCR_TXRISETUNE_LSB) +#define USBPCR_TXRISETUNE_DFT (0x3 << USBPCR_TXRISETUNE_LSB) + +#define USBPCR_TXVREFTUNE_LSB 0 +#define USBPCR_TXVREFTUNE_MASK GENMASK(3, USBPCR_TXVREFTUNE_LSB) +#define USBPCR_TXVREFTUNE_INC_25PPT (0x7 << USBPCR_TXVREFTUNE_LSB) +#define USBPCR_TXVREFTUNE_DFT (0x5 << USBPCR_TXVREFTUNE_LSB) + +/* bits within the USBRDTR register */ +#define USBRDT_UTMI_RST BIT(27) +#define USBRDT_HB_MASK BIT(26) +#define USBRDT_VBFIL_LD_EN BIT(25) +#define USBRDT_IDDIG_EN BIT(24) +#define USBRDT_IDDIG_REG BIT(23) +#define USBRDT_VBFIL_EN BIT(2) + +/* bits within the USBPCR1 register */ +#define USBPCR1_BVLD_REG BIT(31) +#define USBPCR1_DPPD BIT(29) +#define USBPCR1_DMPD BIT(28) +#define USBPCR1_USB_SEL BIT(28) +#define USBPCR1_WORD_IF_16BIT BIT(19) + +enum ingenic_usb_phy_version { + ID_JZ4770, + ID_JZ4780, + ID_X1000, + ID_X1830, +}; -#define USBRDT_USBRDT_LSB 0 -#define USBRDT_USBRDT_MASK GENMASK(22, USBRDT_USBRDT_LSB) +struct ingenic_soc_info { + enum ingenic_usb_phy_version version; -/* USBPCR1 */ -#define USBPCR1_UHC_POWON BIT(5) + void (*usb_phy_init)(struct usb_phy *phy); +}; struct jz4770_phy { + const struct ingenic_soc_info *soc_info; + struct usb_phy phy; struct usb_otg otg; struct device *dev; @@ -90,12 +121,18 @@ static inline struct jz4770_phy *phy_to_jz4770_phy(struct usb_phy *phy) return container_of(phy, struct jz4770_phy, phy); } -static int jz4770_phy_set_peripheral(struct usb_otg *otg, +static int ingenic_usb_phy_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { struct jz4770_phy *priv = otg_to_jz4770_phy(otg); u32 reg; + if (priv->soc_info->version >= ID_X1000) { + reg = readl(priv->base + REG_USBPCR1_OFFSET); + reg |= USBPCR1_BVLD_REG; + writel(reg, priv->base + REG_USBPCR1_OFFSET); + } + reg = readl(priv->base + REG_USBPCR_OFFSET); reg &= ~USBPCR_USB_MODE; reg |= USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | USBPCR_OTG_DISABLE; @@ -104,7 +141,7 @@ static int jz4770_phy_set_peripheral(struct usb_otg *otg, return 0; } -static int jz4770_phy_set_host(struct usb_otg *otg, struct usb_bus *host) +static int ingenic_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host) { struct jz4770_phy *priv = otg_to_jz4770_phy(otg); u32 reg; @@ -117,7 +154,7 @@ static int jz4770_phy_set_host(struct usb_otg *otg, struct usb_bus *host) return 0; } -static int jz4770_phy_init(struct usb_phy *phy) +static int ingenic_usb_phy_init(struct usb_phy *phy) { struct jz4770_phy *priv = phy_to_jz4770_phy(phy); int err; @@ -135,15 +172,7 @@ static int jz4770_phy_init(struct usb_phy *phy) return err; } - reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_IDPULLUP_ALWAYS | - (USBPCR_COMPDISTUNE_DFT << USBPCR_COMPDISTUNE_LSB) | - (USBPCR_OTGTUNE_DFT << USBPCR_OTGTUNE_LSB) | - (USBPCR_SQRXTUNE_DFT << USBPCR_SQRXTUNE_LSB) | - (USBPCR_TXFSLSTUNE_DFT << USBPCR_TXFSLSTUNE_LSB) | - (USBPCR_TXRISETUNE_DFT << USBPCR_TXRISETUNE_LSB) | - (USBPCR_TXVREFTUNE_DFT << USBPCR_TXVREFTUNE_LSB) | - USBPCR_POR; - writel(reg, priv->base + REG_USBPCR_OFFSET); + priv->soc_info->usb_phy_init(phy); /* Wait for PHY to reset */ usleep_range(30, 300); @@ -153,7 +182,7 @@ static int jz4770_phy_init(struct usb_phy *phy) return 0; } -static void jz4770_phy_shutdown(struct usb_phy *phy) +static void ingenic_usb_phy_shutdown(struct usb_phy *phy) { struct jz4770_phy *priv = phy_to_jz4770_phy(phy); @@ -161,11 +190,100 @@ static void jz4770_phy_shutdown(struct usb_phy *phy) regulator_disable(priv->vcc_supply); } -static void jz4770_phy_remove(void *phy) +static void ingenic_usb_phy_remove(void *phy) { usb_remove_phy(phy); } +static void jz4770_usb_phy_init(struct usb_phy *phy) +{ + struct jz4770_phy *priv = phy_to_jz4770_phy(phy); + u32 reg; + + reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_IDPULLUP_ALWAYS | + USBPCR_COMPDISTUNE_DFT | USBPCR_OTGTUNE_DFT | USBPCR_SQRXTUNE_DFT | + USBPCR_TXFSLSTUNE_DFT | USBPCR_TXRISETUNE_DFT | USBPCR_TXVREFTUNE_DFT | + USBPCR_POR; + writel(reg, priv->base + REG_USBPCR_OFFSET); +} + +static void jz4780_usb_phy_init(struct usb_phy *phy) +{ + struct jz4770_phy *priv = phy_to_jz4770_phy(phy); + u32 reg; + + reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL | + USBPCR1_WORD_IF_16BIT; + writel(reg, priv->base + REG_USBPCR1_OFFSET); + + reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR; + writel(reg, priv->base + REG_USBPCR_OFFSET); +} + +static void x1000_usb_phy_init(struct usb_phy *phy) +{ + struct jz4770_phy *priv = phy_to_jz4770_phy(phy); + u32 reg; + + reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT; + writel(reg, priv->base + REG_USBPCR1_OFFSET); + + reg = USBPCR_SQRXTUNE_DCR_20PCT | USBPCR_TXPREEMPHTUNE | + USBPCR_TXHSXVTUNE_DCR_15MV | USBPCR_TXVREFTUNE_INC_25PPT | + USBPCR_COMMONONN | USBPCR_POR; + writel(reg, priv->base + REG_USBPCR_OFFSET); +} + +static void x1830_usb_phy_init(struct usb_phy *phy) +{ + struct jz4770_phy *priv = phy_to_jz4770_phy(phy); + u32 reg; + + /* rdt */ + writel(USBRDT_VBFIL_EN | USBRDT_UTMI_RST, priv->base + REG_USBRDT_OFFSET); + + reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT | + USBPCR1_DMPD | USBPCR1_DPPD; + writel(reg, priv->base + REG_USBPCR1_OFFSET); + + reg = USBPCR_IDPULLUP_OTG | USBPCR_VBUSVLDEXT | USBPCR_TXPREEMPHTUNE | + USBPCR_COMMONONN | USBPCR_POR; + writel(reg, priv->base + REG_USBPCR_OFFSET); +} + +static const struct ingenic_soc_info jz4770_soc_info = { + .version = ID_JZ4770, + + .usb_phy_init = jz4770_usb_phy_init, +}; + +static const struct ingenic_soc_info jz4780_soc_info = { + .version = ID_JZ4780, + + .usb_phy_init = jz4780_usb_phy_init, +}; + +static const struct ingenic_soc_info x1000_soc_info = { + .version = ID_X1000, + + .usb_phy_init = x1000_usb_phy_init, +}; + +static const struct ingenic_soc_info x1830_soc_info = { + .version = ID_X1830, + + .usb_phy_init = x1830_usb_phy_init, +}; + +static const struct of_device_id ingenic_usb_phy_of_matches[] = { + { .compatible = "ingenic,jz4770-phy", .data = &jz4770_soc_info }, + { .compatible = "ingenic,jz4780-phy", .data = &jz4780_soc_info }, + { .compatible = "ingenic,x1000-phy", .data = &x1000_soc_info }, + { .compatible = "ingenic,x1830-phy", .data = &x1830_soc_info }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ingenic_usb_phy_of_matches); + static int jz4770_phy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -176,18 +294,24 @@ static int jz4770_phy_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + priv->soc_info = device_get_match_data(&pdev->dev); + if (!priv->soc_info) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + platform_set_drvdata(pdev, priv); priv->dev = dev; priv->phy.dev = dev; priv->phy.otg = &priv->otg; - priv->phy.label = "jz4770-phy"; - priv->phy.init = jz4770_phy_init; - priv->phy.shutdown = jz4770_phy_shutdown; + priv->phy.label = "ingenic-usb-phy"; + priv->phy.init = ingenic_usb_phy_init; + priv->phy.shutdown = ingenic_usb_phy_shutdown; priv->otg.state = OTG_STATE_UNDEFINED; priv->otg.usb_phy = &priv->phy; - priv->otg.set_host = jz4770_phy_set_host; - priv->otg.set_peripheral = jz4770_phy_set_peripheral; + priv->otg.set_host = ingenic_usb_phy_set_host; + priv->otg.set_peripheral = ingenic_usb_phy_set_peripheral; priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { @@ -218,26 +342,20 @@ static int jz4770_phy_probe(struct platform_device *pdev) return err; } - return devm_add_action_or_reset(dev, jz4770_phy_remove, &priv->phy); + return devm_add_action_or_reset(dev, ingenic_usb_phy_remove, &priv->phy); } -#ifdef CONFIG_OF -static const struct of_device_id jz4770_phy_of_matches[] = { - { .compatible = "ingenic,jz4770-phy" }, - { } -}; -MODULE_DEVICE_TABLE(of, jz4770_phy_of_matches); -#endif - -static struct platform_driver jz4770_phy_driver = { +static struct platform_driver ingenic_phy_driver = { .probe = jz4770_phy_probe, .driver = { .name = "jz4770-phy", - .of_match_table = of_match_ptr(jz4770_phy_of_matches), + .of_match_table = of_match_ptr(ingenic_usb_phy_of_matches), }, }; -module_platform_driver(jz4770_phy_driver); +module_platform_driver(ingenic_phy_driver); +MODULE_AUTHOR("å‘¨ç°æ° (Zhou Yanjie) <zhouyanjie@wanyeetech.com>"); +MODULE_AUTHOR("æ¼†é¹æŒ¯ (Qi Pengzhen) <aric.pzqi@ingenic.com>"); MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); -MODULE_DESCRIPTION("Ingenic JZ4770 USB PHY driver"); +MODULE_DESCRIPTION("Ingenic SoCs USB PHY driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index 9c226b57153b739a7a155ead92fb96de46dae2a6..358d05cb643d76a0dc09056c9d1d92e7b1dc6754 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -2,7 +2,7 @@ /* * phy-keystone - USB PHY, talking to dwc3 controller in Keystone. * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com * * Author: WingMan Kwok <w-kwok2@ti.com> */ diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 06b47f1028b3afb69feddb91f221cc12a4435f49..ce767ecc0636641527fb304d45d39bbc34640507 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -334,7 +334,7 @@ static void mv_otg_update_state(struct mv_otg *mvotg) switch (old_state) { case OTG_STATE_UNDEFINED: mvotg->phy.otg->state = OTG_STATE_B_IDLE; - /* FALL THROUGH */ + fallthrough; case OTG_STATE_B_IDLE: if (otg_ctrl->id == 0) mvotg->phy.otg->state = OTG_STATE_A_IDLE; diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 9a7e655d528011e57d9319be026e0914f8ddbf8b..8ba6c5a91557083f8401ed52bf203c74a21a47df 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -2,7 +2,7 @@ /* * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver. * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com * * Author: Hema HK <hemahk@ti.com> */ diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index ad25546308897897c98256cb918857bc47620f19..b47285f023cf778bd0c5d92fd9c873f565cefb08 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -88,7 +88,7 @@ static void usb_phy_set_default_current(struct usb_phy *usb_phy) /** * usb_phy_notify_charger_work - notify the USB charger state - * @work - the charger work to notify the USB charger state + * @work: the charger work to notify the USB charger state * * This work can be issued when USB charger state has been changed or * USB charger current has been changed, then we can notify the current @@ -160,9 +160,9 @@ static void __usb_phy_get_charger_type(struct usb_phy *usb_phy) /** * usb_phy_get_charger_type - get charger type from extcon subsystem - * @nb -the notifier block to determine charger type - * @state - the cable state - * @data - private data + * @nb: the notifier block to determine charger type + * @state: the cable state + * @data: private data * * Determin the charger type from extcon subsystem which also means the * charger state has been chaned, then we should notify this event. @@ -178,8 +178,8 @@ static int usb_phy_get_charger_type(struct notifier_block *nb, /** * usb_phy_set_charger_current - set the USB charger current - * @usb_phy - the USB phy to be used - * @mA - the current need to be set + * @usb_phy: the USB phy to be used + * @mA: the current need to be set * * Usually we only change the charger default current when USB finished the * enumeration as one SDP charger. As one SDP charger, usb_phy_set_power() @@ -231,9 +231,9 @@ EXPORT_SYMBOL_GPL(usb_phy_set_charger_current); /** * usb_phy_get_charger_current - get the USB charger current - * @usb_phy - the USB phy to be used - * @min - the minimum current - * @max - the maximum current + * @usb_phy: the USB phy to be used + * @min: the minimum current + * @max: the maximum current * * Usually we will notify the maximum current to power user, but for some * special case, power user also need the minimum current value. Then the @@ -269,8 +269,8 @@ EXPORT_SYMBOL_GPL(usb_phy_get_charger_current); /** * usb_phy_set_charger_state - set the USB charger state - * @usb_phy - the USB phy to be used - * @state - the new state need to be set for charger + * @usb_phy: the USB phy to be used + * @state: the new state need to be set for charger * * The usb phy driver can issue this function when the usb phy driver * detected the charger state has been changed, in this case the charger @@ -414,8 +414,8 @@ static int usb_add_extcon(struct usb_phy *x) /** * devm_usb_get_phy - find the USB PHY - * @dev - device that requests this phy - * @type - the type of the phy the controller requires + * @dev: device that requests this phy + * @type: the type of the phy the controller requires * * Gets the phy using usb_get_phy(), and associates a device with it using * devres. On driver detach, release function is invoked on the devres data, @@ -444,7 +444,7 @@ EXPORT_SYMBOL_GPL(devm_usb_get_phy); /** * usb_get_phy - find the USB PHY - * @type - the type of the phy the controller requires + * @type: the type of the phy the controller requires * * Returns the phy driver, after getting a refcount to it; or * -ENODEV if there is no such phy. The caller is responsible for @@ -480,9 +480,9 @@ EXPORT_SYMBOL_GPL(usb_get_phy); /** * devm_usb_get_phy_by_node - find the USB PHY by device_node - * @dev - device that requests this phy - * @node - the device_node for the phy device. - * @nb - a notifier_block to register with the phy. + * @dev: device that requests this phy + * @node: the device_node for the phy device. + * @nb: a notifier_block to register with the phy. * * Returns the phy driver associated with the given device_node, * after getting a refcount to it, -ENODEV if there is no such phy or @@ -540,9 +540,9 @@ EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_node); /** * devm_usb_get_phy_by_phandle - find the USB PHY by phandle - * @dev - device that requests this phy - * @phandle - name of the property holding the phy phandle value - * @index - the index of the phy + * @dev: device that requests this phy + * @phandle: name of the property holding the phy phandle value + * @index: the index of the phy * * Returns the phy driver associated with the given phandle value, * after getting a refcount to it, -ENODEV if there is no such phy or @@ -578,8 +578,8 @@ EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); /** * devm_usb_put_phy - release the USB PHY - * @dev - device that wants to release this phy - * @phy - the phy returned by devm_usb_get_phy() + * @dev: device that wants to release this phy + * @phy: the phy returned by devm_usb_get_phy() * * destroys the devres associated with this phy and invokes usb_put_phy * to release the phy. @@ -615,9 +615,9 @@ void usb_put_phy(struct usb_phy *x) EXPORT_SYMBOL_GPL(usb_put_phy); /** - * usb_add_phy - declare the USB PHY + * usb_add_phy: declare the USB PHY * @x: the USB phy to be used; or NULL - * @type - the type of this PHY + * @type: the type of this PHY * * This call is exclusively for use by phy drivers, which * coordinate the activities of drivers for host and peripheral @@ -714,6 +714,7 @@ EXPORT_SYMBOL_GPL(usb_remove_phy); /** * usb_phy_set_event - set event to phy event * @x: the phy returned by usb_get_phy(); + * @event: event to set * * This sets event to phy event */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 53489cafecc18bc9ea32d6b5efdd944e15cc74e1..105132ae87acbcc33241bdb2b75601a60fbbd6f4 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -509,7 +509,7 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, case READ_STATUS_STAGE: case WRITE_STATUS_STAGE: usbhs_dcp_control_transfer_done(pipe); - /* fall through */ + fallthrough; default: return ret; } diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 9e5afdde1adbf8263e9a72bc67b8b7dea034085b..e7334b7fb3a62dd200b5541ae984a6e92a39ffdf 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -308,7 +308,7 @@ static void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) switch (pid) { case PID_STALL11: usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); - /* fall-through */ + fallthrough; case PID_STALL10: usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); } diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 84d52953dd0a1df9f60bb0c0d008269639cdbd62..a1df686c306648ec68471ead3d6dca0ee8a62771 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -117,7 +117,7 @@ static int aircable_process_packet(struct usb_serial_port *port, static void aircable_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - char *data = (char *)urb->transfer_buffer; + char *data = urb->transfer_buffer; int has_headers; int count; int len; diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 8fbaef5c9d69353b4bdc8ebc17f4ab87b34689e7..a2e2f56c88cd0783f06c3214da0c41055ec8af0b 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -59,7 +59,11 @@ #define CH341_REQ_MODEM_CTRL 0xA4 #define CH341_REG_BREAK 0x05 +#define CH341_REG_PRESCALER 0x12 +#define CH341_REG_DIVISOR 0x13 #define CH341_REG_LCR 0x18 +#define CH341_REG_LCR2 0x25 + #define CH341_NBREAK_BITS 0x01 #define CH341_LCR_ENABLE_RX 0x80 @@ -74,6 +78,7 @@ #define CH341_LCR_CS5 0x00 #define CH341_QUIRK_LIMITED_PRESCALER BIT(0) +#define CH341_QUIRK_SIMULATE_BREAK BIT(1) static const struct usb_device_id id_table[] = { { USB_DEVICE(0x4348, 0x5523) }, @@ -91,6 +96,7 @@ struct ch341_private { u8 msr; u8 lcr; unsigned long quirks; + unsigned long break_end; }; static void ch341_set_termios(struct tty_struct *tty, @@ -153,6 +159,10 @@ static const speed_t ch341_min_rates[] = { CH341_MIN_RATE(3), }; +/* Supported range is 46 to 3000000 bps. */ +#define CH341_MIN_BPS DIV_ROUND_UP(CH341_CLKRATE, CH341_CLK_DIV(0, 0) * 256) +#define CH341_MAX_BPS (CH341_CLKRATE / (CH341_CLK_DIV(3, 0) * 2)) + /* * The device line speed is given by the following equation: * @@ -163,10 +173,9 @@ static const speed_t ch341_min_rates[] = { * 2 <= div <= 256 if fact = 0, or * 9 <= div <= 256 if fact = 1 */ -static int ch341_get_divisor(struct ch341_private *priv) +static int ch341_get_divisor(struct ch341_private *priv, speed_t speed) { unsigned int fact, div, clk_div; - speed_t speed = priv->baud_rate; bool force_fact0 = false; int ps; @@ -174,7 +183,7 @@ static int ch341_get_divisor(struct ch341_private *priv) * Clamp to supported range, this makes the (ps < 0) and (div < 2) * sanity checks below redundant. */ - speed = clamp(speed, 46U, 3000000U); + speed = clamp_val(speed, CH341_MIN_BPS, CH341_MAX_BPS); /* * Start with highest possible base clock (fact = 1) that will give a @@ -229,15 +238,16 @@ static int ch341_get_divisor(struct ch341_private *priv) } static int ch341_set_baudrate_lcr(struct usb_device *dev, - struct ch341_private *priv, u8 lcr) + struct ch341_private *priv, + speed_t baud_rate, u8 lcr) { int val; int r; - if (!priv->baud_rate) + if (!baud_rate) return -EINVAL; - val = ch341_get_divisor(priv); + val = ch341_get_divisor(priv, baud_rate); if (val < 0) return -EINVAL; @@ -247,11 +257,20 @@ static int ch341_set_baudrate_lcr(struct usb_device *dev, */ val |= BIT(7); - r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, val); + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, + CH341_REG_DIVISOR << 8 | CH341_REG_PRESCALER, + val); if (r) return r; - r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, lcr); + /* + * Chip versions before version 0x30 as read using + * CH341_REQ_READ_VERSION used separate registers for line control + * (stop bits, parity and word length). Version 0x30 and above use + * CH341_REG_LCR only and CH341_REG_LCR2 is always set to zero. + */ + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, + CH341_REG_LCR2 << 8 | CH341_REG_LCR, lcr); if (r) return r; @@ -308,7 +327,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - r = ch341_set_baudrate_lcr(dev, priv, priv->lcr); + r = ch341_set_baudrate_lcr(dev, priv, priv->baud_rate, priv->lcr); if (r < 0) goto out; @@ -341,8 +360,8 @@ static int ch341_detect_quirks(struct usb_serial_port *port) USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, CH341_REG_BREAK, 0, buffer, size, DEFAULT_TIMEOUT); if (r == -EPIPE) { - dev_dbg(&port->dev, "break control not supported\n"); - quirks = CH341_QUIRK_LIMITED_PRESCALER; + dev_info(&port->dev, "break control not supported, using simulated break\n"); + quirks = CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK; r = 0; goto out; } @@ -523,7 +542,8 @@ static void ch341_set_termios(struct tty_struct *tty, if (baud_rate) { priv->baud_rate = baud_rate; - r = ch341_set_baudrate_lcr(port->serial->dev, priv, lcr); + r = ch341_set_baudrate_lcr(port->serial->dev, priv, + priv->baud_rate, lcr); if (r < 0 && old_termios) { priv->baud_rate = tty_termios_baud_rate(old_termios); tty_termios_copy_hw(&tty->termios, old_termios); @@ -542,15 +562,98 @@ static void ch341_set_termios(struct tty_struct *tty, ch341_set_handshake(port->serial->dev, priv->mcr); } +/* + * A subset of all CH34x devices don't support a real break condition and + * reading CH341_REG_BREAK fails (see also ch341_detect_quirks). This function + * simulates a break condition by lowering the baud rate to the minimum + * supported by the hardware upon enabling the break condition and sending + * a NUL byte. + * + * Incoming data is corrupted while the break condition is being simulated. + * + * Normally the duration of the break condition can be controlled individually + * by userspace using TIOCSBRK and TIOCCBRK or by passing an argument to + * TCSBRKP. Due to how the simulation is implemented the duration can't be + * controlled. The duration is always about (1s / 46bd * 9bit) = 196ms. + */ +static void ch341_simulate_break(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + struct ch341_private *priv = usb_get_serial_port_data(port); + unsigned long now, delay; + int r; + + if (break_state != 0) { + dev_dbg(&port->dev, "enter break state requested\n"); + + r = ch341_set_baudrate_lcr(port->serial->dev, priv, + CH341_MIN_BPS, + CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8); + if (r < 0) { + dev_err(&port->dev, + "failed to change baud rate to %u: %d\n", + CH341_MIN_BPS, r); + goto restore; + } + + r = tty_put_char(tty, '\0'); + if (r < 0) { + dev_err(&port->dev, + "failed to write NUL byte for simulated break condition: %d\n", + r); + goto restore; + } + + /* + * Compute expected transmission duration including safety + * margin. The original baud rate is only restored after the + * computed point in time. + * + * 11 bits = 1 start, 8 data, 1 stop, 1 margin + */ + priv->break_end = jiffies + (11 * HZ / CH341_MIN_BPS); + + return; + } + + dev_dbg(&port->dev, "leave break state requested\n"); + + now = jiffies; + + if (time_before(now, priv->break_end)) { + /* Wait until NUL byte is written */ + delay = priv->break_end - now; + dev_dbg(&port->dev, + "wait %d ms while transmitting NUL byte at %u baud\n", + jiffies_to_msecs(delay), CH341_MIN_BPS); + schedule_timeout_interruptible(delay); + } + +restore: + /* Restore original baud rate */ + r = ch341_set_baudrate_lcr(port->serial->dev, priv, priv->baud_rate, + priv->lcr); + if (r < 0) + dev_err(&port->dev, + "restoring original baud rate of %u failed: %d\n", + priv->baud_rate, r); +} + static void ch341_break_ctl(struct tty_struct *tty, int break_state) { const uint16_t ch341_break_reg = ((uint16_t) CH341_REG_LCR << 8) | CH341_REG_BREAK; struct usb_serial_port *port = tty->driver_data; + struct ch341_private *priv = usb_get_serial_port_data(port); int r; uint16_t reg_contents; uint8_t *break_reg; + if (priv->quirks & CH341_QUIRK_SIMULATE_BREAK) { + ch341_simulate_break(tty, break_state); + return; + } + break_reg = kmalloc(2, GFP_KERNEL); if (!break_reg) return; diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 7d289302ff6cfd22578885acbbadb6a048a9f5af..b97aa40ca4d1f7af83389a2a1d437329603a3b66 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -79,7 +79,7 @@ static int usb_console_setup(struct console *co, char *options) if (*s) doflow = (*s++ == 'r'); } - + /* Sane default */ if (baud == 0) baud = 9600; @@ -102,6 +102,9 @@ static int usb_console_setup(struct console *co, char *options) break; } + if (doflow) + cflag |= CRTSCTS; + /* * no need to check the index here: if the index is wrong, console * code won't call us diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index f5143eedbc48c4c89a4389cd923924affb718a68..d0c05aa8a0d6e3f848227da8ca125ab62797f4a3 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -50,6 +50,9 @@ static void cp210x_release(struct usb_serial *); static int cp210x_port_probe(struct usb_serial_port *); static int cp210x_port_remove(struct usb_serial_port *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); +static void cp210x_process_read_urb(struct urb *urb); +static void cp210x_enable_event_mode(struct usb_serial_port *port); +static void cp210x_disable_event_mode(struct usb_serial_port *port); static const struct usb_device_id id_table[] = { { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ @@ -253,9 +256,21 @@ struct cp210x_serial_private { bool use_actual_rate; }; +enum cp210x_event_state { + ES_DATA, + ES_ESCAPE, + ES_LSR, + ES_LSR_DATA_0, + ES_LSR_DATA_1, + ES_MSR +}; + struct cp210x_port_private { - __u8 bInterfaceNumber; + u8 bInterfaceNumber; bool has_swapped_line_ctl; + bool event_mode; + enum cp210x_event_state event_state; + u8 lsr; }; static struct usb_serial_driver cp210x_device = { @@ -272,14 +287,18 @@ static struct usb_serial_driver cp210x_device = { .break_ctl = cp210x_break_ctl, .set_termios = cp210x_set_termios, .tx_empty = cp210x_tx_empty, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, .tiocmget = cp210x_tiocmget, .tiocmset = cp210x_tiocmset, + .get_icount = usb_serial_generic_get_icount, .attach = cp210x_attach, .disconnect = cp210x_disconnect, .release = cp210x_release, .port_probe = cp210x_port_probe, .port_remove = cp210x_port_remove, - .dtr_rts = cp210x_dtr_rts + .dtr_rts = cp210x_dtr_rts, + .process_read_urb = cp210x_process_read_urb, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -401,13 +420,22 @@ struct cp210x_comm_status { */ #define PURGE_ALL 0x000f +/* CP210X_EMBED_EVENTS */ +#define CP210X_ESCCHAR 0xec + +#define CP210X_LSR_OVERRUN BIT(1) +#define CP210X_LSR_PARITY BIT(2) +#define CP210X_LSR_FRAME BIT(3) +#define CP210X_LSR_BREAK BIT(4) + + /* CP210X_GET_FLOW/CP210X_SET_FLOW read/write these 0x10 bytes */ struct cp210x_flow_ctl { __le32 ulControlHandshake; __le32 ulFlowReplace; __le32 ulXonLimit; __le32 ulXoffLimit; -} __packed; +}; /* cp210x_flow_ctl::ulControlHandshake */ #define CP210X_SERIAL_DTR_MASK GENMASK(1, 0) @@ -441,7 +469,7 @@ struct cp210x_flow_ctl { struct cp210x_pin_mode { u8 eci; u8 sci; -} __packed; +}; #define CP210X_PIN_MODE_MODEM 0 #define CP210X_PIN_MODE_GPIO BIT(0) @@ -504,7 +532,7 @@ struct cp210x_single_port_config { struct cp210x_gpio_write { u8 mask; u8 state; -} __packed; +}; /* * Helper to get interface number when we only have struct usb_serial. @@ -807,6 +835,7 @@ static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl) static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); int result; result = cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_ENABLE); @@ -818,21 +847,144 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) /* Configure the termios structure */ cp210x_get_termios(tty, port); - /* The baud rate must be initialised on cp2104 */ - if (tty) + if (tty) { + /* The baud rate must be initialised on cp2104 */ cp210x_change_speed(tty, port, NULL); - return usb_serial_generic_open(tty, port); + if (I_INPCK(tty)) + cp210x_enable_event_mode(port); + } + + result = usb_serial_generic_open(tty, port); + if (result) + goto err_disable; + + return 0; + +err_disable: + cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_DISABLE); + port_priv->event_mode = false; + + return result; } static void cp210x_close(struct usb_serial_port *port) { + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + usb_serial_generic_close(port); /* Clear both queues; cp2108 needs this to avoid an occasional hang */ cp210x_write_u16_reg(port, CP210X_PURGE, PURGE_ALL); cp210x_write_u16_reg(port, CP210X_IFC_ENABLE, UART_DISABLE); + + /* Disabling the interface disables event-insertion mode. */ + port_priv->event_mode = false; +} + +static void cp210x_process_lsr(struct usb_serial_port *port, unsigned char lsr, char *flag) +{ + if (lsr & CP210X_LSR_BREAK) { + port->icount.brk++; + *flag = TTY_BREAK; + } else if (lsr & CP210X_LSR_PARITY) { + port->icount.parity++; + *flag = TTY_PARITY; + } else if (lsr & CP210X_LSR_FRAME) { + port->icount.frame++; + *flag = TTY_FRAME; + } + + if (lsr & CP210X_LSR_OVERRUN) { + port->icount.overrun++; + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); + } +} + +static bool cp210x_process_char(struct usb_serial_port *port, unsigned char *ch, char *flag) +{ + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + + switch (port_priv->event_state) { + case ES_DATA: + if (*ch == CP210X_ESCCHAR) { + port_priv->event_state = ES_ESCAPE; + break; + } + return false; + case ES_ESCAPE: + switch (*ch) { + case 0: + dev_dbg(&port->dev, "%s - escape char\n", __func__); + *ch = CP210X_ESCCHAR; + port_priv->event_state = ES_DATA; + return false; + case 1: + port_priv->event_state = ES_LSR_DATA_0; + break; + case 2: + port_priv->event_state = ES_LSR; + break; + case 3: + port_priv->event_state = ES_MSR; + break; + default: + dev_err(&port->dev, "malformed event 0x%02x\n", *ch); + port_priv->event_state = ES_DATA; + break; + } + break; + case ES_LSR_DATA_0: + port_priv->lsr = *ch; + port_priv->event_state = ES_LSR_DATA_1; + break; + case ES_LSR_DATA_1: + dev_dbg(&port->dev, "%s - lsr = 0x%02x, data = 0x%02x\n", + __func__, port_priv->lsr, *ch); + cp210x_process_lsr(port, port_priv->lsr, flag); + port_priv->event_state = ES_DATA; + return false; + case ES_LSR: + dev_dbg(&port->dev, "%s - lsr = 0x%02x\n", __func__, *ch); + port_priv->lsr = *ch; + cp210x_process_lsr(port, port_priv->lsr, flag); + port_priv->event_state = ES_DATA; + break; + case ES_MSR: + dev_dbg(&port->dev, "%s - msr = 0x%02x\n", __func__, *ch); + /* unimplemented */ + port_priv->event_state = ES_DATA; + break; + } + + return true; +} + +static void cp210x_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + unsigned char *ch = urb->transfer_buffer; + char flag; + int i; + + if (!urb->actual_length) + return; + + if (port_priv->event_mode) { + for (i = 0; i < urb->actual_length; i++, ch++) { + flag = TTY_NORMAL; + + if (cp210x_process_char(port, ch, &flag)) + continue; + + tty_insert_flip_char(&port->port, *ch, flag); + } + } else { + tty_insert_flip_string(&port->port, ch, urb->actual_length); + } + tty_flip_buffer_push(&port->port); } /* @@ -915,6 +1067,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, u32 baud; u16 bits; u32 ctl_hs; + u32 flow_repl; cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud); @@ -1015,6 +1168,22 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) { dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); + /* + * When the port is closed, the CP210x hardware disables + * auto-RTS and RTS is deasserted but it leaves auto-CTS when + * in hardware flow control mode. When re-opening the port, if + * auto-CTS is enabled on the cp210x, then auto-RTS must be + * re-enabled in the driver. + */ + flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace); + flow_repl &= ~CP210X_SERIAL_RTS_MASK; + flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL); + flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl); + cp210x_write_reg_block(port, + CP210X_SET_FLOW, + &flow_ctl, + sizeof(flow_ctl)); + cflag |= CRTSCTS; } else { dev_dbg(dev, "%s - flow control = NONE\n", __func__); @@ -1148,6 +1317,41 @@ static void cp210x_change_speed(struct tty_struct *tty, tty_encode_baud_rate(tty, baud, baud); } +static void cp210x_enable_event_mode(struct usb_serial_port *port) +{ + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + int ret; + + if (port_priv->event_mode) + return; + + port_priv->event_state = ES_DATA; + port_priv->event_mode = true; + + ret = cp210x_write_u16_reg(port, CP210X_EMBED_EVENTS, CP210X_ESCCHAR); + if (ret) { + dev_err(&port->dev, "failed to enable events: %d\n", ret); + port_priv->event_mode = false; + } +} + +static void cp210x_disable_event_mode(struct usb_serial_port *port) +{ + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); + int ret; + + if (!port_priv->event_mode) + return; + + ret = cp210x_write_u16_reg(port, CP210X_EMBED_EVENTS, 0); + if (ret) { + dev_err(&port->dev, "failed to disable events: %d\n", ret); + return; + } + + port_priv->event_mode = false; +} + static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -1270,6 +1474,14 @@ static void cp210x_set_termios(struct tty_struct *tty, sizeof(flow_ctl)); } + /* + * Enable event-insertion mode only if input parity checking is + * enabled for now. + */ + if (I_INPCK(tty)) + cp210x_enable_event_mode(port); + else + cp210x_disable_event_mode(port); } static int cp210x_tiocmset(struct tty_struct *tty, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index ecda82198798e6df35698d181f89cef7d797f1b8..cc028601c388e8f7eb025daeba7d09cd8d4b213e 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1048,7 +1048,7 @@ static void cypress_read_int_callback(struct urb *urb) return; case -EPIPE: /* Can't call usb_clear_halt while in_interrupt */ - /* FALLS THROUGH */ + fallthrough; default: /* something ugly is going on... */ dev_err(dev, "%s - unexpected nonzero read status received: %d\n", @@ -1197,7 +1197,7 @@ static void cypress_write_int_callback(struct urb *urb) return; case -EPIPE: /* Cannot call usb_clear_halt while in_interrupt */ - /* FALLTHROUGH */ + fallthrough; default: dev_err(dev, "%s - unexpected nonzero write status received: %d\n", __func__, status); diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index dcda7fb164b43059a59133d6b50b40123a6cfdca..0c7eacc630e0ec6da40c8e6c83296007cda125d0 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -424,7 +424,7 @@ static void f81232_process_read_urb(struct urb *urb) lsr = data[i]; tty_flag = f81232_handle_lsr(port, lsr); - if (port->port.console && port->sysrq) { + if (port->sysrq) { if (usb_serial_handle_sysrq_char(port, data[i + 1])) continue; } @@ -461,7 +461,7 @@ static void f81534a_process_read_urb(struct urb *urb) lsr = data[len - 1]; tty_flag = f81232_handle_lsr(port, lsr); - if (port->port.console && port->sysrq) { + if (port->sysrq) { for (i = 1; i < len - 1; ++i) { if (!usb_serial_handle_sysrq_char(port, data[i])) { tty_insert_flip_char(&port->port, data[i], diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 2b39bda035c71b95f103ad7028c107e77ddfc455..5661fd03e5456aea43c8fc80e441b910a6b51a7c 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1238,7 +1238,7 @@ static void f81534_process_per_serial_block(struct usb_serial_port *port, schedule_work(&port_priv->lsr_work); } - if (port->port.console && port->sysrq) { + if (port->sysrq) { if (usb_serial_handle_sysrq_char(port, data[i])) continue; } diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9ad44a96dfe3a830806645f6bed32c7fdf4c6073..871cdccf3a5f1c6ec69d30ad0bd0bd2fa33f3af5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2480,12 +2480,12 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, #define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE) static int ftdi_process_packet(struct usb_serial_port *port, - struct ftdi_private *priv, char *packet, int len) + struct ftdi_private *priv, unsigned char *buf, int len) { + unsigned char status; + bool brkint = false; int i; - char status; char flag; - char *ch; if (len < 2) { dev_dbg(&port->dev, "malformed packet\n"); @@ -2495,7 +2495,7 @@ static int ftdi_process_packet(struct usb_serial_port *port, /* Compare new line status to the old one, signal if different/ N.B. packet may be processed more than once, but differences are only processed once. */ - status = packet[0] & FTDI_STATUS_B0_MASK; + status = buf[0] & FTDI_STATUS_B0_MASK; if (status != priv->prev_status) { char diff_status = status ^ priv->prev_status; @@ -2521,13 +2521,12 @@ static int ftdi_process_packet(struct usb_serial_port *port, } /* save if the transmitter is empty or not */ - if (packet[1] & FTDI_RS_TEMT) + if (buf[1] & FTDI_RS_TEMT) priv->transmit_empty = 1; else priv->transmit_empty = 0; - len -= 2; - if (!len) + if (len == 2) return 0; /* status only */ /* @@ -2535,47 +2534,57 @@ static int ftdi_process_packet(struct usb_serial_port *port, * data payload to avoid over-reporting. */ flag = TTY_NORMAL; - if (packet[1] & FTDI_RS_ERR_MASK) { - /* Break takes precedence over parity, which takes precedence - * over framing errors */ - if (packet[1] & FTDI_RS_BI) { - flag = TTY_BREAK; + if (buf[1] & FTDI_RS_ERR_MASK) { + /* + * Break takes precedence over parity, which takes precedence + * over framing errors. Note that break is only associated + * with the last character in the buffer and only when it's a + * NUL. + */ + if (buf[1] & FTDI_RS_BI && buf[len - 1] == '\0') { port->icount.brk++; - usb_serial_handle_break(port); - } else if (packet[1] & FTDI_RS_PE) { + brkint = true; + } + if (buf[1] & FTDI_RS_PE) { flag = TTY_PARITY; port->icount.parity++; - } else if (packet[1] & FTDI_RS_FE) { + } else if (buf[1] & FTDI_RS_FE) { flag = TTY_FRAME; port->icount.frame++; } /* Overrun is special, not associated with a char */ - if (packet[1] & FTDI_RS_OE) { + if (buf[1] & FTDI_RS_OE) { port->icount.overrun++; tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); } } - port->icount.rx += len; - ch = packet + 2; + port->icount.rx += len - 2; - if (port->port.console && port->sysrq) { - for (i = 0; i < len; i++, ch++) { - if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(&port->port, *ch, flag); + if (brkint || port->sysrq) { + for (i = 2; i < len; i++) { + if (brkint && i == len - 1) { + if (usb_serial_handle_break(port)) + return len - 3; + flag = TTY_BREAK; + } + if (usb_serial_handle_sysrq_char(port, buf[i])) + continue; + tty_insert_flip_char(&port->port, buf[i], flag); } } else { - tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len); + tty_insert_flip_string_fixed_flag(&port->port, buf + 2, flag, + len - 2); } - return len; + return len - 2; } static void ftdi_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; struct ftdi_private *priv = usb_get_serial_port_data(port); - char *data = (char *)urb->transfer_buffer; + char *data = urb->transfer_buffer; int i; int len; int count = 0; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index a79a1325b4d9614861d936caf769e38cb96a7b79..be1641e0408b0d7411b8ac4874c0f05c0678ed7c 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -302,7 +302,7 @@ enum ftdi_sio_baudrate { /* * FTDI_SIO_GET_LATENCY_TIMER * - * Set the timeout interval. The FTDI collects data from the slave + * Set the timeout interval. The FTDI collects data from the * device, transmitting it to the host when either A) 62 bytes are * received, or B) the timeout interval has elapsed and the buffer * contains at least 1 byte. Setting this value to a small number @@ -324,7 +324,7 @@ enum ftdi_sio_baudrate { /* * FTDI_SIO_SET_LATENCY_TIMER * - * Set the timeout interval. The FTDI collects data from the slave + * Set the timeout interval. The FTDI collects data from the * device, transmitting it to the host when either A) 62 bytes are * received, or B) the timeout interval has elapsed and the buffer * contains at least 1 byte. Setting this value to a small number diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index d63072fee099ce062757ebb9aa25bd25ba901f51..c02c19bb118377628eec8fb1f0089d9b2866affb 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -179,19 +179,22 @@ static unsigned char const GARMIN_START_SESSION_REPLY[] = { 0, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0 }; static unsigned char const GARMIN_BULK_IN_AVAIL_REPLY[] = { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; +static unsigned char const GARMIN_STOP_TRANSFER_REQ[] + = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0 }; +static unsigned char const GARMIN_STOP_TRANSFER_REQ_V2[] + = { 20, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 0 }; + +/* packets currently unused, left as documentation */ +#if 0 static unsigned char const GARMIN_APP_LAYER_REPLY[] = { 0x14, 0, 0, 0 }; static unsigned char const GARMIN_START_PVT_REQ[] = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 49, 0 }; static unsigned char const GARMIN_STOP_PVT_REQ[] = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 50, 0 }; -static unsigned char const GARMIN_STOP_TRANSFER_REQ[] - = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0 }; -static unsigned char const GARMIN_STOP_TRANSFER_REQ_V2[] - = { 20, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 0 }; static unsigned char const PRIVATE_REQ[] = { 0x4B, 0x6E, 0x10, 0x01, 0xFF, 0, 0, 0, 0xFF, 0, 0, 0 }; - +#endif static const struct usb_device_id id_table[] = { diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 5cdf180cda23e90ff8b8c3456022d4491221fde3..d10aa3d2ee490976182483b21399806bfee768cd 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -345,7 +345,7 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs); void usb_serial_generic_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - char *ch = (char *)urb->transfer_buffer; + char *ch = urb->transfer_buffer; int i; if (!urb->actual_length) @@ -355,13 +355,13 @@ void usb_serial_generic_process_read_urb(struct urb *urb) * stuff like 3G modems, so shortcircuit it in the 99.9999999% of * cases where the USB serial is not a console anyway. */ - if (!port->port.console || !port->sysrq) { - tty_insert_flip_string(&port->port, ch, urb->actual_length); - } else { + if (port->sysrq) { for (i = 0; i < urb->actual_length; i++, ch++) { if (!usb_serial_handle_sysrq_char(port, *ch)) tty_insert_flip_char(&port->port, *ch, TTY_NORMAL); } + } else { + tty_insert_flip_string(&port->port, ch, urb->actual_length); } tty_flip_buffer_push(&port->port); } @@ -571,10 +571,10 @@ int usb_serial_generic_get_icount(struct tty_struct *tty, } EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount); -#ifdef CONFIG_MAGIC_SYSRQ +#if defined(CONFIG_USB_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) { - if (port->sysrq && port->port.console) { + if (port->sysrq) { if (ch && time_before(jiffies, port->sysrq)) { handle_sysrq(ch); port->sysrq = 0; @@ -584,16 +584,13 @@ int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) } return 0; } -#else -int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) -{ - return 0; -} -#endif EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); int usb_serial_handle_break(struct usb_serial_port *port) { + if (!port->port.console) + return 0; + if (!port->sysrq) { port->sysrq = jiffies + HZ*5; return 1; @@ -602,6 +599,7 @@ int usb_serial_handle_break(struct usb_serial_port *port) return 0; } EXPORT_SYMBOL_GPL(usb_serial_handle_break); +#endif /** * usb_serial_handle_dcd_change - handle a change of carrier detect state diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 4cca0b836f43092506f40c10fe0f2589fd12de1a..ba5d8df695189fdd3701684a93b46baeef84ada7 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1752,7 +1752,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, edge_serial->rxState = EXPECT_HDR2; break; } - /* Fall through */ + fallthrough; case EXPECT_HDR2: edge_serial->rxHeader2 = *buffer; ++buffer; @@ -1804,7 +1804,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, edge_serial->rxState = EXPECT_DATA; break; } - /* Fall through */ + fallthrough; case EXPECT_DATA: /* Expect data */ if (bufferLength < edge_serial->rxBytesRemaining) { rxLen = bufferLength; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index b8dfeb4fb2ed6e1301df7eebc191969d4c478398..b4ba79123d9dae7fb64bcf8defd6f37bfb93a3dc 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -158,7 +158,6 @@ static int iuu_tiocmget(struct tty_struct *tty) static void iuu_rxcmd(struct urb *urb) { struct usb_serial_port *port = urb->context; - int result; int status = urb->status; if (status) { @@ -174,7 +173,7 @@ static void iuu_rxcmd(struct urb *urb) port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, 1, read_rxcmd_callback, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + usb_submit_urb(port->write_urb, GFP_ATOMIC); } static int iuu_reset(struct usb_serial_port *port, u8 wt) @@ -241,7 +240,6 @@ static void iuu_update_status_callback(struct urb *urb) static void iuu_status_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; - int result; int status = urb->status; dev_dbg(&port->dev, "%s - status = %d\n", __func__, status); @@ -250,7 +248,7 @@ static void iuu_status_callback(struct urb *urb) port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, 256, iuu_update_status_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + usb_submit_urb(port->read_urb, GFP_ATOMIC); } static int iuu_status(struct usb_serial_port *port) @@ -351,12 +349,12 @@ static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1, static void iuu_led_activity_on(struct urb *urb) { struct usb_serial_port *port = urb->context; - int result; char *buf_ptr = port->write_urb->transfer_buffer; - *buf_ptr++ = IUU_SET_LED; + if (xmas) { - get_random_bytes(buf_ptr, 6); - *(buf_ptr+7) = 1; + buf_ptr[0] = IUU_SET_LED; + get_random_bytes(buf_ptr + 1, 6); + buf_ptr[7] = 1; } else { iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255); } @@ -366,27 +364,27 @@ static void iuu_led_activity_on(struct urb *urb) port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, 8 , iuu_rxcmd, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + usb_submit_urb(port->write_urb, GFP_ATOMIC); } static void iuu_led_activity_off(struct urb *urb) { struct usb_serial_port *port = urb->context; - int result; char *buf_ptr = port->write_urb->transfer_buffer; + if (xmas) { iuu_rxcmd(urb); return; - } else { - *buf_ptr++ = IUU_SET_LED; - iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255); } + + iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255); + usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, 8 , iuu_rxcmd, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + usb_submit_urb(port->write_urb, GFP_ATOMIC); } diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index bf988f77d4006717b23617f0cffe99ab325a228a..c1333919716b67950e924e503d00384b53b0cebe 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -664,11 +664,10 @@ static void keyspan_pda_close(struct usb_serial_port *port) /* download the firmware to a "fake" device (pre-renumeration) */ static int keyspan_pda_fake_startup(struct usb_serial *serial) { - int response; const char *fw_name; /* download the firmware here ... */ - response = ezusb_fx1_set_reset(serial->dev, 1); + ezusb_fx1_set_reset(serial->dev, 1); if (0) { ; } #ifdef KEYSPAN diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index e9882ba209330472c0674526efd0eaf2f798974a..49aacb0a327ca47419814041fd7ec239f0d62081 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -499,7 +499,7 @@ static void kobil_set_termios(struct tty_struct *tty, break; default: speed = 9600; - /* fall through */ + fallthrough; case 9600: urb_val = SUSBCR_SBR_9600; break; @@ -526,6 +526,10 @@ static void kobil_set_termios(struct tty_struct *tty, 0, KOBIL_TIMEOUT ); + if (result) { + dev_err(&port->dev, "failed to update line settings: %d\n", + result); + } } static int kobil_ioctl(struct tty_struct *tty, diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 2513ee9027790b4aa900d3099cd968ea9302a9f8..5d38c2a0f5902a0119464fc65e92e8c50e33de31 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -327,14 +327,14 @@ static void mxuport_process_read_urb_data(struct usb_serial_port *port, { int i; - if (!port->port.console || !port->sysrq) { - tty_insert_flip_string(&port->port, data, size); - } else { + if (port->sysrq) { for (i = 0; i < size; i++, data++) { if (!usb_serial_handle_sysrq_char(port, *data)) tty_insert_flip_char(&port->port, *data, TTY_NORMAL); } + } else { + tty_insert_flip_string(&port->port, data, size); } tty_flip_buffer_push(&port->port); } diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9b7cee98ea6072f3006cf54f2700be3dfb363b02..89b3192af3269b5acc80fd8df7e3727585852c50 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2157,8 +2157,7 @@ static void option_instat_callback(struct urb *urb) dev_dbg(dev, "%s: urb %p port %p has data %p\n", __func__, urb, port, portdata); if (status == 0) { - struct usb_ctrlrequest *req_pkt = - (struct usb_ctrlrequest *)urb->transfer_buffer; + struct usb_ctrlrequest *req_pkt = urb->transfer_buffer; if (!req_pkt) { dev_dbg(dev, "%s: NULL req_pkt\n", __func__); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index c5a2995dfa2e371eed561974e09af10adc1df843..048452d8a4a4a00c54db156235c67b470caf5cfd 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1101,7 +1101,7 @@ static void pl2303_process_read_urb(struct urb *urb) if (line_status & UART_OVERRUN_ERROR) tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); - if (port->port.console && port->sysrq) { + if (port->sysrq) { for (i = 0; i < urb->actual_length; ++i) if (!usb_serial_handle_sysrq_char(port, data[i])) tty_insert_flip_char(&port->port, data[i], diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index d147feae83e69484719a01189b2ffd3e4fd2f576..c8d1ea0e6e6fc0c104e98001734d8b04619bd9c7 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -155,6 +155,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */ + {DEVICE_SWI(0x1199, 0x9062)}, /* Sierra Wireless EM7305 QDL */ {DEVICE_SWI(0x1199, 0x9063)}, /* Sierra Wireless EM7305 */ {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx */ {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx */ @@ -365,9 +366,8 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) * a specific function, while the subclass indicate a * specific firmware source * - * This is a blacklist of functions known to be - * non-serial. The rest are assumed to be serial and - * will be handled by this driver + * This is a list of functions known to be non-serial. The rest + * are assumed to be serial and will be handled by this driver */ switch (intf->desc.bInterfaceProtocol) { /* QMI combined (qmi_wwan) */ diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index f93b81a297d6798f6b10da299945e60533c8d56f..872d1bc86ab433d975550a6f9de486c4db44f2c6 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -480,21 +480,6 @@ static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) } } -/* not needed, kept to document functionality */ -static void qt2_process_xmit_empty(struct usb_serial_port *port, - unsigned char *ch) -{ - int bytes_written; - - bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4); -} - -/* not needed, kept to document functionality */ -static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch) -{ - return; -} - static void qt2_process_read_urb(struct urb *urb) { struct usb_serial *serial; @@ -540,7 +525,7 @@ static void qt2_process_read_urb(struct urb *urb) __func__); break; } - qt2_process_xmit_empty(port, ch + 3); + /* bytes_written = (ch[1] << 4) + ch[0]; */ i += 4; escapeflag = true; break; @@ -569,7 +554,6 @@ static void qt2_process_read_urb(struct urb *urb) break; case QT2_REC_FLUSH: case QT2_XMIT_FLUSH: - qt2_process_flush(port, ch + 2); i += 2; escapeflag = true; break; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index a43263a0edd88e2e61521907ae6baff55b2af32d..57fc3c31712e5aa288859d6098c8f91c53a8745b 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -45,10 +45,9 @@ static bool nmea; -/* Used in interface blacklisting */ -struct sierra_iface_info { - const u32 infolen; /* number of interface numbers on blacklist */ - const u8 *ifaceinfo; /* pointer to the array holding the numbers */ +struct sierra_iface_list { + const u8 *nums; /* array of interface numbers */ + size_t count; /* number of elements in array */ }; struct sierra_intf_private { @@ -101,38 +100,19 @@ static int sierra_calc_num_ports(struct usb_serial *serial, return num_ports; } -static int is_blacklisted(const u8 ifnum, - const struct sierra_iface_info *blacklist) +static bool is_listed(const u8 ifnum, const struct sierra_iface_list *list) { - const u8 *info; int i; - if (blacklist) { - info = blacklist->ifaceinfo; + if (!list) + return false; - for (i = 0; i < blacklist->infolen; i++) { - if (info[i] == ifnum) - return 1; - } + for (i = 0; i < list->count; i++) { + if (list->nums[i] == ifnum) + return true; } - return 0; -} - -static int is_himemory(const u8 ifnum, - const struct sierra_iface_info *himemorylist) -{ - const u8 *info; - int i; - if (himemorylist) { - info = himemorylist->ifaceinfo; - - for (i=0; i < himemorylist->infolen; i++) { - if (info[i] == ifnum) - return 1; - } - } - return 0; + return false; } static u8 sierra_interface_num(struct usb_serial *serial) @@ -143,6 +123,7 @@ static u8 sierra_interface_num(struct usb_serial *serial) static int sierra_probe(struct usb_serial *serial, const struct usb_device_id *id) { + const struct sierra_iface_list *ignore_list; int result = 0; struct usb_device *udev; u8 ifnum; @@ -161,10 +142,10 @@ static int sierra_probe(struct usb_serial *serial, usb_set_interface(udev, ifnum, 1); } - if (is_blacklisted(ifnum, - (struct sierra_iface_info *)id->driver_info)) { - dev_dbg(&serial->dev->dev, - "Ignoring blacklisted interface #%d\n", ifnum); + ignore_list = (const struct sierra_iface_list *)id->driver_info; + + if (is_listed(ifnum, ignore_list)) { + dev_dbg(&serial->dev->dev, "Ignoring interface #%d\n", ifnum); return -ENODEV; } @@ -173,22 +154,22 @@ static int sierra_probe(struct usb_serial *serial, /* interfaces with higher memory requirements */ static const u8 hi_memory_typeA_ifaces[] = { 0, 2 }; -static const struct sierra_iface_info typeA_interface_list = { - .infolen = ARRAY_SIZE(hi_memory_typeA_ifaces), - .ifaceinfo = hi_memory_typeA_ifaces, +static const struct sierra_iface_list typeA_interface_list = { + .nums = hi_memory_typeA_ifaces, + .count = ARRAY_SIZE(hi_memory_typeA_ifaces), }; static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 }; -static const struct sierra_iface_info typeB_interface_list = { - .infolen = ARRAY_SIZE(hi_memory_typeB_ifaces), - .ifaceinfo = hi_memory_typeB_ifaces, +static const struct sierra_iface_list typeB_interface_list = { + .nums = hi_memory_typeB_ifaces, + .count = ARRAY_SIZE(hi_memory_typeB_ifaces), }; -/* 'blacklist' of interfaces not served by this driver */ +/* 'ignorelist' of interfaces not served by this driver */ static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11, 19, 20 }; -static const struct sierra_iface_info direct_ip_interface_blacklist = { - .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), - .ifaceinfo = direct_ip_non_serial_ifaces, +static const struct sierra_iface_list direct_ip_interface_ignore = { + .nums = direct_ip_non_serial_ifaces, + .count = ARRAY_SIZE(direct_ip_non_serial_ifaces), }; static const struct usb_device_id id_table[] = { @@ -264,19 +245,19 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */ /* Sierra Wireless Direct IP modems */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68A3, 0xFF, 0xFF, 0xFF), - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore }, { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68AA, 0xFF, 0xFF, 0xFF), - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore }, { USB_DEVICE(0x1199, 0x68AB) }, /* Sierra Wireless AR8550 */ /* AT&T Direct IP LTE modems */ { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF), - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore }, /* Airprime/Sierra Wireless Direct IP modems */ { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68A3, 0xFF, 0xFF, 0xFF), - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + .driver_info = (kernel_ulong_t)&direct_ip_interface_ignore }, { } @@ -589,8 +570,7 @@ static void sierra_instat_callback(struct urb *urb) urb, port, portdata); if (status == 0) { - struct usb_ctrlrequest *req_pkt = - (struct usb_ctrlrequest *)urb->transfer_buffer; + struct usb_ctrlrequest *req_pkt = urb->transfer_buffer; if (!req_pkt) { dev_dbg(&port->dev, "%s: NULL req_pkt\n", @@ -879,7 +859,7 @@ static int sierra_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct sierra_port_private *portdata; - const struct sierra_iface_info *himemoryp; + const struct sierra_iface_list *himemory_list; u8 ifnum; portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); @@ -898,16 +878,16 @@ static int sierra_port_probe(struct usb_serial_port *port) if (serial->num_ports == 1) { /* Get interface number for composite device */ ifnum = sierra_interface_num(serial); - himemoryp = &typeB_interface_list; + himemory_list = &typeB_interface_list; } else { /* This is really the usb-serial port number of the interface * rather than the interface number. */ ifnum = port->port_number; - himemoryp = &typeA_interface_list; + himemory_list = &typeA_interface_list; } - if (is_himemory(ifnum, himemoryp)) { + if (is_listed(ifnum, himemory_list)) { portdata->num_out_urbs = N_OUT_URB_HM; portdata->num_in_urbs = N_IN_URB_HM; } diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index f6aea9f1be1a98b2d31dfe9741f5e6e614986710..7d39d35e52a130aedc6acc462b8ba26bfae6b99c 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -495,7 +495,7 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, static void ssu100_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; - char *packet = (char *)urb->transfer_buffer; + char *packet = urb->transfer_buffer; char flag = TTY_NORMAL; u32 len = urb->actual_length; int i; @@ -517,13 +517,14 @@ static void ssu100_process_read_urb(struct urb *urb) if (!len) return; /* status only */ - if (port->port.console && port->sysrq) { + if (port->sysrq) { for (i = 0; i < len; i++, ch++) { if (!usb_serial_handle_sysrq_char(port, *ch)) tty_insert_flip_char(&port->port, *ch, flag); } - } else + } else { tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len); + } tty_flip_buffer_push(&port->port); } diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c index 1ba1401d27d7a1f1e9c04f8c31cf92a722cfd5aa..0a2268c479af4a8dedb585ee869428ac785dd522 100644 --- a/drivers/usb/serial/upd78f0730.c +++ b/drivers/usb/serial/upd78f0730.c @@ -332,7 +332,7 @@ static void upd78f0730_set_termios(struct tty_struct *tty, tty->termios.c_cflag &= ~CSIZE; tty->termios.c_cflag |= CS8; dev_warn(dev, "data size is not supported, using 8 bits\n"); - /* fall through */ + fallthrough; case CS8: request.params |= UPD78F0730_DATA_SIZE_8_BITS; dev_dbg(dev, "%s - 8 data bits\n", __func__); diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 5335a7ff5d1460230398d50335d2445f173cd727..d17b60a644efbe77427afc8c4ecb508b0fefdff7 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -57,7 +57,7 @@ config USB_STORAGE_FREECOM tristate "Freecom USB/ATAPI Bridge support" help Support for the Freecom USB to IDE/ATAPI adaptor. - Freecom has a web page at <http://www.freecom.de/>. + Freecom has a web page at <https://www.freecom.de/>. If this driver is compiled as a module, it will be named ums-freecom. diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index ddab2cd3d2e7522a1812541b6eb79f4fb81235a3..20b857e97e60cf74242b725965bf777a399c3b02 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -453,9 +453,8 @@ static int alauda_check_media(struct us_data *us) { struct alauda_info *info = (struct alauda_info *) us->extra; unsigned char status[2]; - int rc; - rc = alauda_get_media_status(us, status); + alauda_get_media_status(us, status); /* Check for no media or door open */ if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10) diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 34e7eaff1174c0271cd12027d6e309427d59190c..3d5f7d0ff0f1ff1a916dc1020a8795a0b1150c29 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -11,7 +11,7 @@ * * This driver was developed with information provided in FREECOM's USB * Programmers Reference Guide. For further information contact Freecom - * (http://www.freecom.de/) + * (https://www.freecom.de/) */ #include <linux/module.h> diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index f4c2359abb1b0015af491daff990b5dd9d83846c..e5a971b83e3f567d17623b88e1826b5bd429dfdb 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -298,7 +298,7 @@ static int slave_configure(struct scsi_device *sdev) } else { /* - * Non-disk-type devices don't need to blacklist any pages + * Non-disk-type devices don't need to ignore any pages * or to force 192-byte transfer lengths for MODE SENSE. * But they do need to use MODE SENSE(10). */ diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h index 3734a25e09e539f05f16e9f16b5dfb371d0e3799..3f720faa6f97c1d313ba45c48822b7c7d6aa7496 100644 --- a/drivers/usb/storage/uas-detect.h +++ b/drivers/usb/storage/uas-detect.h @@ -120,7 +120,7 @@ static int uas_use_uas_driver(struct usb_interface *intf, if (flags & US_FL_IGNORE_UAS) { dev_warn(&udev->dev, - "UAS is blacklisted for this device, using usb-storage instead\n"); + "UAS is ignored for this device, using usb-storage instead\n"); return 0; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b6a9a74516201df0ebcf61ef463203f9c0aecdd3..220ae2c356eee84d5fa869af9491f3a261967667 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -44,7 +44,7 @@ * mode. Existing userspace solutions are superior. * * New mode switching devices should instead be added to the database - * maintained at http://www.draisberghof.de/usb_modeswitch/ + * maintained at https://www.draisberghof.de/usb_modeswitch/ */ #if !defined(CONFIG_USB_STORAGE_SDDR09) && \ diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 0edfb89e04a86d92f8d0fb410a9f417cd7d8f6df..7b20073d7fc0ab7b7d78fe3a2d1d2f9508ecde0b 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/** +/* * USB Typec-C DisplayPort Alternate Mode driver * * Copyright (C) 2018 Intel Corporation @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/usb/pd_vdo.h> #include <linux/usb/typec_dp.h> +#include "displayport.h" #define DP_HEADER(_dp, cmd) (VDO((_dp)->alt->svid, 1, cmd) | \ VDO_OPOS(USB_TYPEC_DP_MODE)) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index c9234748537a3b13e420c125edab9a7f6f00bc0f..02655694f200ab43102ed2c2d447e0e9d6422112 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -580,7 +580,7 @@ EXPORT_SYMBOL_GPL(typec_partner_set_identity); * SVID listed in response to Discover Modes command need to be listed in an * array in @desc. * - * Returns handle to the alternate mode on success or NULL on failure. + * Returns handle to the alternate mode on success or ERR_PTR on failure. */ struct typec_altmode * typec_partner_register_altmode(struct typec_partner *partner, diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index 70ddc9d6d49e4636dbeadc41604908fe53f5d8c6..e4021e13af40a3b3b440b9eed1fa53887a513fa1 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/usb/pd.h> #include <linux/usb/role.h> #include <linux/usb/typec_mux.h> #include <linux/usb/typec_dp.h> @@ -19,6 +20,10 @@ #define PMC_USBC_CMD 0xa7 +/* Response status bits */ +#define PMC_USB_RESP_STATUS_FAILURE BIT(0) +#define PMC_USB_RESP_STATUS_FATAL BIT(1) + /* "Usage" OOB Message field values */ enum { PMC_USB_CONNECT, @@ -130,8 +135,8 @@ static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len) */ intel_scu_ipc_dev_command(port->pmc->ipc, PMC_USBC_CMD, 0, msg, len, response, sizeof(response)); - if (response[2]) { - if (response[2] & BIT(1)) + if (response[2] & PMC_USB_RESP_STATUS_FAILURE) { + if (response[2] & PMC_USB_RESP_STATUS_FATAL) return -EIO; return -EBUSY; } @@ -227,6 +232,43 @@ pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state) return pmc_usb_command(port, (void *)&req, sizeof(req)); } +static int +pmc_usb_mux_usb4(struct pmc_usb_port *port, struct typec_mux_state *state) +{ + struct enter_usb_data *data = state->data; + struct altmode_req req = { }; + u8 cable_speed; + + req.usage = PMC_USB_ALT_MODE; + req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT; + req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT; + + /* USB4 Mode */ + req.mode_data = PMC_USB_ALTMODE_FORCE_LSR; + + if (data->active_link_training) + req.mode_data |= PMC_USB_ALTMODE_ACTIVE_LINK; + + req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT; + req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT; + + switch ((data->eudo & EUDO_CABLE_TYPE_MASK) >> EUDO_CABLE_TYPE_SHIFT) { + case EUDO_CABLE_TYPE_PASSIVE: + break; + case EUDO_CABLE_TYPE_OPTICAL: + req.mode_data |= PMC_USB_ALTMODE_CABLE_TYPE; + fallthrough; + default: + req.mode_data |= PMC_USB_ALTMODE_ACTIVE_CABLE; + break; + } + + cable_speed = (data->eudo & EUDO_CABLE_SPEED_MASK) >> EUDO_CABLE_SPEED_SHIFT; + req.mode_data |= PMC_USB_ALTMODE_CABLE_SPD(cable_speed); + + return pmc_usb_command(port, (void *)&req, sizeof(req)); +} + static int pmc_usb_mux_safe_state(struct pmc_usb_port *port) { u8 msg; @@ -268,17 +310,31 @@ pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state) { struct pmc_usb_port *port = typec_mux_get_drvdata(mux); - if (!state->alt) + if (port->orientation == TYPEC_ORIENTATION_NONE || port->role == USB_ROLE_NONE) return 0; if (state->mode == TYPEC_STATE_SAFE) return pmc_usb_mux_safe_state(port); - - switch (state->alt->svid) { - case USB_TYPEC_TBT_SID: - return pmc_usb_mux_tbt(port, state); - case USB_TYPEC_DP_SID: - return pmc_usb_mux_dp(port, state); + if (state->mode == TYPEC_STATE_USB) + return pmc_usb_connect(port); + + if (state->alt) { + switch (state->alt->svid) { + case USB_TYPEC_TBT_SID: + return pmc_usb_mux_tbt(port, state); + case USB_TYPEC_DP_SID: + return pmc_usb_mux_dp(port, state); + } + } else { + switch (state->mode) { + case TYPEC_MODE_USB2: + /* REVISIT: Try with usb3_port set to 0? */ + break; + case TYPEC_MODE_USB3: + return pmc_usb_connect(port); + case TYPEC_MODE_USB4: + return pmc_usb_mux_usb4(port, state); + } } return -EOPNOTSUPP; diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index b28facece43c4c68b9259c644528fb6c83d783d5..99562cc65ca697daaefe340d48564aa15fc1e7cc 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -178,6 +178,7 @@ static void _fusb302_log(struct fusb302_chip *chip, const char *fmt, mutex_unlock(&chip->logbuffer_lock); } +__printf(2, 3) static void fusb302_log(struct fusb302_chip *chip, const char *fmt, ...) { va_list args; diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index 753645bb25273a9babb9d4c97a13ecb67554798f..f57d91fd0e092454fc5df9dc807a3a2859f9bb65 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -227,6 +227,14 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable) enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0); } +static int tcpci_set_bist_data(struct tcpc_dev *tcpc, bool enable) +{ + struct tcpci *tcpci = tcpc_to_tcpci(tcpc); + + return regmap_update_bits(tcpci->regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_BIST_TM, + enable ? TCPC_TCPC_CTRL_BIST_TM : 0); +} + static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached, enum typec_role role, enum typec_data_role data) { @@ -530,6 +538,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx; tcpci->tcpc.set_roles = tcpci_set_roles; tcpci->tcpc.pd_transmit = tcpci_pd_transmit; + tcpci->tcpc.set_bist_data = tcpci_set_bist_data; err = tcpci_parse_config(tcpci); if (err < 0) diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h index 303ebde265465c05a82221886bf15c79df7b81c4..11c36d086c86086f3058bc1de3d35938fbd71225 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/drivers/usb/typec/tcpm/tcpci.h @@ -36,6 +36,7 @@ #define TCPC_TCPC_CTRL 0x19 #define TCPC_TCPC_CTRL_ORIENTATION BIT(0) +#define TCPC_TCPC_CTRL_BIST_TM BIT(1) #define TCPC_ROLE_CTRL 0x1a #define TCPC_ROLE_CTRL_DRP BIT(6) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 82b19ebd7838e0c129d3bcff33a80b0217d80940..3ef37202ee3757597b900dec25b34b823f7424b9 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -159,6 +159,14 @@ enum pd_msg_request { PD_MSG_DATA_SOURCE_CAP, }; +enum adev_actions { + ADEV_NONE = 0, + ADEV_NOTIFY_USB_AND_QUEUE_VDM, + ADEV_QUEUE_VDM, + ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL, + ADEV_ATTENTION, +}; + /* Events from low level driver */ #define TCPM_CC_EVENT BIT(0) @@ -961,24 +969,38 @@ static void tcpm_queue_message(struct tcpm_port *port, static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, const u32 *data, int cnt) { + WARN_ON(!mutex_is_locked(&port->lock)); + + /* Make sure we are not still processing a previous VDM packet */ + WARN_ON(port->vdm_state > VDM_STATE_DONE); + port->vdo_count = cnt + 1; port->vdo_data[0] = header; memcpy(&port->vdo_data[1], data, sizeof(u32) * cnt); /* Set ready, vdm state machine will actually send */ port->vdm_retries = 0; port->vdm_state = VDM_STATE_READY; + + mod_delayed_work(port->wq, &port->vdm_state_machine, 0); } -static void svdm_consume_identity(struct tcpm_port *port, const __le32 *payload, - int cnt) +static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header, + const u32 *data, int cnt) { - u32 vdo = le32_to_cpu(payload[VDO_INDEX_IDH]); - u32 product = le32_to_cpu(payload[VDO_INDEX_PRODUCT]); + mutex_lock(&port->lock); + tcpm_queue_vdm(port, header, data, cnt); + mutex_unlock(&port->lock); +} + +static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt) +{ + u32 vdo = p[VDO_INDEX_IDH]; + u32 product = p[VDO_INDEX_PRODUCT]; memset(&port->mode_data, 0, sizeof(port->mode_data)); port->partner_ident.id_header = vdo; - port->partner_ident.cert_stat = le32_to_cpu(payload[VDO_INDEX_CSTAT]); + port->partner_ident.cert_stat = p[VDO_INDEX_CSTAT]; port->partner_ident.product = product; typec_partner_set_identity(port->partner); @@ -988,17 +1010,15 @@ static void svdm_consume_identity(struct tcpm_port *port, const __le32 *payload, PD_PRODUCT_PID(product), product & 0xffff); } -static bool svdm_consume_svids(struct tcpm_port *port, const __le32 *payload, - int cnt) +static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt) { struct pd_mode_data *pmdata = &port->mode_data; int i; for (i = 1; i < cnt; i++) { - u32 p = le32_to_cpu(payload[i]); u16 svid; - svid = (p >> 16) & 0xffff; + svid = (p[i] >> 16) & 0xffff; if (!svid) return false; @@ -1008,7 +1028,7 @@ static bool svdm_consume_svids(struct tcpm_port *port, const __le32 *payload, pmdata->svids[pmdata->nsvids++] = svid; tcpm_log(port, "SVID %d: 0x%x", pmdata->nsvids, svid); - svid = p & 0xffff; + svid = p[i] & 0xffff; if (!svid) return false; @@ -1024,8 +1044,7 @@ static bool svdm_consume_svids(struct tcpm_port *port, const __le32 *payload, return false; } -static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload, - int cnt) +static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt) { struct pd_mode_data *pmdata = &port->mode_data; struct typec_altmode_desc *paltmode; @@ -1042,7 +1061,7 @@ static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload, paltmode->svid = pmdata->svids[pmdata->svid_index]; paltmode->mode = i; - paltmode->vdo = le32_to_cpu(payload[i]); + paltmode->vdo = p[i]; tcpm_log(port, " Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x", pmdata->altmodes, paltmode->svid, @@ -1061,30 +1080,28 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port) for (i = 0; i < modep->altmodes; i++) { altmode = typec_partner_register_altmode(port->partner, &modep->altmode_desc[i]); - if (!altmode) + if (IS_ERR(altmode)) { tcpm_log(port, "Failed to register partner SVID 0x%04x", modep->altmode_desc[i].svid); + altmode = NULL; + } port->partner_altmode[i] = altmode; } } #define supports_modal(port) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header) -static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, - u32 *response) +static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, + const u32 *p, int cnt, u32 *response, + enum adev_actions *adev_action) { - struct typec_altmode *adev; struct typec_altmode *pdev; struct pd_mode_data *modep; - u32 p[PD_MAX_PAYLOAD]; int rlen = 0; int cmd_type; int cmd; int i; - for (i = 0; i < cnt; i++) - p[i] = le32_to_cpu(payload[i]); - cmd_type = PD_VDO_CMDT(p[0]); cmd = PD_VDO_CMD(p[0]); @@ -1093,9 +1110,6 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, modep = &port->mode_data; - adev = typec_match_altmode(port->port_altmode, ALTMODE_DISCOVERY_MAX, - PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0])); - pdev = typec_match_altmode(port->partner_altmode, ALTMODE_DISCOVERY_MAX, PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0])); @@ -1121,8 +1135,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, break; case CMD_ATTENTION: /* Attention command does not have response */ - if (adev) - typec_altmode_attention(adev, p[1]); + *adev_action = ADEV_ATTENTION; return 0; default: break; @@ -1145,13 +1158,13 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, switch (cmd) { case CMD_DISCOVER_IDENT: /* 6.4.4.3.1 */ - svdm_consume_identity(port, payload, cnt); + svdm_consume_identity(port, p, cnt); response[0] = VDO(USB_SID_PD, 1, CMD_DISCOVER_SVID); rlen = 1; break; case CMD_DISCOVER_SVID: /* 6.4.4.3.2 */ - if (svdm_consume_svids(port, payload, cnt)) { + if (svdm_consume_svids(port, p, cnt)) { response[0] = VDO(USB_SID_PD, 1, CMD_DISCOVER_SVID); rlen = 1; @@ -1163,7 +1176,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, break; case CMD_DISCOVER_MODES: /* 6.4.4.3.3 */ - svdm_consume_modes(port, payload, cnt); + svdm_consume_modes(port, p, cnt); modep->svid_index++; if (modep->svid_index < modep->nsvids) { u16 svid = modep->svids[modep->svid_index]; @@ -1176,23 +1189,15 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, case CMD_ENTER_MODE: if (adev && pdev) { typec_altmode_update_active(pdev, true); - - if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) { - response[0] = VDO(adev->svid, 1, - CMD_EXIT_MODE); - response[0] |= VDO_OPOS(adev->mode); - return 1; - } + *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL; } return 0; case CMD_EXIT_MODE: if (adev && pdev) { typec_altmode_update_active(pdev, false); - /* Back to USB Operation */ - WARN_ON(typec_altmode_notify(adev, - TYPEC_STATE_USB, - NULL)); + *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM; + return 0; } break; default: @@ -1203,11 +1208,8 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, switch (cmd) { case CMD_ENTER_MODE: /* Back to USB Operation */ - if (adev) - WARN_ON(typec_altmode_notify(adev, - TYPEC_STATE_USB, - NULL)); - break; + *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM; + return 0; default: break; } @@ -1217,24 +1219,30 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, } /* Informing the alternate mode drivers about everything */ - if (adev) - typec_altmode_vdm(adev, p[0], &p[1], cnt); - + *adev_action = ADEV_QUEUE_VDM; return rlen; } static void tcpm_handle_vdm_request(struct tcpm_port *port, const __le32 *payload, int cnt) { - int rlen = 0; + enum adev_actions adev_action = ADEV_NONE; + struct typec_altmode *adev; + u32 p[PD_MAX_PAYLOAD]; u32 response[8] = { }; - u32 p0 = le32_to_cpu(payload[0]); + int i, rlen = 0; + + for (i = 0; i < cnt; i++) + p[i] = le32_to_cpu(payload[i]); + + adev = typec_match_altmode(port->port_altmode, ALTMODE_DISCOVERY_MAX, + PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0])); if (port->vdm_state == VDM_STATE_BUSY) { /* If UFP responded busy retry after timeout */ - if (PD_VDO_CMDT(p0) == CMDT_RSP_BUSY) { + if (PD_VDO_CMDT(p[0]) == CMDT_RSP_BUSY) { port->vdm_state = VDM_STATE_WAIT_RSP_BUSY; - port->vdo_retry = (p0 & ~VDO_CMDT_MASK) | + 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)); @@ -1243,13 +1251,65 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, port->vdm_state = VDM_STATE_DONE; } - if (PD_VDO_SVDM(p0)) - rlen = tcpm_pd_svdm(port, payload, cnt, response); + if (PD_VDO_SVDM(p[0])) + rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action); - if (rlen > 0) { - tcpm_queue_vdm(port, response[0], &response[1], rlen - 1); - mod_delayed_work(port->wq, &port->vdm_state_machine, 0); + /* + * We are done with any state stored in the port struct now, except + * for any port struct changes done by the tcpm_queue_vdm() call + * below, which is a separate operation. + * + * So we can safely release the lock here; and we MUST release the + * lock here to avoid an AB BA lock inversion: + * + * If we keep the lock here then the lock ordering in this path is: + * 1. tcpm_pd_rx_handler take the tcpm port lock + * 2. One of the typec_altmode_* calls below takes the alt-mode's lock + * + * And we also have this ordering: + * 1. alt-mode driver takes the alt-mode's lock + * 2. alt-mode driver calls tcpm_altmode_enter which takes the + * tcpm port lock + * + * Dropping our lock here avoids this. + */ + mutex_unlock(&port->lock); + + if (adev) { + switch (adev_action) { + case ADEV_NONE: + break; + case ADEV_NOTIFY_USB_AND_QUEUE_VDM: + WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL)); + typec_altmode_vdm(adev, p[0], &p[1], cnt); + break; + case ADEV_QUEUE_VDM: + typec_altmode_vdm(adev, p[0], &p[1], cnt); + break; + case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL: + if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) { + response[0] = VDO(adev->svid, 1, CMD_EXIT_MODE); + response[0] |= VDO_OPOS(adev->mode); + rlen = 1; + } + break; + case ADEV_ATTENTION: + typec_altmode_attention(adev, p[1]); + break; + } } + + /* + * We must re-take the lock here to balance the unlock in + * tcpm_pd_rx_handler, note that no changes, other then the + * tcpm_queue_vdm call, are made while the lock is held again. + * All that is done after the call is unwinding the call stack until + * we return to tcpm_pd_rx_handler and do the unlock there. + */ + mutex_lock(&port->lock); + + if (rlen > 0) + tcpm_queue_vdm(port, response[0], &response[1], rlen - 1); } static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd, @@ -1264,8 +1324,6 @@ static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd, header = VDO(vid, ((vid & USB_SID_PD) == USB_SID_PD) ? 1 : (PD_VDO_CMD(cmd) <= CMD_ATTENTION), cmd); tcpm_queue_vdm(port, header, data, count); - - mod_delayed_work(port->wq, &port->vdm_state_machine, 0); } static unsigned int vdm_ready_timeout(u32 vdm_hdr) @@ -1508,14 +1566,10 @@ static int tcpm_altmode_enter(struct typec_altmode *altmode, u32 *vdo) struct tcpm_port *port = typec_altmode_get_drvdata(altmode); u32 header; - mutex_lock(&port->lock); header = VDO(altmode->svid, vdo ? 2 : 1, CMD_ENTER_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm(port, header, vdo, vdo ? 1 : 0); - mod_delayed_work(port->wq, &port->vdm_state_machine, 0); - mutex_unlock(&port->lock); - + tcpm_queue_vdm_unlocked(port, header, vdo, vdo ? 1 : 0); return 0; } @@ -1524,14 +1578,10 @@ static int tcpm_altmode_exit(struct typec_altmode *altmode) struct tcpm_port *port = typec_altmode_get_drvdata(altmode); u32 header; - mutex_lock(&port->lock); header = VDO(altmode->svid, 1, CMD_EXIT_MODE); header |= VDO_OPOS(altmode->mode); - tcpm_queue_vdm(port, header, NULL, 0); - mod_delayed_work(port->wq, &port->vdm_state_machine, 0); - mutex_unlock(&port->lock); - + tcpm_queue_vdm_unlocked(port, header, NULL, 0); return 0; } @@ -1540,11 +1590,7 @@ static int tcpm_altmode_vdm(struct typec_altmode *altmode, { struct tcpm_port *port = typec_altmode_get_drvdata(altmode); - mutex_lock(&port->lock); - tcpm_queue_vdm(port, header, data, count - 1); - mod_delayed_work(port->wq, &port->vdm_state_machine, 0); - mutex_unlock(&port->lock); - + tcpm_queue_vdm_unlocked(port, header, data, count - 1); return 0; } @@ -2746,6 +2792,11 @@ static void tcpm_detach(struct tcpm_port *port) if (!port->attached) return; + if (port->tcpc->set_bist_data) { + tcpm_log(port, "disable BIST MODE TESTDATA"); + port->tcpc->set_bist_data(port->tcpc, false); + } + if (tcpm_port_is_disconnected(port)) port->hard_reset_count = 0; @@ -3554,12 +3605,18 @@ static void run_state_machine(struct tcpm_port *port) switch (BDO_MODE_MASK(port->bist_request)) { case BDO_MODE_CARRIER2: tcpm_pd_transmit(port, TCPC_TX_BIST_MODE_2, NULL); + tcpm_set_state(port, unattached_state(port), + PD_T_BIST_CONT_MODE); + break; + case BDO_MODE_TESTDATA: + if (port->tcpc->set_bist_data) { + tcpm_log(port, "Enable BIST MODE TESTDATA"); + port->tcpc->set_bist_data(port->tcpc, true); + } break; default: break; } - /* Always switch to unattached state */ - tcpm_set_state(port, unattached_state(port), 0); break; case GET_STATUS_SEND: tcpm_pd_send_control(port, PD_CTRL_GET_STATUS); @@ -3949,6 +4006,9 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) static void _tcpm_pd_hard_reset(struct tcpm_port *port) { tcpm_log_force(port, "Received hard reset"); + if (port->bist_request == BDO_MODE_TESTDATA && port->tcpc->set_bist_data) + port->tcpc->set_bist_data(port->tcpc, false); + /* * If we keep receiving hard reset requests, executing the hard reset * must have failed. Revert to error recovery if that happens. diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index b7c9fe5caabef1129f1502e03f0ec2f8780d3bd5..3db33bb622c387c35a4afcd31b534ff5ce891b85 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -100,7 +100,7 @@ struct tps6598x { /* * Max data bytes for Data1, Data2, and other registers. See ch 1.3.2: - * http://www.ti.com/lit/ug/slvuan1a/slvuan1a.pdf + * https://www.ti.com/lit/ug/slvuan1a/slvuan1a.pdf */ #define TPS_MAX_LEN 64 diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 15c2ac7db02d54b789e8a27f4c2b9e2e4078155b..2192d7c4fec7fc7bcb997a6fcd9a074fee95dcd1 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -18,7 +18,7 @@ config TYPEC_UCSI for every supported interface method. The UCSI specification can be downloaded from: - http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html + https://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html To compile the driver as a module, choose M here: the module will be called typec_ucsi. diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index d0c63afaf345d337ef87d62fb6837b793ac3fc0d..affd024190c9116cafb112e7bbc5c7d690cfdf0a 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1002,7 +1002,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) * * Registers all ports @ucsi has and enables all notification events. */ -int ucsi_init(struct ucsi *ucsi) +static int ucsi_init(struct ucsi *ucsi) { struct ucsi_connector *con; u64 command; @@ -1078,7 +1078,6 @@ int ucsi_init(struct ucsi *ucsi) return ret; } -EXPORT_SYMBOL_GPL(ucsi_init); static void ucsi_init_work(struct work_struct *work) { diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index e2b0195322340a7d4cce9f6d7e93992806fd4924..325c22008e5367980a79cc80b861a125cee3b99e 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -424,7 +424,7 @@ static void masking_bogus_flags(struct urb *urb) case USB_ENDPOINT_XFER_BULK: if (is_out) allowed |= URB_ZERO_PACKET; - /* FALLTHROUGH */ + fallthrough; default: /* all non-iso endpoints */ if (!is_out) allowed |= URB_SHORT_NOT_OK; diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 65850e9c719055218545d07505f9febe75810066..1b598db5d8b9ddb49e101fdcf62316bb0cbd4df7 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -508,7 +508,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_U1_TIMEOUT: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_U1_TIMEOUT\n"); - /* Fall through */ + fallthrough; case USB_PORT_FEAT_U2_TIMEOUT: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n"); @@ -561,7 +561,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, "supported for USB 2.0 roothub\n"); goto error; } - /* FALLS THROUGH */ + fallthrough; case USB_PORT_FEAT_RESET: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_RESET\n"); @@ -584,8 +584,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, /* 50msec reset signaling */ vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(50); - - /* FALLS THROUGH */ + fallthrough; default: usbip_dbg_vhci_rh(" SetPortFeature: default %d\n", wValue); diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index 00fc98741c5d1176bed0cc399a5e1e6e39a8cab5..266024cbb64fe7d82e6ae6ce2653cf92c3c1147c 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -27,7 +27,7 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) switch (status) { case -ENOENT: - /* fall through */ + fallthrough; case -ECONNRESET: dev_dbg(&urb->dev->dev, "urb seq# %u was unlinked %ssynchronously\n", diff --git a/drivers/usb/usbip/vudc_transfer.c b/drivers/usb/usbip/vudc_transfer.c index c9db846ee4f6f1e19efedf82f6365925dcf4e0d2..7e801fee33bfcf3703c6aacbd50f3c26fe4fef97 100644 --- a/drivers/usb/usbip/vudc_transfer.c +++ b/drivers/usb/usbip/vudc_transfer.c @@ -404,7 +404,7 @@ static void v_timer(struct timer_list *t) * for now, give unlimited bandwidth */ limit += urb->transfer_buffer_length; - /* fallthrough */ + fallthrough; default: treat_control_like_bulk: total -= transfer(udc, urb, ep, limit); @@ -479,7 +479,7 @@ void v_kick_timer(struct vudc *udc, unsigned long time) return; case VUDC_TR_IDLE: t->state = VUDC_TR_RUNNING; - /* fallthrough */ + fallthrough; case VUDC_TR_STOPPED: /* we may want to kick timer to unqueue urbs */ mod_timer(&t->timer, time); diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index ff397c0d5c07403bb0828ef8d7c6b3cc08b5dcd2..5db2b11ab0855c102fb20699dbb54c93d52c0664 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -504,8 +504,6 @@ struct tb_ring { #define RING_FLAG_NO_SUSPEND BIT(0) /* Configure the ring to be in frame mode */ #define RING_FLAG_FRAME BIT(1) -/* Enable end-to-end flow control */ -#define RING_FLAG_E2E BIT(2) struct ring_frame; typedef void (*ring_cb)(struct tb_ring *, struct ring_frame *, bool canceled); diff --git a/include/linux/usb.h b/include/linux/usb.h index 9f3c721c70dc16be937a039256d38438a14516e8..20c555db4621d58425cdd7cb559243af732bc357 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -341,7 +341,7 @@ struct usb_interface_cache { * @interface: array of pointers to usb_interface structures, one for each * interface in the configuration. The number of interfaces is stored * in desc.bNumInterfaces. These pointers are valid only while the - * the configuration is active. + * configuration is active. * @intf_cache: array of pointers to usb_interface_cache structures, one * for each interface in the configuration. These structures exist * for the entire life of the device. @@ -422,7 +422,7 @@ struct usb_devmap { * Allocated per bus (tree of devices) we have: */ struct usb_bus { - struct device *controller; /* host/master side hardware */ + struct device *controller; /* host side hardware */ struct device *sysdev; /* as seen from firmware or bus */ int busnum; /* Bus number (in order of reg) */ const char *bus_name; /* stable id (PCI slot_name etc) */ @@ -620,9 +620,9 @@ struct usb3_lpm_parameters { * Management to be disabled for this usb_device. This count should only * be manipulated by those functions, with the bandwidth_mutex is held. * @hub_delay: cached value consisting of: - * parent->hub_delay + wHubDelay + tTPTransmissionDelay (40ns) - * + * parent->hub_delay + wHubDelay + tTPTransmissionDelay (40ns) * Will be used as wValue for SetIsochDelay requests. + * @use_generic_driver: ask driver core to reprobe using the generic driver. * * Notes: * Usbcore drivers should not set usbdev->state directly. Instead use @@ -1215,6 +1215,7 @@ struct usb_driver { * struct usb_device_driver - identifies USB device driver to usbcore * @name: The driver name should be unique among USB drivers, * and should normally be the same as the module name. + * @match: If set, used for better device/driver matching. * @probe: Called to see if the driver is willing to manage a particular * device. If it is, probe returns zero and uses dev_set_drvdata() * to associate driver-specific data with the device. If unwilling @@ -1227,13 +1228,16 @@ struct usb_driver { * @dev_groups: Attributes attached to the device that will be created once it * is bound to the driver. * @drvwrap: Driver-model core structure wrapper. + * @id_table: used with @match() to select better matching driver at + * probe() time. * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend * for devices bound to this driver. * @generic_subclass: if set to 1, the generic USB driver's probe, disconnect, * resume and suspend functions will be called in addition to the driver's * own, so this part of the setup does not need to be replicated. * - * USB drivers must provide all the fields listed above except drvwrap. + * USB drivers must provide all the fields listed above except drvwrap, + * match, and id_table. */ struct usb_device_driver { const char *name; diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 58b83066bea4671721b6be040f0486fa9ef79240..604c6c514a5048b7d11a01600142e728a84f337e 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -6,13 +6,13 @@ * Wireless USB 1.0 (spread around). Linux has several APIs in C that * need these: * - * - the master/host side Linux-USB kernel driver API; + * - the host side Linux-USB kernel driver API; * - the "usbfs" user space API; and - * - the Linux "gadget" slave/device/peripheral side driver API. + * - the Linux "gadget" device/peripheral side driver API. * * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems - * act either as a USB master/host or as a USB slave/device. That means - * the master and slave side APIs benefit from working well together. + * act either as a USB host or as a USB device. That means the host and + * device side APIs benefit from working well together. * * There's also "Wireless USB", using low power short range radios for * peripheral interconnection but otherwise building on the USB framework. diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 54167a2d28ea224bed8cad11e3bfd94df1d60586..025b41687ce968470db63e38b52abdb25eba54fa 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -99,5 +99,7 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, struct ci_hdrc_platform_data *platdata); /* Remove ci hdrc device */ void ci_hdrc_remove_device(struct platform_device *pdev); +/* Get current available role */ +enum usb_dr_mode ci_hdrc_query_available_role(struct platform_device *pdev); #endif diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 6a178177e4c9a714c4a1911dbc303aa29feb0171..52ce1f6b8f833404d702cc8cefef7773fb2a834f 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -4,7 +4,8 @@ * * We call the USB code inside a Linux-based peripheral device a "gadget" * driver, except for the hardware-specific bus glue. One USB host can - * master many USB gadgets, but the gadgets are only slaved to one host. + * talk to many USB gadgets, but the gadgets are only able to communicate + * to one host. * * * (C) Copyright 2002-2004 by David Brownell @@ -328,7 +329,7 @@ struct usb_gadget_ops { }; /** - * struct usb_gadget - represents a usb slave device + * struct usb_gadget - represents a usb device * @work: (internal use) Workqueue to be used for sysfs_notify() * @udc: struct usb_udc pointer for this gadget * @ops: Function pointers used to access hardware-specific operations. @@ -602,7 +603,7 @@ static inline int usb_gadget_activate(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ /** - * struct usb_gadget_driver - driver for usb 'slave' devices + * struct usb_gadget_driver - driver for usb gadget devices * @function: String describing the gadget's function * @max_speed: Highest speed the driver handles. * @setup: Invoked for ep0 control requests that aren't handled by @@ -730,7 +731,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver); * it will first disconnect(). The driver is also requested * to unbind() and clean up any device state, before this procedure * finally returns. It's expected that the unbind() functions - * will in in exit sections, so may not be linked in some kernels. + * will be in exit sections, so may not be linked in some kernels. */ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index a665d7f211424dce7963873d497eb87208514368..b6c233e79bd457fea84e48d92c8c2a6a1cc8af05 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -483,4 +483,5 @@ 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/linux/usb/pd_vdo.h b/include/linux/usb/pd_vdo.h index 35b8e15efaa0c7c2321b15cbff16f7ab52e50725..68bdc4e2f5a907831c7a548fd297ca3946ba7300 100644 --- a/include/linux/usb/pd_vdo.h +++ b/include/linux/usb/pd_vdo.h @@ -249,7 +249,7 @@ * SVDM Discover SVIDs request -> response * * Request is properly formatted VDM Header with discover SVIDs command. - * Response is a set of SVIDs of all all supported SVIDs with all zero's to + * Response is a set of SVIDs of all supported SVIDs with all zero's to * mark the end of SVIDs. If more than 12 SVIDs are supported command SHOULD be * repeated. */ diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h index 407f530061cdeff6917798a80da3876b4b7beed7..263196f05015bc46d1e2546b162a87df06b79651 100644 --- a/include/linux/usb/phy_companion.h +++ b/include/linux/usb/phy_companion.h @@ -2,7 +2,7 @@ /* * phy-companion.h -- phy companion to indicate the comparator part of PHY * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 22c1f579afe3020b22ed36a40523ab34c08a3292..5e4c497f54d6dc0645ddb223e2d8cbb7543401f7 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -69,7 +69,7 @@ /* Hub needs extra delay after resetting its port. */ #define USB_QUIRK_HUB_SLOW_RESET BIT(14) -/* device has blacklisted endpoints */ -#define USB_QUIRK_ENDPOINT_BLACKLIST BIT(15) +/* device has endpoints that should be ignored */ +#define USB_QUIRK_ENDPOINT_IGNORE BIT(15) #endif /* __LINUX_USB_QUIRKS_H */ diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 14cac4a1ae8f3bd25a93788a1d8cbb6a1cc06681..8e67eff9039fa893e64928090157048ff09ebede 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -17,7 +17,6 @@ #include <linux/kref.h> #include <linux/mutex.h> #include <linux/serial.h> -#include <linux/sysrq.h> #include <linux/kfifo.h> /* The maximum number of ports one device can grab at once */ @@ -213,7 +212,7 @@ struct usb_serial_endpoints { * Return 0 to continue on with the initialization sequence. Anything * else will abort it. * @attach: pointer to the driver's attach function. - * This will be called when the struct usb_serial structure is fully set + * This will be called when the struct usb_serial structure is fully * set up. Do any local initialization of the device, or any private * memory structure allocation at this point in time. * @disconnect: pointer to the driver's disconnect function. This will be @@ -316,19 +315,19 @@ struct usb_serial_driver { #define to_usb_serial_driver(d) \ container_of(d, struct usb_serial_driver, driver) -extern int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], +int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], const char *name, const struct usb_device_id *id_table); -extern void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]); -extern void usb_serial_port_softint(struct usb_serial_port *port); +void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]); +void usb_serial_port_softint(struct usb_serial_port *port); -extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message); -extern int usb_serial_resume(struct usb_interface *intf); +int usb_serial_suspend(struct usb_interface *intf, pm_message_t message); +int usb_serial_resume(struct usb_interface *intf); /* USB Serial console functions */ #ifdef CONFIG_USB_SERIAL_CONSOLE -extern void usb_serial_console_init(int minor); -extern void usb_serial_console_exit(void); -extern void usb_serial_console_disconnect(struct usb_serial *serial); +void usb_serial_console_init(int minor); +void usb_serial_console_exit(void); +void usb_serial_console_disconnect(struct usb_serial *serial); #else static inline void usb_serial_console_init(int minor) { } static inline void usb_serial_console_exit(void) { } @@ -336,45 +335,49 @@ static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} #endif /* Functions needed by other parts of the usbserial core */ -extern struct usb_serial_port *usb_serial_port_get_by_minor(unsigned int minor); -extern void usb_serial_put(struct usb_serial *serial); -extern int usb_serial_generic_open(struct tty_struct *tty, - struct usb_serial_port *port); -extern int usb_serial_generic_write_start(struct usb_serial_port *port, - gfp_t mem_flags); -extern int usb_serial_generic_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count); -extern void usb_serial_generic_close(struct usb_serial_port *port); -extern int usb_serial_generic_resume(struct usb_serial *serial); -extern int usb_serial_generic_write_room(struct tty_struct *tty); -extern int usb_serial_generic_chars_in_buffer(struct tty_struct *tty); -extern void usb_serial_generic_wait_until_sent(struct tty_struct *tty, - long timeout); -extern void usb_serial_generic_read_bulk_callback(struct urb *urb); -extern void usb_serial_generic_write_bulk_callback(struct urb *urb); -extern void usb_serial_generic_throttle(struct tty_struct *tty); -extern void usb_serial_generic_unthrottle(struct tty_struct *tty); -extern int usb_serial_generic_tiocmiwait(struct tty_struct *tty, - unsigned long arg); -extern int usb_serial_generic_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); -extern int usb_serial_generic_register(void); -extern void usb_serial_generic_deregister(void); -extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, - gfp_t mem_flags); -extern void usb_serial_generic_process_read_urb(struct urb *urb); -extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); -extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port, - unsigned int ch); -extern int usb_serial_handle_break(struct usb_serial_port *port); -extern void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, - struct tty_struct *tty, - unsigned int status); +struct usb_serial_port *usb_serial_port_get_by_minor(unsigned int minor); +void usb_serial_put(struct usb_serial *serial); +int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port); +int usb_serial_generic_write_start(struct usb_serial_port *port, gfp_t mem_flags); +int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +void usb_serial_generic_close(struct usb_serial_port *port); +int usb_serial_generic_resume(struct usb_serial *serial); +int usb_serial_generic_write_room(struct tty_struct *tty); +int usb_serial_generic_chars_in_buffer(struct tty_struct *tty); +void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout); +void usb_serial_generic_read_bulk_callback(struct urb *urb); +void usb_serial_generic_write_bulk_callback(struct urb *urb); +void usb_serial_generic_throttle(struct tty_struct *tty); +void usb_serial_generic_unthrottle(struct tty_struct *tty); +int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg); +int usb_serial_generic_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount); +int usb_serial_generic_register(void); +void usb_serial_generic_deregister(void); +int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, gfp_t mem_flags); +void usb_serial_generic_process_read_urb(struct urb *urb); +int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size); + +#if defined(CONFIG_USB_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch); +int usb_serial_handle_break(struct usb_serial_port *port); +#else +static inline int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) +{ + return 0; +} +static inline int usb_serial_handle_break(struct usb_serial_port *port) +{ + return 0; +} +#endif + +void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, + struct tty_struct *tty, unsigned int status); -extern int usb_serial_bus_register(struct usb_serial_driver *device); -extern void usb_serial_bus_deregister(struct usb_serial_driver *device); +int usb_serial_bus_register(struct usb_serial_driver *device); +void usb_serial_bus_deregister(struct usb_serial_driver *device); extern struct bus_type usb_serial_bus_type; extern struct tty_driver *usb_serial_tty_driver; diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index e7979c01c3517cbf808ab9f3e0231f4be252a653..89f58760cf48003b895b3542d8c8070b36ee35be 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h @@ -79,6 +79,7 @@ enum tcpm_transmit_type { * @try_role: Optional; called to set a preferred role * @pd_transmit:Called to transmit PD message * @mux: Pointer to multiplexer data + * @set_bist_data: Turn on/off bist data mode for compliance testing */ struct tcpc_dev { struct fwnode_handle *fwnode; @@ -103,6 +104,7 @@ struct tcpc_dev { int (*try_role)(struct tcpc_dev *dev, int role); int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type, const struct pd_message *msg); + int (*set_bist_data)(struct tcpc_dev *dev, bool on); }; struct tcpm_port; diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index 5daa1c49761c3a2156558a468c00024caac891e8..9cb1bec94b7102fd0afd2dd722fad8637a0fab33 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -72,6 +72,20 @@ enum typec_orientation { TYPEC_ORIENTATION_REVERSE, }; +/* + * struct enter_usb_data - Enter_USB Message details + * @eudo: Enter_USB Data Object + * @active_link_training: Active Cable Plug Link Training + * + * @active_link_training is a flag that should be set with uni-directional SBRX + * communication, and left 0 with passive cables and with bi-directional SBRX + * communication. + */ +struct enter_usb_data { + u32 eudo; + unsigned char active_link_training:1; +}; + /* * struct usb_pd_identity - USB Power Delivery identity data * @id_header: ID Header VDO diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h index d834e236c6df63d67ba2533132f7e1fe7e335db3..a4b65eaa0f6236ffea29161ab477f05080fa4598 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -95,13 +95,7 @@ enum { * * Port drivers can use TYPEC_MODE_AUDIO and TYPEC_MODE_DEBUG as the mode * value for typec_set_mode() when accessory modes are supported. - */ -enum { - TYPEC_MODE_AUDIO = TYPEC_STATE_MODAL, /* Audio Accessory */ - TYPEC_MODE_DEBUG, /* Debug Accessory */ -}; - -/* + * * USB4 also requires that the pins on the connector are repurposed, just like * Alternate Modes. USB4 mode is however not entered with the Enter Mode Command * like the Alternate Modes are, but instead with a special Enter_USB Message. @@ -112,9 +106,11 @@ enum { * state values, just like the Accessory Modes. */ enum { - TYPEC_MODE_USB2 = TYPEC_MODE_DEBUG, /* USB 2.0 mode */ + TYPEC_MODE_USB2 = TYPEC_STATE_MODAL, /* USB 2.0 mode */ TYPEC_MODE_USB3, /* USB 3.2 mode */ - TYPEC_MODE_USB4 /* USB4 mode */ + TYPEC_MODE_USB4, /* USB4 mode */ + TYPEC_MODE_AUDIO, /* Audio Accessory */ + TYPEC_MODE_DEBUG, /* Debug Accessory */ }; #define TYPEC_MODAL_STATE(_state_) ((_state_) + TYPEC_STATE_MODAL) diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index 2b623f36af6bc960738ab2c5c4923b5cd3c8f7a6..48766fdf65801875863cdcb5443b65876924ab82 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -138,11 +138,11 @@ * Test Mode Selectors * See USB 2.0 spec Table 9-7 */ -#define TEST_J 1 -#define TEST_K 2 -#define TEST_SE0_NAK 3 -#define TEST_PACKET 4 -#define TEST_FORCE_EN 5 +#define USB_TEST_J 1 +#define USB_TEST_K 2 +#define USB_TEST_SE0_NAK 3 +#define USB_TEST_PACKET 4 +#define USB_TEST_FORCE_ENABLE 5 /* Status Type */ #define USB_STATUS_TYPE_STANDARD 0 @@ -326,6 +326,10 @@ struct usb_device_descriptor { #define USB_CLASS_CONTENT_SEC 0x0d /* content security */ #define USB_CLASS_VIDEO 0x0e #define USB_CLASS_WIRELESS_CONTROLLER 0xe0 +#define USB_CLASS_PERSONAL_HEALTHCARE 0x0f +#define USB_CLASS_AUDIO_VIDEO 0x10 +#define USB_CLASS_BILLBOARD 0x11 +#define USB_CLASS_USB_TYPE_C_BRIDGE 0x12 #define USB_CLASS_MISC 0xef #define USB_CLASS_APP_SPEC 0xfe #define USB_CLASS_VENDOR_SPEC 0xff @@ -364,6 +368,9 @@ struct usb_config_descriptor { /*-------------------------------------------------------------------------*/ +/* USB String descriptors can contain at most 126 characters. */ +#define USB_MAX_STRING_LEN 126 + /* USB_DT_STRING: String descriptor */ struct usb_string_descriptor { __u8 bLength; diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8 index a6097be25d28f6624ff373032e1fcc219490abc6..a15d20063b98f2f07441b0d53272d4b76658178e 100644 --- a/tools/usb/usbip/doc/usbip.8 +++ b/tools/usb/usbip/doc/usbip.8 @@ -83,7 +83,9 @@ List local USB devices. .SH EXAMPLES client:# usbip list --remote=server - - List exportable usb devices on the server. + - List devices exported by remote server. + + client:# modprobe vhci-hcd client:# usbip attach --remote=server --busid=1-2 - Connect the remote USB device. diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8 index ac4635db3f0368ded92f66a4c1a815d58057c9e2..fb62a756893bfa57682aaa0a81063e1b81d17d49 100644 --- a/tools/usb/usbip/doc/usbipd.8 +++ b/tools/usb/usbip/doc/usbipd.8 @@ -73,7 +73,7 @@ USB/IP client can connect and use exported devices. .SH EXAMPLES - server:# modprobe usbip + server:# modprobe usbip-host server:# usbipd -D - Start usbip daemon. diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c index d1d8ba2a4a40c71b2b39a7dc3c7572193e61f0c4..ca78aa368476207c5a93196ea45da46c649e94f4 100644 --- a/tools/usb/usbip/libsrc/usbip_host_common.c +++ b/tools/usb/usbip/libsrc/usbip_host_common.c @@ -23,7 +23,7 @@ #include "list.h" #include "sysfs_utils.h" -struct udev *udev_context; +extern struct udev *udev_context; static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) { diff --git a/tools/usb/usbip/vudc/vudc_server_example.sh b/tools/usb/usbip/vudc/vudc_server_example.sh index 2736be64f203bc197caf8cb7e8736492783ce51d..fed53f51ee01657a17a7438ad3424ac3253018ac 100755 --- a/tools/usb/usbip/vudc/vudc_server_example.sh +++ b/tools/usb/usbip/vudc/vudc_server_example.sh @@ -24,7 +24,7 @@ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # -# For more information, please refer to <http://unlicense.org/> +# For more information, please refer to <https://unlicense.org/> ################################################################################ ################################################################################