diff options
68 files changed, 946 insertions, 893 deletions
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt index 88d9f4a4b280..266c2d917a28 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt @@ -32,7 +32,7 @@ Required properties: "mcu_ck": mcu_bus clock for register access, "dma_ck": dma_bus clock for data transfer by DMA - - phys : a list of phandle + phy specifier pairs + - phys : see usb-hcd.txt in the current directory Optional properties: - wakeup-source : enable USB remote wakeup; @@ -52,6 +52,9 @@ Optional properties: See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - imod-interval-ns: default interrupt moderation interval is 5000ns +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + Example: usb30: usb@11270000 { compatible = "mediatek,mt8173-xhci"; diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt index d589a1ef96a1..3382b5cb471d 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt @@ -17,7 +17,7 @@ Required properties: - clock-names : must contain "sys_ck" for clock of controller, the following clocks are optional: "ref_ck", "mcu_ck" and "dam_ck"; - - phys : a list of phandle + phy specifier pairs + - phys : see usb-hcd.txt in the current directory - dr_mode : should be one of "host", "peripheral" or "otg", refer to usb/generic.txt @@ -53,6 +53,9 @@ Optional properties: - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, bit1 for u3port1, ... etc; +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + Sub-nodes: The xhci should be added as subnode to mtu3 as shown in the following example if host mode is enabled. The DT binding details of xhci can be found in: diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt index 3efde12b5d68..0f1b75386207 100644 --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt @@ -16,10 +16,12 @@ Optional properties: - has-transaction-translator : boolean, set this if EHCI have a Transaction Translator built into the root hub. - clocks : a list of phandle + clock specifier pairs - - phys : phandle + phy specifier pair - - phy-names : "usb" + - phys : see usb-hcd.txt in the current directory - resets : phandle + reset specifier pair +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + Example (Sequoia 440EPx): ehci@e0000300 { compatible = "ibm,usb-ehci-440epx", "usb-ehci"; diff --git a/Documentation/devicetree/bindings/usb/usb-hcd.txt b/Documentation/devicetree/bindings/usb/usb-hcd.txt new file mode 100644 index 000000000000..50529b838c9c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-hcd.txt @@ -0,0 +1,9 @@ +Generic USB HCD (Host Controller Device) Properties + +Optional properties: +- phys: a list of all USB PHYs on this HCD + +Example: + &usb1 { + phys = <&usb2_phy1>, <&usb3_phy1>; + }; diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt index 09e70c875bc6..a8d2103d1f3d 100644 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt @@ -13,10 +13,12 @@ Optional properties: - remote-wakeup-connected: remote wakeup is wired on the platform - num-ports : u32, to override the detected port count - clocks : a list of phandle + clock specifier pairs -- phys : phandle + phy specifier pair -- phy-names : "usb" +- phys : see usb-hcd.txt in the current directory - resets : a list of phandle + reset specifier pairs +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + Example: ohci0: usb@1c14400 { diff --git a/Documentation/devicetree/bindings/usb/usb-uhci.txt b/Documentation/devicetree/bindings/usb/usb-uhci.txt index 298133416c97..cc2e6f7d602e 100644 --- a/Documentation/devicetree/bindings/usb/usb-uhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-uhci.txt @@ -6,6 +6,9 @@ Required properties: - reg : Should contain 1 register ranges(address and length) - interrupts : UHCI controller interrupt +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + Example: uhci@d8007b00 { diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index 1651483a7048..c4c00dff4b56 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -33,6 +33,11 @@ Optional properties: - usb3-lpm-capable: determines if platform is USB3 LPM capable - quirk-broken-port-ped: set if the controller has broken port disable mechanism - imod-interval-ns: default interrupt moderation interval is 5000ns + - phys : see usb-hcd.txt in the current directory + +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + Example: usb@f0931000 { diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412356c9..076d97eaff6f 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -21,7 +21,6 @@ struct tcpci { struct device *dev; - struct i2c_client *client; struct tcpm_port *port; @@ -30,6 +29,12 @@ struct tcpci { bool controls_vbus; struct tcpc_dev tcpc; + struct tcpci_data *data; +}; + +struct tcpci_chip { + struct tcpci *tcpci; + struct tcpci_data data; }; static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) return container_of(tcpc, struct tcpci, tcpc); } -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, - u16 *val) +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) { return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); } @@ -98,9 +102,17 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, enum typec_cc_status cc) { + int ret; struct tcpci *tcpci = tcpc_to_tcpci(tcpc); unsigned int reg = TCPC_ROLE_CTRL_DRP; + /* Handle vendor drp toggling */ + if (tcpci->data->start_drp_toggling) { + ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc); + if (ret < 0) + return ret; + } + switch (cc) { default: case TYPEC_CC_RP_DEF: @@ -117,7 +129,17 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, break; } - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (cc == TYPEC_CC_RD) + reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); + else + reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + return regmap_write(tcpci->regmap, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); } static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) @@ -178,6 +200,13 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable) struct tcpci *tcpci = tcpc_to_tcpci(tcpc); int ret; + /* Handle vendor set vconn */ + if (tcpci->data->set_vconn) { + ret = tcpci->data->set_vconn(tcpci, tcpci->data, enable); + if (ret < 0) + return ret; + } + ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL, enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0); if (ret < 0) @@ -323,6 +352,13 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->data->init) { + ret = tcpci->data->init(tcpci, tcpci->data); + if (ret < 0) + return ret; + } + /* Clear all events */ ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff); if (ret < 0) @@ -344,9 +380,8 @@ static int tcpci_init(struct tcpc_dev *tcpc) return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg); } -static irqreturn_t tcpci_irq(int irq, void *dev_id) +irqreturn_t tcpci_irq(struct tcpci *tcpci) { - struct tcpci *tcpci = dev_id; u16 status; tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +447,14 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(tcpci_irq); + +static irqreturn_t _tcpci_irq(int irq, void *dev_id) +{ + struct tcpci_chip *chip = dev_id; + + return tcpci_irq(chip->tcpci); +} static const struct regmap_config tcpci_regmap_config = { .reg_bits = 8, @@ -435,22 +478,18 @@ static int tcpci_parse_config(struct tcpci *tcpci) return 0; } -static int tcpci_probe(struct i2c_client *client, - const struct i2c_device_id *i2c_id) +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) { struct tcpci *tcpci; int err; - tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL); + tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL); if (!tcpci) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - tcpci->client = client; - tcpci->dev = &client->dev; - i2c_set_clientdata(client, tcpci); - tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); - if (IS_ERR(tcpci->regmap)) - return PTR_ERR(tcpci->regmap); + tcpci->dev = dev; + tcpci->data = data; + tcpci->regmap = data->regmap; tcpci->tcpc.init = tcpci_init; tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +506,63 @@ static int tcpci_probe(struct i2c_client *client, err = tcpci_parse_config(tcpci); if (err < 0) - return err; + return ERR_PTR(err); - /* Disable chip interrupts */ - tcpci_write16(tcpci, TCPC_ALERT_MASK, 0); + tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); + if (PTR_ERR_OR_ZERO(tcpci->port)) + return ERR_CAST(tcpci->port); - err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL, - tcpci_irq, + return tcpci; +} +EXPORT_SYMBOL_GPL(tcpci_register_port); + +void tcpci_unregister_port(struct tcpci *tcpci) +{ + tcpm_unregister_port(tcpci->port); +} +EXPORT_SYMBOL_GPL(tcpci_unregister_port); + +static int tcpci_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct tcpci_chip *chip; + int err; + u16 val = 0; + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); + if (IS_ERR(chip->data.regmap)) + return PTR_ERR(chip->data.regmap); + + /* Disable chip interrupts before requesting irq */ + err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val, + sizeof(u16)); + if (err < 0) + return err; + + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + _tcpci_irq, IRQF_ONESHOT | IRQF_TRIGGER_LOW, - dev_name(tcpci->dev), tcpci); + dev_name(&client->dev), chip); if (err < 0) return err; - tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); - return PTR_ERR_OR_ZERO(tcpci->port); + chip->tcpci = tcpci_register_port(&client->dev, &chip->data); + if (PTR_ERR_OR_ZERO(chip->tcpci)) + return PTR_ERR(chip->tcpci); + + i2c_set_clientdata(client, chip); + return 0; } static int tcpci_remove(struct i2c_client *client) { - struct tcpci *tcpci = i2c_get_clientdata(client); + struct tcpci_chip *chip = i2c_get_clientdata(client); - tcpm_unregister_port(tcpci->port); + tcpci_unregister_port(chip->tcpci); return 0; } diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h index fdfb06cc3b86..34c865f0dcf6 100644 --- a/drivers/staging/typec/tcpci.h +++ b/drivers/staging/typec/tcpci.h @@ -121,4 +121,18 @@ #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78 +struct tcpci; +struct tcpci_data { + struct regmap *regmap; + int (*init)(struct tcpci *tcpci, struct tcpci_data *data); + int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data, + bool enable); + int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data, + enum typec_cc_status cc); +}; + +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); +void tcpci_unregister_port(struct tcpci *tcpci); +irqreturn_t tcpci_irq(struct tcpci *tcpci); + #endif /* __LINUX_USB_TCPCI_H */ diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index c9e1a165ed82..ce648cb3ed94 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -45,18 +45,7 @@ static int ci_device_show(struct seq_file *s, void *data) return 0; } - -static int ci_device_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_device_show, inode->i_private); -} - -static const struct file_operations ci_device_fops = { - .open = ci_device_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(ci_device); /** * ci_port_test_show: reads port test mode @@ -156,18 +145,7 @@ static int ci_qheads_show(struct seq_file *s, void *data) return 0; } - -static int ci_qheads_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_qheads_show, inode->i_private); -} - -static const struct file_operations ci_qheads_fops = { - .open = ci_qheads_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(ci_qheads); /** * ci_requests_show: DMA contents of all requests currently queued (all endpts) @@ -204,18 +182,7 @@ static int ci_requests_show(struct seq_file *s, void *data) return 0; } - -static int ci_requests_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_requests_show, inode->i_private); -} - -static const struct file_operations ci_requests_fops = { - .open = ci_requests_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(ci_requests); static int ci_otg_show(struct seq_file *s, void *unused) { @@ -278,18 +245,7 @@ static int ci_otg_show(struct seq_file *s, void *unused) return 0; } - -static int ci_otg_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_otg_show, inode->i_private); -} - -static const struct file_operations ci_otg_fops = { - .open = ci_otg_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(ci_otg); static int ci_role_show(struct seq_file *s, void *data) { @@ -376,18 +332,7 @@ static int ci_registers_show(struct seq_file *s, void *unused) return 0; } - -static int ci_registers_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_registers_show, inode->i_private); -} - -static const struct file_operations ci_registers_fops = { - .open = ci_registers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(ci_registers); /** * dbg_create_files: initializes the attribute interface diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 19d60ed7e41f..af45aa3222b5 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -124,10 +124,8 @@ static int host_start(struct ci_hdrc *ci) hcd->power_budget = ci->platdata->power_budget; hcd->tpl_support = ci->platdata->tpl_support; - if (ci->phy) - hcd->phy = ci->phy; - else - hcd->usb_phy = ci->usb_phy; + if (ci->phy || ci->usb_phy) + hcd->skip_phy_initialization = 1; ehci = hcd_to_ehci(hcd); ehci->caps = ci->hw_bank.cap; diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 92c9cefb4317..18e874b0441e 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -6,7 +6,7 @@ usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o -usbcore-y += port.o +usbcore-y += phy.o port.o usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_USB_PCI) += hcd-pci.o diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index fc32391a34d5..5a92d8f7c484 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -37,6 +37,7 @@ #include <linux/usb/otg.h> #include "usb.h" +#include "phy.h" /*-------------------------------------------------------------------------*/ @@ -2260,6 +2261,9 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) usb_set_device_state(rhdev, USB_STATE_SUSPENDED); hcd->state = HC_STATE_SUSPENDED; + if (!PMSG_IS_AUTO(msg)) + usb_phy_roothub_power_off(hcd->phy_roothub); + /* Did we race with a root-hub wakeup event? */ if (rhdev->do_remote_wakeup) { char buffer[6]; @@ -2296,6 +2300,13 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "resume"); return 0; } + + if (!PMSG_IS_AUTO(msg)) { + status = usb_phy_roothub_power_on(hcd->phy_roothub); + if (status) + return status; + } + if (!hcd->driver->bus_resume) return -ENOENT; if (HCD_RH_RUNNING(hcd)) @@ -2333,6 +2344,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) } } else { hcd->state = old_state; + usb_phy_roothub_power_off(hcd->phy_roothub); dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", "resume", status); if (status != -ESHUTDOWN) @@ -2727,7 +2739,7 @@ int usb_add_hcd(struct usb_hcd *hcd, int retval; struct usb_device *rhdev; - if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) { + if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->skip_phy_initialization) { struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0); if (IS_ERR(phy)) { @@ -2745,28 +2757,16 @@ int usb_add_hcd(struct usb_hcd *hcd, } } - if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) { - struct phy *phy = phy_get(hcd->self.sysdev, "usb"); - - if (IS_ERR(phy)) { - retval = PTR_ERR(phy); - if (retval == -EPROBE_DEFER) - goto err_phy; - } else { - retval = phy_init(phy); - if (retval) { - phy_put(phy); - goto err_phy; - } - retval = phy_power_on(phy); - if (retval) { - phy_exit(phy); - phy_put(phy); - goto err_phy; - } - hcd->phy = phy; - hcd->remove_phy = 1; + if (!hcd->skip_phy_initialization) { + hcd->phy_roothub = usb_phy_roothub_init(hcd->self.sysdev); + if (IS_ERR(hcd->phy_roothub)) { + retval = PTR_ERR(hcd->phy_roothub); + goto err_phy_roothub_init; } + + retval = usb_phy_roothub_power_on(hcd->phy_roothub); + if (retval) + goto err_usb_phy_roothub_power_on; } dev_info(hcd->self.controller, "%s\n", hcd->product_desc); @@ -2933,13 +2933,10 @@ err_allocate_root_hub: err_register_bus: hcd_buffer_destroy(hcd); err_create_buf: - if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) { - phy_power_off(hcd->phy); - phy_exit(hcd->phy); - phy_put(hcd->phy); - hcd->phy = NULL; - } -err_phy: + usb_phy_roothub_power_off(hcd->phy_roothub); +err_usb_phy_roothub_power_on: + usb_phy_roothub_exit(hcd->phy_roothub); +err_phy_roothub_init: if (hcd->remove_phy && hcd->usb_phy) { usb_phy_shutdown(hcd->usb_phy); usb_put_phy(hcd->usb_phy); @@ -3017,12 +3014,9 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); - if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) { - phy_power_off(hcd->phy); - phy_exit(hcd->phy); - phy_put(hcd->phy); - hcd->phy = NULL; - } + usb_phy_roothub_power_off(hcd->phy_roothub); + usb_phy_roothub_exit(hcd->phy_roothub); + if (hcd->remove_phy && hcd->usb_phy) { usb_phy_shutdown(hcd->usb_phy); usb_put_phy(hcd->usb_phy); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c5c1f6cf3228..ac7bab772a3a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -5505,21 +5505,15 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); - /* Disable LPM and LTM while we reset the device and reinstall the alt - * settings. Device-initiated LPM settings, and system exit latency - * settings are cleared when the device is reset, so we have to set - * them up again. + /* Disable LPM while we reset the device and reinstall the alt settings. + * Device-initiated LPM, and system exit latency settings are cleared + * when the device is reset, so we have to set them up again. */ ret = usb_unlocked_disable_lpm(udev); if (ret) { 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__); - goto re_enumerate_no_bos; - } bos = udev->bos; udev->bos = NULL; diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c new file mode 100644 index 000000000000..09b7c43c0ea4 --- /dev/null +++ b/drivers/usb/core/phy.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * A wrapper for multiple PHYs which passes all phy_* function calls to + * multiple (actual) PHY devices. This is comes handy when initializing + * all PHYs on a HCD and to keep them all in the same state. + * + * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + */ + +#include <linux/device.h> +#include <linux/list.h> +#include <linux/phy/phy.h> +#include <linux/of.h> + +#include "phy.h" + +struct usb_phy_roothub { + struct phy *phy; + struct list_head list; +}; + +static struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev) +{ + struct usb_phy_roothub *roothub_entry; + + roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL); + if (!roothub_entry) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&roothub_entry->list); + + return roothub_entry; +} + +static int usb_phy_roothub_add_phy(struct device *dev, int index, + struct list_head *list) +{ + struct usb_phy_roothub *roothub_entry; + struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index); + + if (IS_ERR_OR_NULL(phy)) { + if (!phy || PTR_ERR(phy) == -ENODEV) + return 0; + else + return PTR_ERR(phy); + } + + roothub_entry = usb_phy_roothub_alloc(dev); + if (IS_ERR(roothub_entry)) + return PTR_ERR(roothub_entry); + + roothub_entry->phy = phy; + + list_add_tail(&roothub_entry->list, list); + + return 0; +} + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev) +{ + struct usb_phy_roothub *phy_roothub; + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int i, num_phys, err; + + num_phys = of_count_phandle_with_args(dev->of_node, "phys", + "#phy-cells"); + if (num_phys <= 0) + return NULL; + + phy_roothub = usb_phy_roothub_alloc(dev); + if (IS_ERR(phy_roothub)) + return phy_roothub; + + for (i = 0; i < num_phys; i++) { + err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list); + if (err) + goto err_out; + } + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_init(roothub_entry->phy); + if (err) + goto err_exit_phys; + } + + return phy_roothub; + +err_exit_phys: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_exit(roothub_entry->phy); + +err_out: + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_init); + +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err, ret = 0; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_exit(roothub_entry->phy); + if (err) + ret = ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_exit); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + struct list_head *head; + int err; + + if (!phy_roothub) + return 0; + + head = &phy_roothub->list; + + list_for_each_entry(roothub_entry, head, list) { + err = phy_power_on(roothub_entry->phy); + if (err) + goto err_out; + } + + return 0; + +err_out: + list_for_each_entry_continue_reverse(roothub_entry, head, list) + phy_power_off(roothub_entry->phy); + + return err; +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on); + +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) +{ + struct usb_phy_roothub *roothub_entry; + + if (!phy_roothub) + return; + + list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list) + phy_power_off(roothub_entry->phy); +} +EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off); diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h new file mode 100644 index 000000000000..6fde59bfbff8 --- /dev/null +++ b/drivers/usb/core/phy.h @@ -0,0 +1,7 @@ +struct usb_phy_roothub; + +struct usb_phy_roothub *usb_phy_roothub_init(struct device *dev); +int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub); + +int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); +void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub); diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 84da17460568..e221861b3187 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -90,8 +90,8 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle, acpi_status status; /* - * According to ACPI Spec 9.13. PLD indicates whether usb port is - * user visible and _UPC indicates whether it is connectable. If + * According to 9.14 in ACPI Spec 6.2. _PLD indicates whether usb port + * is user visible and _UPC indicates whether it is connectable. If * the port was visible and connectable, it could be freely connected * and disconnected with USB devices. If no visible and connectable, * a usb device is directly hard-wired to the port. If no visible and diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index f4650a88be78..5e0d7f2bd2af 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -170,19 +170,7 @@ static int state_show(struct seq_file *seq, void *v) return 0; } - -static int state_open(struct inode *inode, struct file *file) -{ - return single_open(file, state_show, inode->i_private); -} - -static const struct file_operations state_fops = { - .owner = THIS_MODULE, - .open = state_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(state); /** * fifo_show - debugfs: show the fifo information @@ -219,19 +207,7 @@ static int fifo_show(struct seq_file *seq, void *v) return 0; } - -static int fifo_open(struct inode *inode, struct file *file) -{ - return single_open(file, fifo_show, inode->i_private); -} - -static const struct file_operations fifo_fops = { - .owner = THIS_MODULE, - .open = fifo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(fifo); static const char *decode_direction(int is_in) { @@ -303,19 +279,7 @@ static int ep_show(struct seq_file *seq, void *v) return 0; } - -static int ep_open(struct inode *inode, struct file *file) -{ - return single_open(file, ep_show, inode->i_private); -} - -static const struct file_operations ep_fops = { - .owner = THIS_MODULE, - .open = ep_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(ep); /** * dwc2_hsotg_create_debug - create debugfs directory and files @@ -770,19 +734,7 @@ static int params_show(struct seq_file *seq, void *v) return 0; } - -static int params_open(struct inode *inode, struct file *file) -{ - return single_open(file, params_show, inode->i_private); -} - -static const struct file_operations params_fops = { - .owner = THIS_MODULE, - .open = params_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(params); static int hw_params_show(struct seq_file *seq, void *v) { @@ -817,19 +769,7 @@ static int hw_params_show(struct seq_file *seq, void *v) return 0; } - -static int hw_params_open(struct inode *inode, struct file *file) -{ - return single_open(file, hw_params_show, inode->i_private); -} - -static const struct file_operations hw_params_fops = { - .owner = THIS_MODULE, - .open = hw_params_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(hw_params); static int dr_mode_show(struct seq_file *seq, void *v) { @@ -840,19 +780,7 @@ static int dr_mode_show(struct seq_file *seq, void *v) seq_printf(seq, "%s\n", dr_mode); return 0; } - -static int dr_mode_open(struct inode *inode, struct file *file) -{ - return single_open(file, dr_mode_show, inode->i_private); -} - -static const struct file_operations dr_mode_fops = { - .owner = THIS_MODULE, - .open = dr_mode_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(dr_mode); int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) { diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 465ccd1104de..3a8df8601074 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -2158,6 +2158,7 @@ static int bcm63xx_usbd_dbg_show(struct seq_file *s, void *p) return 0; } +DEFINE_SHOW_ATTRIBUTE(bcm63xx_usbd_dbg); /* * bcm63xx_iudma_dbg_show - Show IUDMA status and descriptors. @@ -2238,33 +2239,7 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p) return 0; } - -static int bcm63xx_usbd_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, bcm63xx_usbd_dbg_show, inode->i_private); -} - -static int bcm63xx_iudma_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, bcm63xx_iudma_dbg_show, inode->i_private); -} - -static const struct file_operations usbd_dbg_fops = { - .owner = THIS_MODULE, - .open = bcm63xx_usbd_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; - -static const struct file_operations iudma_dbg_fops = { - .owner = THIS_MODULE, - .open = bcm63xx_iudma_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; - +DEFINE_SHOW_ATTRIBUTE(bcm63xx_iudma_dbg); /** * bcm63xx_udc_init_debugfs - Create debugfs entries. @@ -2282,11 +2257,11 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc) goto err_root; usbd = debugfs_create_file("usbd", 0400, root, udc, - &usbd_dbg_fops); + &bcm63xx_usbd_dbg_fops); if (!usbd) goto err_usbd; iudma = debugfs_create_file("iudma", 0400, root, udc, - &iudma_dbg_fops); + &bcm63xx_iudma_dbg_fops); if (!iudma) goto err_iudma; diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index b3fb1bbdb854..ca83c15d8ea4 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -179,8 +179,7 @@ static void gr_seq_ep_show(struct seq_file *seq, struct gr_ep *ep) seq_puts(seq, "\n"); } - -static int gr_seq_show(struct seq_file *seq, void *v) +static int gr_dfs_show(struct seq_file *seq, void *v) { struct gr_udc *dev = seq->private; u32 control = gr_read32(&dev->regs->control); @@ -203,19 +202,7 @@ static int gr_seq_show(struct seq_file *seq, void *v) return 0; } - -static int gr_dfs_open(struct inode *inode, struct file *file) -{ - return single_open(file, gr_seq_show, inode->i_private); -} - -static const struct file_operations gr_dfs_fops = { - .owner = THIS_MODULE, - .open = gr_dfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(gr_dfs); static void gr_dfs_create(struct gr_udc *dev) { diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 0e3f5faa000e..d4be53559f2e 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1233,8 +1233,7 @@ static const struct usb_gadget_ops pxa25x_udc_ops = { #ifdef CONFIG_USB_GADGET_DEBUG_FS -static int -udc_seq_show(struct seq_file *m, void *_d) +static int udc_debug_show(struct seq_file *m, void *_d) { struct pxa25x_udc *dev = m->private; unsigned long flags; @@ -1335,25 +1334,12 @@ done: local_irq_restore(flags); return 0; } - -static int -udc_debugfs_open(struct inode *inode, struct file *file) -{ - return single_open(file, udc_seq_show, inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = udc_debugfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(udc_debug); #define create_debug_files(dev) \ do { \ dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \ - S_IRUGO, NULL, dev, &debug_fops); \ + S_IRUGO, NULL, dev, &udc_debug_fops); \ } while (0) #define remove_debug_files(dev) debugfs_remove(dev->debugfs_udc) diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index fadcf2653c3d..a58242e901df 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -131,6 +131,7 @@ static int state_dbg_show(struct seq_file *s, void *p) return 0; } +DEFINE_SHOW_ATTRIBUTE(state_dbg); static int queues_dbg_show(struct seq_file *s, void *p) { @@ -163,6 +164,7 @@ static int queues_dbg_show(struct seq_file *s, void *p) return 0; } +DEFINE_SHOW_ATTRIBUTE(queues_dbg); static int eps_dbg_show(struct seq_file *s, void *p) { @@ -199,45 +201,7 @@ static int eps_dbg_show(struct seq_file *s, void *p) return 0; } - -static int eps_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, eps_dbg_show, inode->i_private); -} - -static int queues_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, queues_dbg_show, inode->i_private); -} - -static int state_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, state_dbg_show, inode->i_private); -} - -static const struct file_operations state_dbg_fops = { - .owner = THIS_MODULE, - .open = state_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; - -static const struct file_operations queues_dbg_fops = { - .owner = THIS_MODULE, - .open = queues_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; - -static const struct file_operations eps_dbg_fops = { - .owner = THIS_MODULE, - .open = eps_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(eps_dbg); static void pxa_init_debugfs(struct pxa_udc *udc) { diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index c5094cb88cd5..0a9fd2022acf 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -155,6 +155,8 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) retval = -ENODEV; goto err2; } + + hcd->skip_phy_initialization = 1; } #endif return retval; diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 21307d862af6..4c6c08b675b5 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -73,10 +73,9 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) if (!qh) goto done; qh->hw = (struct ehci_qh_hw *) - dma_pool_alloc(ehci->qh_pool, flags, &dma); + dma_pool_zalloc(ehci->qh_pool, flags, &dma); if (!qh->hw) goto fail; - memset(qh->hw, 0, sizeof *qh->hw); qh->qh_dma = dma; // INIT_LIST_HEAD (&qh->qh_list); INIT_LIST_HEAD (&qh->qtd_list); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index b065a960adc2..4c306fb6b069 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -27,7 +27,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/usb.h> @@ -44,8 +43,6 @@ struct ehci_platform_priv { struct clk *clks[EHCI_MAX_CLKS]; struct reset_control *rsts; - struct phy **phys; - int num_phys; bool reset_on_resume; }; @@ -80,7 +77,7 @@ static int ehci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk, ret, phy_num; + int clk, ret; for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) { ret = clk_prepare_enable(priv->clks[clk]); @@ -88,24 +85,8 @@ static int ehci_platform_power_on(struct platform_device *dev) goto err_disable_clks; } - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - ret = phy_init(priv->phys[phy_num]); - if (ret) - goto err_exit_phy; - ret = phy_power_on(priv->phys[phy_num]); - if (ret) { - phy_exit(priv->phys[phy_num]); - goto err_exit_phy; - } - } - return 0; -err_exit_phy: - while (--phy_num >= 0) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } err_disable_clks: while (--clk >= 0) clk_disable_unprepare(priv->clks[clk]); @@ -117,12 +98,7 @@ static void ehci_platform_power_off(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk, phy_num; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } + int clk; for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--) if (priv->clks[clk]) @@ -149,7 +125,7 @@ static int ehci_platform_probe(struct platform_device *dev) struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv; struct ehci_hcd *ehci; - int err, irq, phy_num, clk = 0; + int err, irq, clk = 0; if (usb_disabled()) return -ENODEV; @@ -202,29 +178,6 @@ static int ehci_platform_probe(struct platform_device *dev) "has-transaction-translator")) hcd->has_tt = 1; - priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, - "phys", "#phy-cells"); - - if (priv->num_phys > 0) { - priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, - sizeof(struct phy *), GFP_KERNEL); - if (!priv->phys) - return -ENOMEM; - } else - priv->num_phys = 0; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - priv->phys[phy_num] = devm_of_phy_get_by_index( - &dev->dev, dev->dev.of_node, phy_num); - if (IS_ERR(priv->phys[phy_num])) { - err = PTR_ERR(priv->phys[phy_num]); - goto err_put_hcd; - } else if (!hcd->phy) { - /* Avoiding phy_get() in usb_add_hcd() */ - hcd->phy = priv->phys[phy_num]; - } - } - for (clk = 0; clk < EHCI_MAX_CLKS; clk++) { priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); if (IS_ERR(priv->clks[clk])) { @@ -306,7 +259,7 @@ err_reset: err_put_clks: while (--clk >= 0) clk_put(priv->clks[clk]); -err_put_hcd: + if (pdata == &ehci_platform_defaults) dev->dev.platform_data = NULL; diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e56db44708bc..28e2a338b481 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1287,7 +1287,7 @@ itd_urb_transaction( } else { alloc_itd: spin_unlock_irqrestore(&ehci->lock, flags); - itd = dma_pool_alloc(ehci->itd_pool, mem_flags, + itd = dma_pool_zalloc(ehci->itd_pool, mem_flags, &itd_dma); spin_lock_irqsave(&ehci->lock, flags); if (!itd) { @@ -1297,7 +1297,6 @@ itd_urb_transaction( } } - memset(itd, 0, sizeof(*itd)); itd->itd_dma = itd_dma; itd->frame = NO_FRAME; list_add(&itd->itd_list, &sched->td_list); @@ -2081,7 +2080,7 @@ sitd_urb_transaction( } else { alloc_sitd: spin_unlock_irqrestore(&ehci->lock, flags); - sitd = dma_pool_alloc(ehci->sitd_pool, mem_flags, + sitd = dma_pool_zalloc(ehci->sitd_pool, mem_flags, &sitd_dma); spin_lock_irqsave(&ehci->lock, flags); if (!sitd) { @@ -2091,7 +2090,6 @@ sitd_urb_transaction( } } - memset(sitd, 0, sizeof(*sitd)); sitd->sitd_dma = sitd_dma; sitd->frame = NO_FRAME; list_add(&sitd->sitd_list, &iso_sched->td_list); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index c809f7d2f08f..a6f4389f7e88 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -461,6 +461,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_clk_en; } hcd->usb_phy = u_phy; + hcd->skip_phy_initialization = 1; tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, "nvidia,needs-double-reset"); diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c index fafa91189e45..ebf9bb219f75 100644 --- a/drivers/usb/host/fhci-dbg.c +++ b/drivers/usb/host/fhci-dbg.c @@ -55,6 +55,7 @@ static int fhci_dfs_regs_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(fhci_dfs_regs); static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v) { @@ -75,30 +76,7 @@ static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v) return 0; } - -static int fhci_dfs_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, fhci_dfs_regs_show, inode->i_private); -} - -static int fhci_dfs_irq_stat_open(struct inode *inode, struct file *file) -{ - return single_open(file, fhci_dfs_irq_stat_show, inode->i_private); -} - -static const struct file_operations fhci_dfs_regs_fops = { - .open = fhci_dfs_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations fhci_dfs_irq_stat_fops = { - .open = fhci_dfs_irq_stat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(fhci_dfs_irq_stat); void fhci_dfs_create(struct fhci_hcd *fhci) { diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c index b964f9a51d87..a213ed6f07b5 100644 --- a/drivers/usb/host/imx21-dbg.c +++ b/drivers/usb/host/imx21-dbg.c @@ -245,6 +245,7 @@ static int debug_status_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_status); static int debug_dmem_show(struct seq_file *s, void *v) { @@ -266,6 +267,7 @@ static int debug_dmem_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_dmem); static int debug_etd_show(struct seq_file *s, void *v) { @@ -334,6 +336,7 @@ static int debug_etd_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_etd); static void debug_statistics_show_one(struct seq_file *s, const char *name, struct debug_stats *stats) @@ -368,6 +371,7 @@ static int debug_statistics_show(struct seq_file *s, void *v) return 0; } +DEFINE_SHOW_ATTRIBUTE(debug_statistics); static void debug_isoc_show_one(struct seq_file *s, const char *name, int index, struct debug_isoc_trace *trace) @@ -409,66 +413,7 @@ static int debug_isoc_show(struct seq_file *s, void *v) return 0; } - -static int debug_status_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_status_show, inode->i_private); -} - -static int debug_dmem_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_dmem_show, inode->i_private); -} - -static int debug_etd_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_etd_show, inode->i_private); -} - -static int debug_statistics_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_statistics_show, inode->i_private); -} - -static int debug_isoc_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_isoc_show, inode->i_private); -} - -static const struct file_operations debug_status_fops = { - .open = debug_status_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_dmem_fops = { - .open = debug_dmem_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_etd_fops = { - .open = debug_etd_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_statistics_fops = { - .open = debug_statistics_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_isoc_fops = { - .open = debug_isoc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(debug_isoc); static void create_debug_files(struct imx21 *imx21) { diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5f9234b9cf7b..4602ed801f0a 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1168,7 +1168,7 @@ static void dump_int(struct seq_file *s, char *label, u32 mask) mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : ""); } -static int isp116x_show_dbg(struct seq_file *s, void *unused) +static int isp116x_debug_show(struct seq_file *s, void *unused) { struct isp116x *isp116x = s->private; @@ -1196,18 +1196,7 @@ static int isp116x_show_dbg(struct seq_file *s, void *unused) return 0; } - -static int isp116x_open_seq(struct inode *inode, struct file *file) -{ - return single_open(file, isp116x_show_dbg, inode->i_private); -} - -static const struct file_operations isp116x_debug_fops = { - .open = isp116x_open_seq, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(isp116x_debug); static int create_debug_file(struct isp116x *isp116x) { diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 0201c49bc4fc..d8d35d456456 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -230,6 +230,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) } else { return -EPROBE_DEFER; } + hcd->skip_phy_initialization = 1; ohci->start_hnp = start_hnp; } #endif diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 1e6c954f4b3f..65a1c3fdc88c 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -21,7 +21,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/err.h> -#include <linux/phy/phy.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> @@ -38,8 +38,6 @@ struct ohci_platform_priv { struct clk *clks[OHCI_MAX_CLKS]; struct reset_control *resets; - struct phy **phys; - int num_phys; }; static const char hcd_name[] = "ohci-platform"; @@ -48,7 +46,7 @@ static int ohci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); - int clk, ret, phy_num; + int clk, ret; for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) { ret = clk_prepare_enable(priv->clks[clk]); @@ -56,24 +54,8 @@ static int ohci_platform_power_on(struct platform_device *dev) goto err_disable_clks; } - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - ret = phy_init(priv->phys[phy_num]); - if (ret) - goto err_exit_phy; - ret = phy_power_on(priv->phys[phy_num]); - if (ret) { - phy_exit(priv->phys[phy_num]); - goto err_exit_phy; - } - } - return 0; -err_exit_phy: - while (--phy_num >= 0) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } err_disable_clks: while (--clk >= 0) clk_disable_unprepare(priv->clks[clk]); @@ -85,12 +67,7 @@ static void ohci_platform_power_off(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); - int clk, phy_num; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - phy_power_off(priv->phys[phy_num]); - phy_exit(priv->phys[phy_num]); - } + int clk; for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--) if (priv->clks[clk]) @@ -117,7 +94,7 @@ static int ohci_platform_probe(struct platform_device *dev) struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); struct ohci_platform_priv *priv; struct ohci_hcd *ohci; - int err, irq, phy_num, clk = 0; + int err, irq, clk = 0; if (usb_disabled()) return -ENODEV; @@ -169,29 +146,6 @@ static int ohci_platform_probe(struct platform_device *dev) of_property_read_u32(dev->dev.of_node, "num-ports", &ohci->num_ports); - priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, - "phys", "#phy-cells"); - - if (priv->num_phys > 0) { - priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, - sizeof(struct phy *), GFP_KERNEL); - if (!priv->phys) - return -ENOMEM; - } else - priv->num_phys = 0; - - for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { - priv->phys[phy_num] = devm_of_phy_get_by_index( - &dev->dev, dev->dev.of_node, phy_num); - if (IS_ERR(priv->phys[phy_num])) { - err = PTR_ERR(priv->phys[phy_num]); - goto err_put_hcd; - } else if (!hcd->phy) { - /* Avoiding phy_get() in usb_add_hcd() */ - hcd->phy = priv->phys[phy_num]; - } - } - for (clk = 0; clk < OHCI_MAX_CLKS; clk++) { priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); if (IS_ERR(priv->clks[clk])) { @@ -277,7 +231,7 @@ err_reset: err_put_clks: while (--clk >= 0) clk_put(priv->clks[clk]); -err_put_hcd: + if (pdata == &ohci_platform_defaults) dev->dev.platform_data = NULL; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index fa88a903fa2e..5b061e599948 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1381,7 +1381,7 @@ static void dump_irq(struct seq_file *s, char *label, u8 mask) (mask & SL11H_INTMASK_DP) ? " dp" : ""); } -static int sl811h_show(struct seq_file *s, void *unused) +static int sl811h_debug_show(struct seq_file *s, void *unused) { struct sl811 *sl811 = s->private; struct sl811h_ep *ep; @@ -1491,25 +1491,14 @@ static int sl811h_show(struct seq_file *s, void *unused) return 0; } - -static int sl811h_open(struct inode *inode, struct file *file) -{ - return single_open(file, sl811h_show, inode->i_private); -} - -static const struct file_operations debug_ops = { - .open = sl811h_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(sl811h_debug); /* expect just one sl811 per system */ static void create_debug_file(struct sl811 *sl811) { sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO, usb_debug_root, sl811, - &debug_ops); + &sl811h_debug_fops); } static void remove_debug_file(struct sl811 *sl811) diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c index f154e5791bfd..8ddfe3f1f693 100644 --- a/drivers/usb/host/whci/debug.c +++ b/drivers/usb/host/whci/debug.c @@ -72,7 +72,7 @@ static void qset_print(struct seq_file *s, struct whc_qset *qset) } } -static int di_print(struct seq_file *s, void *p) +static int di_show(struct seq_file *s, void *p) { struct whc *whc = s->private; int d; @@ -91,8 +91,9 @@ static int di_print(struct seq_file *s, void *p) } return 0; } +DEFINE_SHOW_ATTRIBUTE(di); -static int asl_print(struct seq_file *s, void *p) +static int asl_show(struct seq_file *s, void *p) { struct whc *whc = s->private; struct whc_qset *qset; @@ -103,8 +104,9 @@ static int asl_print(struct seq_file *s, void *p) return 0; } +DEFINE_SHOW_ATTRIBUTE(asl); -static int pzl_print(struct seq_file *s, void *p) +static int pzl_show(struct seq_file *s, void *p) { struct whc *whc = s->private; struct whc_qset *qset; @@ -118,45 +120,7 @@ static int pzl_print(struct seq_file *s, void *p) } return 0; } - -static int di_open(struct inode *inode, struct file *file) -{ - return single_open(file, di_print, inode->i_private); -} - -static int asl_open(struct inode *inode, struct file *file) -{ - return single_open(file, asl_print, inode->i_private); -} - -static int pzl_open(struct inode *inode, struct file *file) -{ - return single_open(file, pzl_print, inode->i_private); -} - -static const struct file_operations di_fops = { - .open = di_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations asl_fops = { - .open = asl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations pzl_fops = { - .open = pzl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(pzl); void whc_dbg_init(struct whc *whc) { diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index 75f0b92694ba..48779c44c361 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -447,9 +447,10 @@ int xhci_dbc_tty_register_device(struct xhci_hcd *xhci) xhci_dbc_tty_init_port(xhci, port); tty_dev = tty_port_register_device(&port->port, dbc_tty_driver, 0, NULL); - ret = IS_ERR_OR_NULL(tty_dev); - if (ret) + if (IS_ERR(tty_dev)) { + ret = PTR_ERR(tty_dev); goto register_fail; + } ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL); if (ret) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 332420d10be9..e5ace8995b3b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -913,6 +913,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (dev->out_ctx) xhci_free_container_ctx(xhci, dev->out_ctx); + if (dev->udev && dev->udev->slot_id) + dev->udev->slot_id = 0; kfree(xhci->devs[slot_id]); xhci->devs[slot_id] = NULL; } diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index b0ab4d5e2751..7334da9e9779 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -14,7 +14,6 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -352,62 +351,6 @@ static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = { static struct hc_driver __read_mostly xhci_mtk_hc_driver; -static int xhci_mtk_phy_init(struct xhci_hcd_mtk *mtk) -{ - int i; - int ret; - - for (i = 0; i < mtk->num_phys; i++) { - ret = phy_init(mtk->phys[i]); - if (ret) - goto exit_phy; - } - return 0; - -exit_phy: - for (; i > 0; i--) - phy_exit(mtk->phys[i - 1]); - - return ret; -} - -static int xhci_mtk_phy_exit(struct xhci_hcd_mtk *mtk) -{ - int i; - - for (i = 0; i < mtk->num_phys; i++) - phy_exit(mtk->phys[i]); - - return 0; -} - -static int xhci_mtk_phy_power_on(struct xhci_hcd_mtk *mtk) -{ - int i; - int ret; - - for (i = 0; i < mtk->num_phys; i++) { - ret = phy_power_on(mtk->phys[i]); - if (ret) - goto power_off_phy; - } - return 0; - -power_off_phy: - for (; i > 0; i--) - phy_power_off(mtk->phys[i - 1]); - - return ret; -} - -static void xhci_mtk_phy_power_off(struct xhci_hcd_mtk *mtk) -{ - unsigned int i; - - for (i = 0; i < mtk->num_phys; i++) - phy_power_off(mtk->phys[i]); -} - static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk) { int ret; @@ -488,8 +431,6 @@ static int xhci_mtk_probe(struct platform_device *pdev) struct xhci_hcd *xhci; struct resource *res; struct usb_hcd *hcd; - struct phy *phy; - int phy_num; int ret = -ENODEV; int irq; @@ -529,16 +470,6 @@ static int xhci_mtk_probe(struct platform_device *pdev) return ret; } - mtk->num_phys = of_count_phandle_with_args(node, - "phys", "#phy-cells"); - if (mtk->num_phys > 0) { - mtk->phys = devm_kcalloc(dev, mtk->num_phys, - sizeof(*mtk->phys), GFP_KERNEL); - if (!mtk->phys) - return -ENOMEM; - } else { - mtk->num_phys = 0; - } pm_runtime_enable(dev); pm_runtime_get_sync(dev); device_enable_async_suspend(dev); @@ -596,23 +527,6 @@ static int xhci_mtk_probe(struct platform_device *pdev) mtk->has_ippc = false; } - for (phy_num = 0; phy_num < mtk->num_phys; phy_num++) { - phy = devm_of_phy_get_by_index(dev, node, phy_num); - if (IS_ERR(phy)) { - ret = PTR_ERR(phy); - goto put_usb2_hcd; - } - mtk->phys[phy_num] = phy; - } - - ret = xhci_mtk_phy_init(mtk); - if (ret) - goto put_usb2_hcd; - - ret = xhci_mtk_phy_power_on(mtk); - if (ret) - goto exit_phys; - device_init_wakeup(dev, true); xhci = hcd_to_xhci(hcd); @@ -630,7 +544,7 @@ static int xhci_mtk_probe(struct platform_device *pdev) dev_name(dev), hcd); if (!xhci->shared_hcd) { ret = -ENOMEM; - goto power_off_phys; + goto disable_device_wakeup; } ret = usb_add_hcd(hcd, irq, IRQF_SHARED); @@ -653,13 +567,9 @@ put_usb3_hcd: xhci_mtk_sch_exit(mtk); usb_put_hcd(xhci->shared_hcd); -power_off_phys: - xhci_mtk_phy_power_off(mtk); +disable_device_wakeup: device_init_wakeup(dev, false); -exit_phys: - xhci_mtk_phy_exit(mtk); - put_usb2_hcd: usb_put_hcd(hcd); @@ -682,8 +592,6 @@ static int xhci_mtk_remove(struct platform_device *dev) struct xhci_hcd *xhci = hcd_to_xhci(hcd); usb_remove_hcd(xhci->shared_hcd); - xhci_mtk_phy_power_off(mtk); - xhci_mtk_phy_exit(mtk); device_init_wakeup(&dev->dev, false); usb_remove_hcd(hcd); @@ -718,7 +626,6 @@ static int __maybe_unused xhci_mtk_suspend(struct device *dev) del_timer_sync(&xhci->shared_hcd->rh_timer); xhci_mtk_host_disable(mtk); - xhci_mtk_phy_power_off(mtk); xhci_mtk_clks_disable(mtk); usb_wakeup_set(mtk, true); return 0; @@ -732,7 +639,6 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev) usb_wakeup_set(mtk, false); xhci_mtk_clks_enable(mtk); - xhci_mtk_phy_power_on(mtk); xhci_mtk_host_enable(mtk); xhci_dbg(xhci, "%s: restart port polling\n", __func__); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 6652e2d5bd2e..df327dcc2bac 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -284,6 +284,7 @@ static int xhci_plat_probe(struct platform_device *pdev) ret = usb_phy_init(hcd->usb_phy); if (ret) goto put_usb3_hcd; + hcd->skip_phy_initialization = 1; } ret = usb_add_hcd(hcd, irq, IRQF_SHARED); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index daa94c3aed80..91a1a824673d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1436,7 +1436,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, case TRB_STOP_RING: WARN_ON(slot_id != TRB_TO_SLOT_ID( le32_to_cpu(cmd_trb->generic.field[3]))); - xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event); + if (!cmd->completion) + xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event); break; case TRB_SET_DEQ: WARN_ON(slot_id != TRB_TO_SLOT_ID( @@ -1815,8 +1816,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, - struct xhci_td *td, union xhci_trb *ep_trb, + unsigned int stream_id, struct xhci_td *td, enum xhci_ep_reset_type reset_type) { struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; @@ -1829,9 +1829,10 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, xhci_queue_reset_ep(xhci, command, slot_id, ep_index, reset_type); - if (reset_type == EP_HARD_RESET) + if (reset_type == EP_HARD_RESET) { + ep->ep_state |= EP_HARD_CLEAR_TOGGLE; xhci_cleanup_stalled_ring(xhci, ep_index, stream_id, td); - + } xhci_ring_cmd_db(xhci); } @@ -1922,7 +1923,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, } static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event, + struct xhci_transfer_event *event, struct xhci_virt_ep *ep, int *status) { struct xhci_virt_device *xdev; @@ -1957,8 +1958,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, * The class driver clears the device side halt later. */ xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, - ep_ring->stream_id, td, ep_trb, - EP_HARD_RESET); + ep_ring->stream_id, td, EP_HARD_RESET); } else { /* Update ring dequeue pointer */ while (ep_ring->dequeue != td->last_trb) @@ -2083,7 +2083,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length = requested; finish_td: - return finish_td(xhci, td, ep_trb, event, ep, status); + return finish_td(xhci, td, event, ep, status); } /* @@ -2170,7 +2170,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->actual_length += frame->actual_length; - return finish_td(xhci, td, ep_trb, event, ep, status); + return finish_td(xhci, td, event, ep, status); } static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, @@ -2260,7 +2260,7 @@ finish_td: remaining); td->urb->actual_length = 0; } - return finish_td(xhci, td, ep_trb, event, ep, status); + return finish_td(xhci, td, event, ep, status); } /* @@ -2318,7 +2318,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, case COMP_INVALID_STREAM_TYPE_ERROR: case COMP_INVALID_STREAM_ID_ERROR: xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, 0, - NULL, NULL, EP_SOFT_RESET); + NULL, EP_SOFT_RESET); goto cleanup; case COMP_RING_UNDERRUN: case COMP_RING_OVERRUN: @@ -2584,8 +2584,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, ep_ring->stream_id, - td, ep_trb, - EP_HARD_RESET); + td, EP_HARD_RESET); goto cleanup; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 5d37700ae4b0..9b27798ecce5 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1290,7 +1290,8 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag struct xhci_hcd *xhci = hcd_to_xhci(hcd); unsigned long flags; int ret = 0; - unsigned int slot_id, ep_index, ep_state; + unsigned int slot_id, ep_index; + unsigned int *ep_state; struct urb_priv *urb_priv; int num_tds; @@ -1300,6 +1301,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag slot_id = urb->dev->slot_id; ep_index = xhci_get_endpoint_index(&urb->ep->desc); + ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state; if (!HCD_HW_ACCESSIBLE(hcd)) { if (!in_interrupt()) @@ -1351,6 +1353,17 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ret = -ESHUTDOWN; goto free_priv; } + if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { + xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", + *ep_state); + ret = -EINVAL; + goto free_priv; + } + if (*ep_state & EP_SOFT_CLEAR_TOGGLE) { + xhci_warn(xhci, "Can't enqueue URB while manually clearing toggle\n"); + ret = -EINVAL; + goto free_priv; + } switch (usb_endpoint_type(&urb->ep->desc)) { @@ -1359,23 +1372,13 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag slot_id, ep_index); break; case USB_ENDPOINT_XFER_BULK: - ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; - if (ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { - xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", - ep_state); - ret = -EINVAL; - break; - } ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); break; - - case USB_ENDPOINT_XFER_INT: ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); break; - case USB_ENDPOINT_XFER_ISOC: ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb, slot_id, ep_index); @@ -2874,33 +2877,103 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, } } -/* Called when clearing halted device. The core should have sent the control - * message to clear the device halt condition. The host side of the halt should - * already be cleared with a reset endpoint command issued when the STALL tx - * event was received. +/* + * Called after usb core issues a clear halt control message. + * The host side of the halt should already be cleared by a reset endpoint + * command issued when the STALL event was received. * - * Context: in_interrupt + * The reset endpoint command may only be issued to endpoints in the halted + * state. For software that wishes to reset the data toggle or sequence number + * of an endpoint that isn't in the halted state this function will issue a + * configure endpoint command with the Drop and Add bits set for the target + * endpoint. Refer to the additional note in xhci spcification section 4.6.8. */ static void xhci_endpoint_reset(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) + struct usb_host_endpoint *host_ep) { struct xhci_hcd *xhci; + struct usb_device *udev; + struct xhci_virt_device *vdev; + struct xhci_virt_ep *ep; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_command *stop_cmd, *cfg_cmd; + unsigned int ep_index; + unsigned long flags; + u32 ep_flag; xhci = hcd_to_xhci(hcd); + if (!host_ep->hcpriv) + return; + udev = (struct usb_device *) host_ep->hcpriv; + vdev = xhci->devs[udev->slot_id]; + ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = &vdev->eps[ep_index]; + + /* Bail out if toggle is already being cleared by a endpoint reset */ + if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) { + ep->ep_state &= ~EP_HARD_CLEAR_TOGGLE; + return; + } + /* Only interrupt and bulk ep's use data toggle, USB2 spec 5.5.4-> */ + if (usb_endpoint_xfer_control(&host_ep->desc) || + usb_endpoint_xfer_isoc(&host_ep->desc)) + return; + + ep_flag = xhci_get_endpoint_flag(&host_ep->desc); + + if (ep_flag == SLOT_FLAG || ep_flag == EP0_FLAG) + return; + + stop_cmd = xhci_alloc_command(xhci, true, GFP_NOWAIT); + if (!stop_cmd) + return; + + cfg_cmd = xhci_alloc_command_with_ctx(xhci, true, GFP_NOWAIT); + if (!cfg_cmd) + goto cleanup; + + spin_lock_irqsave(&xhci->lock, flags); + + /* block queuing new trbs and ringing ep doorbell */ + ep->ep_state |= EP_SOFT_CLEAR_TOGGLE; /* - * We might need to implement the config ep cmd in xhci 4.8.1 note: - * The Reset Endpoint Command may only be issued to endpoints in the - * Halted state. If software wishes reset the Data Toggle or Sequence - * Number of an endpoint that isn't in the Halted state, then software - * may issue a Configure Endpoint Command with the Drop and Add bits set - * for the target endpoint. that is in the Stopped state. + * Make sure endpoint ring is empty before resetting the toggle/seq. + * Driver is required to synchronously cancel all transfer request. + * Stop the endpoint to force xHC to update the output context */ - /* For now just print debug to follow the situation */ - xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n", - ep->desc.bEndpointAddress); + if (!list_empty(&ep->ring->td_list)) { + dev_err(&udev->dev, "EP not empty, refuse reset\n"); + spin_unlock_irqrestore(&xhci->lock, flags); + goto cleanup; + } + xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id, ep_index, 0); + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + wait_for_completion(stop_cmd->completion); + + spin_lock_irqsave(&xhci->lock, flags); + + /* config ep command clears toggle if add and drop ep flags are set */ + ctrl_ctx = xhci_get_input_control_ctx(cfg_cmd->in_ctx); + xhci_setup_input_ctx_for_config_ep(xhci, cfg_cmd->in_ctx, vdev->out_ctx, + ctrl_ctx, ep_flag, ep_flag); + xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index); + + xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma, + udev->slot_id, false); + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + wait_for_completion(cfg_cmd->completion); + + ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE; + xhci_free_command(xhci, cfg_cmd); +cleanup: + xhci_free_command(xhci, stop_cmd); } static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, @@ -4768,6 +4841,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) * quirks */ struct device *dev = hcd->self.sysdev; + unsigned int minor_rev; int retval; /* Accept arbitrarily long scatter-gather lists */ @@ -4795,12 +4869,19 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) */ hcd->has_tt = 1; } else { - /* Some 3.1 hosts return sbrn 0x30, can't rely on sbrn alone */ - if (xhci->sbrn == 0x31 || xhci->usb3_rhub.min_rev >= 1) { - xhci_info(xhci, "Host supports USB 3.1 Enhanced SuperSpeed\n"); + /* + * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol + * minor revision instead of sbrn + */ + minor_rev = xhci->usb3_rhub.min_rev; + if (minor_rev) { hcd->speed = HCD_USB31; hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS; } + xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n", + minor_rev, + minor_rev ? "Enhanced" : ""); + /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 866e141d4972..8acc8f8d790f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -922,6 +922,8 @@ struct xhci_virt_ep { #define EP_HAS_STREAMS (1 << 4) /* Transitioning the endpoint to not using streams, don't enqueue URBs */ #define EP_GETTING_NO_STREAMS (1 << 5) +#define EP_HARD_CLEAR_TOGGLE (1 << 6) +#define EP_SOFT_CLEAR_TOGGLE (1 << 7) /* ---- Related to URB cancellation ---- */ struct list_head cancelled_td_list; /* Watchdog timer for stop endpoint command to cancel URBs */ diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index bac4ef5d9512..1714b2258b54 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1441,7 +1441,6 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq, unsigned long irqflags) { struct isp1760_udc *udc = &isp->udc; - const char *devname; int ret; udc->irq = -1; @@ -1455,13 +1454,10 @@ int isp1760_udc_register(struct isp1760_device *isp, int irq, if (ret < 0) return ret; - devname = dev_name(isp->dev); - udc->irqname = kmalloc(strlen(devname) + 7, GFP_KERNEL); + udc->irqname = kasprintf(GFP_KERNEL, "%s (udc)", dev_name(isp->dev)); if (!udc->irqname) return -ENOMEM; - sprintf(udc->irqname, "%s (udc)", devname); - ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags, udc->irqname, udc); if (ret < 0) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 4b8712733fc7..b3160afe0458 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -54,7 +54,7 @@ MODULE_DEVICE_TABLE(usb, device_table); /* we can have up to this number of device plugged in at once */ #define MAX_DEVICES 16 -#define COMMAND_TIMEOUT (2*HZ) /* 60 second timeout for a command */ +#define COMMAND_TIMEOUT (2*HZ) /* * The locking scheme is a vanilla 3-lock: @@ -132,6 +132,8 @@ static void adu_abort_transfers(struct adu_device *dev) spin_lock_irqsave(&dev->buflock, flags); if (!dev->out_urb_finished) { spin_unlock_irqrestore(&dev->buflock, flags); + wait_event_timeout(dev->write_wait, dev->out_urb_finished, + COMMAND_TIMEOUT); usb_kill_urb(dev->interrupt_out_urb); } else spin_unlock_irqrestore(&dev->buflock, flags); diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 716cb515523e..cf5828ce927a 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -168,14 +168,10 @@ static int chaoskey_probe(struct usb_interface *interface, */ if (udev->product && udev->serial) { - dev->name = kmalloc(strlen(udev->product) + 1 + - strlen(udev->serial) + 1, GFP_KERNEL); + dev->name = kasprintf(GFP_KERNEL, "%s-%s", udev->product, + udev->serial); if (dev->name == NULL) goto out; - - strcpy(dev->name, udev->product); - strcat(dev->name, "-"); - strcat(dev->name, udev->serial); } dev->interface = interface; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 90028ef541e3..9e1142b8b91b 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -2028,11 +2028,14 @@ test_queue(struct usbtest_dev *dev, struct usbtest_param_32 *param, unsigned i; unsigned long packets = 0; int status = 0; - struct urb *urbs[param->sglen]; + struct urb *urbs[MAX_SGLEN]; if (!param->sglen || param->iterations > UINT_MAX / param->sglen) return -EINVAL; + if (param->sglen > MAX_SGLEN) + return -EINVAL; + memset(&context, 0, sizeof(context)); context.count = param->iterations * param->sglen; context.dev = dev; diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 7cf5a1bbdaff..025b2c8630df 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -112,11 +112,7 @@ static int musb_regdump_show(struct seq_file *s, void *unused) pm_runtime_put_autosuspend(musb->controller); return 0; } - -static int musb_regdump_open(struct inode *inode, struct file *file) -{ - return single_open(file, musb_regdump_show, inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(musb_regdump); static int musb_test_mode_show(struct seq_file *s, void *unused) { @@ -161,13 +157,6 @@ static int musb_test_mode_show(struct seq_file *s, void *unused) return 0; } -static const struct file_operations musb_regdump_fops = { - .open = musb_regdump_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int musb_test_mode_open(struct inode *inode, struct file *file) { return single_open(file, musb_test_mode_show, inode->i_private); diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/fusb302/fusb302.c index dcd8ef085b30..06794c06330f 100644 --- a/drivers/usb/typec/fusb302/fusb302.c +++ b/drivers/usb/typec/fusb302/fusb302.c @@ -199,7 +199,7 @@ static void fusb302_log(struct fusb302_chip *chip, const char *fmt, ...) va_end(args); } -static int fusb302_seq_show(struct seq_file *s, void *v) +static int fusb302_debug_show(struct seq_file *s, void *v) { struct fusb302_chip *chip = (struct fusb302_chip *)s->private; int tail; @@ -216,18 +216,7 @@ static int fusb302_seq_show(struct seq_file *s, void *v) return 0; } - -static int fusb302_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, fusb302_seq_show, inode->i_private); -} - -static const struct file_operations fusb302_debug_operations = { - .open = fusb302_debug_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(fusb302_debug); static struct dentry *rootdir; @@ -242,7 +231,7 @@ static int fusb302_debugfs_init(struct fusb302_chip *chip) chip->dentry = debugfs_create_file(dev_name(chip->dev), S_IFREG | 0444, rootdir, - chip, &fusb302_debug_operations); + chip, &fusb302_debug_fops); return 0; } diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c index 8b637a4b474b..4c0fc5493d58 100644 --- a/drivers/usb/typec/tcpm.c +++ b/drivers/usb/typec/tcpm.c @@ -503,7 +503,7 @@ static void tcpm_log_source_caps(struct tcpm_port *port) } } -static int tcpm_seq_show(struct seq_file *s, void *v) +static int tcpm_debug_show(struct seq_file *s, void *v) { struct tcpm_port *port = (struct tcpm_port *)s->private; int tail; @@ -520,18 +520,7 @@ static int tcpm_seq_show(struct seq_file *s, void *v) return 0; } - -static int tcpm_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, tcpm_seq_show, inode->i_private); -} - -static const struct file_operations tcpm_debug_operations = { - .open = tcpm_debug_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(tcpm_debug); static struct dentry *rootdir; @@ -547,7 +536,7 @@ static int tcpm_debugfs_init(struct tcpm_port *port) port->dentry = debugfs_create_file(dev_name(port->dev), S_IFREG | 0444, rootdir, - port, &tcpm_debug_operations); + port, &tcpm_debug_fops); return 0; } @@ -1041,7 +1030,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, break; case CMDT_RSP_ACK: /* silently drop message if we are not connected */ - if (!port->partner) + if (IS_ERR_OR_NULL(port->partner)) break; switch (cmd) { @@ -3664,8 +3653,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->port_type = tcpc->config->type; port->typec_port = typec_register_port(port->dev, &port->typec_caps); - if (!port->typec_port) { - err = -ENOMEM; + if (IS_ERR(port->typec_port)) { + err = PTR_ERR(port->typec_port); goto out_destroy_wq; } @@ -3674,15 +3663,17 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) i = 0; while (paltmode->svid && i < ARRAY_SIZE(port->port_altmode)) { - port->port_altmode[i] = - typec_port_register_altmode(port->typec_port, - paltmode); - if (!port->port_altmode[i]) { + struct typec_altmode *alt; + + alt = typec_port_register_altmode(port->typec_port, + paltmode); + if (IS_ERR(alt)) { tcpm_log(port, "%s: failed to register port alternate mode 0x%x", dev_name(dev), paltmode->svid); break; } + port->port_altmode[i] = alt; i++; paltmode++; } diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index 2719f5d382f7..37a15c14a6c6 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -158,15 +158,15 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) desc.identity = &tps->partner_identity; } - tps->partner = typec_register_partner(tps->port, &desc); - if (!tps->partner) - return -ENODEV; - typec_set_pwr_opmode(tps->port, mode); typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status)); + tps->partner = typec_register_partner(tps->port, &desc); + if (IS_ERR(tps->partner)) + return PTR_ERR(tps->partner); + if (desc.identity) typec_partner_set_identity(tps->partner); @@ -175,7 +175,8 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) static void tps6598x_disconnect(struct tps6598x *tps, u32 status) { - typec_unregister_partner(tps->partner); + if (!IS_ERR(tps->partner)) + typec_unregister_partner(tps->partner); tps->partner = NULL; typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB); typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); @@ -418,8 +419,8 @@ static int tps6598x_probe(struct i2c_client *client) tps->typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; tps->port = typec_register_port(&client->dev, &tps->typec_cap); - if (!tps->port) - return -ENODEV; + if (IS_ERR(tps->port)) + return PTR_ERR(tps->port); if (status & TPS_STATUS_PLUG_PRESENT) { ret = tps6598x_connect(tps, status); diff --git a/drivers/usb/typec/typec.c b/drivers/usb/typec/typec.c index 735726ced602..dc28ad868d93 100644 --- a/drivers/usb/typec/typec.c +++ b/drivers/usb/typec/typec.c @@ -386,7 +386,7 @@ typec_register_altmode(struct device *parent, alt = kzalloc(sizeof(*alt), GFP_KERNEL); if (!alt) - return NULL; + return ERR_PTR(-ENOMEM); alt->svid = desc->svid; alt->n_modes = desc->n_modes; @@ -402,7 +402,7 @@ typec_register_altmode(struct device *parent, dev_err(parent, "failed to register alternate mode (%d)\n", ret); put_device(&alt->dev); - return NULL; + return ERR_PTR(ret); } return alt; @@ -417,7 +417,7 @@ typec_register_altmode(struct device *parent, */ void typec_unregister_altmode(struct typec_altmode *alt) { - if (alt) + if (!IS_ERR_OR_NULL(alt)) device_unregister(&alt->dev); } EXPORT_SYMBOL_GPL(typec_unregister_altmode); @@ -509,7 +509,7 @@ EXPORT_SYMBOL_GPL(typec_partner_register_altmode); * * Registers a device for USB Type-C Partner described in @desc. * - * Returns handle to the partner on success or NULL on failure. + * Returns handle to the partner on success or ERR_PTR on failure. */ struct typec_partner *typec_register_partner(struct typec_port *port, struct typec_partner_desc *desc) @@ -519,7 +519,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port, partner = kzalloc(sizeof(*partner), GFP_KERNEL); if (!partner) - return NULL; + return ERR_PTR(-ENOMEM); partner->usb_pd = desc->usb_pd; partner->accessory = desc->accessory; @@ -542,7 +542,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port, if (ret) { dev_err(&port->dev, "failed to register partner (%d)\n", ret); put_device(&partner->dev); - return NULL; + return ERR_PTR(ret); } return partner; @@ -557,7 +557,7 @@ EXPORT_SYMBOL_GPL(typec_register_partner); */ void typec_unregister_partner(struct typec_partner *partner) { - if (partner) + if (!IS_ERR_OR_NULL(partner)) device_unregister(&partner->dev); } EXPORT_SYMBOL_GPL(typec_unregister_partner); @@ -587,7 +587,7 @@ static const struct device_type typec_plug_dev_type = { * the plug lists 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_plug_register_altmode(struct typec_plug *plug, @@ -606,7 +606,7 @@ EXPORT_SYMBOL_GPL(typec_plug_register_altmode); * Cable Plug represents a plug with electronics in it that can response to USB * Power Delivery SOP Prime or SOP Double Prime packages. * - * Returns handle to the cable plug on success or NULL on failure. + * Returns handle to the cable plug on success or ERR_PTR on failure. */ struct typec_plug *typec_register_plug(struct typec_cable *cable, struct typec_plug_desc *desc) @@ -617,7 +617,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable, plug = kzalloc(sizeof(*plug), GFP_KERNEL); if (!plug) - return NULL; + return ERR_PTR(-ENOMEM); sprintf(name, "plug%d", desc->index); @@ -631,7 +631,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable, if (ret) { dev_err(&cable->dev, "failed to register plug (%d)\n", ret); put_device(&plug->dev); - return NULL; + return ERR_PTR(ret); } return plug; @@ -646,7 +646,7 @@ EXPORT_SYMBOL_GPL(typec_register_plug); */ void typec_unregister_plug(struct typec_plug *plug) { - if (plug) + if (!IS_ERR_OR_NULL(plug)) device_unregister(&plug->dev); } EXPORT_SYMBOL_GPL(typec_unregister_plug); @@ -724,7 +724,7 @@ EXPORT_SYMBOL_GPL(typec_cable_set_identity); * Registers a device for USB Type-C Cable described in @desc. The cable will be * parent for the optional cable plug devises. * - * Returns handle to the cable on success or NULL on failure. + * Returns handle to the cable on success or ERR_PTR on failure. */ struct typec_cable *typec_register_cable(struct typec_port *port, struct typec_cable_desc *desc) @@ -734,7 +734,7 @@ struct typec_cable *typec_register_cable(struct typec_port *port, cable = kzalloc(sizeof(*cable), GFP_KERNEL); if (!cable) - return NULL; + return ERR_PTR(-ENOMEM); cable->type = desc->type; cable->active = desc->active; @@ -757,7 +757,7 @@ struct typec_cable *typec_register_cable(struct typec_port *port, if (ret) { dev_err(&port->dev, "failed to register cable (%d)\n", ret); put_device(&cable->dev); - return NULL; + return ERR_PTR(ret); } return cable; @@ -772,7 +772,7 @@ EXPORT_SYMBOL_GPL(typec_register_cable); */ void typec_unregister_cable(struct typec_cable *cable) { - if (cable) + if (!IS_ERR_OR_NULL(cable)) device_unregister(&cable->dev); } EXPORT_SYMBOL_GPL(typec_unregister_cable); @@ -1256,7 +1256,7 @@ EXPORT_SYMBOL_GPL(typec_set_pwr_opmode); * This routine is used to register an alternate mode that @port is capable of * supporting. * - * 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_port_register_altmode(struct typec_port *port, @@ -1273,7 +1273,7 @@ EXPORT_SYMBOL_GPL(typec_port_register_altmode); * * Registers a device for USB Type-C Port described in @cap. * - * Returns handle to the port on success or NULL on failure. + * Returns handle to the port on success or ERR_PTR on failure. */ struct typec_port *typec_register_port(struct device *parent, const struct typec_capability *cap) @@ -1285,12 +1285,12 @@ struct typec_port *typec_register_port(struct device *parent, port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) - return NULL; + return ERR_PTR(-ENOMEM); id = ida_simple_get(&typec_index_ida, 0, 0, GFP_KERNEL); if (id < 0) { kfree(port); - return NULL; + return ERR_PTR(id); } if (cap->type == TYPEC_PORT_DFP) @@ -1326,7 +1326,7 @@ struct typec_port *typec_register_port(struct device *parent, if (ret) { dev_err(parent, "failed to register port (%d)\n", ret); put_device(&port->dev); - return NULL; + return ERR_PTR(ret); } return port; @@ -1341,7 +1341,7 @@ EXPORT_SYMBOL_GPL(typec_register_port); */ void typec_unregister_port(struct typec_port *port) { - if (port) + if (!IS_ERR_OR_NULL(port)) device_unregister(&port->dev); } EXPORT_SYMBOL_GPL(typec_unregister_port); diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 79046fe66426..69d544cfcd45 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -260,38 +260,45 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con) static int ucsi_register_partner(struct ucsi_connector *con) { - struct typec_partner_desc partner; + struct typec_partner_desc desc; + struct typec_partner *partner; if (con->partner) return 0; - memset(&partner, 0, sizeof(partner)); + memset(&desc, 0, sizeof(desc)); switch (con->status.partner_type) { case UCSI_CONSTAT_PARTNER_TYPE_DEBUG: - partner.accessory = TYPEC_ACCESSORY_DEBUG; + desc.accessory = TYPEC_ACCESSORY_DEBUG; break; case UCSI_CONSTAT_PARTNER_TYPE_AUDIO: - partner.accessory = TYPEC_ACCESSORY_AUDIO; + desc.accessory = TYPEC_ACCESSORY_AUDIO; break; default: break; } - partner.usb_pd = con->status.pwr_op_mode == UCSI_CONSTAT_PWR_OPMODE_PD; + desc.usb_pd = con->status.pwr_op_mode == UCSI_CONSTAT_PWR_OPMODE_PD; - con->partner = typec_register_partner(con->port, &partner); - if (!con->partner) { - dev_err(con->ucsi->dev, "con%d: failed to register partner\n", - con->num); - return -ENODEV; + partner = typec_register_partner(con->port, &desc); + if (IS_ERR(partner)) { + dev_err(con->ucsi->dev, + "con%d: failed to register partner (%ld)\n", con->num, + PTR_ERR(partner)); + return PTR_ERR(partner); } + con->partner = partner; + return 0; } static void ucsi_unregister_partner(struct ucsi_connector *con) { + if (!con->partner) + return; + typec_unregister_partner(con->partner); con->partner = NULL; } @@ -606,8 +613,8 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) /* Register the connector */ con->port = typec_register_port(ucsi->dev, cap); - if (!con->port) - return -ENODEV; + if (IS_ERR(con->port)) + return PTR_ERR(con->port); /* Get the status */ UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 26ca0ec01fd5..c3ddd0f1f449 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -640,4 +640,4 @@ static struct usb_driver skel_driver = { module_usb_driver(skel_driver); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index eeefa29f8aa2..a20b65cb6678 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -27,7 +27,7 @@ config USBIP_VHCI_HCD config USBIP_VHCI_HC_PORTS int "Number of ports per USB/IP virtual host controller" - range 1 31 + range 1 15 default 8 depends on USBIP_VHCI_HCD ---help--- diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 4c00be2d1993..aff50eb09ca9 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -202,7 +202,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, struct scatterlist sg[4], sg_dst; void *dst_buf; size_t dst_size; - u8 iv[crypto_skcipher_ivsize(tfm_cbc)]; + u8 *iv; size_t zero_padding; /* @@ -224,7 +224,9 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, if (!dst_buf) goto error_dst_buf; - memset(iv, 0, sizeof(iv)); + iv = kzalloc(crypto_skcipher_ivsize(tfm_cbc), GFP_KERNEL); + if (!iv) + goto error_iv; /* Setup B0 */ scratch->b0.flags = 0x59; /* Format B0 */ @@ -276,6 +278,8 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, bytewise_xor(mic, &scratch->ax, iv, 8); result = 8; error_cbc_crypt: + kfree(iv); +error_iv: kfree(dst_buf); error_dst_buf: return result; diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c index 9fdcb6b84abf..5f0656db5482 100644 --- a/drivers/usb/wusbcore/wa-nep.c +++ b/drivers/usb/wusbcore/wa-nep.c @@ -93,7 +93,6 @@ static void wa_notif_dispatch(struct work_struct *ws) goto out; /* screw it */ #endif atomic_dec(&wa->notifs_queued); /* Throttling ctl */ - dev = &wa->usb_iface->dev; size = nw->size; itr = nw->data; diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c index 991374b13571..f1622bae13be 100644 --- a/drivers/uwb/uwb-debug.c +++ b/drivers/uwb/uwb-debug.c @@ -206,7 +206,7 @@ static const struct file_operations command_fops = { .owner = THIS_MODULE, }; -static int reservations_print(struct seq_file *s, void *p) +static int reservations_show(struct seq_file *s, void *p) { struct uwb_rc *rc = s->private; struct uwb_rsv *rsv; @@ -240,21 +240,9 @@ static int reservations_print(struct seq_file *s, void *p) return 0; } +DEFINE_SHOW_ATTRIBUTE(reservations); -static int reservations_open(struct inode *inode, struct file *file) -{ - return single_open(file, reservations_print, inode->i_private); -} - -static const struct file_operations reservations_fops = { - .open = reservations_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int drp_avail_print(struct seq_file *s, void *p) +static int drp_avail_show(struct seq_file *s, void *p) { struct uwb_rc *rc = s->private; @@ -264,19 +252,7 @@ static int drp_avail_print(struct seq_file *s, void *p) return 0; } - -static int drp_avail_open(struct inode *inode, struct file *file) -{ - return single_open(file, drp_avail_print, inode->i_private); -} - -static const struct file_operations drp_avail_fops = { - .open = drp_avail_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(drp_avail); static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel) { diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 176900528822..aef50cb2ed1b 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -103,7 +103,7 @@ struct usb_hcd { * other external phys should be software-transparent */ struct usb_phy *usb_phy; - struct phy *phy; + struct usb_phy_roothub *phy_roothub; /* Flags that need to be manipulated atomically because they can * change while the host controller is running. Always use @@ -151,6 +151,12 @@ struct usb_hcd { unsigned msix_enabled:1; /* driver has MSI-X enabled? */ unsigned msi_enabled:1; /* driver has MSI enabled? */ unsigned remove_phy:1; /* auto-remove USB phy */ + /* + * do not manage the PHY state in the HCD core, instead let the driver + * handle this (for example if the PHY can only be turned on after a + * specific event) + */ + unsigned skip_phy_initialization:1; /* The next flag is a stopgap, to be removed when all the HCDs * support the new root-hub polling mechanism. */ diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index b3d41d7409b3..ff359bdfdc7b 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -35,6 +35,13 @@ enum pd_ctrl_msg_type { PD_CTRL_WAIT = 12, PD_CTRL_SOFT_RESET = 13, /* 14-15 Reserved */ + PD_CTRL_NOT_SUPP = 16, + PD_CTRL_GET_SOURCE_CAP_EXT = 17, + PD_CTRL_GET_STATUS = 18, + PD_CTRL_FR_SWAP = 19, + PD_CTRL_GET_PPS_STATUS = 20, + PD_CTRL_GET_COUNTRY_CODES = 21, + /* 22-31 Reserved */ }; enum pd_data_msg_type { @@ -43,13 +50,39 @@ enum pd_data_msg_type { PD_DATA_REQUEST = 2, PD_DATA_BIST = 3, PD_DATA_SINK_CAP = 4, - /* 5-14 Reserved */ + PD_DATA_BATT_STATUS = 5, + PD_DATA_ALERT = 6, + PD_DATA_GET_COUNTRY_INFO = 7, + /* 8-14 Reserved */ PD_DATA_VENDOR_DEF = 15, + /* 16-31 Reserved */ +}; + +enum pd_ext_msg_type { + /* 0 Reserved */ + PD_EXT_SOURCE_CAP_EXT = 1, + PD_EXT_STATUS = 2, + PD_EXT_GET_BATT_CAP = 3, + PD_EXT_GET_BATT_STATUS = 4, + PD_EXT_BATT_CAP = 5, + PD_EXT_GET_MANUFACTURER_INFO = 6, + PD_EXT_MANUFACTURER_INFO = 7, + PD_EXT_SECURITY_REQUEST = 8, + PD_EXT_SECURITY_RESPONSE = 9, + PD_EXT_FW_UPDATE_REQUEST = 10, + PD_EXT_FW_UPDATE_RESPONSE = 11, + PD_EXT_PPS_STATUS = 12, + PD_EXT_COUNTRY_INFO = 13, + PD_EXT_COUNTRY_CODES = 14, + /* 15-31 Reserved */ }; #define PD_REV10 0x0 #define PD_REV20 0x1 +#define PD_REV30 0x2 +#define PD_MAX_REV PD_REV30 +#define PD_HEADER_EXT_HDR BIT(15) #define PD_HEADER_CNT_SHIFT 12 #define PD_HEADER_CNT_MASK 0x7 #define PD_HEADER_ID_SHIFT 9 @@ -59,18 +92,19 @@ enum pd_data_msg_type { #define PD_HEADER_REV_MASK 0x3 #define PD_HEADER_DATA_ROLE BIT(5) #define PD_HEADER_TYPE_SHIFT 0 -#define PD_HEADER_TYPE_MASK 0xf +#define PD_HEADER_TYPE_MASK 0x1f -#define PD_HEADER(type, pwr, data, id, cnt) \ +#define PD_HEADER(type, pwr, data, rev, id, cnt, ext_hdr) \ ((((type) & PD_HEADER_TYPE_MASK) << PD_HEADER_TYPE_SHIFT) | \ ((pwr) == TYPEC_SOURCE ? PD_HEADER_PWR_ROLE : 0) | \ ((data) == TYPEC_HOST ? PD_HEADER_DATA_ROLE : 0) | \ - (PD_REV20 << PD_HEADER_REV_SHIFT) | \ + (rev << PD_HEADER_REV_SHIFT) | \ (((id) & PD_HEADER_ID_MASK) << PD_HEADER_ID_SHIFT) | \ - (((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT)) + (((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT) | \ + ((ext_hdr) ? PD_HEADER_EXT_HDR : 0)) #define PD_HEADER_LE(type, pwr, data, id, cnt) \ - cpu_to_le16(PD_HEADER((type), (pwr), (data), (id), (cnt))) + cpu_to_le16(PD_HEADER((type), (pwr), (data), PD_REV20, (id), (cnt), (0))) static inline unsigned int pd_header_cnt(u16 header) { @@ -102,16 +136,75 @@ static inline unsigned int pd_header_msgid_le(__le16 header) return pd_header_msgid(le16_to_cpu(header)); } +static inline unsigned int pd_header_rev(u16 header) +{ + return (header >> PD_HEADER_REV_SHIFT) & PD_HEADER_REV_MASK; +} + +static inline unsigned int pd_header_rev_le(__le16 header) +{ + return pd_header_rev(le16_to_cpu(header)); +} + +#define PD_EXT_HDR_CHUNKED BIT(15) +#define PD_EXT_HDR_CHUNK_NUM_SHIFT 11 +#define PD_EXT_HDR_CHUNK_NUM_MASK 0xf +#define PD_EXT_HDR_REQ_CHUNK BIT(10) +#define PD_EXT_HDR_DATA_SIZE_SHIFT 0 +#define PD_EXT_HDR_DATA_SIZE_MASK 0x1ff + +#define PD_EXT_HDR(data_size, req_chunk, chunk_num, chunked) \ + ((((data_size) & PD_EXT_HDR_DATA_SIZE_MASK) << PD_EXT_HDR_DATA_SIZE_SHIFT) | \ + ((req_chunk) ? PD_EXT_HDR_REQ_CHUNK : 0) | \ + (((chunk_num) & PD_EXT_HDR_CHUNK_NUM_MASK) << PD_EXT_HDR_CHUNK_NUM_SHIFT) | \ + ((chunked) ? PD_EXT_HDR_CHUNKED : 0)) + +#define PD_EXT_HDR_LE(data_size, req_chunk, chunk_num, chunked) \ + cpu_to_le16(PD_EXT_HDR((data_size), (req_chunk), (chunk_num), (chunked))) + +static inline unsigned int pd_ext_header_chunk_num(u16 ext_header) +{ + return (ext_header >> PD_EXT_HDR_CHUNK_NUM_SHIFT) & + PD_EXT_HDR_CHUNK_NUM_MASK; +} + +static inline unsigned int pd_ext_header_data_size(u16 ext_header) +{ + return (ext_header >> PD_EXT_HDR_DATA_SIZE_SHIFT) & + PD_EXT_HDR_DATA_SIZE_MASK; +} + +static inline unsigned int pd_ext_header_data_size_le(__le16 ext_header) +{ + return pd_ext_header_data_size(le16_to_cpu(ext_header)); +} + #define PD_MAX_PAYLOAD 7 +#define PD_EXT_MAX_CHUNK_DATA 26 /** - * struct pd_message - PD message as seen on wire - * @header: PD message header - * @payload: PD message payload - */ + * struct pd_chunked_ext_message_data - PD chunked extended message data as + * seen on wire + * @header: PD extended message header + * @data: PD extended message data + */ +struct pd_chunked_ext_message_data { + __le16 header; + u8 data[PD_EXT_MAX_CHUNK_DATA]; +} __packed; + +/** + * struct pd_message - PD message as seen on wire + * @header: PD message header + * @payload: PD message payload + * @ext_msg: PD message chunked extended message data + */ struct pd_message { __le16 header; - __le32 payload[PD_MAX_PAYLOAD]; + union { + __le32 payload[PD_MAX_PAYLOAD]; + struct pd_chunked_ext_message_data ext_msg; + }; } __packed; /* PDO: Power Data Object */ @@ -121,6 +214,7 @@ enum pd_pdo_type { PDO_TYPE_FIXED = 0, PDO_TYPE_BATT = 1, PDO_TYPE_VAR = 2, + PDO_TYPE_APDO = 3, }; #define PDO_TYPE_SHIFT 30 @@ -174,6 +268,34 @@ enum pd_pdo_type { (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \ PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma)) +enum pd_apdo_type { + APDO_TYPE_PPS = 0, +}; + +#define PDO_APDO_TYPE_SHIFT 28 /* Only valid value currently is 0x0 - PPS */ +#define PDO_APDO_TYPE_MASK 0x3 + +#define PDO_APDO_TYPE(t) ((t) << PDO_APDO_TYPE_SHIFT) + +#define PDO_PPS_APDO_MAX_VOLT_SHIFT 17 /* 100mV units */ +#define PDO_PPS_APDO_MIN_VOLT_SHIFT 8 /* 100mV units */ +#define PDO_PPS_APDO_MAX_CURR_SHIFT 0 /* 50mA units */ + +#define PDO_PPS_APDO_VOLT_MASK 0xff +#define PDO_PPS_APDO_CURR_MASK 0x7f + +#define PDO_PPS_APDO_MIN_VOLT(mv) \ + ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MIN_VOLT_SHIFT) +#define PDO_PPS_APDO_MAX_VOLT(mv) \ + ((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MAX_VOLT_SHIFT) +#define PDO_PPS_APDO_MAX_CURR(ma) \ + ((((ma) / 50) & PDO_PPS_APDO_CURR_MASK) << PDO_PPS_APDO_MAX_CURR_SHIFT) + +#define PDO_PPS_APDO(min_mv, max_mv, max_ma) \ + (PDO_TYPE(PDO_TYPE_APDO) | PDO_APDO_TYPE(APDO_TYPE_PPS) | \ + PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) | \ + PDO_PPS_APDO_MAX_CURR(max_ma)) + static inline enum pd_pdo_type pdo_type(u32 pdo) { return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK; @@ -204,6 +326,29 @@ static inline unsigned int pdo_max_power(u32 pdo) return ((pdo >> PDO_BATT_MAX_PWR_SHIFT) & PDO_PWR_MASK) * 250; } +static inline enum pd_apdo_type pdo_apdo_type(u32 pdo) +{ + return (pdo >> PDO_APDO_TYPE_SHIFT) & PDO_APDO_TYPE_MASK; +} + +static inline unsigned int pdo_pps_apdo_min_voltage(u32 pdo) +{ + return ((pdo >> PDO_PPS_APDO_MIN_VOLT_SHIFT) & + PDO_PPS_APDO_VOLT_MASK) * 100; +} + +static inline unsigned int pdo_pps_apdo_max_voltage(u32 pdo) +{ + return ((pdo >> PDO_PPS_APDO_MAX_VOLT_SHIFT) & + PDO_PPS_APDO_VOLT_MASK) * 100; +} + +static inline unsigned int pdo_pps_apdo_max_current(u32 pdo) +{ + return ((pdo >> PDO_PPS_APDO_MAX_CURR_SHIFT) & + PDO_PPS_APDO_CURR_MASK) * 50; +} + /* RDO: Request Data Object */ #define RDO_OBJ_POS_SHIFT 28 #define RDO_OBJ_POS_MASK 0x7 @@ -237,6 +382,24 @@ static inline unsigned int pdo_max_power(u32 pdo) (RDO_OBJ(idx) | (flags) | \ RDO_BATT_OP_PWR(op_mw) | RDO_BATT_MAX_PWR(max_mw)) +#define RDO_PROG_VOLT_MASK 0x7ff +#define RDO_PROG_CURR_MASK 0x7f + +#define RDO_PROG_VOLT_SHIFT 9 +#define RDO_PROG_CURR_SHIFT 0 + +#define RDO_PROG_VOLT_MV_STEP 20 +#define RDO_PROG_CURR_MA_STEP 50 + +#define PDO_PROG_OUT_VOLT(mv) \ + ((((mv) / RDO_PROG_VOLT_MV_STEP) & RDO_PROG_VOLT_MASK) << RDO_PROG_VOLT_SHIFT) +#define PDO_PROG_OP_CURR(ma) \ + ((((ma) / RDO_PROG_CURR_MA_STEP) & RDO_PROG_CURR_MASK) << RDO_PROG_CURR_SHIFT) + +#define RDO_PROG(idx, out_mv, op_ma, flags) \ + (RDO_OBJ(idx) | (flags) | \ + PDO_PROG_OUT_VOLT(out_mv) | PDO_PROG_OP_CURR(op_ma)) + static inline unsigned int rdo_index(u32 rdo) { return (rdo >> RDO_OBJ_POS_SHIFT) & RDO_OBJ_POS_MASK; diff --git a/include/linux/usb/pd_ado.h b/include/linux/usb/pd_ado.h new file mode 100644 index 000000000000..9aa1cf31c93c --- /dev/null +++ b/include/linux/usb/pd_ado.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Dialog Semiconductor + * + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> + */ + +#ifndef __LINUX_USB_PD_ADO_H +#define __LINUX_USB_PD_ADO_H + +/* ADO : Alert Data Object */ +#define USB_PD_ADO_TYPE_SHIFT 24 +#define USB_PD_ADO_TYPE_MASK 0xff +#define USB_PD_ADO_FIXED_BATT_SHIFT 20 +#define USB_PD_ADO_FIXED_BATT_MASK 0xf +#define USB_PD_ADO_HOT_SWAP_BATT_SHIFT 16 +#define USB_PD_ADO_HOT_SWAP_BATT_MASK 0xf + +#define USB_PD_ADO_TYPE_BATT_STATUS_CHANGE BIT(1) +#define USB_PD_ADO_TYPE_OCP BIT(2) +#define USB_PD_ADO_TYPE_OTP BIT(3) +#define USB_PD_ADO_TYPE_OP_COND_CHANGE BIT(4) +#define USB_PD_ADO_TYPE_SRC_INPUT_CHANGE BIT(5) +#define USB_PD_ADO_TYPE_OVP BIT(6) + +static inline unsigned int usb_pd_ado_type(u32 ado) +{ + return (ado >> USB_PD_ADO_TYPE_SHIFT) & USB_PD_ADO_TYPE_MASK; +} + +static inline unsigned int usb_pd_ado_fixed_batt(u32 ado) +{ + return (ado >> USB_PD_ADO_FIXED_BATT_SHIFT) & + USB_PD_ADO_FIXED_BATT_MASK; +} + +static inline unsigned int usb_pd_ado_hot_swap_batt(u32 ado) +{ + return (ado >> USB_PD_ADO_HOT_SWAP_BATT_SHIFT) & + USB_PD_ADO_HOT_SWAP_BATT_MASK; +} +#endif /* __LINUX_USB_PD_ADO_H */ diff --git a/include/linux/usb/pd_ext_sdb.h b/include/linux/usb/pd_ext_sdb.h new file mode 100644 index 000000000000..0eb83ce19597 --- /dev/null +++ b/include/linux/usb/pd_ext_sdb.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Dialog Semiconductor + * + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> + */ + +#ifndef __LINUX_USB_PD_EXT_SDB_H +#define __LINUX_USB_PD_EXT_SDB_H + +/* SDB : Status Data Block */ +enum usb_pd_ext_sdb_fields { + USB_PD_EXT_SDB_INTERNAL_TEMP = 0, + USB_PD_EXT_SDB_PRESENT_INPUT, + USB_PD_EXT_SDB_PRESENT_BATT_INPUT, + USB_PD_EXT_SDB_EVENT_FLAGS, + USB_PD_EXT_SDB_TEMP_STATUS, + USB_PD_EXT_SDB_DATA_SIZE, +}; + +/* Event Flags */ +#define USB_PD_EXT_SDB_EVENT_OCP BIT(1) +#define USB_PD_EXT_SDB_EVENT_OTP BIT(2) +#define USB_PD_EXT_SDB_EVENT_OVP BIT(3) +#define USB_PD_EXT_SDB_EVENT_CF_CV_MODE BIT(4) + +#define USB_PD_EXT_SDB_PPS_EVENTS (USB_PD_EXT_SDB_EVENT_OCP | \ + USB_PD_EXT_SDB_EVENT_OTP | \ + USB_PD_EXT_SDB_EVENT_OVP) + +#endif /* __LINUX_USB_PD_EXT_SDB_H */ diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c index 001bb8e8f668..bb424638d75b 100644 --- a/tools/usb/usbip/libsrc/usbip_common.c +++ b/tools/usb/usbip/libsrc/usbip_common.c @@ -66,6 +66,29 @@ const char *usbip_speed_string(int num) return "Unknown Speed"; } +struct op_common_status_string { + int num; + char *desc; +}; + +static struct op_common_status_string op_common_status_strings[] = { + { ST_OK, "Request Completed Successfully" }, + { ST_NA, "Request Failed" }, + { ST_DEV_BUSY, "Device busy (exported)" }, + { ST_DEV_ERR, "Device in error state" }, + { ST_NODEV, "Device not found" }, + { ST_ERROR, "Unexpected response" }, + { 0, NULL} +}; + +const char *usbip_op_common_status_string(int status) +{ + for (int i = 0; op_common_status_strings[i].desc != NULL; i++) + if (op_common_status_strings[i].num == status) + return op_common_status_strings[i].desc; + + return "Unknown Op Common Status"; +} #define DBG_UDEV_INTEGER(name)\ dbg("%-20s = %x", to_string(name), (int) udev->name) diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h index e45ec9d2fdbc..73a367a7fa10 100644 --- a/tools/usb/usbip/libsrc/usbip_common.h +++ b/tools/usb/usbip/libsrc/usbip_common.h @@ -43,6 +43,16 @@ #define SYSFS_PATH_MAX 256 #define SYSFS_BUS_ID_SIZE 32 +/* Defines for op_code status in server/client op_common PDUs */ +#define ST_OK 0x00 +#define ST_NA 0x01 + /* Device requested for import is not available */ +#define ST_DEV_BUSY 0x02 + /* Device requested for import is in error state */ +#define ST_DEV_ERR 0x03 +#define ST_NODEV 0x04 +#define ST_ERROR 0x05 + extern int usbip_use_syslog; extern int usbip_use_stderr; extern int usbip_use_debug ; @@ -130,6 +140,7 @@ int read_usb_interface(struct usbip_usb_device *udev, int i, const char *usbip_speed_string(int num); const char *usbip_status_string(int32_t status); +const char *usbip_op_common_status_string(int status); int usbip_names_init(char *); void usbip_names_free(void); diff --git a/tools/usb/usbip/libsrc/usbip_host_common.c b/tools/usb/usbip/libsrc/usbip_host_common.c index 6ff7b601f854..dc93fadbee96 100644 --- a/tools/usb/usbip/libsrc/usbip_host_common.c +++ b/tools/usb/usbip/libsrc/usbip_host_common.c @@ -234,14 +234,17 @@ int usbip_export_device(struct usbip_exported_device *edev, int sockfd) switch (edev->status) { case SDEV_ST_ERROR: dbg("status SDEV_ST_ERROR"); + ret = ST_DEV_ERR; break; case SDEV_ST_USED: dbg("status SDEV_ST_USED"); + ret = ST_DEV_BUSY; break; default: dbg("status unknown: 0x%x", edev->status); + ret = -1; } - return -1; + return ret; } /* only the first interface is true */ diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index 7f07b2d50f59..ba88728483ff 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c @@ -135,6 +135,7 @@ static int query_import_device(int sockfd, char *busid) struct op_import_request request; struct op_import_reply reply; uint16_t code = OP_REP_IMPORT; + int status; memset(&request, 0, sizeof(request)); memset(&reply, 0, sizeof(reply)); @@ -157,9 +158,10 @@ static int query_import_device(int sockfd, char *busid) } /* receive a reply */ - rc = usbip_net_recv_op_common(sockfd, &code); + rc = usbip_net_recv_op_common(sockfd, &code, &status); if (rc < 0) { - err("recv op_common"); + err("Attach Request for %s failed - %s\n", + busid, usbip_op_common_status_string(status)); return -1; } @@ -194,10 +196,8 @@ static int attach_device(char *host, char *busid) } rhport = query_import_device(sockfd, busid); - if (rhport < 0) { - err("query"); + if (rhport < 0) return -1; - } close(sockfd); diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c index d65a9f444174..8d4ccf4b9480 100644 --- a/tools/usb/usbip/src/usbip_list.c +++ b/tools/usb/usbip/src/usbip_list.c @@ -62,6 +62,7 @@ static int get_exported_devices(char *host, int sockfd) struct usbip_usb_interface uintf; unsigned int i; int rc, j; + int status; rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); if (rc < 0) { @@ -69,9 +70,10 @@ static int get_exported_devices(char *host, int sockfd) return -1; } - rc = usbip_net_recv_op_common(sockfd, &code); + rc = usbip_net_recv_op_common(sockfd, &code, &status); if (rc < 0) { - dbg("usbip_net_recv_op_common failed"); + err("Exported Device List Request failed - %s\n", + usbip_op_common_status_string(status)); return -1; } diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c index b4c37e76a6e0..8ffcd47d9638 100644 --- a/tools/usb/usbip/src/usbip_network.c +++ b/tools/usb/usbip/src/usbip_network.c @@ -163,7 +163,7 @@ int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) return 0; } -int usbip_net_recv_op_common(int sockfd, uint16_t *code) +int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status) { struct op_common op_common; int rc; @@ -179,8 +179,8 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code) PACK_OP_COMMON(0, &op_common); if (op_common.version != USBIP_VERSION) { - dbg("version mismatch: %d %d", op_common.version, - USBIP_VERSION); + err("USBIP Kernel and tool version mismatch: %d %d:", + op_common.version, USBIP_VERSION); goto err; } @@ -191,10 +191,14 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code) if (op_common.code != *code) { dbg("unexpected pdu %#0x for %#0x", op_common.code, *code); + /* return error status */ + *status = ST_ERROR; goto err; } } + *status = op_common.status; + if (op_common.status != ST_OK) { dbg("request failed at peer: %d", op_common.status); goto err; diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h index 7032687621d3..555215eae43e 100644 --- a/tools/usb/usbip/src/usbip_network.h +++ b/tools/usb/usbip/src/usbip_network.h @@ -27,9 +27,7 @@ struct op_common { #define OP_REPLY (0x00 << 8) uint16_t code; - /* add more error code */ -#define ST_OK 0x00 -#define ST_NA 0x01 + /* status codes defined in usbip_common.h */ uint32_t status; /* op_code status (for reply) */ } __attribute__((packed)); @@ -176,7 +174,7 @@ void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf); ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen); ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen); int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status); -int usbip_net_recv_op_common(int sockfd, uint16_t *code); +int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status); int usbip_net_set_reuseaddr(int sockfd); int usbip_net_set_nodelay(int sockfd); int usbip_net_set_keepalive(int sockfd); diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index c6dad2a13c80..f8ff735eb100 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c @@ -107,7 +107,7 @@ static int recv_request_import(int sockfd) struct usbip_usb_device pdu_udev; struct list_head *i; int found = 0; - int error = 0; + int status = ST_OK; int rc; memset(&req, 0, sizeof(req)); @@ -133,22 +133,21 @@ static int recv_request_import(int sockfd) usbip_net_set_nodelay(sockfd); /* export device needs a TCP/IP socket descriptor */ - rc = usbip_export_device(edev, sockfd); - if (rc < 0) - error = 1; + status = usbip_export_device(edev, sockfd); + if (status < 0) + status = ST_NA; } else { info("requested device not found: %s", req.busid); - error = 1; + status = ST_NODEV; } - rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, - (!error ? ST_OK : ST_NA)); + rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, status); if (rc < 0) { dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT); return -1; } - if (error) { + if (status) { dbg("import request busid %s: failed", req.busid); return -1; } @@ -251,8 +250,9 @@ static int recv_pdu(int connfd) { uint16_t code = OP_UNSPEC; int ret; + int status; - ret = usbip_net_recv_op_common(connfd, &code); + ret = usbip_net_recv_op_common(connfd, &code, &status); if (ret < 0) { dbg("could not receive opcode: %#0x", code); return -1; |