Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf6e5d3c 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



commit 23a3b8d5a2365653fd9bc5a9454d1e7f4facbf85 upstream.

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 133b9023
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -79,9 +79,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" */
@@ -370,6 +373,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
@@ -5071,7 +5071,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);
@@ -5171,6 +5171,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)
{
@@ -5440,6 +5441,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
@@ -1922,6 +1922,8 @@ struct xhci_driver_overrides {
	int (*start)(struct usb_hcd *hcd);
	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
@@ -2076,6 +2078,8 @@ void xhci_init_driver(struct hc_driver *drv,
		      const struct xhci_driver_overrides *over);
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);