From 5f0337b549e97fda07ccf48b9eebcee983c255bf Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 20 Nov 2017 17:40:15 +0000 Subject: USB: serial: iuu_phoenix: remove redundant assignment of DIV to itself The assignment of DIV to itself is redundant and can be removed. Signed-off-by: Colin Ian King Signed-off-by: Johan Hovold --- drivers/usb/serial/iuu_phoenix.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 397a8012ffa3..62c91e360baf 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -472,7 +472,6 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) } } P2 = ((P - PO) / 2) - 4; - DIV = DIV; PUMP = 0x04; PBmsb = (P2 >> 8 & 0x03); PBlsb = P2 & 0xFF; -- cgit v1.2.3 From d8a42b1ff8a3755cc710785c7e4b5e59636399ca Mon Sep 17 00:00:00 2001 From: Gimcuan Hui Date: Mon, 27 Nov 2017 15:36:51 +0000 Subject: USB: serial: ark3116: clean up return values of register accessors write_reg returns 0 on success, we can make it more explicit by returning number 0 instead of result variable. read_reg should return 0 on success since this is a more common pattern. The user of read_reg has been clean-up and should be at the same commit. Signed-off-by: Gimcuan Hui Signed-off-by: Johan Hovold --- drivers/usb/serial/ark3116.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 3c544782f60b..23d46ef87d64 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -83,7 +83,10 @@ static int ark3116_write_reg(struct usb_serial *serial, usb_sndctrlpipe(serial->dev, 0), 0xfe, 0x40, val, reg, NULL, 0, ARK_TIMEOUT); - return result; + if (result) + return result; + + return 0; } static int ark3116_read_reg(struct usb_serial *serial, @@ -105,7 +108,7 @@ static int ark3116_read_reg(struct usb_serial *serial, return result; } - return buf[0]; + return 0; } static inline int calc_divisor(int bps) @@ -355,13 +358,13 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) /* read modem status */ result = ark3116_read_reg(serial, UART_MSR, buf); - if (result < 0) + if (result) goto err_close; priv->msr = *buf; /* read line status */ result = ark3116_read_reg(serial, UART_LSR, buf); - if (result < 0) + if (result) goto err_close; priv->lsr = *buf; -- cgit v1.2.3 From 2124c8881eef4549d6b070a2aef3770cccaa5bd2 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 7 Nov 2017 03:58:29 -0500 Subject: usb: core: lower log level when device is not able to deal with string USB devices should work just fine when they don't support language id. Lower the log level so user won't panic in the future. BugLink: https://bugs.launchpad.net/bugs/1729618 Signed-off-by: Kai-Heng Feng Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 77001bcfc504..5a8ab77bc367 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -776,7 +776,7 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) * deal with strings at all. Set string_langid to -1 in order to * prevent any string to be retrieved from the device */ if (err < 0) { - dev_err(&dev->dev, "string descriptor 0 read error: %d\n", + dev_info(&dev->dev, "string descriptor 0 read error: %d\n", err); dev->string_langid = -1; return -EPIPE; -- cgit v1.2.3 From 8a4821d0619ef6cf6b0fbfa466a213728d55b83b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 8 Nov 2017 13:46:36 +0000 Subject: USB: host: whci: remove redundant variable t Variable t is assigned but never read, it is redundant and therefore can be removed. Cleans up clang warning: drivers/usb/host/whci/asl.c:106:3: warning: Value stored to 't' is never read Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/whci/asl.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index c5ac9efb076a..276fb34c8efd 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c @@ -90,9 +90,7 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) while (qset->ntds) { struct whc_qtd *td; - int t; - t = qset->td_start; td = &qset->qtd[qset->td_start]; status = le32_to_cpu(td->status); -- cgit v1.2.3 From 81d8a8eb0a975e151cdbd14f90516a8147d35ee2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 22 Nov 2017 19:39:53 +0000 Subject: USB: usbip: fix spelling mistake: "synchronuously" -> "synchronously" Trivial fix to spelling mistake in error message text Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index 90577e8b2282..a9813f1d507d 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -31,7 +31,7 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) /* fall through */ case -ECONNRESET: dev_info(&urb->dev->dev, - "urb %p was unlinked %ssynchronuously.\n", urb, + "urb %p was unlinked %ssynchronously.\n", urb, status == -ENOENT ? "" : "a"); break; case -EINPROGRESS: -- cgit v1.2.3 From cf140a3569714be6db8f3db56ba68c8554c108c9 Mon Sep 17 00:00:00 2001 From: Mats Karrman Date: Fri, 24 Nov 2017 00:03:16 +0100 Subject: typec: fusb302: Use dev_err during probe If probe fails, fusb302_debugfs_exit is called making it impossible to view any logs so use normal dev_err for any error messages during probe. Signed-off-by: Mats Karrman Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/fusb302/fusb302.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c index 72cb060b3fca..4ce1df248c2f 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/fusb302/fusb302.c @@ -1731,24 +1731,24 @@ static int init_gpio(struct fusb302_chip *chip) chip->gpio_int_n = of_get_named_gpio(node, "fcs,int_n", 0); if (!gpio_is_valid(chip->gpio_int_n)) { ret = chip->gpio_int_n; - fusb302_log(chip, "cannot get named GPIO Int_N, ret=%d", ret); + dev_err(chip->dev, "cannot get named GPIO Int_N, ret=%d", ret); return ret; } ret = devm_gpio_request(chip->dev, chip->gpio_int_n, "fcs,int_n"); if (ret < 0) { - fusb302_log(chip, "cannot request GPIO Int_N, ret=%d", ret); + dev_err(chip->dev, "cannot request GPIO Int_N, ret=%d", ret); return ret; } ret = gpio_direction_input(chip->gpio_int_n); if (ret < 0) { - fusb302_log(chip, - "cannot set GPIO Int_N to input, ret=%d", ret); + dev_err(chip->dev, + "cannot set GPIO Int_N to input, ret=%d", ret); return ret; } ret = gpio_to_irq(chip->gpio_int_n); if (ret < 0) { - fusb302_log(chip, - "cannot request IRQ for GPIO Int_N, ret=%d", ret); + dev_err(chip->dev, + "cannot request IRQ for GPIO Int_N, ret=%d", ret); return ret; } chip->gpio_int_n_irq = ret; @@ -1845,7 +1845,7 @@ static int fusb302_probe(struct i2c_client *client, chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev); if (IS_ERR(chip->tcpm_port)) { ret = PTR_ERR(chip->tcpm_port); - fusb302_log(chip, "cannot register tcpm port, ret=%d", ret); + dev_err(dev, "cannot register tcpm port, ret=%d", ret); goto destroy_workqueue; } @@ -1854,8 +1854,7 @@ static int fusb302_probe(struct i2c_client *client, IRQF_ONESHOT | IRQF_TRIGGER_LOW, "fsc_interrupt_int_n", chip); if (ret < 0) { - fusb302_log(chip, - "cannot request IRQ for GPIO Int_N, ret=%d", ret); + dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); goto tcpm_unregister_port; } enable_irq_wake(chip->gpio_int_n_irq); -- cgit v1.2.3 From ab69f61321140ff632d560775bc226259a78dfa2 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 21 Nov 2017 14:12:12 +0000 Subject: typec: tcpm: fusb302: Resolve out of order messaging events The expectation in the FUSB302 driver is that a TX_SUCCESS event should occur after a message has been sent, but before a GCRCSENT event is raised to indicate successful receipt of a message from the partner. However in some circumstances it is possible to see the hardware raise a GCRCSENT event before a TX_SUCCESS event is raised. The upshot of this is that the GCRCSENT handling portion of code ends up reporting the GoodCRC message to TCPM because the TX_SUCCESS event hasn't yet arrived to trigger a consumption of it. When TX_SUCCESS is then raised by the chip it ends up consuming the actual message that was meant for TCPM, and this incorrect sequence results in a hard reset from TCPM. To avoid this problem, this commit updates the message reading code to check whether a GoodCRC message was received or not. Based on this check it will either report that the previous transmission has completed or it will pass the msg data to TCPM for futher processing. This way the incorrect ordering of the events no longer matters. Signed-off-by: Adam Thomson Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/fusb302/fusb302.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c index 4ce1df248c2f..1877edef6584 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/fusb302/fusb302.c @@ -1543,6 +1543,21 @@ static int fusb302_pd_read_message(struct fusb302_chip *chip, fusb302_log(chip, "PD message header: %x", msg->header); fusb302_log(chip, "PD message len: %d", len); + /* + * Check if we've read off a GoodCRC message. If so then indicate to + * TCPM that the previous transmission has completed. Otherwise we pass + * the received message over to TCPM for processing. + * + * We make this check here instead of basing the reporting decision on + * the IRQ event type, as it's possible for the chip to report the + * TX_SUCCESS and GCRCSENT events out of order on occasion, so we need + * to check the message type to ensure correct reporting to TCPM. + */ + if ((!len) && (pd_header_type_le(msg->header) == PD_CTRL_GOOD_CRC)) + tcpm_pd_transmit_complete(chip->tcpm_port, TCPC_TX_SUCCESS); + else + tcpm_pd_receive(chip->tcpm_port, msg); + return ret; } @@ -1650,13 +1665,12 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) if (interrupta & FUSB_REG_INTERRUPTA_TX_SUCCESS) { fusb302_log(chip, "IRQ: PD tx success"); - /* read out the received good CRC */ ret = fusb302_pd_read_message(chip, &pd_msg); if (ret < 0) { - fusb302_log(chip, "cannot read in GCRC, ret=%d", ret); + fusb302_log(chip, + "cannot read in PD message, ret=%d", ret); goto done; } - tcpm_pd_transmit_complete(chip->tcpm_port, TCPC_TX_SUCCESS); } if (interrupta & FUSB_REG_INTERRUPTA_HARDRESET) { @@ -1677,7 +1691,6 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) "cannot read in PD message, ret=%d", ret); goto done; } - tcpm_pd_receive(chip->tcpm_port, &pd_msg); } done: mutex_unlock(&chip->lock); -- cgit v1.2.3 From 1a7e3948cb9f5bb9241112706267b8fbc7812c7a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 9 Nov 2017 18:07:21 +0100 Subject: USB: add device-tree support for interfaces Add OF device-tree support for USB interfaces. USB "interface nodes" are children of USB "device nodes" and are identified by an interface number and a configuration value: &usb1 { /* host controller */ dev1: device@1 { /* device at port 1 */ compatible = "usb1234,5678"; reg = <1>; #address-cells = <2>; #size-cells = <0>; interface@0,2 { /* interface 0 of configuration 2 */ compatible = "usbif1234,5678.config2.0"; reg = <0 2>; }; }; }; The configuration component is not included in the textual representation of an interface-node unit address for configuration 1: &dev1 { interface@0 { /* interface 0 of configuration 1 */ compatible = "usbif1234,5678.config1.0"; reg = <0 1>; }; }; When a USB device of class 0 or 9 (hub) has only a single configuration with a single interface, a special case "combined node" is used instead of a device node with an interface node: &usb1 { device@2 { compatible = "usb1234,abcd"; reg = <2>; }; }; Combined nodes are shared by the two device structures representing the USB device and its interface in the kernel's device model. Note that, as for device nodes, the compatible strings for interface nodes are currently not used. For more details see "Open Firmware Recommended Practice: Universal Serial Bus Version 1" and the binding documentation. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 18 ++++++++---- drivers/usb/core/of.c | 70 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 5a8ab77bc367..f836bae1e485 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -18,6 +18,7 @@ #include #include #include /* for usbcore internals */ +#include #include #include "usb.h" @@ -1583,6 +1584,7 @@ static void usb_release_interface(struct device *dev) kref_put(&intfc->ref, usb_release_interface_cache); usb_put_dev(interface_to_usbdev(intf)); + of_node_put(dev->of_node); kfree(intf); } @@ -1868,6 +1870,7 @@ free_interfaces: struct usb_interface_cache *intfc; struct usb_interface *intf; struct usb_host_interface *alt; + u8 ifnum; cp->interface[i] = intf = new_interfaces[i]; intfc = cp->intf_cache[i]; @@ -1886,11 +1889,17 @@ free_interfaces: if (!alt) alt = &intf->altsetting[0]; - intf->intf_assoc = - find_iad(dev, cp, alt->desc.bInterfaceNumber); + ifnum = alt->desc.bInterfaceNumber; + intf->intf_assoc = find_iad(dev, cp, ifnum); intf->cur_altsetting = alt; usb_enable_interface(dev, intf, true); intf->dev.parent = &dev->dev; + if (usb_of_has_combined_node(dev)) { + device_set_of_node_from_dev(&intf->dev, &dev->dev); + } else { + intf->dev.of_node = usb_of_get_interface_node(dev, + configuration, ifnum); + } intf->dev.driver = NULL; intf->dev.bus = &usb_bus_type; intf->dev.type = &usb_if_device_type; @@ -1905,9 +1914,8 @@ free_interfaces: intf->minor = -1; device_initialize(&intf->dev); pm_runtime_no_callbacks(&intf->dev); - dev_set_name(&intf->dev, "%d-%s:%d.%d", - dev->bus->busnum, dev->devpath, - configuration, alt->desc.bInterfaceNumber); + dev_set_name(&intf->dev, "%d-%s:%d.%d", dev->bus->busnum, + dev->devpath, configuration, ifnum); usb_get_dev(dev); } kfree(new_interfaces); diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index 2be968353257..074fabc26d6c 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -3,7 +3,8 @@ * of.c The helpers for hcd device tree support * * Copyright (C) 2016 Freescale Semiconductor, Inc. - * Author: Peter Chen + * Author: Peter Chen + * Copyright (C) 2017 Johan Hovold */ #include @@ -37,6 +38,73 @@ struct device_node *usb_of_get_child_node(struct device_node *parent, } EXPORT_SYMBOL_GPL(usb_of_get_child_node); +/** + * usb_of_has_combined_node() - determine whether a device has a combined node + * @udev: USB device + * + * 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: + * + * 1) bDeviceClass is 0 or 9, and + * 2) bNumConfigurations is 1, and + * 3) bNumInterfaces is 1. + * + * Return: True iff the device has a device node and its descriptors match the + * criteria for a combined node. + */ +bool usb_of_has_combined_node(struct usb_device *udev) +{ + struct usb_device_descriptor *ddesc = &udev->descriptor; + struct usb_config_descriptor *cdesc; + + if (!udev->dev.of_node) + return false; + + switch (ddesc->bDeviceClass) { + case USB_CLASS_PER_INTERFACE: + case USB_CLASS_HUB: + if (ddesc->bNumConfigurations == 1) { + cdesc = &udev->config->desc; + if (cdesc->bNumInterfaces == 1) + return true; + } + } + + return false; +} +EXPORT_SYMBOL_GPL(usb_of_has_combined_node); + +/** + * usb_of_get_interface_node() - get a USB interface node + * @udev: USB device of interface + * @config: configuration value + * @ifnum: interface number + * + * Look up the node of a USB interface given its USB device, configuration + * value and interface number. + * + * Return: A pointer to the node with incremented refcount if found, or + * %NULL otherwise. + */ +struct device_node * +usb_of_get_interface_node(struct usb_device *udev, u8 config, u8 ifnum) +{ + struct device_node *node; + u32 reg[2]; + + for_each_child_of_node(udev->dev.of_node, node) { + if (of_property_read_u32_array(node, "reg", reg, 2)) + continue; + + if (reg[0] == ifnum && reg[1] == config) + return node; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(usb_of_get_interface_node); + /** * usb_of_get_companion_dev - Find the companion device * @dev: the device pointer to find a companion -- cgit v1.2.3 From 03310a15484ab6a8f6d91bbf7fe486b17275c09a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 9 Nov 2017 18:07:22 +0100 Subject: USB: ledtrig-usbport: fix of-node leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code looks up a USB device node from a given parent USB device but never dropped its reference to the returned node. As only the address of the node is used for a later matching, the reference can be dropped immediately. Note that this trigger implementation confuses the description of the USB device connected to a port with the port itself (which does not have a device-tree representation). Fixes: 4f04c210d031 ("usb: core: read USB ports from DT in the usbport LED trigger driver") Cc: Rafał Miłecki Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/ledtrig-usbport.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index 9dbb429cd471..f1fde5165068 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -137,11 +137,17 @@ static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data, if (!led_np) return false; - /* Get node of port being added */ + /* + * Get node of port being added + * + * FIXME: This is really the device node of the connected device + */ port_np = usb_of_get_child_node(usb_dev->dev.of_node, port1); if (!port_np) return false; + of_node_put(port_np); + /* Amount of trigger sources for this LED */ count = of_count_phandle_with_args(led_np, "trigger-sources", "#trigger-source-cells"); -- cgit v1.2.3 From 7739376eb1ed68593805e5b4ed359123d0718549 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 9 Nov 2017 18:07:23 +0100 Subject: USB: of: clean up device-node helper Clean up the USB device-node helper that is used to look up a device node given a parent hub device and a port number. Also pass in a struct usb_device as first argument to provide some type checking. Give the helper the more descriptive name usb_of_get_device_node(), which matches the new usb_of_get_interface_node() helper that is used to look up a second type of of child node from a USB device. Note that the terms "device node" and "interface node" are defined and used by the OF Recommended Practice for USB. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/ledtrig-usbport.c | 2 +- drivers/usb/core/of.c | 27 ++++++++++++++------------- drivers/usb/core/usb.c | 3 +-- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index f1fde5165068..d775ffea20c3 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -142,7 +142,7 @@ static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data, * * FIXME: This is really the device node of the connected device */ - port_np = usb_of_get_child_node(usb_dev->dev.of_node, port1); + port_np = usb_of_get_device_node(usb_dev, port1); if (!port_np) return false; diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index 074fabc26d6c..fd77442c2d12 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -12,31 +12,32 @@ #include /** - * usb_of_get_child_node - Find the device node match port number - * @parent: the parent device node - * @portnum: the port number which device is connecting + * usb_of_get_device_node() - get a USB device node + * @hub: hub to which device is connected + * @port1: one-based index of port * - * Find the node from device tree according to its port number. + * Look up the node of a USB device given its parent hub device and one-based + * port number. * * Return: A pointer to the node with incremented refcount if found, or * %NULL otherwise. */ -struct device_node *usb_of_get_child_node(struct device_node *parent, - int portnum) +struct device_node *usb_of_get_device_node(struct usb_device *hub, int port1) { struct device_node *node; - u32 port; + u32 reg; - for_each_child_of_node(parent, node) { - if (!of_property_read_u32(node, "reg", &port)) { - if (port == portnum) - return node; - } + for_each_child_of_node(hub->dev.of_node, node) { + if (of_property_read_u32(node, "reg", ®)) + continue; + + if (reg == port1) + return node; } return NULL; } -EXPORT_SYMBOL_GPL(usb_of_get_child_node); +EXPORT_SYMBOL_GPL(usb_of_get_device_node); /** * usb_of_has_combined_node() - determine whether a device has a combined node diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 845286f08ab0..2f5fbc56a9dd 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -645,8 +645,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, raw_port = usb_hcd_find_raw_port_number(usb_hcd, port1); } - dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node, - raw_port); + dev->dev.of_node = usb_of_get_device_node(parent, raw_port); /* hub driver sets up TT records */ } -- cgit v1.2.3 From 1ccc417e6c3201cc6fc72f48981271256bd53a5a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 5 Dec 2017 22:22:05 -0800 Subject: usb: core: Fix logging messages with spurious periods after newlines Using a period after a newline causes bad output. Miscellanea: o Coalesce formats too Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 8 ++++---- drivers/usb/core/hub.c | 17 +++++++---------- drivers/usb/core/message.c | 6 +++--- 3 files changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 64262a9a8829..d8d7377b5fb8 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -342,8 +342,8 @@ static int usb_probe_interface(struct device *dev) if (driver->disable_hub_initiated_lpm) { lpm_disable_error = usb_unlocked_disable_lpm(udev); if (lpm_disable_error) { - dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); + dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n", + __func__, driver->name); error = lpm_disable_error; goto err; } @@ -537,8 +537,8 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (driver->disable_hub_initiated_lpm) { lpm_disable_error = usb_unlocked_disable_lpm(udev); if (lpm_disable_error) { - dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); + dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n", + __func__, driver->name); return -ENOMEM; } } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7ccdd3d4db84..916bcd539afa 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1049,12 +1049,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) ret = hcd->driver->update_hub_device(hcd, hdev, &hub->tt, GFP_NOIO); if (ret < 0) { - dev_err(hub->intfdev, "Host not " - "accepting hub info " - "update.\n"); - dev_err(hub->intfdev, "LS/FS devices " - "and hubs may not work " - "under this hub\n."); + dev_err(hub->intfdev, + "Host not accepting hub info update\n"); + dev_err(hub->intfdev, + "LS/FS devices and hubs may not work under this hub\n"); } } hub_power_on(hub, true); @@ -3157,7 +3155,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) usb_set_usb2_hardware_lpm(udev, 0); if (usb_disable_ltm(udev)) { - dev_err(&udev->dev, "Failed to disable LTM before suspend\n."); + dev_err(&udev->dev, "Failed to disable LTM before suspend\n"); status = -ENOMEM; if (PMSG_IS_AUTO(msg)) goto err_ltm; @@ -5475,13 +5473,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) */ ret = usb_unlocked_disable_lpm(udev); if (ret) { - dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__); goto re_enumerate_no_bos; } ret = usb_disable_ltm(udev); if (ret) { - dev_err(&udev->dev, "%s Failed to disable LTM\n.", - __func__); + dev_err(&udev->dev, "%s Failed to disable LTM\n", __func__); goto re_enumerate_no_bos; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f836bae1e485..dac4adeec213 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1356,7 +1356,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * so that the xHCI driver can recalculate the U1/U2 timeouts. */ if (usb_disable_lpm(dev)) { - dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&iface->dev, "%s Failed to disable LPM\n", __func__); mutex_unlock(hcd->bandwidth_mutex); return -ENOMEM; } @@ -1500,7 +1500,7 @@ int usb_reset_configuration(struct usb_device *dev) * that the xHCI driver can recalculate the U1/U2 timeouts. */ if (usb_disable_lpm(dev)) { - dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&dev->dev, "%s Failed to disable LPM\n", __func__); mutex_unlock(hcd->bandwidth_mutex); return -ENOMEM; } @@ -1848,7 +1848,7 @@ free_interfaces: * timeouts. */ if (dev->actconfig && usb_disable_lpm(dev)) { - dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + dev_err(&dev->dev, "%s Failed to disable LPM\n", __func__); mutex_unlock(hcd->bandwidth_mutex); ret = -ENOMEM; goto free_interfaces; -- cgit v1.2.3 From fb345a66060d9631cf12e64af3cac037b6ae10d1 Mon Sep 17 00:00:00 2001 From: Pravin Shedge Date: Tue, 5 Dec 2017 07:34:55 +0530 Subject: usb: typec: remove duplicate includes These duplicate includes have been found with scripts/checkincludes.pl but they have been removed manually to avoid removing false positives. Signed-off-by: Pravin Shedge Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/fusb302/fusb302.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c index 1877edef6584..9ce4756adad6 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/fusb302/fusb302.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 52eccd230ba98ceb21d1327da7f26dc71d585f45 Mon Sep 17 00:00:00 2001 From: Mikhail Zaytsev Date: Thu, 30 Nov 2017 11:54:07 +0300 Subject: USB: storage: Remove obsolete "FIXME" The fix of "FIXME: Notify the subdrivers..." doesn't actually have any real effect. The "FIXME" changed to simple comment. Signed-off-by: Mikhail Zaytsev Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index a0c07e05a8f1..3eb934792465 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -211,8 +211,8 @@ int usb_stor_reset_resume(struct usb_interface *iface) usb_stor_report_bus_reset(us); /* - * FIXME: Notify the subdrivers that they need to reinitialize - * the device + * If any of the subdrivers implemented a reinitialization scheme, + * this is where the callback would be invoked. */ return 0; } @@ -243,8 +243,8 @@ int usb_stor_post_reset(struct usb_interface *iface) usb_stor_report_bus_reset(us); /* - * FIXME: Notify the subdrivers that they need to reinitialize - * the device + * If any of the subdrivers implemented a reinitialization scheme, + * this is where the callback would be invoked. */ mutex_unlock(&us->dev_mutex); -- cgit v1.2.3 From c0f3ed87fde812ee4511b650516f23e4bdf1642b Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 4 Dec 2017 14:05:45 +0200 Subject: usb: Don't print a warning if interface driver rebind is deferred at resume Interface drivers like btusb that don't support reset-resume will be rebound at resume if port was reset. Rebind is done during the pm_ops .complete callback when probe returns EPROBE_DEFER as default. Remove the "rebind failed: -517" message. Device probe will eventually take place later. [one-liner by Jerry Snitselaar posted in a mailing list question -Mathias] Suggested-by: Jerry Snitselaar Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d8d7377b5fb8..9792cedfc351 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1070,7 +1070,7 @@ static void usb_rebind_intf(struct usb_interface *intf) if (!intf->dev.power.is_prepared) { intf->needs_binding = 0; rc = device_attach(&intf->dev); - if (rc < 0) + if (rc < 0 && rc != -EPROBE_DEFER) dev_warn(&intf->dev, "rebind failed: %d\n", rc); } } -- cgit v1.2.3 From cb6a0db8fdc12433ed4281331de0c3923dc2807b Mon Sep 17 00:00:00 2001 From: Vasyl Gomonovych Date: Thu, 30 Nov 2017 23:05:24 +0100 Subject: usb: host: fotg210: Use dma_pool_zalloc Replacing dma_pool_alloc and memset with a single call to dma_pool_zalloc Signed-off-by: Vasyl Gomonovych Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fotg210-hcd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 62fc955085a1..f3e1e7df88a5 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -1865,11 +1865,9 @@ static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210, qh = kzalloc(sizeof(*qh), GFP_ATOMIC); if (!qh) goto done; - qh->hw = (struct fotg210_qh_hw *) - dma_pool_alloc(fotg210->qh_pool, flags, &dma); + qh->hw = dma_pool_zalloc(fotg210->qh_pool, flags, &dma); if (!qh->hw) goto fail; - memset(qh->hw, 0, sizeof(*qh->hw)); qh->qh_dma = dma; INIT_LIST_HEAD(&qh->qtd_list); @@ -4121,7 +4119,7 @@ static int itd_urb_transaction(struct fotg210_iso_stream *stream, } else { alloc_itd: spin_unlock_irqrestore(&fotg210->lock, flags); - itd = dma_pool_alloc(fotg210->itd_pool, mem_flags, + itd = dma_pool_zalloc(fotg210->itd_pool, mem_flags, &itd_dma); spin_lock_irqsave(&fotg210->lock, flags); if (!itd) { @@ -4131,7 +4129,6 @@ alloc_itd: } } - memset(itd, 0, sizeof(*itd)); itd->itd_dma = itd_dma; list_add(&itd->itd_list, &sched->td_list); } -- cgit v1.2.3 From 92335ad9e895d453707ff3d9896e252980c314c5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 29 Nov 2017 10:16:17 +0100 Subject: uas: Remove US_FL_NO_ATA_1X unusual device entries for Seagate devices Since commit 7fee72d5e8f1 ("uas: Always apply US_FL_NO_ATA_1X quirk to Seagate devices"), the US_FL_NO_ATA_1X is always set for Seagate devices, so the per device unusual_uas.h entries for Seagate devices can be removed. Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_uas.h | 63 --------------------------------------- 1 file changed, 63 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index d520374a824e..bf457b0f6a1f 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -38,20 +38,6 @@ UNUSUAL_DEV(0x0984, 0x0301, 0x0128, 0x0128, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_UAS), -/* https://bugzilla.kernel.org/show_bug.cgi?id=79511 */ -UNUSUAL_DEV(0x0bc2, 0x2312, 0x0000, 0x9999, - "Seagate", - "Expansion Desk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - -/* https://bbs.archlinux.org/viewtopic.php?id=183190 */ -UNUSUAL_DEV(0x0bc2, 0x3312, 0x0000, 0x9999, - "Seagate", - "Expansion Desk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - /* Reported-by: David Webb */ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, "Seagate", @@ -59,55 +45,6 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_LUNS), -/* Reported-by: Hans de Goede */ -UNUSUAL_DEV(0x0bc2, 0x3320, 0x0000, 0x9999, - "Seagate", - "Expansion Desk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - -/* Reported-by: Bogdan Mihalcea */ -UNUSUAL_DEV(0x0bc2, 0xa003, 0x0000, 0x9999, - "Seagate", - "Backup Plus", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - -/* Reported-by: Marcin Zajączkowski */ -UNUSUAL_DEV(0x0bc2, 0xa013, 0x0000, 0x9999, - "Seagate", - "Backup Plus", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - -/* Reported-by: Hans de Goede */ -UNUSUAL_DEV(0x0bc2, 0xa0a4, 0x0000, 0x9999, - "Seagate", - "Backup Plus Desk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - -/* https://bbs.archlinux.org/viewtopic.php?id=183190 */ -UNUSUAL_DEV(0x0bc2, 0xab20, 0x0000, 0x9999, - "Seagate", - "Backup+ BK", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - -/* https://bbs.archlinux.org/viewtopic.php?id=183190 */ -UNUSUAL_DEV(0x0bc2, 0xab21, 0x0000, 0x9999, - "Seagate", - "Backup+ BK", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - -/* Reported-by: G. Richard Bellamy */ -UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999, - "Seagate", - "BUP Fast HDD", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - /* Reported-by: Benjamin Tissoires */ UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, "Initio Corporation", -- cgit v1.2.3 From 4bda35a06560509a0f85c5963edb6b066795a69b Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Tue, 28 Nov 2017 12:52:24 +0800 Subject: usb: early: Correct the endpoint type value for bulk in endpoint This corrects the endpiont type value set to the DbC bulk in endpoint. The previous value doesn't cause any problems because that we now only use the bulk out endpoint. Set the hardware with the correct value any way. Signed-off-by: Lu Baolu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/early/xhci-dbc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 8a700b45b9a9..e15e896f356c 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -328,7 +328,7 @@ static void xdbc_mem_init(void) ep_in = (struct xdbc_ep_context *)&ctx->in; ep_in->ep_info1 = 0; - ep_in->ep_info2 = cpu_to_le32(EP_TYPE(BULK_OUT_EP) | MAX_PACKET(1024) | MAX_BURST(max_burst)); + ep_in->ep_info2 = cpu_to_le32(EP_TYPE(BULK_IN_EP) | MAX_PACKET(1024) | MAX_BURST(max_burst)); ep_in->deq = cpu_to_le64(xdbc.in_seg.dma | xdbc.in_ring.cycle_state); /* Set DbC context and info registers: */ -- cgit v1.2.3 From 5007e1b5db736e76360047a6974c5cf7beb2d40e Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Wed, 15 Nov 2017 17:01:55 -0800 Subject: typec: tcpm: Validate source and sink caps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The source and sink caps should follow the following rules. This patch validates whether the src_caps/snk_caps adheres to it. 6.4.1 Capabilities Message A Capabilities message (Source Capabilities message or Sink Capabilities message) shall have at least one Power Data Object for vSafe5V. The Capabilities message shall also contain the sending Port’s information followed by up to 6 additional Power Data Objects. Power Data Objects in a Capabilities message shall be sent in the following order: 1. The vSafe5V Fixed Supply Object shall always be the first object. 2. The remaining Fixed Supply Objects, if present, shall be sent in voltage order; lowest to highest. 3. The Battery Supply Objects, if present shall be sent in Minimum Voltage order; lowest to highest. 4. The Variable Supply (non-battery) Objects, if present, shall be sent in Minimum Voltage order; lowest to highest. Errors in source/sink_caps of the local port will prevent the port registration. Whereas, errors in source caps of partner device would only log them. Signed-off-by: Badhri Jagan Sridharan Acked-by: Heikki Krogerus Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm.c | 130 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 121 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c index c166fc77dfb8..8b637a4b474b 100644 --- a/drivers/usb/typec/tcpm.c +++ b/drivers/usb/typec/tcpm.c @@ -1247,6 +1247,100 @@ static void vdm_state_machine_work(struct work_struct *work) mutex_unlock(&port->lock); } +enum pdo_err { + PDO_NO_ERR, + PDO_ERR_NO_VSAFE5V, + PDO_ERR_VSAFE5V_NOT_FIRST, + PDO_ERR_PDO_TYPE_NOT_IN_ORDER, + PDO_ERR_FIXED_NOT_SORTED, + PDO_ERR_VARIABLE_BATT_NOT_SORTED, + PDO_ERR_DUPE_PDO, +}; + +static const char * const pdo_err_msg[] = { + [PDO_ERR_NO_VSAFE5V] = + " err: source/sink caps should atleast have vSafe5V", + [PDO_ERR_VSAFE5V_NOT_FIRST] = + " err: vSafe5V Fixed Supply Object Shall always be the first object", + [PDO_ERR_PDO_TYPE_NOT_IN_ORDER] = + " err: PDOs should be in the following order: Fixed; Battery; Variable", + [PDO_ERR_FIXED_NOT_SORTED] = + " err: Fixed supply pdos should be in increasing order of their fixed voltage", + [PDO_ERR_VARIABLE_BATT_NOT_SORTED] = + " err: Variable/Battery supply pdos should be in increasing order of their minimum voltage", + [PDO_ERR_DUPE_PDO] = + " err: Variable/Batt supply pdos cannot have same min/max voltage", +}; + +static enum pdo_err tcpm_caps_err(struct tcpm_port *port, const u32 *pdo, + unsigned int nr_pdo) +{ + unsigned int i; + + /* Should at least contain vSafe5v */ + if (nr_pdo < 1) + return PDO_ERR_NO_VSAFE5V; + + /* The vSafe5V Fixed Supply Object Shall always be the first object */ + if (pdo_type(pdo[0]) != PDO_TYPE_FIXED || + pdo_fixed_voltage(pdo[0]) != VSAFE5V) + return PDO_ERR_VSAFE5V_NOT_FIRST; + + for (i = 1; i < nr_pdo; i++) { + if (pdo_type(pdo[i]) < pdo_type(pdo[i - 1])) { + return PDO_ERR_PDO_TYPE_NOT_IN_ORDER; + } else if (pdo_type(pdo[i]) == pdo_type(pdo[i - 1])) { + enum pd_pdo_type type = pdo_type(pdo[i]); + + switch (type) { + /* + * The remaining Fixed Supply Objects, if + * present, shall be sent in voltage order; + * lowest to highest. + */ + case PDO_TYPE_FIXED: + if (pdo_fixed_voltage(pdo[i]) <= + pdo_fixed_voltage(pdo[i - 1])) + return PDO_ERR_FIXED_NOT_SORTED; + break; + /* + * The Battery Supply Objects and Variable + * supply, if present shall be sent in Minimum + * Voltage order; lowest to highest. + */ + case PDO_TYPE_VAR: + case PDO_TYPE_BATT: + if (pdo_min_voltage(pdo[i]) < + pdo_min_voltage(pdo[i - 1])) + return PDO_ERR_VARIABLE_BATT_NOT_SORTED; + else if ((pdo_min_voltage(pdo[i]) == + pdo_min_voltage(pdo[i - 1])) && + (pdo_max_voltage(pdo[i]) == + pdo_min_voltage(pdo[i - 1]))) + return PDO_ERR_DUPE_PDO; + break; + default: + tcpm_log_force(port, " Unknown pdo type"); + } + } + } + + return PDO_NO_ERR; +} + +static int tcpm_validate_caps(struct tcpm_port *port, const u32 *pdo, + unsigned int nr_pdo) +{ + enum pdo_err err_index = tcpm_caps_err(port, pdo, nr_pdo); + + if (err_index != PDO_NO_ERR) { + tcpm_log_force(port, " %s", pdo_err_msg[err_index]); + return -EINVAL; + } + + return 0; +} + /* * PD (data, control) command handling functions */ @@ -1269,6 +1363,9 @@ static void tcpm_pd_data_request(struct tcpm_port *port, tcpm_log_source_caps(port); + tcpm_validate_caps(port, port->source_caps, + port->nr_source_caps); + /* * This message may be received even if VBUS is not * present. This is quite unexpected; see USB PD @@ -3435,9 +3532,12 @@ static int tcpm_copy_vdos(u32 *dest_vdo, const u32 *src_vdo, return nr_vdo; } -void tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo) +int tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo, + unsigned int nr_pdo) { + if (tcpm_validate_caps(port, pdo, nr_pdo)) + return -EINVAL; + mutex_lock(&port->lock); port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, pdo, nr_pdo); switch (port->state) { @@ -3457,16 +3557,20 @@ void tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo, break; } mutex_unlock(&port->lock); + return 0; } EXPORT_SYMBOL_GPL(tcpm_update_source_capabilities); -void tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, - unsigned int nr_pdo, - unsigned int max_snk_mv, - unsigned int max_snk_ma, - unsigned int max_snk_mw, - unsigned int operating_snk_mw) +int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, + unsigned int nr_pdo, + unsigned int max_snk_mv, + unsigned int max_snk_ma, + unsigned int max_snk_mw, + unsigned int operating_snk_mw) { + if (tcpm_validate_caps(port, pdo, nr_pdo)) + return -EINVAL; + mutex_lock(&port->lock); port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, pdo, nr_pdo); port->max_snk_mv = max_snk_mv; @@ -3485,6 +3589,7 @@ void tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, break; } mutex_unlock(&port->lock); + return 0; } EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities); @@ -3520,7 +3625,15 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) init_completion(&port->tx_complete); init_completion(&port->swap_complete); + tcpm_debugfs_init(port); + if (tcpm_validate_caps(port, tcpc->config->src_pdo, + tcpc->config->nr_src_pdo) || + tcpm_validate_caps(port, tcpc->config->snk_pdo, + tcpc->config->nr_snk_pdo)) { + err = -EINVAL; + goto out_destroy_wq; + } port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcpc->config->src_pdo, tcpc->config->nr_src_pdo); port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo, @@ -3575,7 +3688,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) } } - tcpm_debugfs_init(port); mutex_lock(&port->lock); tcpm_init(port); mutex_unlock(&port->lock); -- cgit v1.2.3 From 57e6f0d7b8042cb0f2da61f280c56e5ac0db18e5 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Wed, 15 Nov 2017 17:01:56 -0800 Subject: typec: tcpm: Only request matching pdos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At present, TCPM code assumes that local device supports variable/batt pdos and always selects the pdo with highest possible power within the board limit. This assumption might not hold good for all devices. To overcome this, this patch makes TCPM only accept a source_pdo when there is a matching sink pdo. For Fixed pdos: The voltage should match between the incoming source_cap and the registered snk_pdo For Variable/Batt pdos: The incoming source_cap voltage range should fall within the registered snk_pdo's voltage range. Also, when the cap_mismatch bit is set, the max_power/current should be set to the max_current/power of the sink_pdo. This is according to: "If the Capability Mismatch bit is set to one The Maximum Operating Current/Power field may contain a value larger than the maximum current/power offered in the Source Capabilities message’s PDO as referenced by the Object position field. This enables the Sink to indicate that it requires more current/power than is being offered. If the Sink requires a different voltage this will be indicated by its Sink Capabilities message. Signed-off-by: Badhri Jagan Sridharan Acked-by: Heikki Krogerus Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm.c | 163 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 121 insertions(+), 42 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c index 8b637a4b474b..f4d563ee7690 100644 --- a/drivers/usb/typec/tcpm.c +++ b/drivers/usb/typec/tcpm.c @@ -252,6 +252,9 @@ struct tcpm_port { unsigned int nr_src_pdo; u32 snk_pdo[PDO_MAX_OBJECTS]; unsigned int nr_snk_pdo; + unsigned int nr_fixed; /* number of fixed sink PDOs */ + unsigned int nr_var; /* number of variable sink PDOs */ + unsigned int nr_batt; /* number of battery sink PDOs */ u32 snk_vdo[VDO_MAX_OBJECTS]; unsigned int nr_snk_vdo; @@ -1767,39 +1770,90 @@ static int tcpm_pd_check_request(struct tcpm_port *port) return 0; } -static int tcpm_pd_select_pdo(struct tcpm_port *port) +#define min_power(x, y) min(pdo_max_power(x), pdo_max_power(y)) +#define min_current(x, y) min(pdo_max_current(x), pdo_max_current(y)) + +static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo, + int *src_pdo) { - unsigned int i, max_mw = 0, max_mv = 0; + unsigned int i, j, max_mw = 0, max_mv = 0, mw = 0, mv = 0, ma = 0; int ret = -EINVAL; /* - * Select the source PDO providing the most power while staying within - * the board's voltage limits. Prefer PDO providing exp + * Select the source PDO providing the most power which has a + * matchig sink cap. */ for (i = 0; i < port->nr_source_caps; i++) { u32 pdo = port->source_caps[i]; enum pd_pdo_type type = pdo_type(pdo); - unsigned int mv, ma, mw; - if (type == PDO_TYPE_FIXED) - mv = pdo_fixed_voltage(pdo); - else - mv = pdo_min_voltage(pdo); - - if (type == PDO_TYPE_BATT) { - mw = pdo_max_power(pdo); - } else { - ma = min(pdo_max_current(pdo), - port->max_snk_ma); - mw = ma * mv / 1000; - } - - /* Perfer higher voltages if available */ - if ((mw > max_mw || (mw == max_mw && mv > max_mv)) && - mv <= port->max_snk_mv) { - ret = i; - max_mw = mw; - max_mv = mv; + if (type == PDO_TYPE_FIXED) { + for (j = 0; j < port->nr_fixed; j++) { + if (pdo_fixed_voltage(pdo) == + pdo_fixed_voltage(port->snk_pdo[j])) { + ma = min_current(pdo, port->snk_pdo[j]); + mv = pdo_fixed_voltage(pdo); + mw = ma * mv / 1000; + if (mw > max_mw || + (mw == max_mw && mv > max_mv)) { + ret = 0; + *src_pdo = i; + *sink_pdo = j; + max_mw = mw; + max_mv = mv; + } + /* There could only be one fixed pdo + * at a specific voltage level. + * So breaking here. + */ + break; + } + } + } else if (type == PDO_TYPE_BATT) { + for (j = port->nr_fixed; + j < port->nr_fixed + + port->nr_batt; + j++) { + if (pdo_min_voltage(pdo) >= + pdo_min_voltage(port->snk_pdo[j]) && + pdo_max_voltage(pdo) <= + pdo_max_voltage(port->snk_pdo[j])) { + mw = min_power(pdo, port->snk_pdo[j]); + mv = pdo_min_voltage(pdo); + if (mw > max_mw || + (mw == max_mw && mv > max_mv)) { + ret = 0; + *src_pdo = i; + *sink_pdo = j; + max_mw = mw; + max_mv = mv; + } + } + } + } else if (type == PDO_TYPE_VAR) { + for (j = port->nr_fixed + + port->nr_batt; + j < port->nr_fixed + + port->nr_batt + + port->nr_var; + j++) { + if (pdo_min_voltage(pdo) >= + pdo_min_voltage(port->snk_pdo[j]) && + pdo_max_voltage(pdo) <= + pdo_max_voltage(port->snk_pdo[j])) { + ma = min_current(pdo, port->snk_pdo[j]); + mv = pdo_min_voltage(pdo); + mw = ma * mv / 1000; + if (mw > max_mw || + (mw == max_mw && mv > max_mv)) { + ret = 0; + *src_pdo = i; + *sink_pdo = j; + max_mw = mw; + max_mv = mv; + } + } + } } } @@ -1811,13 +1865,14 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) unsigned int mv, ma, mw, flags; unsigned int max_ma, max_mw; enum pd_pdo_type type; - int index; - u32 pdo; + int src_pdo_index, snk_pdo_index; + u32 pdo, matching_snk_pdo; - index = tcpm_pd_select_pdo(port); - if (index < 0) + if (tcpm_pd_select_pdo(port, &snk_pdo_index, &src_pdo_index) < 0) return -EINVAL; - pdo = port->source_caps[index]; + + pdo = port->source_caps[src_pdo_index]; + matching_snk_pdo = port->snk_pdo[snk_pdo_index]; type = pdo_type(pdo); if (type == PDO_TYPE_FIXED) @@ -1825,26 +1880,28 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) else mv = pdo_min_voltage(pdo); - /* Select maximum available current within the board's power limit */ + /* Select maximum available current within the sink pdo's limit */ if (type == PDO_TYPE_BATT) { - mw = pdo_max_power(pdo); - ma = 1000 * min(mw, port->max_snk_mw) / mv; + mw = min_power(pdo, matching_snk_pdo); + ma = 1000 * mw / mv; } else { - ma = min(pdo_max_current(pdo), - 1000 * port->max_snk_mw / mv); + ma = min_current(pdo, matching_snk_pdo); + mw = ma * mv / 1000; } - ma = min(ma, port->max_snk_ma); flags = RDO_USB_COMM | RDO_NO_SUSPEND; /* Set mismatch bit if offered power is less than operating power */ - mw = ma * mv / 1000; max_ma = ma; max_mw = mw; if (mw < port->operating_snk_mw) { flags |= RDO_CAP_MISMATCH; - max_mw = port->operating_snk_mw; - max_ma = max_mw * 1000 / mv; + if (type == PDO_TYPE_BATT && + (pdo_max_power(matching_snk_pdo) > pdo_max_power(pdo))) + max_mw = pdo_max_power(matching_snk_pdo); + else if (pdo_max_current(matching_snk_pdo) > + pdo_max_current(pdo)) + max_ma = pdo_max_current(matching_snk_pdo); } tcpm_log(port, "cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d", @@ -1853,16 +1910,16 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo) port->polarity); if (type == PDO_TYPE_BATT) { - *rdo = RDO_BATT(index + 1, mw, max_mw, flags); + *rdo = RDO_BATT(src_pdo_index + 1, mw, max_mw, flags); tcpm_log(port, "Requesting PDO %d: %u mV, %u mW%s", - index, mv, mw, + src_pdo_index, mv, mw, flags & RDO_CAP_MISMATCH ? " [mismatch]" : ""); } else { - *rdo = RDO_FIXED(index + 1, ma, max_ma, flags); + *rdo = RDO_FIXED(src_pdo_index + 1, ma, max_ma, flags); tcpm_log(port, "Requesting PDO %d: %u mV, %u mA%s", - index, mv, ma, + src_pdo_index, mv, ma, flags & RDO_CAP_MISMATCH ? " [mismatch]" : ""); } @@ -3593,6 +3650,19 @@ int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo, } EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities); +static int nr_type_pdos(const u32 *pdo, unsigned int nr_pdo, + enum pd_pdo_type type) +{ + int count = 0; + int i; + + for (i = 0; i < nr_pdo; i++) { + if (pdo_type(pdo[i]) == type) + count++; + } + return count; +} + struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) { struct tcpm_port *port; @@ -3638,6 +3708,15 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpc->config->nr_src_pdo); port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo, tcpc->config->nr_snk_pdo); + port->nr_fixed = nr_type_pdos(port->snk_pdo, + port->nr_snk_pdo, + PDO_TYPE_FIXED); + port->nr_var = nr_type_pdos(port->snk_pdo, + port->nr_snk_pdo, + PDO_TYPE_VAR); + port->nr_batt = nr_type_pdos(port->snk_pdo, + port->nr_snk_pdo, + PDO_TYPE_BATT); port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcpc->config->snk_vdo, tcpc->config->nr_snk_vdo); -- cgit v1.2.3 From 78a0db2a61b0f59a2faa090df75fe722f25d27f1 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Fri, 8 Dec 2017 17:59:02 +0200 Subject: usb: xhci: remove unused variable last_freed_endpoint Fix the build warning about variable 'last_freed_endpoint' set but not used [-Wunused-but-set-variable] Signed-off-by: Corentin Labbe Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 2424d3020ca3..31e3e468f14e 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3363,7 +3363,6 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, unsigned int slot_id; struct xhci_virt_device *virt_dev; struct xhci_command *reset_device_cmd; - int last_freed_endpoint; struct xhci_slot_ctx *slot_ctx; int old_active_eps = 0; @@ -3478,7 +3477,6 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, } /* Everything but endpoint 0 is disabled, so free the rings. */ - last_freed_endpoint = 1; for (i = 1; i < 31; i++) { struct xhci_virt_ep *ep = &virt_dev->eps[i]; @@ -3493,7 +3491,6 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, if (ep->ring) { xhci_debugfs_remove_endpoint(xhci, virt_dev, i); xhci_free_endpoint_ring(xhci, virt_dev, i); - last_freed_endpoint = i; } if (!list_empty(&virt_dev->eps[i].bw_endpoint_list)) xhci_drop_ep_from_interval_table(xhci, -- cgit v1.2.3 From bed53019d9d811e06203914ef39cea44bfdad74a Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Fri, 8 Dec 2017 17:59:03 +0200 Subject: usb: xhci: remove unused variable ep Fix the build warning: variable 'ep' set but not used Signed-off-by: Corentin Labbe Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 31e3e468f14e..89ad7c057454 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2838,12 +2838,10 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, unsigned int stream_id, struct xhci_td *td) { struct xhci_dequeue_state deq_state; - struct xhci_virt_ep *ep; struct usb_device *udev = td->urb->dev; xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, "Cleaning up stalled endpoint ring"); - ep = &xhci->devs[udev->slot_id]->eps[ep_index]; /* We need to move the HW's dequeue pointer past this TD, * or it will attempt to resend it on the next doorbell ring. */ -- cgit v1.2.3 From ce5b2a6857cc674b1a8ebf9c4bce5851a84991ef Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Fri, 8 Dec 2017 17:59:04 +0200 Subject: usb: xhci: remove unused variable urb_priv Fix the build warning: variable 'urb_priv' set but not used Signed-off-by: Corentin Labbe Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c239c688076c..9a914b638b02 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1878,12 +1878,10 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, struct xhci_ring *ep_ring, int *status) { - struct urb_priv *urb_priv; struct urb *urb = NULL; /* Clean up the endpoint's TD list */ urb = td->urb; - urb_priv = urb->hcpriv; /* if a bounce buffer was used to align this td then unmap it */ xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); -- cgit v1.2.3 From 58e8a4dad3c06f568bbde585d04ae84b47ddba02 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Fri, 8 Dec 2017 17:59:05 +0200 Subject: usb: xhci: remove unused variable ep_ring Fix the build warning about variable 'ep_ring' set but not used [Minor commit message change -Mathias] Signed-off-by: Corentin Labbe Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9a914b638b02..6e555200e41b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1992,7 +1992,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, struct xhci_virt_ep *ep, int *status) { struct xhci_virt_device *xdev; - struct xhci_ring *ep_ring; unsigned int slot_id; int ep_index; struct xhci_ep_ctx *ep_ctx; @@ -2004,7 +2003,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); xdev = xhci->devs[slot_id]; ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); requested = td->urb->transfer_buffer_length; -- cgit v1.2.3 From 14d49b7a0bfe76ef694a61e0c7b5f091ea780b91 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 8 Dec 2017 17:59:07 +0200 Subject: xhci: add helper to allocate command with input context Add a xhci_alloc_command_with_ctx() helper to get rid of one of the boolean parameters telling if a context should be allocated with the command. No functional changes, improves core readability Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 24 ++++++++++++++++++++++-- drivers/usb/host/xhci.c | 4 ++-- drivers/usb/host/xhci.h | 2 ++ 3 files changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index e1fba4688509..7ab4020336f3 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -650,7 +650,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, /* Allocate everything needed to free the stream rings later */ stream_info->free_streams_command = - xhci_alloc_command(xhci, true, true, mem_flags); + xhci_alloc_command_with_ctx(xhci, true, mem_flags); if (!stream_info->free_streams_command) goto cleanup_ctx; @@ -1736,6 +1736,26 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, return command; } +struct xhci_command *xhci_alloc_command_with_ctx(struct xhci_hcd *xhci, + bool allocate_completion, gfp_t mem_flags) +{ + struct xhci_command *command; + + command = xhci_alloc_command(xhci, false, allocate_completion, + mem_flags); + if (!command) + return NULL; + + command->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, + mem_flags); + if (!command->in_ctx) { + kfree(command->completion); + kfree(command); + return NULL; + } + return command; +} + void xhci_urb_free_priv(struct urb_priv *urb_priv) { kfree(urb_priv); @@ -2409,7 +2429,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); xhci_dbg_cmd_ptrs(xhci); - xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags); + xhci->lpm_command = xhci_alloc_command_with_ctx(xhci, true, flags); if (!xhci->lpm_command) goto fail; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 89ad7c057454..5d99a6077d57 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3090,7 +3090,7 @@ static int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, return -ENOSYS; } - config_cmd = xhci_alloc_command(xhci, true, true, mem_flags); + config_cmd = xhci_alloc_command_with_ctx(xhci, true, mem_flags); if (!config_cmd) return -ENOMEM; @@ -4675,7 +4675,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, return -EINVAL; } - config_cmd = xhci_alloc_command(xhci, true, true, mem_flags); + config_cmd = xhci_alloc_command_with_ctx(xhci, true, mem_flags); if (!config_cmd) return -ENOMEM; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 99a014a920d3..147f1a0cb933 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1994,6 +1994,8 @@ struct xhci_ring *xhci_stream_id_to_ring( struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, bool allocate_in_ctx, bool allocate_completion, gfp_t mem_flags); +struct xhci_command *xhci_alloc_command_with_ctx(struct xhci_hcd *xhci, + bool allocate_completion, gfp_t mem_flags); void xhci_urb_free_p