mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	USB fixes for 5.2-rc6
Here are 4 small USB fixes for 5.2-rc6. They include 2 xhci bugfixes, a chipidea fix, and a small dwc2 fix. Nothing major, just nice things to get resolved for reported issues. All have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXQyIYw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymYqACZAUq5QM3+CZ6FcGMcTJObGkyVF0IAnjWjkEuc U9nYe1q1wWVTmfqUVWM0 =aMsk -----END PGP SIGNATURE----- Merge tag 'usb-5.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are four small USB fixes for 5.2-rc6. They include two xhci bugfixes, a chipidea fix, and a small dwc2 fix. Nothing major, just nice things to get resolved for reported issues. All have been in linux-next with no reported issues" * tag 'usb-5.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: xhci: detect USB 3.2 capable host controllers correctly usb: xhci: Don't try to recover an endpoint if port is in error state. usb: dwc2: Use generic PHY width in params setup usb: chipidea: udc: workaround for endpoint conflict issue
This commit is contained in:
		
						commit
						cf24242189
					
				
					 6 changed files with 72 additions and 15 deletions
				
			
		| 
						 | 
					@ -1622,6 +1622,25 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
 | 
				
			||||||
static int ci_udc_start(struct usb_gadget *gadget,
 | 
					static int ci_udc_start(struct usb_gadget *gadget,
 | 
				
			||||||
			 struct usb_gadget_driver *driver);
 | 
								 struct usb_gadget_driver *driver);
 | 
				
			||||||
static int ci_udc_stop(struct usb_gadget *gadget);
 | 
					static int ci_udc_stop(struct usb_gadget *gadget);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Match ISOC IN from the highest endpoint */
 | 
				
			||||||
 | 
					static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget,
 | 
				
			||||||
 | 
								      struct usb_endpoint_descriptor *desc,
 | 
				
			||||||
 | 
								      struct usb_ss_ep_comp_descriptor *comp_desc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
 | 
				
			||||||
 | 
						struct usb_ep *ep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (usb_endpoint_xfer_isoc(desc) && usb_endpoint_dir_in(desc)) {
 | 
				
			||||||
 | 
							list_for_each_entry_reverse(ep, &ci->gadget.ep_list, ep_list) {
 | 
				
			||||||
 | 
								if (ep->caps.dir_in && !ep->claimed)
 | 
				
			||||||
 | 
									return ep;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Device operations part of the API to the USB controller hardware,
 | 
					 * Device operations part of the API to the USB controller hardware,
 | 
				
			||||||
 * which don't involve endpoints (or i/o)
 | 
					 * which don't involve endpoints (or i/o)
 | 
				
			||||||
| 
						 | 
					@ -1635,6 +1654,7 @@ static const struct usb_gadget_ops usb_gadget_ops = {
 | 
				
			||||||
	.vbus_draw	= ci_udc_vbus_draw,
 | 
						.vbus_draw	= ci_udc_vbus_draw,
 | 
				
			||||||
	.udc_start	= ci_udc_start,
 | 
						.udc_start	= ci_udc_start,
 | 
				
			||||||
	.udc_stop	= ci_udc_stop,
 | 
						.udc_stop	= ci_udc_stop,
 | 
				
			||||||
 | 
						.match_ep 	= ci_udc_match_ep,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int init_eps(struct ci_hdrc *ci)
 | 
					static int init_eps(struct ci_hdrc *ci)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,6 +253,15 @@ static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg)
 | 
				
			||||||
	val = (hsotg->hw_params.utmi_phy_data_width ==
 | 
						val = (hsotg->hw_params.utmi_phy_data_width ==
 | 
				
			||||||
	       GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
 | 
						       GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hsotg->phy) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If using the generic PHY framework, check if the PHY bus
 | 
				
			||||||
 | 
							 * width is 8-bit and set the phyif appropriately.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (phy_get_bus_width(hsotg->phy) == 8)
 | 
				
			||||||
 | 
								val = 8;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hsotg->params.phy_utmi_width = val;
 | 
						hsotg->params.phy_utmi_width = val;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -271,15 +271,6 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hsotg->plat = dev_get_platdata(hsotg->dev);
 | 
						hsotg->plat = dev_get_platdata(hsotg->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hsotg->phy) {
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * If using the generic PHY framework, check if the PHY bus
 | 
					 | 
				
			||||||
		 * width is 8-bit and set the phyif appropriately.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (phy_get_bus_width(hsotg->phy) == 8)
 | 
					 | 
				
			||||||
			hsotg->params.phy_utmi_width = 8;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Clock */
 | 
						/* Clock */
 | 
				
			||||||
	hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg");
 | 
						hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg");
 | 
				
			||||||
	if (IS_ERR(hsotg->clk)) {
 | 
						if (IS_ERR(hsotg->clk)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1612,8 +1612,13 @@ static void handle_port_status(struct xhci_hcd *xhci,
 | 
				
			||||||
		usb_hcd_resume_root_hub(hcd);
 | 
							usb_hcd_resume_root_hub(hcd);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE)
 | 
						if (hcd->speed >= HCD_USB3 &&
 | 
				
			||||||
 | 
						    (portsc & PORT_PLS_MASK) == XDEV_INACTIVE) {
 | 
				
			||||||
 | 
							slot_id = xhci_find_slot_id_by_port(hcd, xhci, hcd_portnum + 1);
 | 
				
			||||||
 | 
							if (slot_id && xhci->devs[slot_id])
 | 
				
			||||||
 | 
								xhci->devs[slot_id]->flags |= VDEV_PORT_ERROR;
 | 
				
			||||||
		bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
 | 
							bus_state->port_remote_wakeup &= ~(1 << hcd_portnum);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
 | 
						if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {
 | 
				
			||||||
		xhci_dbg(xhci, "port resume event for port %d\n", port_id);
 | 
							xhci_dbg(xhci, "port resume event for port %d\n", port_id);
 | 
				
			||||||
| 
						 | 
					@ -1801,6 +1806,14 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
 | 
						struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
 | 
				
			||||||
	struct xhci_command *command;
 | 
						struct xhci_command *command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Avoid resetting endpoint if link is inactive. Can cause host hang.
 | 
				
			||||||
 | 
						 * Device will be reset soon to recover the link so don't do anything
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
 | 
						command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
 | 
				
			||||||
	if (!command)
 | 
						if (!command)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1466,6 +1466,10 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
 | 
				
			||||||
			xhci_dbg(xhci, "urb submitted during PCI suspend\n");
 | 
								xhci_dbg(xhci, "urb submitted during PCI suspend\n");
 | 
				
			||||||
		return -ESHUTDOWN;
 | 
							return -ESHUTDOWN;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
 | 
				
			||||||
 | 
							xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (usb_endpoint_xfer_isoc(&urb->ep->desc))
 | 
						if (usb_endpoint_xfer_isoc(&urb->ep->desc))
 | 
				
			||||||
		num_tds = urb->number_of_packets;
 | 
							num_tds = urb->number_of_packets;
 | 
				
			||||||
| 
						 | 
					@ -3754,6 +3758,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* If necessary, update the number of active TTs on this root port */
 | 
						/* If necessary, update the number of active TTs on this root port */
 | 
				
			||||||
	xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
 | 
						xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps);
 | 
				
			||||||
 | 
						virt_dev->flags = 0;
 | 
				
			||||||
	ret = 0;
 | 
						ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
command_cleanup:
 | 
					command_cleanup:
 | 
				
			||||||
| 
						 | 
					@ -5060,16 +5065,26 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol
 | 
							 * Some 3.1 hosts return sbrn 0x30, use xhci supported protocol
 | 
				
			||||||
		 * minor revision instead of sbrn
 | 
							 * minor revision instead of sbrn. Minor revision is a two digit
 | 
				
			||||||
 | 
							 * BCD containing minor and sub-minor numbers, only show minor.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		minor_rev = xhci->usb3_rhub.min_rev;
 | 
							minor_rev = xhci->usb3_rhub.min_rev / 0x10;
 | 
				
			||||||
		if (minor_rev) {
 | 
					
 | 
				
			||||||
 | 
							switch (minor_rev) {
 | 
				
			||||||
 | 
							case 2:
 | 
				
			||||||
 | 
								hcd->speed = HCD_USB32;
 | 
				
			||||||
 | 
								hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
 | 
				
			||||||
 | 
								hcd->self.root_hub->rx_lanes = 2;
 | 
				
			||||||
 | 
								hcd->self.root_hub->tx_lanes = 2;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 1:
 | 
				
			||||||
			hcd->speed = HCD_USB31;
 | 
								hcd->speed = HCD_USB31;
 | 
				
			||||||
			hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
 | 
								hcd->self.root_hub->speed = USB_SPEED_SUPER_PLUS;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		xhci_info(xhci, "Host supports USB 3.%x %s SuperSpeed\n",
 | 
							xhci_info(xhci, "Host supports USB 3.%x %sSuperSpeed\n",
 | 
				
			||||||
			  minor_rev,
 | 
								  minor_rev,
 | 
				
			||||||
			  minor_rev ? "Enhanced" : "");
 | 
								  minor_rev ? "Enhanced " : "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		xhci->usb3_rhub.hcd = hcd;
 | 
							xhci->usb3_rhub.hcd = hcd;
 | 
				
			||||||
		/* xHCI private pointer was set in xhci_pci_probe for the second
 | 
							/* xHCI private pointer was set in xhci_pci_probe for the second
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1010,6 +1010,15 @@ struct xhci_virt_device {
 | 
				
			||||||
	u8				real_port;
 | 
						u8				real_port;
 | 
				
			||||||
	struct xhci_interval_bw_table	*bw_table;
 | 
						struct xhci_interval_bw_table	*bw_table;
 | 
				
			||||||
	struct xhci_tt_bw_info		*tt_info;
 | 
						struct xhci_tt_bw_info		*tt_info;
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * flags for state tracking based on events and issued commands.
 | 
				
			||||||
 | 
						 * Software can not rely on states from output contexts because of
 | 
				
			||||||
 | 
						 * latency between events and xHC updating output context values.
 | 
				
			||||||
 | 
						 * See xhci 1.1 section 4.8.3 for more details
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						unsigned long			flags;
 | 
				
			||||||
 | 
					#define VDEV_PORT_ERROR			BIT(0) /* Port error, link inactive */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The current max exit latency for the enabled USB3 link states. */
 | 
						/* The current max exit latency for the enabled USB3 link states. */
 | 
				
			||||||
	u16				current_mel;
 | 
						u16				current_mel;
 | 
				
			||||||
	/* Used for the debugfs interfaces. */
 | 
						/* Used for the debugfs interfaces. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue