From 10e232c597ac757e7f8600649f7e872e86de190f Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 28 Jun 2013 09:38:12 +0800 Subject: USB: check sg buffer size in usb_submit_urb USB spec stats that short packet can only appear at the end of transfer. Because lost of HC(EHCI/UHCI/OHCI/...) can't build a full packet from discontinuous buffers, we introduce the limit in usb_submit_urb() to avoid such kind of bad sg buffers coming from driver. The limit might be a bit strict: - platform has iommu to do sg list mapping - some host controllers may support to build full packet from discontinuous buffers. But considered that most of HCs don't support that, and driver need work well or keep consistent on different HCs and ARCHs, we have to introduce the limit. Currently, only usbtest is reported to pass such sg buffers to HC, and other users(mass storage, usbfs) don't have the problem. We don't check it on USB wireless device, because: - wireless devices can't be attached to common USB bus(EHCI/UHCI/OHCI/...) - the max packet size of endpoint may be odd, and often can't devide 4KB which is a typical usage in usb mass storage application Reported-by: Konstantin Filatov Reported-by: Denis V. Lunev Cc: Felipe Balbi Acked-by: Alan Stern Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/usb.h b/include/linux/usb.h index a232b7ece1f6..e99b2a114af4 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1258,7 +1258,9 @@ typedef void (*usb_complete_t)(struct urb *); * the device driver is saying that it provided this DMA address, * which the host controller driver should use in preference to the * transfer_buffer. - * @sg: scatter gather buffer list + * @sg: scatter gather buffer list, the buffer size of each element in + * the list (except the last) must be divisible by the endpoint's + * max packet size * @num_mapped_sgs: (internal) number of mapped sg entries * @num_sgs: number of entries in the sg list * @transfer_buffer_length: How big is transfer_buffer. The transfer may -- cgit v1.2.3 From 42189d854f174e7b29e0fdb4da9984ba63126a92 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 2 Jul 2013 10:50:15 +0300 Subject: usb: clamp bInterval to allowed range bInterval must be within the range 1 - 16 when running at High/Super speed, and within the range 1 - 255 when running at Full/Low speed. In order to catch drivers passing a too large bInterval on Super/High speed scenarios (thus overflowing urb->interval), let's clamp() the argument to the allowed ranges. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/usb.h b/include/linux/usb.h index e99b2a114af4..eb4252a0da7e 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1547,10 +1547,16 @@ static inline void usb_fill_int_urb(struct urb *urb, urb->transfer_buffer_length = buffer_length; urb->complete = complete_fn; urb->context = context; - if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) + + if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) { + /* make sure interval is within allowed range */ + interval = clamp(interval, 1, 16); + urb->interval = 1 << (interval - 1); - else + } else { urb->interval = interval; + } + urb->start_frame = -1; } -- cgit v1.2.3 From 410aee70f06da60dd8f78c3ec3346cc74c9bed46 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sun, 30 Jun 2013 15:27:26 +0300 Subject: usb: phy: protect against NULL phy pointers In order to decrease the amount of work done by PHY users, allow NULL phy pointers to be passed. Signed-off-by: Felipe Balbi --- include/linux/usb/phy.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 44036808bf0f..6c0b1c513db7 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -142,7 +142,7 @@ extern void usb_remove_phy(struct usb_phy *); /* helpers for direct access thru low-level io interface */ static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) { - if (x->io_ops && x->io_ops->read) + if (x && x->io_ops && x->io_ops->read) return x->io_ops->read(x, reg); return -EINVAL; @@ -150,7 +150,7 @@ static inline int usb_phy_io_read(struct usb_phy *x, u32 reg) static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) { - if (x->io_ops && x->io_ops->write) + if (x && x->io_ops && x->io_ops->write) return x->io_ops->write(x, val, reg); return -EINVAL; @@ -159,7 +159,7 @@ static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg) static inline int usb_phy_init(struct usb_phy *x) { - if (x->init) + if (x && x->init) return x->init(x); return 0; @@ -168,14 +168,14 @@ usb_phy_init(struct usb_phy *x) static inline void usb_phy_shutdown(struct usb_phy *x) { - if (x->shutdown) + if (x && x->shutdown) x->shutdown(x); } static inline int usb_phy_vbus_on(struct usb_phy *x) { - if (!x->set_vbus) + if (!x || !x->set_vbus) return 0; return x->set_vbus(x, true); @@ -184,7 +184,7 @@ usb_phy_vbus_on(struct usb_phy *x) static inline int usb_phy_vbus_off(struct usb_phy *x) { - if (!x->set_vbus) + if (!x || !x->set_vbus) return 0; return x->set_vbus(x, false); @@ -258,7 +258,7 @@ usb_phy_set_power(struct usb_phy *x, unsigned mA) static inline int usb_phy_set_suspend(struct usb_phy *x, int suspend) { - if (x->set_suspend != NULL) + if (x && x->set_suspend != NULL) return x->set_suspend(x, suspend); else return 0; @@ -267,7 +267,7 @@ usb_phy_set_suspend(struct usb_phy *x, int suspend) static inline int usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) { - if (x->notify_connect) + if (x && x->notify_connect) return x->notify_connect(x, speed); else return 0; @@ -276,7 +276,7 @@ usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed) static inline int usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed) { - if (x->notify_disconnect) + if (x && x->notify_disconnect) return x->notify_disconnect(x, speed); else return 0; -- cgit v1.2.3 From 1494a1f62bf7cf57345e9282c8189fe2a21fab64 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Sun, 30 Jun 2013 13:56:45 +0300 Subject: usb: common: introduce of_usb_get_maximum_speed() this helper will be used for controllers which want to work at a lower speed even though they support higher USB transfer rates. One such case is Texas Instruments' AM437x SoC where it uses a USB3 controller without a USB3 PHY, rendering the controller USB2-only. Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/generic.txt | 24 +++++++++++ drivers/usb/usb-common.c | 49 ++++++++++++++++++----- include/linux/usb/of.h | 8 ++++ 3 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 Documentation/devicetree/bindings/usb/generic.txt (limited to 'include') diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt new file mode 100644 index 000000000000..477d5bb5e51c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/generic.txt @@ -0,0 +1,24 @@ +Generic USB Properties + +Optional properties: + - maximum-speed: tells USB controllers we want to work up to a certain + speed. Valid arguments are "super-speed", "high-speed", + "full-speed" and "low-speed". In case this isn't passed + via DT, USB controllers should default to their maximum + HW capability. + - dr_mode: tells Dual-Role USB controllers that we want to work on a + particular mode. Valid arguments are "host", + "peripheral" and "otg". In case this attribute isn't + passed via DT, USB DRD controllers should default to + OTG. + +This is an attribute to a USB controller such as: + +dwc3@4a030000 { + compatible = "synopsys,dwc3"; + reg = <0x4a030000 0xcfff>; + interrupts = <0 92 4> + usb-phy = <&usb2_phy>, <&usb3,phy>; + maximum-speed = "super-speed"; + dr_mode = "otg"; +}; diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c index 675384dabfe9..d771870a819e 100644 --- a/drivers/usb/usb-common.c +++ b/drivers/usb/usb-common.c @@ -43,20 +43,20 @@ const char *usb_otg_state_string(enum usb_otg_state state) } EXPORT_SYMBOL_GPL(usb_otg_state_string); +static const char *const speed_names[] = { + [USB_SPEED_UNKNOWN] = "UNKNOWN", + [USB_SPEED_LOW] = "low-speed", + [USB_SPEED_FULL] = "full-speed", + [USB_SPEED_HIGH] = "high-speed", + [USB_SPEED_WIRELESS] = "wireless", + [USB_SPEED_SUPER] = "super-speed", +}; + const char *usb_speed_string(enum usb_device_speed speed) { - static const char *const names[] = { - [USB_SPEED_UNKNOWN] = "UNKNOWN", - [USB_SPEED_LOW] = "low-speed", - [USB_SPEED_FULL] = "full-speed", - [USB_SPEED_HIGH] = "high-speed", - [USB_SPEED_WIRELESS] = "wireless", - [USB_SPEED_SUPER] = "super-speed", - }; - - if (speed < 0 || speed >= ARRAY_SIZE(names)) + if (speed < 0 || speed >= ARRAY_SIZE(speed_names)) speed = USB_SPEED_UNKNOWN; - return names[speed]; + return speed_names[speed]; } EXPORT_SYMBOL_GPL(usb_speed_string); @@ -112,6 +112,33 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) return USB_DR_MODE_UNKNOWN; } EXPORT_SYMBOL_GPL(of_usb_get_dr_mode); + +/** + * of_usb_get_maximum_speed - Get maximum requested speed for a given USB + * controller. + * @np: Pointer to the given device_node + * + * The function gets the maximum speed string from property "maximum-speed", + * and returns the corresponding enum usb_device_speed. + */ +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np) +{ + const char *maximum_speed; + int err; + int i; + + err = of_property_read_string(np, "maximum-speed", &maximum_speed); + if (err < 0) + return USB_SPEED_UNKNOWN; + + for (i = 0; i < ARRAY_SIZE(speed_names); i++) + if (strcmp(maximum_speed, speed_names[i]) == 0) + return i; + + return USB_SPEED_UNKNOWN; +} +EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed); + #endif MODULE_LICENSE("GPL"); diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index a0ef405368b8..5a7cb9ebf0ef 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -7,16 +7,24 @@ #ifndef __LINUX_USB_OF_H #define __LINUX_USB_OF_H +#include #include #include #if IS_ENABLED(CONFIG_OF) enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np); +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np); #else static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) { return USB_DR_MODE_UNKNOWN; } + +static inline enum usb_device_speed +of_usb_get_maximum_speed(struct device_node *np) +{ + return USB_SPEED_UNKNOWN; +} #endif #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_PHY) -- cgit v1.2.3 From 5702f75375aa9ecf8ad3431aef3fe6ce8c8dbd15 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 17 Jul 2013 11:09:49 +0300 Subject: usb: gadget: udc-core: move sysfs_notify() to a workqueue usb_gadget_set_state() will call sysfs_notify() which might sleep. Some users might want to call usb_gadget_set_state() from the very IRQ handler which actually changes the gadget state. Instead of having every UDC driver add their own workqueue for such a simple notification, we're adding it generically to our struct usb_gadget, so the details are hidden from all UDC drivers. Acked-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc-core.c | 12 +++++++++++- include/linux/usb/gadget.h | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index c28ac9872030..3122ab942f75 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -105,11 +106,18 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); /* ------------------------------------------------------------------------- */ +static void usb_gadget_state_work(struct work_struct *work) +{ + struct usb_gadget *gadget = work_to_gadget(work); + + sysfs_notify(&gadget->dev.kobj, NULL, "status"); +} + void usb_gadget_set_state(struct usb_gadget *gadget, enum usb_device_state state) { gadget->state = state; - sysfs_notify(&gadget->dev.kobj, NULL, "status"); + schedule_work(&gadget->work); } EXPORT_SYMBOL_GPL(usb_gadget_set_state); @@ -196,6 +204,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, goto err1; dev_set_name(&gadget->dev, "gadget"); + INIT_WORK(&gadget->work, usb_gadget_state_work); gadget->dev.parent = parent; #ifdef CONFIG_HAS_DMA @@ -315,6 +324,7 @@ found: usb_gadget_remove_driver(udc); kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); + flush_work(&gadget->work); device_unregister(&udc->dev); device_unregister(&gadget->dev); } diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index f1b0dca60f12..942ef5e053bf 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -22,6 +22,7 @@ #include #include #include +#include #include struct usb_ep; @@ -475,6 +476,7 @@ struct usb_gadget_ops { /** * struct usb_gadget - represents a usb slave device + * @work: (internal use) Workqueue to be used for sysfs_notify() * @ops: Function pointers used to access hardware-specific operations. * @ep0: Endpoint zero, used when reading or writing responses to * driver setup() requests @@ -520,6 +522,7 @@ struct usb_gadget_ops { * device is acting as a B-Peripheral (so is_a_peripheral is false). */ struct usb_gadget { + struct work_struct work; /* readonly to gadget driver */ const struct usb_gadget_ops *ops; struct usb_ep *ep0; @@ -538,6 +541,7 @@ struct usb_gadget { unsigned out_epnum; unsigned in_epnum; }; +#define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) static inline void set_gadget_data(struct usb_gadget *gadget, void *data) { dev_set_drvdata(&gadget->dev, data); } -- cgit v1.2.3 From f5b8c8b6d3b4697f28b818d8784e3e4b2a290022 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 17 Jul 2013 10:37:49 +0300 Subject: usb: tegra: Use regulators instead of GPIOs for USB PHY VBUS The tegra ehci driver has enabled USB vbus regulators directly using GPIOs and the device tree attribute nvidia,vbus-gpio. This is ugly and causes error messages on boot when both the regulator driver and the ehci driver want access to the same GPIO. After this patch, usb vbus regulators for tegra usb phy devices are specified with the device tree attribute vbus-supply = <&x> where x is a regulator defined in the device tree. The old nvidia,vbus-gpio property is no longer supported. Signed-off-by: Mikko Perttunen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/host/ehci-tegra.c | 34 +--------------------------------- drivers/usb/phy/phy-tegra-usb.c | 24 ++++++++++++++++++++++++ include/linux/usb/tegra_usb_phy.h | 1 + 3 files changed, 26 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 6ee7ef79b4f8..14c1f35a4b10 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -322,33 +322,6 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) free_dma_aligned_buffer(urb); } -static int setup_vbus_gpio(struct platform_device *pdev, - struct tegra_ehci_platform_data *pdata) -{ - int err = 0; - int gpio; - - gpio = pdata->vbus_gpio; - if (!gpio_is_valid(gpio)) - gpio = of_get_named_gpio(pdev->dev.of_node, - "nvidia,vbus-gpio", 0); - if (!gpio_is_valid(gpio)) - return 0; - - err = gpio_request(gpio, "vbus_gpio"); - if (err) { - dev_err(&pdev->dev, "can't request vbus gpio %d", gpio); - return err; - } - err = gpio_direction_output(gpio, 1); - if (err) { - dev_err(&pdev->dev, "can't enable vbus\n"); - return err; - } - - return err; -} - static int tegra_ehci_probe(struct platform_device *pdev) { struct resource *res; @@ -376,14 +349,11 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - setup_vbus_gpio(pdev, pdata); - hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { dev_err(&pdev->dev, "Unable to create HCD\n"); - err = -ENOMEM; - goto cleanup_vbus_gpio; + return -ENOMEM; } platform_set_drvdata(pdev, hcd); ehci = hcd_to_ehci(hcd); @@ -494,8 +464,6 @@ cleanup_clk_get: clk_put(tegra->clk); cleanup_hcd_create: usb_put_hcd(hcd); -cleanup_vbus_gpio: - /* FIXME: Undo setup_vbus_gpio() here */ return err; } diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 3ecd49871b88..d92a63a5b0c9 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -34,6 +34,7 @@ #include #include #include +#include #define ULPI_VIEWPORT 0x170 @@ -613,6 +614,9 @@ static void tegra_usb_phy_close(struct usb_phy *x) { struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); + if (!IS_ERR(phy->vbus)) + regulator_disable(phy->vbus); + clk_disable_unprepare(phy->pll_u); } @@ -705,6 +709,16 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) goto fail; } + if (!IS_ERR(phy->vbus)) { + err = regulator_enable(phy->vbus); + if (err) { + dev_err(phy->dev, + "failed to enable usb vbus regulator: %d\n", + err); + goto fail; + } + } + if (phy->is_ulpi_phy) err = ulpi_open(phy); else @@ -896,6 +910,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) } else tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG; + /* On some boards, the VBUS regulator doesn't need to be controlled */ + if (of_find_property(np, "vbus-supply", NULL)) { + tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus"); + if (IS_ERR(tegra_phy->vbus)) + return PTR_ERR(tegra_phy->vbus); + } else { + dev_notice(&pdev->dev, "no vbus regulator"); + tegra_phy->vbus = ERR_PTR(-ENODEV); + } + tegra_phy->dev = &pdev->dev; err = tegra_usb_phy_init(tegra_phy); if (err < 0) diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d2ca919a5b73..2b5fa947980a 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -55,6 +55,7 @@ struct tegra_usb_phy { struct clk *clk; struct clk *pll_u; struct clk *pad_clk; + struct regulator *vbus; enum tegra_usb_phy_mode mode; void *config; struct usb_phy *ulpi; -- cgit v1.2.3 From 185d0fd570c121c0c3d4527842a097e50e3e7a79 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:01 +0300 Subject: usb: phy: tegra: Remove unnecessary 'dev' field struct usb_phy already has a field for the device pointer, so this unnecessary field can be removed. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 27 +++++++++++++++------------ include/linux/usb/tegra_usb_phy.h | 1 - 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index d92a63a5b0c9..311fe03f16e1 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -211,7 +211,7 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable) static int utmip_pad_open(struct tegra_usb_phy *phy) { - phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads"); + phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads"); if (IS_ERR(phy->pad_clk)) { pr_err("%s: can't get utmip pad clock\n", __func__); return PTR_ERR(phy->pad_clk); @@ -540,13 +540,15 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) ret = gpio_direction_output(phy->reset_gpio, 0); if (ret < 0) { - dev_err(phy->dev, "gpio %d not set to 0\n", phy->reset_gpio); + dev_err(phy->u_phy.dev, "gpio %d not set to 0\n", + phy->reset_gpio); return ret; } msleep(5); ret = gpio_direction_output(phy->reset_gpio, 1); if (ret < 0) { - dev_err(phy->dev, "gpio %d not set to 1\n", phy->reset_gpio); + dev_err(phy->u_phy.dev, "gpio %d not set to 1\n", + phy->reset_gpio); return ret; } @@ -649,29 +651,30 @@ static int ulpi_open(struct tegra_usb_phy *phy) { int err; - phy->clk = devm_clk_get(phy->dev, "ulpi-link"); + phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link"); if (IS_ERR(phy->clk)) { pr_err("%s: can't get ulpi clock\n", __func__); return PTR_ERR(phy->clk); } - err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b"); + err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio, + "ulpi_phy_reset_b"); if (err < 0) { - dev_err(phy->dev, "request failed for gpio: %d\n", + dev_err(phy->u_phy.dev, "request failed for gpio: %d\n", phy->reset_gpio); return err; } err = gpio_direction_output(phy->reset_gpio, 0); if (err < 0) { - dev_err(phy->dev, "gpio %d direction not set to output\n", + dev_err(phy->u_phy.dev, "gpio %d direction not set to output\n", phy->reset_gpio); return err; } phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0); if (!phy->ulpi) { - dev_err(phy->dev, "otg_ulpi_create returned NULL\n"); + dev_err(phy->u_phy.dev, "otg_ulpi_create returned NULL\n"); err = -ENOMEM; return err; } @@ -686,7 +689,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) int i; int err; - phy->pll_u = devm_clk_get(phy->dev, "pll_u"); + phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u"); if (IS_ERR(phy->pll_u)) { pr_err("Can't get pll_u clock\n"); return PTR_ERR(phy->pll_u); @@ -712,7 +715,7 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) if (!IS_ERR(phy->vbus)) { err = regulator_enable(phy->vbus); if (err) { - dev_err(phy->dev, + dev_err(phy->u_phy.dev, "failed to enable usb vbus regulator: %d\n", err); goto fail; @@ -920,7 +923,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->vbus = ERR_PTR(-ENODEV); } - tegra_phy->dev = &pdev->dev; + tegra_phy->u_phy.dev = &pdev->dev; err = tegra_usb_phy_init(tegra_phy); if (err < 0) return err; @@ -953,7 +956,7 @@ static int tegra_usb_phy_match(struct device *dev, void *data) struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev); struct device_node *dn = data; - return (tegra_phy->dev->of_node == dn) ? 1 : 0; + return (tegra_phy->u_phy.dev->of_node == dn) ? 1 : 0; } struct usb_phy *tegra_usb_get_phy(struct device_node *dn) diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 2b5fa947980a..c2bc7106aaa8 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -60,7 +60,6 @@ struct tegra_usb_phy { void *config; struct usb_phy *ulpi; struct usb_phy u_phy; - struct device *dev; bool is_legacy_phy; bool is_ulpi_phy; int reset_gpio; -- cgit v1.2.3 From 5fed6828318119656e243c4f0a11955cefc8eebd Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:04 +0300 Subject: ARM: tegra: Remove USB platform data USB-related platform data is not used anymore in the Tegra USB drivers, so remove all of it. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Acked-by: Stephen Warren Signed-off-by: Felipe Balbi --- arch/arm/mach-tegra/tegra.c | 38 +-------------------------------- include/linux/platform_data/tegra_usb.h | 32 --------------------------- include/linux/usb/tegra_usb_phy.h | 5 ----- 3 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 include/linux/platform_data/tegra_usb.h (limited to 'include') diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 0d1e4128d460..fc97cfd52769 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -46,40 +45,6 @@ #include "fuse.h" #include "iomap.h" -static struct tegra_ehci_platform_data tegra_ehci1_pdata = { - .operating_mode = TEGRA_USB_OTG, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { - .reset_gpio = -1, - .clk = "cdev2", -}; - -static struct tegra_ehci_platform_data tegra_ehci2_pdata = { - .phy_config = &tegra_ehci2_ulpi_phy_config, - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct tegra_ehci_platform_data tegra_ehci3_pdata = { - .operating_mode = TEGRA_USB_HOST, - .power_down_on_bus_suspend = 1, - .vbus_gpio = -1, -}; - -static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = { - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0", - &tegra_ehci1_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1", - &tegra_ehci2_pdata), - OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2", - &tegra_ehci3_pdata), - {} -}; - static void __init tegra_dt_init(void) { struct soc_device_attribute *soc_dev_attr; @@ -112,8 +77,7 @@ static void __init tegra_dt_init(void) * devices */ out: - of_platform_populate(NULL, of_default_bus_match_table, - tegra20_auxdata_lookup, parent); + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); } static void __init trimslice_init(void) diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h deleted file mode 100644 index 66c673fef408..000000000000 --- a/include/linux/platform_data/tegra_usb.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _TEGRA_USB_H_ -#define _TEGRA_USB_H_ - -enum tegra_usb_operating_modes { - TEGRA_USB_DEVICE, - TEGRA_USB_HOST, - TEGRA_USB_OTG, -}; - -struct tegra_ehci_platform_data { - enum tegra_usb_operating_modes operating_mode; - /* power down the phy on bus suspend */ - int power_down_on_bus_suspend; - void *phy_config; - int vbus_gpio; -}; - -#endif /* _TEGRA_USB_H_ */ diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index c2bc7106aaa8..847415313ad2 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -28,11 +28,6 @@ struct tegra_utmip_config { u8 xcvr_lsrslew; }; -struct tegra_ulpi_config { - int reset_gpio; - const char *clk; -}; - enum tegra_usb_phy_port_speed { TEGRA_USB_PHY_PORT_SPEED_FULL = 0, TEGRA_USB_PHY_PORT_SPEED_LOW, -- cgit v1.2.3 From 3b102e8bc0e49d417c7d376af857537080335dbf Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:07 +0300 Subject: usb: phy: tegra: Remove custom PHY locating APIs The Tegra EHCI driver is no longer using these custom functions, so they can be removed. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 24 ------------------------ include/linux/usb/tegra_usb_phy.h | 2 -- 2 files changed, 26 deletions(-) (limited to 'include') diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 441c306c050f..fb5bc8cea680 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -968,29 +968,5 @@ static struct platform_driver tegra_usb_phy_driver = { }; module_platform_driver(tegra_usb_phy_driver); -static int tegra_usb_phy_match(struct device *dev, void *data) -{ - struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev); - struct device_node *dn = data; - - return (tegra_phy->u_phy.dev->of_node == dn) ? 1 : 0; -} - -struct usb_phy *tegra_usb_get_phy(struct device_node *dn) -{ - struct device *dev; - struct tegra_usb_phy *tegra_phy; - - dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn, - tegra_usb_phy_match); - if (!dev) - return ERR_PTR(-EPROBE_DEFER); - - tegra_phy = dev_get_drvdata(dev); - - return &tegra_phy->u_phy; -} -EXPORT_SYMBOL_GPL(tegra_usb_get_phy); - MODULE_DESCRIPTION("Tegra USB PHY driver"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index 847415313ad2..a095c98184d0 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -60,8 +60,6 @@ struct tegra_usb_phy { int reset_gpio; }; -struct usb_phy *tegra_usb_get_phy(struct device_node *dn); - void tegra_usb_phy_preresume(struct usb_phy *phy); void tegra_usb_phy_postresume(struct usb_phy *phy); -- cgit v1.2.3 From 6558d7edbe069df1220b525362d4aa854a65a8bc Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Thu, 25 Jul 2013 21:38:09 +0300 Subject: usb: phy: tegra: Use DT helpers for dr_mode Use the new of_usb_get_dr_mode helper function for parsing dr_mode from the device tree. Also replace the usage of the custom tegra_usb_phy_mode enum with the standard enum. Signed-off-by: Tuomas Tynkkynen Reviewed-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 24 ++++++++++++------------ include/linux/usb/tegra_usb_phy.h | 8 +------- 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index fb469f1e8d10..01c30ff8874e 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -377,7 +377,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); writel(val, base + UTMIP_PLL_CFG1); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); writel(val, base + USB_SUSP_CTRL); @@ -412,7 +412,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) if (phy->is_legacy_phy) { val = readl(base + UTMIP_SPARE_CFG0); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) + if (phy->mode == USB_DR_MODE_PERIPHERAL) val &= ~FUSE_SETUP_SEL; else val |= FUSE_SETUP_SEL; @@ -453,7 +453,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) utmi_phy_clk_disable(phy); - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { + if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5); @@ -907,15 +907,15 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return -EINVAL; } - err = of_property_match_string(np, "dr_mode", "otg"); - if (err < 0) { - err = of_property_match_string(np, "dr_mode", "peripheral"); - if (err < 0) - tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST; - else - tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE; - } else - tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG; + if (of_find_property(np, "dr_mode", NULL)) + tegra_phy->mode = of_usb_get_dr_mode(np); + else + tegra_phy->mode = USB_DR_MODE_HOST; + + if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) { + dev_err(&pdev->dev, "dr_mode is invalid\n"); + return -EINVAL; + } /* On some boards, the VBUS regulator doesn't need to be controlled */ if (of_find_property(np, "vbus-supply", NULL)) { diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index a095c98184d0..d3db274610a1 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -34,12 +34,6 @@ enum tegra_usb_phy_port_speed { TEGRA_USB_PHY_PORT_SPEED_HIGH, }; -enum tegra_usb_phy_mode { - TEGRA_USB_PHY_MODE_DEVICE, - TEGRA_USB_PHY_MODE_HOST, - TEGRA_USB_PHY_MODE_OTG, -}; - struct tegra_xtal_freq; struct tegra_usb_phy { @@ -51,7 +45,7 @@ struct tegra_usb_phy { struct clk *pll_u; struct clk *pad_clk; struct regulator *vbus; - enum tegra_usb_phy_mode mode; + enum usb_dr_mode mode; void *config; struct usb_phy *ulpi; struct usb_phy u_phy; -- cgit v1.2.3 From 9cf7b244187bba5964d4bf7438946baa2a974466 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jul 2013 09:09:15 +0300 Subject: usb: of: fix build breakage caused by recent patches commit 052a11d (usb: phy: make PHY driver selection possible by controller drivers) changed the rules on how drivers/usb/phy/of.c would be compiled and failed to update include/linux/usb/of.h accordingly. Because of that, we can fall into situations where of_usb_get_phy_mode() is redefined. In order to fix the error, we update the IS_ENABLED() check in include/linux/usb/of.h to reflect the condition where of.c is built. Reported-by: Stephen Rothwell Signed-off-by: Felipe Balbi --- include/linux/usb/of.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index 5a7cb9ebf0ef..8c38aa26b3bb 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -27,7 +27,7 @@ of_usb_get_maximum_speed(struct device_node *np) } #endif -#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_PHY) +#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT) enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np); #else static inline enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np) -- cgit v1.2.3 From 626f090c5cbbe557379978c7a9525011ad7fbbf6 Mon Sep 17 00:00:00 2001 From: Yacine Belkadi Date: Fri, 2 Aug 2013 20:10:04 +0200 Subject: usb: fix some scripts/kernel-doc warnings When building the htmldocs (in verbose mode), scripts/kernel-doc reports the following type of warnings: Warning(drivers/usb/core/usb.c:76): No description found for return value of 'usb_find_alt_setting' Fix them by: - adding some missing descriptions of return values - using "Return" sections for those descriptions Signed-off-by: Yacine Belkadi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/buffer.c | 5 ++-- drivers/usb/core/driver.c | 22 +++++++++++++++-- drivers/usb/core/file.c | 2 +- drivers/usb/core/hcd-pci.c | 2 ++ drivers/usb/core/hcd.c | 37 ++++++++++++++++++++-------- drivers/usb/core/hub.c | 37 +++++++++++++++++++--------- drivers/usb/core/message.c | 49 ++++++++++++++++++++----------------- drivers/usb/core/urb.c | 34 ++++++++++++++++---------- drivers/usb/core/usb.c | 60 ++++++++++++++++++++++++++++------------------ include/linux/usb.h | 12 ++++++---- 10 files changed, 173 insertions(+), 87 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index b0585e623ba9..23559746be92 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -43,10 +43,11 @@ static const size_t pool_max[HCD_BUFFER_POOLS] = { * * Call this as part of initializing a host controller that uses the dma * memory allocators. It initializes some pools of dma-coherent memory that - * will be shared by all drivers using that controller, or returns a negative - * errno value on error. + * will be shared by all drivers using that controller. * * Call hcd_buffer_destroy() to clean up after using those pools. + * + * Return: 0 if successful. A negative errno value otherwise. */ int hcd_buffer_create(struct usb_hcd *hcd) { diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 7609ac4aed1c..124bcc50b0b7 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -117,6 +117,8 @@ static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id); * @count: input size * * Removes a dynamic usb device ID from this driver. + * + * Return: @count on success. A negative error code otherwise. */ static ssize_t store_remove_id(struct device_driver *driver, const char *buf, size_t count) @@ -457,6 +459,8 @@ static int usb_unbind_interface(struct device *dev) * Callers must own the device lock, so driver probe() entries don't need * extra locking, but other call contexts may need to explicitly claim that * lock. + * + * Return: 0 on success. */ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) @@ -658,6 +662,8 @@ EXPORT_SYMBOL_GPL(usb_match_one_id); * These device tables are exported with MODULE_DEVICE_TABLE, through * modutils, to support the driver loading functionality of USB hotplugging. * + * Return: The first matching usb_device_id, or %NULL. + * * What Matches: * * The "match_flags" element in a usb_device_id controls which @@ -823,7 +829,8 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) * Registers a USB device driver with the USB core. The list of * unattached devices will be rescanned whenever a new driver is * added, allowing the new driver to attach to any recognized devices. - * Returns a negative error code on failure and 0 on success. + * + * Return: A negative error code on failure and 0 on success. */ int usb_register_device_driver(struct usb_device_driver *new_udriver, struct module *owner) @@ -879,7 +886,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver); * Registers a USB interface driver with the USB core. The list of * unattached interfaces will be rescanned whenever a new driver is * added, allowing the new driver to attach to any recognized interfaces. - * Returns a negative error code on failure and 0 on success. + * + * Return: A negative error code on failure and 0 on success. * * NOTE: if you want your driver to use the USB major number, you must call * usb_register_dev() to enable that functionality. This function no longer @@ -1213,6 +1221,8 @@ done: * unpredictable times. * * This routine can run only in process context. + * + * Return: 0 if the suspend succeeded. */ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) { @@ -1294,6 +1304,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) * unpredictable times. * * This routine can run only in process context. + * + * Return: 0 on success. */ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) { @@ -1491,6 +1503,8 @@ void usb_autosuspend_device(struct usb_device *udev) * The caller must hold @udev's device lock. * * This routine can run only in process context. + * + * Return: 0 on success. A negative error code otherwise. */ int usb_autoresume_device(struct usb_device *udev) { @@ -1600,6 +1614,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend); * However if the autoresume fails then the counter is re-decremented. * * This routine can run only in process context. + * + * Return: 0 on success. */ int usb_autopm_get_interface(struct usb_interface *intf) { @@ -1633,6 +1649,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface); * resumed. * * This routine can run in atomic context. + * + * Return: 0 on success. A negative error code otherwise. */ int usb_autopm_get_interface_async(struct usb_interface *intf) { diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 6a4c40766f0f..7421888087a3 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -153,7 +153,7 @@ void usb_major_cleanup(void) * usb_deregister_dev() must be called when the driver is done with * the minor numbers given out by this function. * - * Returns -EINVAL if something bad happens with trying to register a + * Return: -EINVAL if something bad happens with trying to register a * device, and 0 on success. */ int usb_register_dev(struct usb_interface *intf, diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index caeb8d6d39fb..b9d3c43e3859 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -171,6 +171,8 @@ static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, * through the hotplug entry's driver_data. * * Store this function in the HCD's struct pci_driver as probe(). + * + * Return: 0 if successful. */ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 014dc996b4f6..dc1346fee76c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -378,9 +378,10 @@ MODULE_PARM_DESC(authorized_default, * @buf: Buffer for USB string descriptor (header + UTF-16LE) * @len: Length (in bytes; may be odd) of descriptor buffer. * - * The return value is the number of bytes filled in: 2 + 2*strlen(s) or - * buflen, whichever is less. + * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len, + * whichever is less. * + * Note: * USB String descriptors can contain at most 126 characters; input * strings longer than that are truncated. */ @@ -416,7 +417,8 @@ ascii2desc(char const *s, u8 *buf, unsigned len) * * Produces either a manufacturer, product or serial number string for the * virtual root hub device. - * Returns the number of bytes filled in: the length of the descriptor or + * + * Return: The number of bytes filled in: the length of the descriptor or * of the provided buffer, whichever is less. */ static unsigned @@ -938,6 +940,8 @@ static void usb_bus_init (struct usb_bus *bus) * * Assigns a bus number, and links the controller into usbcore data * structures so that it can be seen by scanning the bus list. + * + * Return: 0 if successful. A negative error code otherwise. */ static int usb_register_bus(struct usb_bus *bus) { @@ -1002,6 +1006,8 @@ static void usb_deregister_bus (struct usb_bus *bus) * the device properly in the device tree and then calls usb_new_device() * to register the usb device. It also assigns the root hub's USB address * (always 1). + * + * Return: 0 if successful. A negative error code otherwise. */ static int register_root_hub(struct usb_hcd *hcd) { @@ -1108,7 +1114,9 @@ EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume); * @isoc: true for isochronous transactions, false for interrupt ones * @bytecount: how many bytes in the transaction. * - * Returns approximate bus time in nanoseconds for a periodic transaction. + * Return: Approximate bus time in nanoseconds for a periodic transaction. + * + * Note: * See USB 2.0 spec section 5.11.3; only periodic transfers need to be * scheduled in software, this function is only used for such scheduling. */ @@ -1166,7 +1174,7 @@ EXPORT_SYMBOL_GPL(usb_calc_bus_time); * be disabled. The actions carried out here are required for URB * submission, as well as for endpoint shutdown and for usb_kill_urb. * - * Returns 0 for no error, otherwise a negative error code (in which case + * Return: 0 for no error, otherwise a negative error code (in which case * the enqueue() method must fail). If no error occurs but enqueue() fails * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing * the private spinlock and returning. @@ -1221,7 +1229,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); * be disabled. The actions carried out here are required for making * sure than an unlink is valid. * - * Returns 0 for no error, otherwise a negative error code (in which case + * Return: 0 for no error, otherwise a negative error code (in which case * the dequeue() method must fail). The possible error codes are: * * -EIDRM: @urb was not submitted or has already completed. @@ -1784,7 +1792,7 @@ rescan: * pass in the current alternate interface setting in cur_alt, * and pass in the new alternate interface setting in new_alt. * - * Returns an error if the requested bandwidth change exceeds the + * Return: An error if the requested bandwidth change exceeds the * bus bandwidth or host controller internal resources. */ int usb_hcd_alloc_bandwidth(struct usb_device *udev, @@ -1954,9 +1962,12 @@ void usb_hcd_reset_endpoint(struct usb_device *udev, * @num_streams: number of streams to allocate. * @mem_flags: flags hcd should use to allocate memory. * - * Sets up a group of bulk endpoints to have num_streams stream IDs available. + * Sets up a group of bulk endpoints to have @num_streams stream IDs available. * Drivers may queue multiple transfers to different stream IDs, which may * complete in a different order than they were queued. + * + * Return: On success, the number of allocated streams. On failure, a negative + * error code. */ int usb_alloc_streams(struct usb_interface *interface, struct usb_host_endpoint **eps, unsigned int num_eps, @@ -2201,6 +2212,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); * khubd identifying and possibly configuring the device. * This is needed by OTG controller drivers, where it helps meet * HNP protocol timing requirements for starting a port reset. + * + * Return: 0 if successful. */ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) { @@ -2235,6 +2248,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum); * * If the controller isn't HALTed, calls the driver's irq handler. * Checks whether the controller is now dead. + * + * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise. */ irqreturn_t usb_hcd_irq (int irq, void *__hcd) { @@ -2320,7 +2335,8 @@ EXPORT_SYMBOL_GPL (usb_hc_died); * HC driver's private data. Initialize the generic members of the * hcd structure. * - * If memory is unavailable, returns NULL. + * Return: On success, a pointer to the created and initialized HCD structure. + * On failure (e.g. if memory is unavailable), %NULL. */ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name, @@ -2384,7 +2400,8 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd); * HC driver's private data. Initialize the generic members of the * hcd structure. * - * If memory is unavailable, returns NULL. + * Return: On success, a pointer to the created and initialized HCD + * structure. On failure (e.g. if memory is unavailable), %NULL. */ struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0416f835cfee..5d6d28a76e0a 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -734,6 +734,8 @@ static void hub_tt_work(struct work_struct *work) * * call this function to control port's power via setting or * clearing the port's PORT_POWER feature. + * + * Return: 0 if successful. A negative error code otherwise. */ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, int port1, bool set) @@ -762,6 +764,8 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, * * It may not be possible for that hub to handle additional full (or low) * speed transactions until that state is fully cleared out. + * + * Return: 0 if successful. A negative error code otherwise. */ int usb_hub_clear_tt_buffer(struct urb *urb) { @@ -964,6 +968,8 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) * see that the device has been disconnected. When the device is * physically unplugged and something is plugged in, the events will * be received and processed normally. + * + * Return: 0 if successful. A negative error code otherwise. */ int usb_remove_device(struct usb_device *udev) { @@ -2115,6 +2121,8 @@ static inline void announce_device(struct usb_device *udev) { } * @udev: newly addressed device (in ADDRESS state) * * Finish enumeration for On-The-Go devices + * + * Return: 0 if successful. A negative error code otherwise. */ static int usb_enumerate_device_otg(struct usb_device *udev) { @@ -2197,6 +2205,8 @@ fail: * If the device is WUSB and not authorized, we don't attempt to read * the string descriptors, as they will be errored out by the device * until it has been authorized. + * + * Return: 0 if successful. A negative error code otherwise. */ static int usb_enumerate_device(struct usb_device *udev) { @@ -2277,13 +2287,14 @@ static void set_usb_port_removable(struct usb_device *udev) * udev has already been installed, but udev is not yet visible through * sysfs or other filesystem code. * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * * This call is synchronous, and may not be used in an interrupt context. * * Only the hub driver or root-hub registrar should ever call this. + * + * Return: Whether the device is configured properly or not. Zero if the + * interface was registered with the driver core; else a negative errno + * value. + * */ int usb_new_device(struct usb_device *udev) { @@ -2391,6 +2402,8 @@ fail: * * We share a lock (that we have) with device_del(), so we need to * defer its call. + * + * Return: 0. */ int usb_deauthorize_device(struct usb_device *usb_dev) { @@ -5025,10 +5038,11 @@ static int descriptors_changed(struct usb_device *udev, * re-connected. All drivers will be unbound, and the device will be * re-enumerated and probed all over again. * - * Returns 0 if the reset succeeded, -ENODEV if the device has been + * Return: 0 if the reset succeeded, -ENODEV if the device has been * flagged for logical disconnection, or some other negative error code * if the reset wasn't even attempted. * + * Note: * The caller must own the device lock. For example, it's safe to use * this from a driver probe() routine after downloading new firmware. * For calls that might not occur during probe(), drivers should lock @@ -5184,8 +5198,9 @@ re_enumerate: * method), performs the port reset, and then lets the drivers know that * the reset is over (using their post_reset method). * - * Return value is the same as for usb_reset_and_verify_device(). + * Return: The same as for usb_reset_and_verify_device(). * + * Note: * The caller must own the device lock. For example, it's safe to use * this from a driver probe() routine after downloading new firmware. * For calls that might not occur during probe(), drivers should lock @@ -5323,7 +5338,7 @@ EXPORT_SYMBOL_GPL(usb_queue_reset_device); * USB drivers call this function to get hub's child device * pointer. * - * Return NULL if input param is invalid and + * Return: %NULL if input param is invalid and * child's usb_device pointer if non-NULL. */ struct usb_device *usb_hub_find_child(struct usb_device *hdev, @@ -5357,8 +5372,8 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, * @hdev: USB device belonging to the usb hub * @port1: port num of the port * - * Return connect type of the port and if input params are - * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN. + * Return: The connect type of the port if successful. Or + * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid. */ enum usb_port_connect_type usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) @@ -5418,8 +5433,8 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev, * @hdev: USB device belonging to the usb hub * @port1: port num of the port * - * Return port's acpi handle if successful, NULL if params are - * invaild. + * Return: Port's acpi handle if successful, %NULL if params are + * invalid. */ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, int port1) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 6549a975b0c5..82927e1ed27d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -119,15 +119,15 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, * This function sends a simple control message to a specified endpoint and * waits for the message to complete, or timeout. * - * If successful, it returns the number of bytes transferred, otherwise a - * negative error number. - * * Don't use this function from within an interrupt context, like a bottom half * handler. If you need an asynchronous message, or need to send a message * from within interrupt context, use usb_submit_urb(). * If a thread in your driver uses this call, make sure your disconnect() * method can wait for it to complete. Since you don't have a handle on the * URB used, you can't cancel the request. + * + * Return: If successful, the number of bytes transferred. Otherwise, a negative + * error number. */ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, @@ -170,15 +170,16 @@ EXPORT_SYMBOL_GPL(usb_control_msg); * This function sends a simple interrupt message to a specified endpoint and * waits for the message to complete, or timeout. * - * If successful, it returns 0, otherwise a negative error number. The number - * of actual bytes transferred will be stored in the actual_length paramater. - * * Don't use this function from within an interrupt context, like a bottom half * handler. If you need an asynchronous message, or need to send a message * from within interrupt context, use usb_submit_urb() If a thread in your * driver uses this call, make sure your disconnect() method can wait for it to * complete. Since you don't have a handle on the URB used, you can't cancel * the request. + * + * Return: + * If successful, 0. Otherwise a negative error number. The number of actual + * bytes transferred will be stored in the @actual_length paramater. */ int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) @@ -203,9 +204,6 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); * This function sends a simple bulk message to a specified endpoint * and waits for the message to complete, or timeout. * - * If successful, it returns 0, otherwise a negative error number. The number - * of actual bytes transferred will be stored in the actual_length paramater. - * * Don't use this function from within an interrupt context, like a bottom half * handler. If you need an asynchronous message, or need to send a message * from within interrupt context, use usb_submit_urb() If a thread in your @@ -217,6 +215,11 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); * users are forced to abuse this routine by using it to submit URBs for * interrupt endpoints. We will take the liberty of creating an interrupt URB * (with the default interval) if the target is an interrupt endpoint. + * + * Return: + * If successful, 0. Otherwise a negative error number. The number of actual + * bytes transferred will be stored in the @actual_length paramater. + * */ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout) @@ -341,9 +344,9 @@ static void sg_complete(struct urb *urb) * send every byte identified in the list. * @mem_flags: SLAB_* flags affecting memory allocations in this call * - * Returns zero for success, else a negative errno value. This initializes a - * scatter/gather request, allocating resources such as I/O mappings and urb - * memory (except maybe memory used by USB controller drivers). + * This initializes a scatter/gather request, allocating resources such as + * I/O mappings and urb memory (except maybe memory used by USB controller + * drivers). * * The request must be issued using usb_sg_wait(), which waits for the I/O to * complete (or to be canceled) and then cleans up all resources allocated by @@ -351,6 +354,8 @@ static void sg_complete(struct urb *urb) * * The request may be canceled with usb_sg_cancel(), either before or after * usb_sg_wait() is called. + * + * Return: Zero for success, else a negative errno value. */ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, unsigned pipe, unsigned period, struct scatterlist *sg, @@ -623,7 +628,7 @@ EXPORT_SYMBOL_GPL(usb_sg_cancel); * * This call is synchronous, and may not be used in an interrupt context. * - * Returns the number of bytes received on success, or else the status code + * Return: The number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ int usb_get_descriptor(struct usb_device *dev, unsigned char type, @@ -671,7 +676,7 @@ EXPORT_SYMBOL_GPL(usb_get_descriptor); * * This call is synchronous, and may not be used in an interrupt context. * - * Returns the number of bytes received on success, or else the status code + * Return: The number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ static int usb_get_string(struct usb_device *dev, unsigned short langid, @@ -805,7 +810,7 @@ static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) * * This call is synchronous, and may not be used in an interrupt context. * - * Returns length of the string (>= 0) or usb_control_msg status (< 0). + * Return: length of the string (>= 0) or usb_control_msg status (< 0). */ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) { @@ -853,8 +858,8 @@ EXPORT_SYMBOL_GPL(usb_string); * @udev: the device whose string descriptor is being read * @index: the descriptor index * - * Returns a pointer to a kmalloc'ed buffer containing the descriptor string, - * or NULL if the index is 0 or the string could not be read. + * Return: A pointer to a kmalloc'ed buffer containing the descriptor string, + * or %NULL if the index is 0 or the string could not be read. */ char *usb_cache_string(struct usb_device *udev, int index) { @@ -894,7 +899,7 @@ char *usb_cache_string(struct usb_device *udev, int index) * * This call is synchronous, and may not be used in an interrupt context. * - * Returns the number of bytes received on success, or else the status code + * Return: The number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) @@ -980,7 +985,7 @@ EXPORT_SYMBOL_GPL(usb_get_status); * * This call is synchronous, and may not be used in an interrupt context. * - * Returns zero on success, or else the status code returned by the + * Return: Zero on success, or else the status code returned by the * underlying usb_control_msg() call. */ int usb_clear_halt(struct usb_device *dev, int pipe) @@ -1277,7 +1282,7 @@ void usb_enable_interface(struct usb_device *dev, * endpoints in that interface; all such urbs must first be completed * (perhaps forced by unlinking). * - * Returns zero on success, or else the status code returned by the + * Return: Zero on success, or else the status code returned by the * underlying usb_control_msg() call. */ int usb_set_interface(struct usb_device *dev, int interface, int alternate) @@ -1431,7 +1436,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); * * The caller must own the device lock. * - * Returns zero on success, else a negative error code. + * Return: Zero on success, else a negative error code. */ int usb_reset_configuration(struct usb_device *dev) { @@ -1973,7 +1978,7 @@ static void cancel_async_set_config(struct usb_device *udev) * routine gets around the normal restrictions by using a work thread to * submit the change-config request. * - * Returns 0 if the request was successfully queued, error code otherwise. + * Return: 0 if the request was successfully queued, error code otherwise. * The caller has no way to know whether the queued request will eventually * succeed. */ diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index e75115a04a2e..4e7a311ff6d7 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -55,12 +55,12 @@ EXPORT_SYMBOL_GPL(usb_init_urb); * Creates an urb for the USB driver to use, initializes a few internal * structures, incrementes the usage counter, and returns a pointer to it. * - * If no memory is available, NULL is returned. - * * If the driver want to use this urb for interrupt, control, or bulk * endpoints, pass '0' as the number of iso packets. * * The driver must call usb_free_urb() when it is finished with the urb. + * + * Return: A pointer to the new urb, or %NULL if no memory is available. */ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) { @@ -103,7 +103,7 @@ EXPORT_SYMBOL_GPL(usb_free_urb); * host controller driver. This allows proper reference counting to happen * for urbs. * - * A pointer to the urb with the incremented reference counter is returned. + * Return: A pointer to the urb with the incremented reference counter. */ struct urb *usb_get_urb(struct urb *urb) { @@ -200,13 +200,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * the particular kind of transfer, although they will not initialize * any transfer flags. * - * Successful submissions return 0; otherwise this routine returns a - * negative error number. If the submission is successful, the complete() - * callback from the URB will be called exactly once, when the USB core and - * Host Controller Driver (HCD) are finished with the URB. When the completion - * function is called, control of the URB is returned to the device - * driver which issued the request. The completion handler may then - * immediately free or reuse that URB. + * If the submission is successful, the complete() callback from the URB + * will be called exactly once, when the USB core and Host Controller Driver + * (HCD) are finished with the URB. When the completion function is called, + * control of the URB is returned to the device driver which issued the + * request. The completion handler may then immediately free or reuse that + * URB. * * With few exceptions, USB device drivers should never access URB fields * provided by usbcore or the HCD until its complete() is called. @@ -241,6 +240,9 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); * that are standardized in the USB 2.0 specification. For bulk * endpoints, a synchronous usb_bulk_msg() call is available. * + * Return: + * 0 on successful submissions. A negative error number otherwise. + * * Request Queuing: * * URBs may be submitted to endpoints before previous ones complete, to @@ -572,6 +574,9 @@ EXPORT_SYMBOL_GPL(usb_submit_urb); * particular, when a driver calls this routine, it must insure that the * completion handler cannot deallocate the URB. * + * Return: -EINPROGRESS on success. See description for other values on + * failure. + * * Unlinking and Endpoint Queues: * * [The behaviors and guarantees described below do not apply to virtual @@ -846,6 +851,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); * * Call this is you want to be sure all an anchor's * URBs have finished + * + * Return: Non-zero if the anchor became unused. Zero on timeout. */ int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned int timeout) @@ -859,8 +866,11 @@ EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); * usb_get_from_anchor - get an anchor's oldest urb * @anchor: the anchor whose urb you want * - * this will take the oldest urb from an anchor, + * This will take the oldest urb from an anchor, * unanchor and return it + * + * Return: The oldest urb from @anchor, or %NULL if @anchor has no + * urbs associated with it. */ struct urb *usb_get_from_anchor(struct usb_anchor *anchor) { @@ -909,7 +919,7 @@ EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs); * usb_anchor_empty - is an anchor empty * @anchor: the anchor you want to query * - * returns 1 if the anchor has no urbs associated with it + * Return: 1 if the anchor has no urbs associated with it. */ int usb_anchor_empty(struct usb_anchor *anchor) { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7dad603dde43..0a6ee2e70b25 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -68,6 +68,8 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); * @alt_num: alternate interface setting number to search for. * * Search the configuration's interface cache for the given alt setting. + * + * Return: The alternate setting, if found. %NULL otherwise. */ struct usb_host_interface *usb_find_alt_setting( struct usb_host_config *config, @@ -103,8 +105,7 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting); * @ifnum: the desired interface * * This walks the device descriptor for the currently active configuration - * and returns a pointer to the interface with that particular interface - * number, or null. + * to find the interface object with the particular interface number. * * Note that configuration descriptors are not required to assign interface * numbers sequentially, so that it would be incorrect to assume that @@ -115,6 +116,9 @@ EXPORT_SYMBOL_GPL(usb_find_alt_setting); * * Don't call this function unless you are bound to one of the interfaces * on this device or you have locked the device! + * + * Return: A pointer to the interface that has @ifnum as interface number, + * if found. %NULL otherwise. */ struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, unsigned ifnum) @@ -139,8 +143,7 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if); * @altnum: the desired alternate setting number * * This searches the altsetting array of the specified interface for - * an entry with the correct bAlternateSetting value and returns a pointer - * to that entry, or null. + * an entry with the correct bAlternateSetting value. * * Note that altsettings need not be stored sequentially by number, so * it would be incorrect to assume that the first altsetting entry in @@ -149,6 +152,9 @@ EXPORT_SYMBOL_GPL(usb_ifnum_to_if); * * Don't call this function unless you are bound to the intf interface * or you have locked the device! + * + * Return: A pointer to the entry of the altsetting array of @intf that + * has @altnum as the alternate setting number. %NULL if not found. */ struct usb_host_interface *usb_altnum_to_altsetting( const struct usb_interface *intf, @@ -191,6 +197,8 @@ static int __find_interface(struct device *dev, void *data) * This walks the bus device list and returns a pointer to the interface * with the matching minor and driver. Note, this only works for devices * that share the USB major number. + * + * Return: A pointer to the interface with the matching major and @minor. */ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) { @@ -390,6 +398,9 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) * controllers) should ever call this. * * This call may not be used in a non-sleeping context. + * + * Return: On success, a pointer to the allocated usb device. %NULL on + * failure. */ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) @@ -501,7 +512,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, * their probe() methods, when they bind to an interface, and release * them by calling usb_put_dev(), in their disconnect() methods. * - * A pointer to the device with the incremented reference counter is returned. + * Return: A pointer to the device with the incremented reference counter. */ struct usb_device *usb_get_dev(struct usb_device *dev) { @@ -535,8 +546,7 @@ EXPORT_SYMBOL_GPL(usb_put_dev); * their probe() methods, when they bind to an interface, and release * them by calling usb_put_intf(), in their disconnect() methods. * - * A pointer to the interface with the incremented reference counter is - * returned. + * Return: A pointer to the interface with the incremented reference counter. */ struct usb_interface *usb_get_intf(struct usb_interface *intf) { @@ -589,7 +599,7 @@ EXPORT_SYMBOL_GPL(usb_put_intf); * disconnect; in some drivers (such as usb-storage) the disconnect() * or suspend() method will block waiting for a device reset to complete. * - * Returns a negative error code for failure, otherwise 0. + * Return: A negative error code for failure, otherwise 0. */ int usb_lock_device_for_reset(struct usb_device *udev, const struct usb_interface *iface) @@ -628,14 +638,15 @@ EXPORT_SYMBOL_GPL(usb_lock_device_for_reset); * usb_get_current_frame_number - return current bus frame number * @dev: the device whose bus is being queried * - * Returns the current frame number for the USB host controller - * used with the given USB device. This can be used when scheduling + * Return: The current frame number for the USB host controller used + * with the given USB device. This can be used when scheduling * isochronous requests. * - * Note that different kinds of host controller have different - * "scheduling horizons". While one type might support scheduling only - * 32 frames into the future, others could support scheduling up to - * 1024 frames into the future. + * Note: Different kinds of host controller have different "scheduling + * horizons". While one type might support scheduling only 32 frames + * into the future, others could support scheduling up to 1024 frames + * into the future. + * */ int usb_get_current_frame_number(struct usb_device *dev) { @@ -685,11 +696,12 @@ EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); * @mem_flags: affect whether allocation may block * @dma: used to return DMA address of buffer * - * Return value is either null (indicating no buffer could be allocated), or - * the cpu-space pointer to a buffer that may be used to perform DMA to the + * Return: Either null (indicating no buffer could be allocated), or the + * cpu-space pointer to a buffer that may be used to perform DMA to the * specified device. Such cpu-space buffers are returned along with the DMA * address (through the pointer provided). * + * Note: * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU * hardware during URB completion/resubmit. The implementation varies between @@ -735,17 +747,18 @@ EXPORT_SYMBOL_GPL(usb_free_coherent); * usb_buffer_map - create DMA mapping(s) for an urb * @urb: urb whose transfer_buffer/setup_packet will be mapped * - * Return value is either null (indicating no buffer could be mapped), or - * the parameter. URB_NO_TRANSFER_DMA_MAP is - * added to urb->transfer_flags if the operation succeeds. If the device - * is connected to this system through a non-DMA controller, this operation - * always succeeds. + * URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags if the operation + * succeeds. If the device is connected to this system through a non-DMA + * controller, this operation always succeeds. * * This call would normally be used for an urb which is reused, perhaps * as the target of a large periodic transfer, with usb_buffer_dmasync() * calls to synchronize memory and dma state. * * Reverse the effect of this call with usb_buffer_unmap(). + * + * Return: Either %NULL (indicating no buffer could be mapped), or @urb. + * */ #if 0 struct urb *usb_buffer_map(struct urb *urb) @@ -850,9 +863,10 @@ EXPORT_SYMBOL_GPL(usb_buffer_unmap); * @sg: the scatterlist to map * @nents: the number of entries in the scatterlist * - * Return value is either < 0 (indicating no buffers could be mapped), or - * the number of DMA mapping array entries in the scatterlist. + * Return: Either < 0 (indicating no buffers could be mapped), or the + * number of DMA mapping array entries in the scatterlist. * + * Note: * The caller is responsible for placing the resulting DMA addresses from * the scatterlist into URB transfer buffer pointers, and for setting the * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. diff --git a/include/linux/usb.h b/include/linux/usb.h index 6efdab089014..acb1b0aa77d8 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -708,7 +708,10 @@ extern int usb_driver_claim_interface(struct usb_driver *driver, * usb_interface_claimed - returns true iff an interface is claimed * @iface: the interface being checked * - * Returns true (nonzero) iff the interface is claimed, else false (zero). + * Return: %true (nonzero) iff the interface is claimed, else %false + * (zero). + * + * Note: * Callers must own the driver model's usb bus readlock. So driver * probe() entries don't need extra locking, but other call contexts * may need to explicitly claim that lock. @@ -745,8 +748,9 @@ extern struct usb_host_interface *usb_find_alt_setting( * @buf: where to put the string * @size: how big is "buf"? * - * Returns length of the string (> 0) or negative if size was too small. + * Return: Length of the string (> 0) or negative if size was too small. * + * Note: * This identifier is intended to be "stable", reflecting physical paths in * hardware such as physical bus addresses for host controllers or ports on * USB hubs. That makes it stay the same until systems are physically @@ -1578,7 +1582,7 @@ extern int usb_anchor_empty(struct usb_anchor *anchor); * usb_urb_dir_in - check if an URB describes an IN transfer * @urb: URB to be checked * - * Returns 1 if @urb describes an IN transfer (device-to-host), + * Return: 1 if @urb describes an IN transfer (device-to-host), * otherwise 0. */ static inline int usb_urb_dir_in(struct urb *urb) @@ -1590,7 +1594,7 @@ static inline int usb_urb_dir_in(struct urb *urb) * usb_urb_dir_out - check if an URB describes an OUT transfer * @urb: URB to be checked * - * Returns 1 if @urb describes an OUT transfer (host-to-device), + * Return: 1 if @urb describes an OUT transfer (host-to-device), * otherwise 0. */ static inline int usb_urb_dir_out(struct urb *urb) -- cgit v1.2.3 From 3fa4d7344be0afebd80382ffeea6b1787cccf971 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 26 Jul 2013 12:16:42 +0200 Subject: usb: phy: rename nop_usb_xceiv => usb_phy_gen_xceiv The "nop" driver isn't a do-nothing-stub but supports a couple functions like clock on/off or is able to use a voltage regulator. This patch simply renames the driver to "generic" since it is easy possible to extend it by a simple function istead of writing a complete driver. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Felipe Balbi --- arch/arm/mach-omap2/board-omap3beagle.c | 4 +- arch/arm/mach-omap2/board-omap3evm.c | 4 +- arch/arm/mach-omap2/board-omap3pandora.c | 2 +- arch/arm/mach-omap2/usb-host.c | 10 +- drivers/usb/dwc3/dwc3-exynos.c | 8 +- drivers/usb/dwc3/dwc3-pci.c | 8 +- drivers/usb/musb/am35x.c | 2 +- drivers/usb/musb/blackfin.c | 2 +- drivers/usb/musb/da8xx.c | 2 +- drivers/usb/musb/davinci.c | 2 +- drivers/usb/musb/musb_dsps.c | 2 +- drivers/usb/musb/tusb6010.c | 2 +- drivers/usb/phy/Makefile | 2 +- drivers/usb/phy/phy-generic.c | 292 +++++++++++++++++++++++++++++++ drivers/usb/phy/phy-nop.c | 292 ------------------------------- include/linux/usb/nop-usb-xceiv.h | 29 --- include/linux/usb/usb_phy_gen_xceiv.h | 29 +++ 17 files changed, 346 insertions(+), 346 deletions(-) create mode 100644 drivers/usb/phy/phy-generic.c delete mode 100644 drivers/usb/phy/phy-nop.c delete mode 100644 include/linux/usb/nop-usb-xceiv.h create mode 100644 include/linux/usb/usb_phy_gen_xceiv.h (limited to 'include') diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 04c116555412..1c6ae5f5bae7 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -279,7 +279,7 @@ static struct regulator_consumer_supply beagle_vsim_supply[] = { static struct gpio_led gpio_leds[]; /* PHY's VCC regulator might be added later, so flag that we need it */ -static struct nop_usb_xceiv_platform_data hsusb2_phy_data = { +static struct usb_phy_gen_xceiv_platform_data hsusb2_phy_data = { .needs_vcc = true, }; diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 8c026269baca..52bdddd41e0e 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -468,7 +468,7 @@ struct wl12xx_platform_data omap3evm_wlan_data __initdata = { static struct regulator_consumer_supply omap3evm_vaux2_supplies[] = { REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"), /* OMAP ISP */ REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"), /* OMAP ISP */ - REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ + REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */ REGULATOR_SUPPLY("vaux2", NULL), }; diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index b1547a0edfcd..d2b455e70486 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -352,7 +352,7 @@ static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = { }; static struct regulator_consumer_supply pandora_usb_phy_supply[] = { - REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"), /* hsusb port 2 */ + REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"), /* hsusb port 2 */ }; /* ads7846 on SPI and 2 nub controllers on I2C */ diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index 2eb19d4d0aa1..e83a6a4b184a 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include "soc.h" #include "omap_device.h" @@ -349,7 +349,7 @@ static struct fixed_voltage_config hsusb_reg_config = { /* .init_data filled later */ }; -static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */ +static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */ static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */ /** @@ -460,9 +460,9 @@ int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys) pdevinfo.name = nop_name; pdevinfo.id = phy->port; pdevinfo.data = phy->platform_data; - pdevinfo.size_data = sizeof(struct nop_usb_xceiv_platform_data); - - scnprintf(phy_id, MAX_STR, "nop_usb_xceiv.%d", + pdevinfo.size_data = + sizeof(struct usb_phy_gen_xceiv_platform_data); + scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d", phy->port); pdev = platform_device_register_full(&pdevinfo); if (IS_ERR(pdev)) { diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 8ce9d7fd6cfc..a179c5a54b39 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include @@ -34,13 +34,13 @@ struct dwc3_exynos { static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) { - struct nop_usb_xceiv_platform_data pdata; + struct usb_phy_gen_xceiv_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); if (!pdev) return -ENOMEM; @@ -51,7 +51,7 @@ static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos) if (ret) goto err1; - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); + pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); if (!pdev) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index ed07ec04a962..87ea3d503fc5 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -43,7 +43,7 @@ #include #include -#include +#include /* FIXME define these in */ #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 @@ -58,13 +58,13 @@ struct dwc3_pci { static int dwc3_pci_register_phys(struct dwc3_pci *glue) { - struct nop_usb_xceiv_platform_data pdata; + struct usb_phy_gen_xceiv_platform_data pdata; struct platform_device *pdev; int ret; memset(&pdata, 0x00, sizeof(pdata)); - pdev = platform_device_alloc("nop_usb_xceiv", 0); + pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); if (!pdev) return -ENOMEM; @@ -75,7 +75,7 @@ static int dwc3_pci_register_phys(struct dwc3_pci *glue) if (ret) goto err1; - pdev = platform_device_alloc("nop_usb_xceiv", 1); + pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); if (!pdev) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 2231850c0625..5733a209ab95 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include "musb_core.h" diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 6ba8439bd5a6..195e96674fff 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 0da6f648a9fe..ccc6b63bc380 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index f8aeaf2e2cd1..91f300e93cf4 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 5233804d66b1..55fe3c292cd2 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2c06a8969a9f..20f182c6184a 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "musb_core.h" diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 070eca3af18b..24c5816409fd 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -14,7 +14,7 @@ phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o -obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o +obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c new file mode 100644 index 000000000000..f379b7ded037 --- /dev/null +++ b/drivers/usb/phy/phy-generic.c @@ -0,0 +1,292 @@ +/* + * drivers/usb/otg/nop-usb-xceiv.c + * + * NOP USB transceiver for all USB transceiver which are either built-in + * into USB IP or which are mostly autonomous. + * + * Copyright (C) 2009 Texas Instruments Inc + * Author: Ajay Kumar Gupta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Current status: + * This provides a "nop" transceiver for PHYs which are + * autonomous such as isp1504, isp1707, etc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct usb_phy_gen_xceiv { + struct usb_phy phy; + struct device *dev; + struct clk *clk; + struct regulator *vcc; + struct regulator *reset; +}; + +static struct platform_device *pd; + +void usb_nop_xceiv_register(void) +{ + if (pd) + return; + pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); + if (!pd) { + pr_err("Unable to register generic usb transceiver\n"); + return; + } +} +EXPORT_SYMBOL(usb_nop_xceiv_register); + +void usb_nop_xceiv_unregister(void) +{ + platform_device_unregister(pd); + pd = NULL; +} +EXPORT_SYMBOL(usb_nop_xceiv_unregister); + +static int nop_set_suspend(struct usb_phy *x, int suspend) +{ + return 0; +} + +static int nop_init(struct usb_phy *phy) +{ + struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); + + if (!IS_ERR(nop->vcc)) { + if (regulator_enable(nop->vcc)) + dev_err(phy->dev, "Failed to enable power\n"); + } + + if (!IS_ERR(nop->clk)) + clk_enable(nop->clk); + + if (!IS_ERR(nop->reset)) { + /* De-assert RESET */ + if (regulator_enable(nop->reset)) + dev_err(phy->dev, "Failed to de-assert reset\n"); + } + + return 0; +} + +static void nop_shutdown(struct usb_phy *phy) +{ + struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); + + if (!IS_ERR(nop->reset)) { + /* Assert RESET */ + if (regulator_disable(nop->reset)) + dev_err(phy->dev, "Failed to assert reset\n"); + } + + if (!IS_ERR(nop->clk)) + clk_disable(nop->clk); + + if (!IS_ERR(nop->vcc)) { + if (regulator_disable(nop->vcc)) + dev_err(phy->dev, "Failed to disable power\n"); + } +} + +static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) +{ + if (!otg) + return -ENODEV; + + if (!gadget) { + otg->gadget = NULL; + return -ENODEV; + } + + otg->gadget = gadget; + otg->phy->state = OTG_STATE_B_IDLE; + return 0; +} + +static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + if (!otg) + return -ENODEV; + + if (!host) { + otg->host = NULL; + return -ENODEV; + } + + otg->host = host; + return 0; +} + +static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usb_phy_gen_xceiv_platform_data *pdata = pdev->dev.platform_data; + struct usb_phy_gen_xceiv *nop; + enum usb_phy_type type = USB_PHY_TYPE_USB2; + int err; + u32 clk_rate = 0; + bool needs_vcc = false; + bool needs_reset = false; + + nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL); + if (!nop) + return -ENOMEM; + + nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg), + GFP_KERNEL); + if (!nop->phy.otg) + return -ENOMEM; + + if (dev->of_node) { + struct device_node *node = dev->of_node; + + if (of_property_read_u32(node, "clock-frequency", &clk_rate)) + clk_rate = 0; + + needs_vcc = of_property_read_bool(node, "vcc-supply"); + needs_reset = of_property_read_bool(node, "reset-supply"); + + } else if (pdata) { + type = pdata->type; + clk_rate = pdata->clk_rate; + needs_vcc = pdata->needs_vcc; + needs_reset = pdata->needs_reset; + } + + nop->clk = devm_clk_get(&pdev->dev, "main_clk"); + if (IS_ERR(nop->clk)) { + dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n", + PTR_ERR(nop->clk)); + } + + if (!IS_ERR(nop->clk) && clk_rate) { + err = clk_set_rate(nop->clk, clk_rate); + if (err) { + dev_err(&pdev->dev, "Error setting clock rate\n"); + return err; + } + } + + if (!IS_ERR(nop->clk)) { + err = clk_prepare(nop->clk); + if (err) { + dev_err(&pdev->dev, "Error preparing clock\n"); + return err; + } + } + + nop->vcc = devm_regulator_get(&pdev->dev, "vcc"); + if (IS_ERR(nop->vcc)) { + dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n", + PTR_ERR(nop->vcc)); + if (needs_vcc) + return -EPROBE_DEFER; + } + + nop->reset = devm_regulator_get(&pdev->dev, "reset"); + if (IS_ERR(nop->reset)) { + dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n", + PTR_ERR(nop->reset)); + if (needs_reset) + return -EPROBE_DEFER; + } + + nop->dev = &pdev->dev; + nop->phy.dev = nop->dev; + nop->phy.label = "nop-xceiv"; + nop->phy.set_suspend = nop_set_suspend; + nop->phy.init = nop_init; + nop->phy.shutdown = nop_shutdown; + nop->phy.state = OTG_STATE_UNDEFINED; + nop->phy.type = type; + + nop->phy.otg->phy = &nop->phy; + nop->phy.otg->set_host = nop_set_host; + nop->phy.otg->set_peripheral = nop_set_peripheral; + + err = usb_add_phy_dev(&nop->phy); + if (err) { + dev_err(&pdev->dev, "can't register transceiver, err: %d\n", + err); + goto err_add; + } + + platform_set_drvdata(pdev, nop); + + ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); + + return 0; + +err_add: + if (!IS_ERR(nop->clk)) + clk_unprepare(nop->clk); + return err; +} + +static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) +{ + struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); + + if (!IS_ERR(nop->clk)) + clk_unprepare(nop->clk); + + usb_remove_phy(&nop->phy); + + return 0; +} + +static const struct of_device_id nop_xceiv_dt_ids[] = { + { .compatible = "usb-nop-xceiv" }, + { } +}; + +MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); + +static struct platform_driver usb_phy_gen_xceiv_driver = { + .probe = usb_phy_gen_xceiv_probe, + .remove = usb_phy_gen_xceiv_remove, + .driver = { + .name = "usb_phy_gen_xceiv", + .owner = THIS_MODULE, + .of_match_table = nop_xceiv_dt_ids, + }, +}; + +static int __init usb_phy_gen_xceiv_init(void) +{ + return platform_driver_register(&usb_phy_gen_xceiv_driver); +} +subsys_initcall(usb_phy_gen_xceiv_init); + +static void __exit usb_phy_gen_xceiv_exit(void) +{ + platform_driver_unregister(&usb_phy_gen_xceiv_driver); +} +module_exit(usb_phy_gen_xceiv_exit); + +MODULE_ALIAS("platform:usb_phy_gen_xceiv"); +MODULE_AUTHOR("Texas Instruments Inc"); +MODULE_DESCRIPTION("NOP USB Transceiver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-nop.c deleted file mode 100644 index 55445e5d72e5..000000000000 --- a/drivers/usb/phy/phy-nop.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * drivers/usb/otg/nop-usb-xceiv.c - * - * NOP USB transceiver for all USB transceiver which are either built-in - * into USB IP or which are mostly autonomous. - * - * Copyright (C) 2009 Texas Instruments Inc - * Author: Ajay Kumar Gupta - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Current status: - * This provides a "nop" transceiver for PHYs which are - * autonomous such as isp1504, isp1707, etc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct nop_usb_xceiv { - struct usb_phy phy; - struct device *dev; - struct clk *clk; - struct regulator *vcc; - struct regulator *reset; -}; - -static struct platform_device *pd; - -void usb_nop_xceiv_register(void) -{ - if (pd) - return; - pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0); - if (!pd) { - printk(KERN_ERR "Unable to register usb nop transceiver\n"); - return; - } -} -EXPORT_SYMBOL(usb_nop_xceiv_register); - -void usb_nop_xceiv_unregister(void) -{ - platform_device_unregister(pd); - pd = NULL; -} -EXPORT_SYMBOL(usb_nop_xceiv_unregister); - -static int nop_set_suspend(struct usb_phy *x, int suspend) -{ - return 0; -} - -static int nop_init(struct usb_phy *phy) -{ - struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); - - if (!IS_ERR(nop->vcc)) { - if (regulator_enable(nop->vcc)) - dev_err(phy->dev, "Failed to enable power\n"); - } - - if (!IS_ERR(nop->clk)) - clk_enable(nop->clk); - - if (!IS_ERR(nop->reset)) { - /* De-assert RESET */ - if (regulator_enable(nop->reset)) - dev_err(phy->dev, "Failed to de-assert reset\n"); - } - - return 0; -} - -static void nop_shutdown(struct usb_phy *phy) -{ - struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); - - if (!IS_ERR(nop->reset)) { - /* Assert RESET */ - if (regulator_disable(nop->reset)) - dev_err(phy->dev, "Failed to assert reset\n"); - } - - if (!IS_ERR(nop->clk)) - clk_disable(nop->clk); - - if (!IS_ERR(nop->vcc)) { - if (regulator_disable(nop->vcc)) - dev_err(phy->dev, "Failed to disable power\n"); - } -} - -static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) -{ - if (!otg) - return -ENODEV; - - if (!gadget) { - otg->gadget = NULL; - return -ENODEV; - } - - otg->gadget = gadget; - otg->phy->state = OTG_STATE_B_IDLE; - return 0; -} - -static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - if (!otg) - return -ENODEV; - - if (!host) { - otg->host = NULL; - return -ENODEV; - } - - otg->host = host; - return 0; -} - -static int nop_usb_xceiv_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data; - struct nop_usb_xceiv *nop; - enum usb_phy_type type = USB_PHY_TYPE_USB2; - int err; - u32 clk_rate = 0; - bool needs_vcc = false; - bool needs_reset = false; - - nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL); - if (!nop) - return -ENOMEM; - - nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg), - GFP_KERNEL); - if (!nop->phy.otg) - return -ENOMEM; - - if (dev->of_node) { - struct device_node *node = dev->of_node; - - if (of_property_read_u32(node, "clock-frequency", &clk_rate)) - clk_rate = 0; - - needs_vcc = of_property_read_bool(node, "vcc-supply"); - needs_reset = of_property_read_bool(node, "reset-supply"); - - } else if (pdata) { - type = pdata->type; - clk_rate = pdata->clk_rate; - needs_vcc = pdata->needs_vcc; - needs_reset = pdata->needs_reset; - } - - nop->clk = devm_clk_get(&pdev->dev, "main_clk"); - if (IS_ERR(nop->clk)) { - dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n", - PTR_ERR(nop->clk)); - } - - if (!IS_ERR(nop->clk) && clk_rate) { - err = clk_set_rate(nop->clk, clk_rate); - if (err) { - dev_err(&pdev->dev, "Error setting clock rate\n"); - return err; - } - } - - if (!IS_ERR(nop->clk)) { - err = clk_prepare(nop->clk); - if (err) { - dev_err(&pdev->dev, "Error preparing clock\n"); - return err; - } - } - - nop->vcc = devm_regulator_get(&pdev->dev, "vcc"); - if (IS_ERR(nop->vcc)) { - dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n", - PTR_ERR(nop->vcc)); - if (needs_vcc) - return -EPROBE_DEFER; - } - - nop->reset = devm_regulator_get(&pdev->dev, "reset"); - if (IS_ERR(nop->reset)) { - dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n", - PTR_ERR(nop->reset)); - if (needs_reset) - return -EPROBE_DEFER; - } - - nop->dev = &pdev->dev; - nop->phy.dev = nop->dev; - nop->phy.label = "nop-xceiv"; - nop->phy.set_suspend = nop_set_suspend; - nop->phy.init = nop_init; - nop->phy.shutdown = nop_shutdown; - nop->phy.state = OTG_STATE_UNDEFINED; - nop->phy.type = type; - - nop->phy.otg->phy = &nop->phy; - nop->phy.otg->set_host = nop_set_host; - nop->phy.otg->set_peripheral = nop_set_peripheral; - - err = usb_add_phy_dev(&nop->phy); - if (err) { - dev_err(&pdev->dev, "can't register transceiver, err: %d\n", - err); - goto err_add; - } - - platform_set_drvdata(pdev, nop); - - ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); - - return 0; - -err_add: - if (!IS_ERR(nop->clk)) - clk_unprepare(nop->clk); - return err; -} - -static int nop_usb_xceiv_remove(struct platform_device *pdev) -{ - struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); - - if (!IS_ERR(nop->clk)) - clk_unprepare(nop->clk); - - usb_remove_phy(&nop->phy); - - return 0; -} - -static const struct of_device_id nop_xceiv_dt_ids[] = { - { .compatible = "usb-nop-xceiv" }, - { } -}; - -MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); - -static struct platform_driver nop_usb_xceiv_driver = { - .probe = nop_usb_xceiv_probe, - .remove = nop_usb_xceiv_remove, - .driver = { - .name = "nop_usb_xceiv", - .owner = THIS_MODULE, - .of_match_table = nop_xceiv_dt_ids, - }, -}; - -static int __init nop_usb_xceiv_init(void) -{ - return platform_driver_register(&nop_usb_xceiv_driver); -} -subsys_initcall(nop_usb_xceiv_init); - -static void __exit nop_usb_xceiv_exit(void) -{ - platform_driver_unregister(&nop_usb_xceiv_driver); -} -module_exit(nop_usb_xceiv_exit); - -MODULE_ALIAS("platform:nop_usb_xceiv"); -MODULE_AUTHOR("Texas Instruments Inc"); -MODULE_DESCRIPTION("NOP USB Transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h deleted file mode 100644 index 148d35171aac..000000000000 --- a/include/linux/usb/nop-usb-xceiv.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __LINUX_USB_NOP_XCEIV_H -#define __LINUX_USB_NOP_XCEIV_H - -#include - -struct nop_usb_xceiv_platform_data { - enum usb_phy_type type; - unsigned long clk_rate; - - /* if set fails with -EPROBE_DEFER if can't get regulator */ - unsigned int needs_vcc:1; - unsigned int needs_reset:1; -}; - -#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE)) -/* sometimes transceivers are accessed only through e.g. ULPI */ -extern void usb_nop_xceiv_register(void); -extern void usb_nop_xceiv_unregister(void); -#else -static inline void usb_nop_xceiv_register(void) -{ -} - -static inline void usb_nop_xceiv_unregister(void) -{ -} -#endif - -#endif /* __LINUX_USB_NOP_XCEIV_H */ diff --git a/include/linux/usb/usb_phy_gen_xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h new file mode 100644 index 000000000000..f9a7e7bc925b --- /dev/null +++ b/include/linux/usb/usb_phy_gen_xceiv.h @@ -0,0 +1,29 @@ +#ifndef __LINUX_USB_NOP_XCEIV_H +#define __LINUX_USB_NOP_XCEIV_H + +#include + +struct usb_phy_gen_xceiv_platform_data { + enum usb_phy_type type; + unsigned long clk_rate; + + /* if set fails with -EPROBE_DEFER if can't get regulator */ + unsigned int needs_vcc:1; + unsigned int needs_reset:1; +}; + +#if IS_ENABLED(CONFIG_NOP_USB_XCEIV) +/* sometimes transceivers are accessed only through e.g. ULPI */ +extern void usb_nop_xceiv_register(void); +extern void usb_nop_xceiv_unregister(void); +#else +static inline void usb_nop_xceiv_register(void) +{ +} + +static inline void usb_nop_xceiv_unregister(void) +{ +} +#endif + +#endif /* __LINUX_USB_NOP_XCEIV_H */ -- cgit v1.2.3 From 3e635202ce40e4d7ff3fafc18db70c5d28cc6622 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:51 +0300 Subject: usb: phy: tegra: Tegra30 support The Tegra30 USB PHY is a bit different than the Tegra20 PHY: - The EHCI controller supports the HOSTPC register extension, and some of the fields that the PHY needs to modify (PHCD and PTS) have moved to the new HOSTPC register. - Some of the UTMI PLL configuration registers have moved from the USB register space to the Clock-And-Reset controller space. In Tegra30 the clock driver is responsible for configuring the UTMI PLL. - The USBMODE register must be explicitly written to enter host mode. - Certain PHY parameters need to be programmed for optimal signal quality. Support for this will be added in the next patch. The new tegra_phy_soc_config structure is added to describe the differences between the SoCs. Signed-off-by: Tuomas Tynkkynen Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 121 +++++++++++++++++++++++++++++--------- include/linux/usb/tegra_usb_phy.h | 19 ++++++ 2 files changed, 112 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index ebbf85fdfc7f..1ad184af7601 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -39,11 +40,16 @@ #define ULPI_VIEWPORT 0x170 -/* PORTSC registers */ +/* PORTSC PTS/PHCD bits, Tegra20 only */ #define TEGRA_USB_PORTSC1 0x184 #define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) #define TEGRA_USB_PORTSC1_PHCD (1 << 23) +/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */ +#define TEGRA_USB_HOSTPC1_DEVLC 0x1b4 +#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) +#define TEGRA_USB_HOSTPC1_DEVLC_PHCD (1 << 22) + /* Bits of PORTSC1, which will get cleared by writing 1 into them */ #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) @@ -141,6 +147,12 @@ #define UTMIP_BIAS_CFG1 0x83c #define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3) +/* For Tegra30 and above only, the address is different in Tegra20 */ +#define USB_USBMODE 0x1f8 +#define USB_USBMODE_MASK (3 << 0) +#define USB_USBMODE_HOST (3 << 0) +#define USB_USBMODE_DEVICE (2 << 0) + static DEFINE_SPINLOCK(utmip_pad_lock); static int utmip_pad_count; @@ -193,10 +205,17 @@ static void set_pts(struct tegra_usb_phy *phy, u8 pts_val) void __iomem *base = phy->regs; unsigned long val; - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - val &= ~TEGRA_USB_PORTSC1_PTS(3); - val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); - writel(val, base + TEGRA_USB_PORTSC1); + if (phy->soc_config->has_hostpc) { + val = readl(base + TEGRA_USB_HOSTPC1_DEVLC); + val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0); + val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val); + writel(val, base + TEGRA_USB_HOSTPC1_DEVLC); + } else { + val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; + val &= ~TEGRA_USB_PORTSC1_PTS(~0); + val |= TEGRA_USB_PORTSC1_PTS(pts_val); + writel(val, base + TEGRA_USB_PORTSC1); + } } static void set_phcd(struct tegra_usb_phy *phy, bool enable) @@ -204,12 +223,21 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable) void __iomem *base = phy->regs; unsigned long val; - val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS; - if (enable) - val |= TEGRA_USB_PORTSC1_PHCD; - else - val &= ~TEGRA_USB_PORTSC1_PHCD; - writel(val, base + TEGRA_USB_PORTSC1); + if (phy->soc_config->has_hostpc) { + val = readl(base + TEGRA_USB_HOSTPC1_DEVLC); + if (enable) + val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD; + else + val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD; + writel(val, base + TEGRA_USB_HOSTPC1_DEVLC); + } else { + val = readl(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS; + if (enable) + val |= TEGRA_USB_PORTSC1_PHCD; + else + val &= ~TEGRA_USB_PORTSC1_PHCD; + writel(val, base + TEGRA_USB_PORTSC1); + } } static int utmip_pad_open(struct tegra_usb_phy *phy) @@ -367,17 +395,21 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE; writel(val, base + UTMIP_MISC_CFG0); - val = readl(base + UTMIP_MISC_CFG1); - val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0)); - val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | - UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); - writel(val, base + UTMIP_MISC_CFG1); - - val = readl(base + UTMIP_PLL_CFG1); - val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); - val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | - UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); - writel(val, base + UTMIP_PLL_CFG1); + if (!phy->soc_config->utmi_pll_config_in_car_module) { + val = readl(base + UTMIP_MISC_CFG1); + val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | + UTMIP_PLLU_STABLE_COUNT(~0)); + val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) | + UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count); + writel(val, base + UTMIP_MISC_CFG1); + + val = readl(base + UTMIP_PLL_CFG1); + val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | + UTMIP_PLLU_ENABLE_DLY_COUNT(~0)); + val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) | + UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay); + writel(val, base + UTMIP_PLL_CFG1); + } if (phy->mode == USB_DR_MODE_PERIPHERAL) { val = readl(base + USB_SUSP_CTRL); @@ -448,6 +480,16 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) utmi_phy_clk_enable(phy); + if (phy->soc_config->requires_usbmode_setup) { + val = readl(base + USB_USBMODE); + val &= ~USB_USBMODE_MASK; + if (phy->mode == USB_DR_MODE_HOST) + val |= USB_USBMODE_HOST; + else + val |= USB_USBMODE_DEVICE; + writel(val, base + USB_USBMODE); + } + if (!phy->is_legacy_phy) set_pts(phy, 0); @@ -864,8 +906,30 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, return 0; } +static const struct tegra_phy_soc_config tegra20_soc_config = { + .utmi_pll_config_in_car_module = false, + .has_hostpc = false, + .requires_usbmode_setup = false, + .requires_extra_tuning_parameters = false, +}; + +static const struct tegra_phy_soc_config tegra30_soc_config = { + .utmi_pll_config_in_car_module = true, + .has_hostpc = true, + .requires_usbmode_setup = true, + .requires_extra_tuning_parameters = true, +}; + +static struct of_device_id tegra_usb_phy_id_table[] = { + { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config }, + { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table); + static int tegra_usb_phy_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct resource *res; struct tegra_usb_phy *tegra_phy = NULL; struct device_node *np = pdev->dev.of_node; @@ -878,6 +942,13 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return -ENOMEM; } + match = of_match_device(tegra_usb_phy_id_table, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + tegra_phy->soc_config = match->data; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Failed to get I/O memory\n"); @@ -968,12 +1039,6 @@ static int tegra_usb_phy_remove(struct platform_device *pdev) return 0; } -static struct of_device_id tegra_usb_phy_id_table[] = { - { .compatible = "nvidia,tegra20-usb-phy", }, - { }, -}; -MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table); - static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, .remove = tegra_usb_phy_remove, diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d3db274610a1..d3a63c354db9 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -18,6 +18,24 @@ #include #include +/* + * utmi_pll_config_in_car_module: true if the UTMI PLL configuration registers + * should be set up by clk-tegra, false if by the PHY code + * has_hostpc: true if the USB controller has the HOSTPC extension, which + * changes the location of the PHCD and PTS fields + * requires_usbmode_setup: true if the USBMODE register needs to be set to + * enter host mode + * requires_extra_tuning_parameters: true if xcvr_hsslew, hssquelch_level + * and hsdiscon_level should be set for adequate signal quality + */ + +struct tegra_phy_soc_config { + bool utmi_pll_config_in_car_module; + bool has_hostpc; + bool requires_usbmode_setup; + bool requires_extra_tuning_parameters; +}; + struct tegra_utmip_config { u8 hssync_start_delay; u8 elastic_limit; @@ -47,6 +65,7 @@ struct tegra_usb_phy { struct regulator *vbus; enum usb_dr_mode mode; void *config; + const struct tegra_phy_soc_config *soc_config; struct usb_phy *ulpi; struct usb_phy u_phy; bool is_legacy_phy; -- cgit v1.2.3 From e497a24d8e18af510879b2ae059ee20a4a58eae8 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Mon, 12 Aug 2013 16:06:53 +0300 Subject: usb: phy: tegra: Program new PHY parameters The Tegra30 TRM recommends configuration of certain PHY parameters for optimal quality. Program the following registers based on device tree parameters: - UTMIP_XCVR_HSSLEW: HS slew rate control. - UTMIP_HSSQUELCH_LEVEL: HS squelch detector level - UTMIP_HSDISCON_LEVEL: HS disconnect detector level. These registers exist in Tegra20, but programming them hasn't been necessary, so these parameters won't be set on Tegra20 to keep the device trees backward compatible. Additionally, the UTMIP_XCVR_SETUP parameter can be set from fuses instead of a software-programmed value, as the optimal value can vary between invidual boards. The boolean property nvidia,xcvr-setup-use-fuses can be used to enable this behaviour. Signed-off-by: Tuomas Tynkkynen Tested-by: Stephen Warren Reviewed-by: Stephen Warren Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tegra-usb.c | 81 ++++++++++++++++++++++++++++++--------- include/linux/usb/tegra_usb_phy.h | 4 ++ 2 files changed, 67 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index 1ad184af7601..3bfb3d1957c1 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -99,11 +99,15 @@ #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) #define UTMIP_XCVR_LSBIAS_SEL (1 << 21) -#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25) +#define UTMIP_XCVR_HSSLEW(x) (((x) & 0x3) << 4) +#define UTMIP_XCVR_HSSLEW_MSB(x) ((((x) & 0x1fc) >> 2) << 25) #define UTMIP_BIAS_CFG0 0x80c #define UTMIP_OTGPD (1 << 11) #define UTMIP_BIASPD (1 << 10) +#define UTMIP_HSSQUELCH_LEVEL(x) (((x) & 0x3) << 0) +#define UTMIP_HSDISCON_LEVEL(x) (((x) & 0x3) << 2) +#define UTMIP_HSDISCON_LEVEL_MSB(x) ((((x) & 0x4) >> 2) << 24) #define UTMIP_HSRX_CFG0 0x810 #define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10) @@ -255,6 +259,7 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) { unsigned long val, flags; void __iomem *base = phy->pad_regs; + struct tegra_utmip_config *config = phy->config; clk_prepare_enable(phy->pad_clk); @@ -263,6 +268,16 @@ static void utmip_pad_power_on(struct tegra_usb_phy *phy) if (utmip_pad_count++ == 0) { val = readl(base + UTMIP_BIAS_CFG0); val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); + + if (phy->soc_config->requires_extra_tuning_parameters) { + val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) | + UTMIP_HSDISCON_LEVEL(~0) | + UTMIP_HSDISCON_LEVEL_MSB(~0)); + + val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level); + val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level); + val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level); + } writel(val, base + UTMIP_BIAS_CFG0); } @@ -431,12 +446,20 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL | UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) | - UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) | - UTMIP_XCVR_HSSLEW_MSB(~0)); - val |= UTMIP_XCVR_SETUP(config->xcvr_setup); - val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); + UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0)); + + if (!config->xcvr_setup_use_fuses) { + val |= UTMIP_XCVR_SETUP(config->xcvr_setup); + val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup); + } val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew); val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew); + + if (phy->soc_config->requires_extra_tuning_parameters) { + val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0)); + val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew); + val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew); + } writel(val, base + UTMIP_XCVR_CFG0); val = readl(base + UTMIP_XCVR_CFG1); @@ -450,14 +473,14 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val |= UTMIP_BIAS_PDTRK_COUNT(0x5); writel(val, base + UTMIP_BIAS_CFG1); - if (phy->is_legacy_phy) { - val = readl(base + UTMIP_SPARE_CFG0); - if (phy->mode == USB_DR_MODE_PERIPHERAL) - val &= ~FUSE_SETUP_SEL; - else - val |= FUSE_SETUP_SEL; - writel(val, base + UTMIP_SPARE_CFG0); - } else { + val = readl(base + UTMIP_SPARE_CFG0); + if (config->xcvr_setup_use_fuses) + val |= FUSE_SETUP_SEL; + else + val &= ~FUSE_SETUP_SEL; + writel(val, base + UTMIP_SPARE_CFG0); + + if (!phy->is_legacy_phy) { val = readl(base + USB_SUSP_CTRL); val |= UTMIP_PHY_ENABLE; writel(val, base + USB_SUSP_CTRL); @@ -888,11 +911,6 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, if (err < 0) return err; - err = read_utmi_param(pdev, "nvidia,xcvr-setup", - &config->xcvr_setup); - if (err < 0) - return err; - err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew", &config->xcvr_lsfslew); if (err < 0) @@ -903,6 +921,33 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, if (err < 0) return err; + if (tegra_phy->soc_config->requires_extra_tuning_parameters) { + err = read_utmi_param(pdev, "nvidia,xcvr-hsslew", + &config->xcvr_hsslew); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,hssquelch-level", + &config->hssquelch_level); + if (err < 0) + return err; + + err = read_utmi_param(pdev, "nvidia,hsdiscon-level", + &config->hsdiscon_level); + if (err < 0) + return err; + } + + config->xcvr_setup_use_fuses = of_property_read_bool( + pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses"); + + if (!config->xcvr_setup_use_fuses) { + err = read_utmi_param(pdev, "nvidia,xcvr-setup", + &config->xcvr_setup); + if (err < 0) + return err; + } + return 0; } diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d3a63c354db9..1de16c324ec8 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -41,9 +41,13 @@ struct tegra_utmip_config { u8 elastic_limit; u8 idle_wait_delay; u8 term_range_adj; + bool xcvr_setup_use_fuses; u8 xcvr_setup; u8 xcvr_lsfslew; u8 xcvr_lsrslew; + u8 xcvr_hsslew; + u8 hssquelch_level; + u8 hsdiscon_level; }; enum tegra_usb_phy_port_speed { -- cgit v1.2.3 From 94dfd7edfd5c9b605caf7b562de7a813d216e011 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 3 Jul 2013 22:53:07 +0800 Subject: USB: HCD: support giveback of URB in tasklet context This patch implements the mechanism of giveback of URB in tasklet context, so that hardware interrupt handling time for usb host controller can be saved much, and HCD interrupt handling can be simplified. Motivations: 1), on some arch(such as ARM), DMA mapping/unmapping is a bit time-consuming, for example: when accessing usb mass storage via EHCI on pandaboard, the common length of transfer buffer is 120KB, the time consumed on DMA unmapping may reach hundreds of microseconds; even on A15 based box, the time is still about scores of microseconds 2), on some arch, reading DMA coherent memoery is very time-consuming, the most common example is usb video class driver[1] 3), driver's complete() callback may do much things which is driver specific, so the time is consumed unnecessarily in hardware irq context. 4), running driver's complete() callback in hardware irq context causes that host controller driver has to release its lock in interrupt handler, so reacquiring the lock after return may busy wait a while and increase interrupt handling time. More seriously, releasing the HCD lock makes HCD becoming quite complicated to deal with introduced races. So the patch proposes to run giveback of URB in tasklet context, then time consumed in HCD irq handling doesn't depend on drivers' complete and DMA mapping/unmapping any more, also we can simplify HCD since the HCD lock isn't needed to be released during irq handling. The patch should be reasonable and doable: 1), for drivers, they don't care if the complete() is called in hard irq context or softirq context 2), the biggest change is the situation in which usb_submit_urb() is called in complete() callback, so the introduced tasklet schedule delay might be a con, but it shouldn't be a big deal: - control/bulk asynchronous transfer isn't sensitive to schedule delay - the patch schedules giveback of periodic URBs using tasklet_hi_schedule, so the introduced delay should be very small - for ISOC transfer, generally, drivers submit several URBs concurrently to avoid interrupt delay, so it is OK with the little schedule delay. - for interrupt transfer, generally, drivers only submit one URB at the same time, but interrupt transfer is often used in event report, polling, ... situations, and a little delay should be OK. Considered that HCDs may optimize on submitting URB in complete(), the patch may cause the optimization not working, so introduces one flag to mark if the HCD supports to run giveback URB in tasklet context. When all HCDs are ready, the flag can be removed. [1], http://marc.info/?t=136438111600010&r=1&w=2 Cc: Oliver Neukum Acked-by: Alan Stern Signed-off-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 147 ++++++++++++++++++++++++++++++++++++++---------- include/linux/usb/hcd.h | 17 ++++++ 2 files changed, 134 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index dc1346fee76c..0ffe016f4036 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -696,15 +696,7 @@ error: /* any errors get returned through the urb completion */ spin_lock_irq(&hcd_root_hub_lock); usb_hcd_unlink_urb_from_ep(hcd, urb); - - /* This peculiar use of spinlocks echoes what real HC drivers do. - * Avoiding calls to local_irq_disable/enable makes the code - * RT-friendly. - */ - spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&hcd_root_hub_lock); - spin_unlock_irq(&hcd_root_hub_lock); return 0; } @@ -744,9 +736,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) memcpy(urb->transfer_buffer, buffer, length); usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, 0); - spin_lock(&hcd_root_hub_lock); } else { length = 0; set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags); @@ -836,10 +826,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (urb == hcd->status_urb) { hcd->status_urb = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); - - spin_unlock(&hcd_root_hub_lock); usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&hcd_root_hub_lock); } } done: @@ -1656,6 +1643,72 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) /*-------------------------------------------------------------------------*/ +static void __usb_hcd_giveback_urb(struct urb *urb) +{ + struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); + int status = urb->unlinked; + unsigned long flags; + + urb->hcpriv = NULL; + if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && + urb->actual_length < urb->transfer_buffer_length && + !status)) + status = -EREMOTEIO; + + unmap_urb_for_dma(hcd, urb); + usbmon_urb_complete(&hcd->self, urb, status); + usb_unanchor_urb(urb); + + /* pass ownership to the completion handler */ + urb->status = status; + + /* + * We disable local IRQs here avoid possible deadlock because + * drivers may call spin_lock() to hold lock which might be + * acquired in one hard interrupt handler. + * + * The local_irq_save()/local_irq_restore() around complete() + * will be removed if current USB drivers have been cleaned up + * and no one may trigger the above deadlock situation when + * running complete() in tasklet. + */ + local_irq_save(flags); + urb->complete(urb); + local_irq_restore(flags); + + atomic_dec(&urb->use_count); + if (unlikely(atomic_read(&urb->reject))) + wake_up(&usb_kill_urb_queue); + usb_put_urb(urb); +} + +static void usb_giveback_urb_bh(unsigned long param) +{ + struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param; + struct list_head local_list; + + spin_lock_irq(&bh->lock); + bh->running = true; + restart: + list_replace_init(&bh->head, &local_list); + spin_unlock_irq(&bh->lock); + + while (!list_empty(&local_list)) { + struct urb *urb; + + urb = list_entry(local_list.next, struct urb, urb_list); + list_del_init(&urb->urb_list); + __usb_hcd_giveback_urb(urb); + } + + /* check if there are new URBs to giveback */ + spin_lock_irq(&bh->lock); + if (!list_empty(&bh->head)) + goto restart; + bh->running = false; + spin_unlock_irq(&bh->lock); +} + /** * usb_hcd_giveback_urb - return URB from HCD to device driver * @hcd: host controller returning the URB @@ -1675,25 +1728,37 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) */ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { - urb->hcpriv = NULL; - if (unlikely(urb->unlinked)) - status = urb->unlinked; - else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < urb->transfer_buffer_length && - !status)) - status = -EREMOTEIO; + struct giveback_urb_bh *bh; + bool running, high_prio_bh; - unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb, status); - usb_unanchor_urb(urb); + /* pass status to tasklet via unlinked */ + if (likely(!urb->unlinked)) + urb->unlinked = status; - /* pass ownership to the completion handler */ - urb->status = status; - urb->complete (urb); - atomic_dec (&urb->use_count); - if (unlikely(atomic_read(&urb->reject))) - wake_up (&usb_kill_urb_queue); - usb_put_urb (urb); + if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) { + __usb_hcd_giveback_urb(urb); + return; + } + + if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) { + bh = &hcd->high_prio_bh; + high_prio_bh = true; + } else { + bh = &hcd->low_prio_bh; + high_prio_bh = false; + } + + spin_lock(&bh->lock); + list_add_tail(&urb->urb_list, &bh->head); + running = bh->running; + spin_unlock(&bh->lock); + + if (running) + ; + else if (high_prio_bh) + tasklet_hi_schedule(&bh->bh); + else + tasklet_schedule(&bh->bh); } EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb); @@ -2322,6 +2387,14 @@ EXPORT_SYMBOL_GPL (usb_hc_died); /*-------------------------------------------------------------------------*/ +static void init_giveback_urb_bh(struct giveback_urb_bh *bh) +{ + + spin_lock_init(&bh->lock); + INIT_LIST_HEAD(&bh->head); + tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh); +} + /** * usb_create_shared_hcd - create and initialize an HCD structure * @driver: HC driver that will use this hcd @@ -2590,6 +2663,10 @@ int usb_add_hcd(struct usb_hcd *hcd, && device_can_wakeup(&hcd->self.root_hub->dev)) dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); + /* initialize tasklets */ + init_giveback_urb_bh(&hcd->high_prio_bh); + init_giveback_urb_bh(&hcd->low_prio_bh); + /* enable irqs just before we start the controller, * if the BIOS provides legacy PCI irqs. */ @@ -2698,6 +2775,16 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_disconnect(&rhdev); /* Sets rhdev to NULL */ mutex_unlock(&usb_bus_list_lock); + /* + * tasklet_kill() isn't needed here because: + * - driver's disconnect() called from usb_disconnect() should + * make sure its URBs are completed during the disconnect() + * callback + * + * - it is too late to run complete() here since driver may have + * been removed already now + */ + /* Prevent any more root-hub status calls from the timer. * The HCD might still restart the timer (if a port status change * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 1e88377e22f4..a9c7d44bd2ed 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -22,6 +22,7 @@ #ifdef __KERNEL__ #include +#include #define MAX_TOPO_LEVEL 6 @@ -67,6 +68,13 @@ /*-------------------------------------------------------------------------*/ +struct giveback_urb_bh { + bool running; + spinlock_t lock; + struct list_head head; + struct tasklet_struct bh; +}; + struct usb_hcd { /* @@ -139,6 +147,9 @@ struct usb_hcd { resource_size_t rsrc_len; /* memory/io resource length */ unsigned power_budget; /* in mA, 0 = no limit */ + struct giveback_urb_bh high_prio_bh; + struct giveback_urb_bh low_prio_bh; + /* bandwidth_mutex should be taken before adding or removing * any new bus bandwidth constraints: * 1. Before adding a configuration for a new device. @@ -221,6 +232,7 @@ struct hc_driver { #define HCD_USB25 0x0030 /* Wireless USB 1.0 (USB 2.5)*/ #define HCD_USB3 0x0040 /* USB 3.0 */ #define HCD_MASK 0x0070 +#define HCD_BH 0x0100 /* URB complete in BH context */ /* called to init HCD and root hub */ int (*reset) (struct usb_hcd *hcd); @@ -361,6 +373,11 @@ struct hc_driver { int (*find_raw_port_number)(struct usb_hcd *, int); }; +static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) +{ + return hcd->driver->flags & HCD_BH; +} + extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, int status); -- cgit v1.2.3 From bcc48f1a7a0d40ae2e5a26aff72c2b674fd8b596 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 8 Aug 2013 21:48:22 +0800 Subject: USB: introduce usb_device_no_sg_constraint() helper Some host controllers(such as xHCI) can support building packet from discontinuous buffers, so introduce one flag and helper for this kind of host controllers, then the feature can help some applications(such as usbnet) by supporting arbitrary length of sg buffers. Acked-by: Alan Stern Signed-off-by: Ming Lei Reviewed-by: Eric Dumazet Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 3 ++- include/linux/usb.h | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 4e7a311ff6d7..c12bc790a6a7 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -416,7 +416,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->iso_frame_desc[n].status = -EXDEV; urb->iso_frame_desc[n].actual_length = 0; } - } else if (dev->speed != USB_SPEED_WIRELESS && urb->num_sgs) { + } else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint && + dev->speed != USB_SPEED_WIRELESS) { struct scatterlist *sg; int i; diff --git a/include/linux/usb.h b/include/linux/usb.h index acb1b0aa77d8..001629cd1a97 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -337,6 +337,7 @@ struct usb_bus { * the ep queue on a short transfer * with the URB_SHORT_NOT_OK flag set. */ + unsigned no_sg_constraint:1; /* no sg constraint */ unsigned sg_tablesize; /* 0 or largest number of sg list entries */ int devnum_next; /* Next open device number in @@ -684,6 +685,11 @@ static inline bool usb_device_supports_ltm(struct usb_device *udev) return udev->bos->ss_cap->bmAttributes & USB_LTM_SUPPORT; } +static inline bool usb_device_no_sg_constraint(struct usb_device *udev) +{ + return udev && udev->bus && udev->bus->no_sg_constraint; +} + /*-------------------------------------------------------------------------*/ @@ -1253,7 +1259,7 @@ typedef void (*usb_complete_t)(struct urb *); * transfer_buffer. * @sg: scatter gather buffer list, the buffer size of each element in * the list (except the last) must be divisible by the endpoint's - * max packet size + * max packet size if no_sg_constraint isn't set in 'struct usb_bus' * @num_mapped_sgs: (internal) number of mapped sg entries * @num_sgs: number of entries in the sg list * @transfer_buffer_length: How big is transfer_buffer. The transfer may -- cgit v1.2.3 From 638c5115a794981441246fa8fa5d95c1875af5ba Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 8 Aug 2013 21:48:24 +0800 Subject: USBNET: support DMA SG This patch introduces support of DMA SG if the USB host controller which usbnet device is attached to is capable of building packet from discontinuous buffers. The patch supports passing the skb fragment buffers to usb stack directly via urb->sg. Cc: Ben Hutchings Cc: Grant Grundler Cc: Freddy Xin Cc: Alan Stern Acked-by: Oliver Neukum Signed-off-by: Ming Lei Reviewed-by: Eric Dumazet Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/usbnet.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- include/linux/usb/usbnet.h | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 06ee82f557d4..27a00b006033 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1197,6 +1197,37 @@ EXPORT_SYMBOL_GPL(usbnet_tx_timeout); /*-------------------------------------------------------------------------*/ +static int build_dma_sg(const struct sk_buff *skb, struct urb *urb) +{ + unsigned num_sgs, total_len = 0; + int i, s = 0; + + num_sgs = skb_shinfo(skb)->nr_frags + 1; + if (num_sgs == 1) + return 0; + + urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC); + if (!urb->sg) + return -ENOMEM; + + urb->num_sgs = num_sgs; + sg_init_table(urb->sg, urb->num_sgs); + + sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb)); + total_len += skb_headlen(skb); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i]; + + total_len += skb_frag_size(f); + sg_set_page(&urb->sg[i + s], f->page.p, f->size, + f->page_offset); + } + urb->transfer_buffer_length = total_len; + + return 1; +} + netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) { @@ -1223,7 +1254,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, goto drop; } } - length = skb->len; if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { netif_dbg(dev, tx_err, dev->net, "no urb\n"); @@ -1233,10 +1263,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; - entry->length = length; usb_fill_bulk_urb (urb, dev->udev, dev->out, skb->data, skb->len, tx_complete, skb); + if (dev->can_dma_sg) { + if (build_dma_sg(skb, urb) < 0) + goto drop; + } + entry->length = length = urb->transfer_buffer_length; /* don't assume the hardware handles USB_ZERO_PACKET * NOTE: strictly conforming cdc-ether devices should expect @@ -1305,7 +1339,10 @@ drop: not_drop: if (skb) dev_kfree_skb_any (skb); - usb_free_urb (urb); + if (urb) { + kfree(urb->sg); + usb_free_urb(urb); + } } else netif_dbg(dev, tx_queued, dev->net, "> tx, len %d, type 0x%x\n", length, skb->protocol); @@ -1356,6 +1393,7 @@ static void usbnet_bh (unsigned long param) rx_process (dev, skb); continue; case tx_done: + kfree(entry->urb->sg); case rx_cleanup: usb_free_urb (entry->urb); dev_kfree_skb (skb); @@ -1689,6 +1727,7 @@ int usbnet_resume (struct usb_interface *intf) retval = usb_submit_urb(res, GFP_ATOMIC); if (retval < 0) { dev_kfree_skb_any(skb); + kfree(res->sg); usb_free_urb(res); usb_autopm_put_interface_async(dev->intf); } else { diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index f18d64129f99..2b47e6364e36 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -34,6 +34,7 @@ struct usbnet { struct mutex phy_mutex; unsigned char suspend_count; unsigned char pkt_cnt, pkt_err; + unsigned can_dma_sg:1; /* i/o info: pipes etc */ unsigned in, out; -- cgit v1.2.3 From 1542d9c35d8166c54e0616574954a0f48449f331 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 14 Aug 2013 12:44:03 +0300 Subject: usb: chipidea: move vbus regulator operation to core The vbus regulator is a common element for USB vbus operation, So, move it from glue layer to core. Tested-by: Marek Vasut Signed-off-by: Michael Grzeschik Signed-off-by: Peter Chen Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 26 ++------------------------ drivers/usb/chipidea/core.c | 23 +++++++++++++++++++++++ include/linux/usb/chipidea.h | 1 + 3 files changed, 26 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 005ad5f11b69..30fdc2fd8771 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "ci.h" #include "ci_hdrc_imx.h" @@ -28,7 +27,6 @@ struct ci_hdrc_imx_data { struct usb_phy *phy; struct platform_device *ci_pdev; struct clk *clk; - struct regulator *reg_vbus; }; static const struct usbmisc_ops *usbmisc_ops; @@ -131,20 +129,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) goto err_clk; } - /* we only support host now, so enable vbus here */ - data->reg_vbus = devm_regulator_get(&pdev->dev, "vbus"); - if (!IS_ERR(data->reg_vbus)) { - ret = regulator_enable(data->reg_vbus); - if (ret) { - dev_err(&pdev->dev, - "Failed to enable vbus regulator, err=%d\n", - ret); - goto err_clk; - } - } else { - data->reg_vbus = NULL; - } - pdata.phy = data->phy; if (!pdev->dev.dma_mask) @@ -157,7 +141,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); - goto err; + goto err_clk; } } @@ -169,7 +153,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can't register ci_hdrc platform device, err=%d\n", ret); - goto err; + goto err_clk; } if (usbmisc_ops && usbmisc_ops->post) { @@ -190,9 +174,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data->ci_pdev); -err: - if (data->reg_vbus) - regulator_disable(data->reg_vbus); err_clk: clk_disable_unprepare(data->clk); return ret; @@ -205,9 +186,6 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); ci_hdrc_remove_device(data->ci_pdev); - if (data->reg_vbus) - regulator_disable(data->reg_vbus); - if (data->phy) usb_phy_shutdown(data->phy); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 5bb3e8154f87..13dbd511f59a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -65,6 +65,7 @@ #include #include #include +#include #include "ci.h" #include "udc.h" @@ -342,6 +343,24 @@ static irqreturn_t ci_irq(int irq, void *data) return ret; } +static int ci_get_platdata(struct device *dev, + struct ci_hdrc_platform_data *platdata) +{ + /* Get the vbus regulator */ + platdata->reg_vbus = devm_regulator_get(dev, "vbus"); + if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { + platdata->reg_vbus = NULL; /* no vbus regualator is needed */ + } else if (IS_ERR(platdata->reg_vbus)) { + dev_err(dev, "Getting regulator error: %ld\n", + PTR_ERR(platdata->reg_vbus)); + return PTR_ERR(platdata->reg_vbus); + } + + return 0; +} + static DEFINE_IDA(ci_ida); struct platform_device *ci_hdrc_add_device(struct device *dev, @@ -351,6 +370,10 @@ struct platform_device *ci_hdrc_add_device(struct device *dev, struct platform_device *pdev; int id, ret; + ret = ci_get_platdata(dev, platdata); + if (ret) + return ERR_PTR(ret); + id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL); if (id < 0) return ERR_PTR(id); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 25629948c842..ce4e1aa071b3 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -24,6 +24,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 void (*notify_event) (struct ci_hdrc *ci, unsigned event); + struct regulator *reg_vbus; }; /* Default offset of capability registers */ -- cgit v1.2.3 From 577b232fc9caba1b6f7a3bb9901c00b10e0ca1ba Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 14 Aug 2013 12:44:08 +0300 Subject: usb: chipidea: add flag CI_HDRC_DUAL_ROLE_NOT_OTG Since we need otgsc to know vbus's status at some chipidea controllers even it is peripheral-only mode. Besides, some SoCs (eg, AR9331 SoC) don't have otgsc register even the DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS. We inroduce flag CI_HDRC_DUAL_ROLE_NOT_OTG to indicate if the controller is dual role, but not supports OTG. If this flag is not set, we follow the rule that if DCCPARAMS_DC and DCCPARAMS_HC are both 1 at CAP_DCCPARAMS, then this controller is otg capable. Signed-off-by: Peter Chen Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/core.c | 37 ++++++++++++++++++++++++++++++------- include/linux/usb/chipidea.h | 5 +++++ 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 75afc524b659..ab01e18bc2f8 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -426,6 +426,18 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) ci_hdrc_host_destroy(ci); } +static void ci_get_otg_capable(struct ci_hdrc *ci) +{ + if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG) + ci->is_otg = false; + else + ci->is_otg = (hw_read(ci, CAP_DCCPARAMS, + DCCPARAMS_DC | DCCPARAMS_HC) + == (DCCPARAMS_DC | DCCPARAMS_HC)); + if (ci->is_otg) + dev_dbg(ci->dev, "It is OTG capable controller\n"); +} + static int ci_hdrc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -480,6 +492,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } + ci_get_otg_capable(ci); + if (!ci->platdata->phy_mode) ci->platdata->phy_mode = of_usb_get_phy_mode(of_node); @@ -512,10 +526,22 @@ static int ci_hdrc_probe(struct platform_device *pdev) } if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { - ci->is_otg = true; - /* ID pin needs 1ms debouce time, we delay 2ms for safe */ - mdelay(2); - ci->role = ci_otg_role(ci); + if (ci->is_otg) { + /* + * ID pin needs 1ms debouce time, + * we delay 2ms for safe. + */ + mdelay(2); + ci->role = ci_otg_role(ci); + ci_hdrc_otg_init(ci); + } else { + /* + * If the controller is not OTG capable, but support + * role switch, the defalt role is gadget, and the + * user can switch it through debugfs. + */ + ci->role = CI_ROLE_GADGET; + } } else { ci->role = ci->roles[CI_ROLE_HOST] ? CI_ROLE_HOST @@ -534,9 +560,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; - if (ci->is_otg) - ci_hdrc_otg_init(ci); - ret = dbg_create_files(ci); if (!ret) return 0; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ce4e1aa071b3..10a607ce9090 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -20,6 +20,11 @@ struct ci_hdrc_platform_data { #define CI_HDRC_REQUIRE_TRANSCEIVER BIT(1) #define CI_HDRC_PULLUP_ON_VBUS BIT(2) #define CI_HDRC_DISABLE_STREAMING BIT(3) + /* + * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, + * but otg is not supported (no register otgsc). + */ +#define CI_HDRC_DUAL_ROLE_NOT_OTG BIT(4) enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 -- cgit v1.2.3 From d268e9bc23f5df4a2f4167da246d277c2a468d3d Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 14 Aug 2013 12:44:14 +0300 Subject: usb: chipidea: retire flag CI_HDRC_PULLUP_ON_VBUS Currently, the controller only runs when the ci->vbus_active is true. So the flag CI_HDRC_PULLUP_ON_VBUS is useless no longer. If the user doesn't have otgsc, he/she needs to change ci_handle_vbus_change to update ci->vbus_active. Signed-off-by: Peter Chen Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 1 - drivers/usb/chipidea/ci_hdrc_msm.c | 1 - drivers/usb/chipidea/udc.c | 24 ++++++------------------ include/linux/usb/chipidea.h | 1 - 4 files changed, 6 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 30fdc2fd8771..cc53e63c9ce9 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -88,7 +88,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) .name = "ci_hdrc_imx", .capoffset = DEF_CAPOFFSET, .flags = CI_HDRC_REQUIRE_TRANSCEIVER | - CI_HDRC_PULLUP_ON_VBUS | CI_HDRC_DISABLE_STREAMING, }; int ret; diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index fb657ef50a9c..2d51d852b474 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -49,7 +49,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { .name = "ci_hdrc_msm", .flags = CI_HDRC_REGS_SHARED | CI_HDRC_REQUIRE_TRANSCEIVER | - CI_HDRC_PULLUP_ON_VBUS | CI_HDRC_DISABLE_STREAMING, .notify_event = ci_hdrc_msm_notify_event, diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 45abf4d46a71..90c3572bd1b0 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1448,9 +1448,6 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) unsigned long flags; int gadget_ready = 0; - if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS)) - return -EOPNOTSUPP; - spin_lock_irqsave(&ci->lock, flags); ci->vbus_active = is_active; if (ci->driver) @@ -1635,13 +1632,11 @@ static int ci_udc_start(struct usb_gadget *gadget, ci->driver = driver; pm_runtime_get_sync(&ci->gadget.dev); - if (ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) { - if (ci->vbus_active) { - hw_device_reset(ci, USBMODE_CM_DC); - } else { - pm_runtime_put_sync(&ci->gadget.dev); - goto done; - } + if (ci->vbus_active) { + hw_device_reset(ci, USBMODE_CM_DC); + } else { + pm_runtime_put_sync(&ci->gadget.dev); + goto done; } retval = hw_device_state(ci, ci->ep0out->qh.dma); @@ -1664,8 +1659,7 @@ static int ci_udc_stop(struct usb_gadget *gadget, spin_lock_irqsave(&ci->lock, flags); - if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) || - ci->vbus_active) { + if (ci->vbus_active) { hw_device_state(ci, 0); if (ci->platdata->notify_event) ci->platdata->notify_event(ci, @@ -1800,12 +1794,6 @@ static int udc_start(struct ci_hdrc *ci) } } - if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS)) { - retval = hw_device_reset(ci, USBMODE_CM_DC); - if (retval) - goto put_transceiver; - } - if (ci->transceiver) { retval = otg_set_peripheral(ci->transceiver->otg, &ci->gadget); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 10a607ce9090..7d399671a566 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -18,7 +18,6 @@ struct ci_hdrc_platform_data { unsigned long flags; #define CI_HDRC_REGS_SHARED BIT(0) #define CI_HDRC_REQUIRE_TRANSCEIVER BIT(1) -#define CI_HDRC_PULLUP_ON_VBUS BIT(2) #define CI_HDRC_DISABLE_STREAMING BIT(3) /* * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1, -- cgit v1.2.3 From 6d33f7bb8c3863e54f8bdede0a2bf97a3585ac20 Mon Sep 17 00:00:00 2001 From: Thomas Pugliese Date: Thu, 15 Aug 2013 12:21:30 -0500 Subject: USB: WUSBCORE: clear RPIPE stall for control endpoints When the HWA encounters a STALL on a control endpoint, it should clear the RPIPE_STALL feature on the RPIPE before processing the next transfer request. Otherwise, all transfer requests on that endpoint after the first STALL will fail because the RPIPE is still in the halted state. This also removes the unneccessary call to spin_lock_irqsave for a nested lock that was present in the first patch. Signed-off-by: Thomas Pugliese Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/wa-hc.h | 15 +++++++- drivers/usb/wusbcore/wa-rpipe.c | 21 +++++++++++ drivers/usb/wusbcore/wa-xfer.c | 84 ++++++++++++++++++++++++++++++++++++----- include/linux/usb/wusb-wa.h | 1 + 4 files changed, 109 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h index d6bea3e0b54a..cf250c21e946 100644 --- a/drivers/usb/wusbcore/wa-hc.h +++ b/drivers/usb/wusbcore/wa-hc.h @@ -91,6 +91,7 @@ struct wusbhc; struct wahc; extern void wa_urb_enqueue_run(struct work_struct *ws); +extern void wa_process_errored_transfers_run(struct work_struct *ws); /** * RPipe instance @@ -190,8 +191,14 @@ struct wahc { struct list_head xfer_list; struct list_head xfer_delayed_list; + struct list_head xfer_errored_list; + /* + * lock for the above xfer lists. Can be taken while a xfer->lock is + * held but not in the reverse order. + */ spinlock_t xfer_list_lock; - struct work_struct xfer_work; + struct work_struct xfer_enqueue_work; + struct work_struct xfer_error_work; atomic_t xfer_id_count; }; @@ -244,8 +251,10 @@ static inline void wa_init(struct wahc *wa) edc_init(&wa->dti_edc); INIT_LIST_HEAD(&wa->xfer_list); INIT_LIST_HEAD(&wa->xfer_delayed_list); + INIT_LIST_HEAD(&wa->xfer_errored_list); spin_lock_init(&wa->xfer_list_lock); - INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run); + INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run); + INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run); atomic_set(&wa->xfer_id_count, 1); } @@ -269,6 +278,8 @@ static inline void rpipe_put(struct wa_rpipe *rpipe) } extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *); +extern void rpipe_clear_feature_stalled(struct wahc *, + struct usb_host_endpoint *); extern int wa_rpipes_create(struct wahc *); extern void wa_rpipes_destroy(struct wahc *); static inline void rpipe_avail_dec(struct wa_rpipe *rpipe) diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index 9a595c1ed867..fd4f1ce6256a 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -527,3 +527,24 @@ void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep) mutex_unlock(&wa->rpipe_mutex); } EXPORT_SYMBOL_GPL(rpipe_ep_disable); + +/* Clear the stalled status of an RPIPE. */ +void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep) +{ + struct wa_rpipe *rpipe; + + mutex_lock(&wa->rpipe_mutex); + rpipe = ep->hcpriv; + if (rpipe != NULL) { + u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); + + usb_control_msg( + wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), + USB_REQ_CLEAR_FEATURE, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, + RPIPE_STALL, index, NULL, 0, 1000); + } + mutex_unlock(&wa->rpipe_mutex); +} +EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled); + diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index f5c81afc6e96..d74fe1ae16ac 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -1100,7 +1100,7 @@ error_xfer_submit: */ void wa_urb_enqueue_run(struct work_struct *ws) { - struct wahc *wa = container_of(ws, struct wahc, xfer_work); + struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work); struct wa_xfer *xfer, *next; struct urb *urb; LIST_HEAD(tmp_list); @@ -1125,6 +1125,49 @@ void wa_urb_enqueue_run(struct work_struct *ws) } EXPORT_SYMBOL_GPL(wa_urb_enqueue_run); +/* + * Process the errored transfers on the Wire Adapter outside of interrupt. + */ +void wa_process_errored_transfers_run(struct work_struct *ws) +{ + struct wahc *wa = container_of(ws, struct wahc, xfer_error_work); + struct wa_xfer *xfer, *next; + LIST_HEAD(tmp_list); + + pr_info("%s: Run delayed STALL processing.\n", __func__); + + /* Create a copy of the wa->xfer_errored_list while holding the lock */ + spin_lock_irq(&wa->xfer_list_lock); + list_cut_position(&tmp_list, &wa->xfer_errored_list, + wa->xfer_errored_list.prev); + spin_unlock_irq(&wa->xfer_list_lock); + + /* + * run rpipe_clear_feature_stalled from temp list without list lock + * held. + */ + list_for_each_entry_safe(xfer, next, &tmp_list, list_node) { + struct usb_host_endpoint *ep; + unsigned long flags; + struct wa_rpipe *rpipe; + + spin_lock_irqsave(&xfer->lock, flags); + ep = xfer->ep; + rpipe = ep->hcpriv; + spin_unlock_irqrestore(&xfer->lock, flags); + + /* clear RPIPE feature stalled without holding a lock. */ + rpipe_clear_feature_stalled(wa, ep); + + /* complete the xfer. This removes it from the tmp list. */ + wa_xfer_completion(xfer); + + /* check for work. */ + wa_xfer_delayed_run(rpipe); + } +} +EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run); + /* * Submit a transfer to the Wire Adapter in a delayed way * @@ -1180,7 +1223,7 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep, spin_lock_irqsave(&wa->xfer_list_lock, my_flags); list_add_tail(&xfer->list_node, &wa->xfer_delayed_list); spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags); - queue_work(wusbd, &wa->xfer_work); + queue_work(wusbd, &wa->xfer_enqueue_work); } else { wa_urb_enqueue_b(xfer); } @@ -1222,7 +1265,8 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb) xfer = urb->hcpriv; if (xfer == NULL) { - /* NOthing setup yet enqueue will see urb->status != + /* + * Nothing setup yet enqueue will see urb->status != * -EINPROGRESS (by hcd layer) and bail out with * error, no need to do completion */ @@ -1360,7 +1404,7 @@ static int wa_xfer_status_to_errno(u8 status) * * inbound transfers: need to schedule a DTI read * - * FIXME: this functio needs to be broken up in parts + * FIXME: this function needs to be broken up in parts */ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) { @@ -1482,17 +1526,37 @@ error_submit_buf_in: seg->result = result; kfree(wa->buf_in_urb->sg); error_sg_alloc: + __wa_xfer_abort(xfer); error_complete: seg->status = WA_SEG_ERROR; xfer->segs_done++; rpipe_ready = rpipe_avail_inc(rpipe); - __wa_xfer_abort(xfer); done = __wa_xfer_is_done(xfer); - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); + /* + * queue work item to clear STALL for control endpoints. + * Otherwise, let endpoint_reset take care of it. + */ + if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) && + usb_endpoint_xfer_control(&xfer->ep->desc) && + done) { + + dev_info(dev, "Control EP stall. Queue delayed work.\n"); + spin_lock_irq(&wa->xfer_list_lock); + /* remove xfer from xfer_list. */ + list_del(&xfer->list_node); + /* add xfer to xfer_errored_list. */ + list_add_tail(&xfer->list_node, &wa->xfer_errored_list); + spin_unlock_irq(&wa->xfer_list_lock); + spin_unlock_irqrestore(&xfer->lock, flags); + queue_work(wusbd, &wa->xfer_error_work); + } else { + spin_unlock_irqrestore(&xfer->lock, flags); + if (done) + wa_xfer_completion(xfer); + if (rpipe_ready) + wa_xfer_delayed_run(rpipe); + } + return; error_bad_seg: diff --git a/include/linux/usb/wusb-wa.h b/include/linux/usb/wusb-wa.h index 6be985b2a434..4ff744e2b678 100644 --- a/include/linux/usb/wusb-wa.h +++ b/include/linux/usb/wusb-wa.h @@ -66,6 +66,7 @@ enum { WA_ENABLE = 0x01, WA_RESET = 0x02, RPIPE_PAUSE = 0x1, + RPIPE_STALL = 0x2, }; /* Responses from Get Status request ([WUSB] section 8.3.1.6) */ -- cgit v1.2.3 From 8ef2d6511f7eba89ef5fe41cc83008ae63368aa2 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Tue, 27 Aug 2013 17:47:34 +0300 Subject: dev-core: fix build break when DEBUG is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When DEBUG is defined, dev_dbg_ratelimited uses dynamic debug data structures even when CONFIG_DYNAMIC_DEBUG is not defined. It leads to build break. For example, when I try to use dev_dbg_ratelimited in USB code and CONFIG_USB_DEBUG is enabled, but CONFIG_DYNAMIC_DEBUG is not, I get: CC [M] drivers/usb/host/xhci-ring.o drivers/usb/host/xhci-ring.c: In function ‘xhci_queue_intr_tx’: drivers/usb/host/xhci-ring.c:3059:3: error: implicit declaration of function ‘DEFINE_DYNAMIC_DEBUG_METADATA’ [-Werror=implicit-function-declaration] drivers/usb/host/xhci-ring.c:3059:3: error: ‘descriptor’ undeclared (first use in this function) drivers/usb/host/xhci-ring.c:3059:3: note: each undeclared identifier is reported only once for each function it appears in drivers/usb/host/xhci-ring.c:3059:3: error: implicit declaration of function ‘__dynamic_pr_debug’ [-Werror=implicit-function-declaration] drivers/usb/host/xhci-ring.c: In function ‘xhci_queue_isoc_tx_prepare’: drivers/usb/host/xhci-ring.c:3847:3: error: ‘descriptor’ undeclared (first use in this function) cc1: some warnings being treated as errors make[2]: *** [drivers/usb/host/xhci-ring.o] Error 1 make[1]: *** [drivers/usb/host] Error 2 make: *** [drivers/usb/] Error 2 This patch separates definition for CONFIG_DYNAMIC_DEBUG and DEBUG cases. [Note, Sarah moved the comment above the macro to avoid checkpatch warnings.] Signed-off-by: Dmitry Kasatkin Signed-off-by: Sarah Sharp Acked-by: Greg Kroah-Hartman --- include/linux/device.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/device.h b/include/linux/device.h index 22b546a58591..7d960d581e9c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -1099,7 +1099,8 @@ do { \ dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__) #define dev_info_ratelimited(dev, fmt, ...) \ dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__) -#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG) +#if defined(CONFIG_DYNAMIC_DEBUG) +/* descriptor check is first to prevent flooding with "callbacks suppressed" */ #define dev_dbg_ratelimited(dev, fmt, ...) \ do { \ static DEFINE_RATELIMIT_STATE(_rs, \ @@ -1108,8 +1109,17 @@ do { \ DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) && \ __ratelimit(&_rs)) \ - __dynamic_pr_debug(&descriptor, pr_fmt(fmt), \ - ##__VA_ARGS__); \ + __dynamic_dev_dbg(&descriptor, dev, fmt, \ + ##__VA_ARGS__); \ +} while (0) +#elif defined(DEBUG) +#define dev_dbg_ratelimited(dev, fmt, ...) \ +do { \ + static DEFINE_RATELIMIT_STATE(_rs, \ + DEFAULT_RATELIMIT_INTERVAL, \ + DEFAULT_RATELIMIT_BURST); \ + if (__ratelimit(&_rs)) \ + dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \ } while (0) #else #define dev_dbg_ratelimited(dev, fmt, ...) \ -- cgit v1.2.3 From 9d8924297cd9c256c23c02abae40202563452453 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 30 Aug 2013 10:46:00 -0400 Subject: USB: fix build error when CONFIG_PM_SLEEP isn't enabled This patch fixes a build error that occurs when CONFIG_PM is enabled and CONFIG_PM_SLEEP isn't: >> drivers/usb/host/ohci-pci.c:294:10: error: 'usb_hcd_pci_pm_ops' undeclared here (not in a function) .pm = &usb_hcd_pci_pm_ops Since the usb_hcd_pci_pm_ops structure is defined and used when CONFIG_PM is enabled, its declaration should not be protected by CONFIG_PM_SLEEP. Signed-off-by: Alan Stern Reported-by: kbuild test robot CC: Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/hcd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index a9c7d44bd2ed..75efc45eaa2f 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -428,7 +428,7 @@ extern int usb_hcd_pci_probe(struct pci_dev *dev, extern void usb_hcd_pci_remove(struct pci_dev *dev); extern void usb_hcd_pci_shutdown(struct pci_dev *dev); -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM extern const struct dev_pm_ops usb_hcd_pci_pm_ops; #endif #endif /* CONFIG_PCI */ -- cgit v1.2.3