diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b649fef2e35d4a..755bfe32f395f8 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2131,8 +2131,14 @@ void usb_disconnect(struct usb_device **pdev) * this quiesces everything except pending urbs. */ usb_set_device_state(udev, USB_STATE_NOTATTACHED); - dev_info(&udev->dev, "USB disconnect, device number %d\n", - udev->devnum); + dev_info(&udev->dev, "USB disconnect, device number %d running at %s\n", + udev->devnum, usb_speed_string(udev->speed)); + + if (udev->speed < USB_SPEED_HIGH ) { + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + if (hcd->driver->change_bus_speed) + hcd->driver->change_bus_speed(hcd, 0); + } usb_lock_device(udev); @@ -4621,6 +4627,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_device *udev = port_dev->child; static int unreliable_port = -1; + unsigned long speed = USB_SPEED_SUPER; /* Disconnect any existing devices under this port */ if (udev) { @@ -4704,6 +4711,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, /* reset (non-USB 3.0 devices) and get descriptor */ usb_lock_port(port_dev); status = hub_port_init(hub, udev, port1, i); + speed = udev->speed; usb_unlock_port(port_dev); if (status < 0) goto loop; @@ -4808,9 +4816,18 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, if (hub->hdev->parent || !hcd->driver->port_handed_over || !(hcd->driver->port_handed_over)(hcd, port1)) { - if (status != -ENOTCONN && status != -ENODEV) - dev_err(&port_dev->dev, - "unable to enumerate USB device\n"); + if (status != -ENOTCONN && status != -ENODEV) { + dev_err(&port_dev->dev, "unable to enumerate USB device" + " at %s while bus at %s \n", + usb_speed_string(speed), + hdev->descriptor.bDeviceProtocol == USB_HUB_PR_FS ? + "FULL_SPEED" : "HIGH_SPEED"); + + if (speed < USB_SPEED_HIGH && + hdev->descriptor.bDeviceProtocol > USB_HUB_PR_FS && + hcd->driver->change_bus_speed) + hcd->driver->change_bus_speed(hcd, 1); + } } done: diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index af8ab9506a1623..82f617800f6a06 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -54,6 +54,19 @@ #include "core.h" #include "hcd.h" +struct wrapper_priv_data { + struct dwc2_hsotg *hsotg; +}; + +/* Gets the dwc2_hsotg from a usb_hcd */ +static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd) +{ + struct wrapper_priv_data *p; + + p = (struct wrapper_priv_data *) &hcd->hcd_priv; + return p->hsotg; +} + /** * dwc2_dump_channel_info() - Prints the state of a host channel * @@ -1339,6 +1352,23 @@ void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, } } } +/* + * 0: high speed + * 1: full speed + */ +static void dwc2_change_bus_speed(struct usb_hcd* hcd, int speed) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + static int last_speed = 0; + + if (speed == last_speed) + return; + + hsotg->core_params->speed = speed; + queue_work(hsotg->wq_otg, &hsotg->wf_otg); + + last_speed = speed; +} static void dwc2_conn_id_status_change(struct work_struct *work) { @@ -2064,18 +2094,6 @@ void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg) #endif } -struct wrapper_priv_data { - struct dwc2_hsotg *hsotg; -}; - -/* Gets the dwc2_hsotg from a usb_hcd */ -static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd) -{ - struct wrapper_priv_data *p; - - p = (struct wrapper_priv_data *) &hcd->hcd_priv; - return p->hsotg; -} static int _dwc2_hcd_start(struct usb_hcd *hcd); @@ -2676,6 +2694,7 @@ static struct hc_driver dwc2_hc_driver = { .hub_status_data = _dwc2_hcd_hub_status_data, .hub_control = _dwc2_hcd_hub_control, .clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete, + .change_bus_speed = dwc2_change_bus_speed, }; /* diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 61ccb537034593..8fef5b793bd64a 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -55,8 +55,8 @@ static const struct dwc2_core_params params_hisi = { .otg_ver = 0, /* 1.3 */ .dma_enable = 1, .dma_desc_enable = 0, -// .speed = 0, /* High Speed */ - .speed = 1, /* Full Speed */ + .speed = 0, /* High Speed */ +// .speed = 1, /* Full Speed */ .enable_dynamic_fifo = 1, .en_multiple_tx_fifo = 1, .host_rx_fifo_size = 512, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index cd96a2bc338897..2f8c9b71005085 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -379,6 +379,7 @@ struct hc_driver { int (*disable_usb3_lpm_timeout)(struct usb_hcd *, struct usb_device *, enum usb3_link_state state); int (*find_raw_port_number)(struct usb_hcd *, int); + void (*change_bus_speed)(struct usb_hcd*, int); }; static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)