Commit 23a3b8d5 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman
Browse files

xhci: Add update_hub_device override for PCI xHCI hosts



Allow PCI hosts to check and tune roothub and port settings
before the hub is up and running.

This override is needed to turn off U1 and U2 LPM for some ports
based on per port ACPI _DSM, _UPC, or possibly vendor specific mmio
values for Intel xHC hosts.

Usb core calls the host update_hub_device once it creates a hub.

Entering U1 or U2 link power save state on ports with this limitation
will cause link to fail, turning the usb device unusable in that setup.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20230116142216.1141605-5-mathias.nyman@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a2bc47c4
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -78,9 +78,12 @@ static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver;

static int xhci_pci_setup(struct usb_hcd *hcd);
static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
				      struct usb_tt *tt, gfp_t mem_flags);

static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {
	.reset = xhci_pci_setup,
	.update_hub_device = xhci_pci_update_hub_device,
};

/* called after powerup, by probe or system-pm "wakeup" */
@@ -386,6 +389,12 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
	return xhci_pci_reinit(xhci, pdev);
}

static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
				      struct usb_tt *tt, gfp_t mem_flags)
{
	return xhci_update_hub_device(hcd, hdev, tt, mem_flags);
}

/*
 * We need to register our own PCI probe function (instead of the USB core's
 * function) in order to create a second roothub under xHCI.
+4 −1
Original line number Diff line number Diff line
@@ -5124,7 +5124,7 @@ static int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
/* Once a hub descriptor is fetched for a device, we need to update the xHC's
 * internal data structures for the device.
 */
static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
			struct usb_tt *tt, gfp_t mem_flags)
{
	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -5224,6 +5224,7 @@ static int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
	xhci_free_command(xhci, config_cmd);
	return ret;
}
EXPORT_SYMBOL_GPL(xhci_update_hub_device);

static int xhci_get_frame(struct usb_hcd *hcd)
{
@@ -5507,6 +5508,8 @@ void xhci_init_driver(struct hc_driver *drv,
			drv->check_bandwidth = over->check_bandwidth;
		if (over->reset_bandwidth)
			drv->reset_bandwidth = over->reset_bandwidth;
		if (over->update_hub_device)
			drv->update_hub_device = over->update_hub_device;
	}
}
EXPORT_SYMBOL_GPL(xhci_init_driver);
+4 −0
Original line number Diff line number Diff line
@@ -1943,6 +1943,8 @@ struct xhci_driver_overrides {
			     struct usb_host_endpoint *ep);
	int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
	void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
	int (*update_hub_device)(struct usb_hcd *hcd, struct usb_device *hdev,
			    struct usb_tt *tt, gfp_t mem_flags);
};

#define	XHCI_CFC_DELAY		10
@@ -2122,6 +2124,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
		       struct usb_host_endpoint *ep);
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
			   struct usb_tt *tt, gfp_t mem_flags);
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
int xhci_ext_cap_init(struct xhci_hcd *xhci);