|
|
@@ -0,0 +1,282 @@
|
|
|
+From 25f51b76f90f10f9bf2fbc05fc51cf685da7ccad Mon Sep 17 00:00:00 2001
|
|
|
+From: Ben Hutchings <[email protected]>
|
|
|
+Date: Wed, 31 Jul 2024 22:32:29 +0200
|
|
|
+Subject: [PATCH] xhci-pci: Make xhci-pci-renesas a proper modular driver
|
|
|
+
|
|
|
+If CONFIG_USB_XHCI_PCI_RENESAS is enabled, xhci-pci conditionally
|
|
|
+calls into the xhci-pci-renesas module, which means both modules must
|
|
|
+be loaded to use any xHCI PCI controller.
|
|
|
+
|
|
|
+The MODULE_FIRMWARE declaration in the base xhci-pci module causes
|
|
|
+initramfs-tools to check for and warn about missing firmware for the
|
|
|
+Renesas xHCI controllers, when any xHCI PCI controller is present.
|
|
|
+And because of the previous oddity, simply moving this declaration to
|
|
|
+xhci-pci-renesas wouldn't help.
|
|
|
+
|
|
|
+To fix this, reverse the relationship between the modules:
|
|
|
+
|
|
|
+- Remove the quirk for the Renesas xHCIs, and the driver_data
|
|
|
+ structure used only for them
|
|
|
+- In xhci-pci:
|
|
|
+ - Rename xhci_pci_probe() to xhci_pci_common_probe()
|
|
|
+ - Export xhci_pci_common_probe() and xhci_pci_remove()
|
|
|
+ - Use a new probe function that rejects the Renesas xHCIs and then
|
|
|
+ calls the common probe function
|
|
|
+- In xhci-pci-renesas:
|
|
|
+ - Stop exporting renesas_xhci_check_request_fw()
|
|
|
+ - Add a probe function that calls renesas_xhci_check_request_fw()
|
|
|
+ followed by xhci_pci_common_probe()
|
|
|
+ - Add and register a new pci_driver matching only the Renesas xHCIs
|
|
|
+ and using its own probe function, but with other operations the
|
|
|
+ same as in xhci-pci
|
|
|
+- Make CONFIG_USB_XHCI_PCI_RENESAS depend on CONFIG_USB_XHCI_PCI,
|
|
|
+ not the other way around
|
|
|
+
|
|
|
+Finally, move the MODULE_FIRMWARE declaration to xhci-pci-renesas.
|
|
|
+
|
|
|
+Signed-off-by: Ben Hutchings <[email protected]>
|
|
|
+Tested-by: Cyril Brulebois <[email protected]>
|
|
|
+Link: https://lore.kernel.org/r/[email protected]
|
|
|
+Signed-off-by: Greg Kroah-Hartman <[email protected]>
|
|
|
+---
|
|
|
+ drivers/usb/host/Kconfig | 2 +-
|
|
|
+ drivers/usb/host/xhci-pci-renesas.c | 48 ++++++++++++++++++++----
|
|
|
+ drivers/usb/host/xhci-pci.c | 57 ++++++++++-------------------
|
|
|
+ drivers/usb/host/xhci-pci.h | 19 +---------
|
|
|
+ drivers/usb/host/xhci.h | 2 +-
|
|
|
+ 5 files changed, 64 insertions(+), 64 deletions(-)
|
|
|
+
|
|
|
+--- a/drivers/usb/host/Kconfig
|
|
|
++++ b/drivers/usb/host/Kconfig
|
|
|
+@@ -40,11 +40,11 @@ config USB_XHCI_DBGCAP
|
|
|
+ config USB_XHCI_PCI
|
|
|
+ tristate
|
|
|
+ depends on USB_PCI
|
|
|
+- depends on USB_XHCI_PCI_RENESAS || !USB_XHCI_PCI_RENESAS
|
|
|
+ default y
|
|
|
+
|
|
|
+ config USB_XHCI_PCI_RENESAS
|
|
|
+ tristate "Support for additional Renesas xHCI controller with firmware"
|
|
|
++ depends on USB_XHCI_PCI
|
|
|
+ help
|
|
|
+ Say 'Y' to enable the support for the Renesas xHCI controller with
|
|
|
+ firmware. Make sure you have the firmware for the device and
|
|
|
+--- a/drivers/usb/host/xhci-pci-renesas.c
|
|
|
++++ b/drivers/usb/host/xhci-pci-renesas.c
|
|
|
+@@ -50,6 +50,8 @@
|
|
|
+ #define RENESAS_RETRY 10000
|
|
|
+ #define RENESAS_DELAY 10
|
|
|
+
|
|
|
++#define RENESAS_FW_NAME "renesas_usb_fw.mem"
|
|
|
++
|
|
|
+ static int renesas_fw_download_image(struct pci_dev *dev,
|
|
|
+ const u32 *fw, size_t step, bool rom)
|
|
|
+ {
|
|
|
+@@ -573,12 +575,10 @@ exit:
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+-int renesas_xhci_check_request_fw(struct pci_dev *pdev,
|
|
|
+- const struct pci_device_id *id)
|
|
|
++static int renesas_xhci_check_request_fw(struct pci_dev *pdev,
|
|
|
++ const struct pci_device_id *id)
|
|
|
+ {
|
|
|
+- struct xhci_driver_data *driver_data =
|
|
|
+- (struct xhci_driver_data *)id->driver_data;
|
|
|
+- const char *fw_name = driver_data->firmware;
|
|
|
++ const char fw_name[] = RENESAS_FW_NAME;
|
|
|
+ const struct firmware *fw;
|
|
|
+ bool has_rom;
|
|
|
+ int err;
|
|
|
+@@ -625,7 +625,41 @@ exit:
|
|
|
+ release_firmware(fw);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+-EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw);
|
|
|
+
|
|
|
+-MODULE_DESCRIPTION("Support for Renesas xHCI controller with firmware");
|
|
|
++static int
|
|
|
++xhci_pci_renesas_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|
|
++{
|
|
|
++ int retval;
|
|
|
++
|
|
|
++ retval = renesas_xhci_check_request_fw(dev, id);
|
|
|
++ if (retval)
|
|
|
++ return retval;
|
|
|
++
|
|
|
++ return xhci_pci_common_probe(dev, id);
|
|
|
++}
|
|
|
++
|
|
|
++static const struct pci_device_id pci_ids[] = {
|
|
|
++ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014) },
|
|
|
++ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015) },
|
|
|
++ { /* end: all zeroes */ }
|
|
|
++};
|
|
|
++MODULE_DEVICE_TABLE(pci, pci_ids);
|
|
|
++
|
|
|
++static struct pci_driver xhci_renesas_pci_driver = {
|
|
|
++ .name = "xhci-pci-renesas",
|
|
|
++ .id_table = pci_ids,
|
|
|
++
|
|
|
++ .probe = xhci_pci_renesas_probe,
|
|
|
++ .remove = xhci_pci_remove,
|
|
|
++
|
|
|
++ .shutdown = usb_hcd_pci_shutdown,
|
|
|
++ .driver = {
|
|
|
++ .pm = pm_ptr(&usb_hcd_pci_pm_ops),
|
|
|
++ },
|
|
|
++};
|
|
|
++module_pci_driver(xhci_renesas_pci_driver);
|
|
|
++
|
|
|
++MODULE_DESCRIPTION("Renesas xHCI PCI Host Controller Driver");
|
|
|
++MODULE_FIRMWARE(RENESAS_FW_NAME);
|
|
|
++MODULE_IMPORT_NS(xhci);
|
|
|
+ MODULE_LICENSE("GPL v2");
|
|
|
+--- a/drivers/usb/host/xhci-pci.c
|
|
|
++++ b/drivers/usb/host/xhci-pci.c
|
|
|
+@@ -300,15 +300,6 @@ static int xhci_pci_reinit(struct xhci_h
|
|
|
+ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|
|
+ {
|
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
|
+- struct xhci_driver_data *driver_data;
|
|
|
+- const struct pci_device_id *id;
|
|
|
+-
|
|
|
+- id = pci_match_id(to_pci_driver(pdev->dev.driver)->id_table, pdev);
|
|
|
+-
|
|
|
+- if (id && id->driver_data) {
|
|
|
+- driver_data = (struct xhci_driver_data *)id->driver_data;
|
|
|
+- xhci->quirks |= driver_data->quirks;
|
|
|
+- }
|
|
|
+
|
|
|
+ /* Look for vendor-specific quirks */
|
|
|
+ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
|
|
|
+@@ -643,21 +634,13 @@ static int xhci_pci_update_hub_device(st
|
|
|
+ * 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.
|
|
|
+ */
|
|
|
+-static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|
|
++int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|
|
+ {
|
|
|
+ int retval;
|
|
|
+ struct xhci_hcd *xhci;
|
|
|
+ struct usb_hcd *hcd;
|
|
|
+- struct xhci_driver_data *driver_data;
|
|
|
+ struct reset_control *reset;
|
|
|
+
|
|
|
+- driver_data = (struct xhci_driver_data *)id->driver_data;
|
|
|
+- if (driver_data && driver_data->quirks & XHCI_RENESAS_FW_QUIRK) {
|
|
|
+- retval = renesas_xhci_check_request_fw(dev, id);
|
|
|
+- if (retval)
|
|
|
+- return retval;
|
|
|
+- }
|
|
|
+-
|
|
|
+ reset = devm_reset_control_get_optional_exclusive(&dev->dev, NULL);
|
|
|
+ if (IS_ERR(reset))
|
|
|
+ return PTR_ERR(reset);
|
|
|
+@@ -722,8 +705,24 @@ put_runtime_pm:
|
|
|
+ pm_runtime_put_noidle(&dev->dev);
|
|
|
+ return retval;
|
|
|
+ }
|
|
|
++EXPORT_SYMBOL_NS_GPL(xhci_pci_common_probe, xhci);
|
|
|
++
|
|
|
++static const struct pci_device_id pci_ids_reject[] = {
|
|
|
++ /* handled by xhci-pci-renesas */
|
|
|
++ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014) },
|
|
|
++ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015) },
|
|
|
++ { /* end: all zeroes */ }
|
|
|
++};
|
|
|
++
|
|
|
++static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|
|
++{
|
|
|
++ if (pci_match_id(pci_ids_reject, dev))
|
|
|
++ return -ENODEV;
|
|
|
++
|
|
|
++ return xhci_pci_common_probe(dev, id);
|
|
|
++}
|
|
|
+
|
|
|
+-static void xhci_pci_remove(struct pci_dev *dev)
|
|
|
++void xhci_pci_remove(struct pci_dev *dev)
|
|
|
+ {
|
|
|
+ struct xhci_hcd *xhci;
|
|
|
+ bool set_power_d3;
|
|
|
+@@ -750,6 +749,7 @@ static void xhci_pci_remove(struct pci_d
|
|
|
+ if (set_power_d3)
|
|
|
+ pci_set_power_state(dev, PCI_D3hot);
|
|
|
+ }
|
|
|
++EXPORT_SYMBOL_NS_GPL(xhci_pci_remove, xhci);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In some Intel xHCI controllers, in order to get D3 working,
|
|
|
+@@ -959,19 +959,8 @@ static void xhci_pci_shutdown(struct usb
|
|
|
+
|
|
|
+ /*-------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+-static const struct xhci_driver_data reneses_data = {
|
|
|
+- .quirks = XHCI_RENESAS_FW_QUIRK,
|
|
|
+- .firmware = "renesas_usb_fw.mem",
|
|
|
+-};
|
|
|
+-
|
|
|
+ /* PCI driver selection metadata; PCI hotplugging uses this */
|
|
|
+ static const struct pci_device_id pci_ids[] = {
|
|
|
+- { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014),
|
|
|
+- .driver_data = (unsigned long)&reneses_data,
|
|
|
+- },
|
|
|
+- { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015),
|
|
|
+- .driver_data = (unsigned long)&reneses_data,
|
|
|
+- },
|
|
|
+ /* handle any USB 3.0 xHCI controller */
|
|
|
+ { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
|
|
|
+ },
|
|
|
+@@ -979,14 +968,6 @@ static const struct pci_device_id pci_id
|
|
|
+ };
|
|
|
+ MODULE_DEVICE_TABLE(pci, pci_ids);
|
|
|
+
|
|
|
+-/*
|
|
|
+- * Without CONFIG_USB_XHCI_PCI_RENESAS renesas_xhci_check_request_fw() won't
|
|
|
+- * load firmware, so don't encumber the xhci-pci driver with it.
|
|
|
+- */
|
|
|
+-#if IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS)
|
|
|
+-MODULE_FIRMWARE("renesas_usb_fw.mem");
|
|
|
+-#endif
|
|
|
+-
|
|
|
+ /* pci driver glue; this is a "new style" PCI driver module */
|
|
|
+ static struct pci_driver xhci_pci_driver = {
|
|
|
+ .name = hcd_name,
|
|
|
+--- a/drivers/usb/host/xhci-pci.h
|
|
|
++++ b/drivers/usb/host/xhci-pci.h
|
|
|
+@@ -4,22 +4,7 @@
|
|
|
+ #ifndef XHCI_PCI_H
|
|
|
+ #define XHCI_PCI_H
|
|
|
+
|
|
|
+-#if IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS)
|
|
|
+-int renesas_xhci_check_request_fw(struct pci_dev *dev,
|
|
|
+- const struct pci_device_id *id);
|
|
|
+-
|
|
|
+-#else
|
|
|
+-static int renesas_xhci_check_request_fw(struct pci_dev *dev,
|
|
|
+- const struct pci_device_id *id)
|
|
|
+-{
|
|
|
+- return 0;
|
|
|
+-}
|
|
|
+-
|
|
|
+-#endif
|
|
|
+-
|
|
|
+-struct xhci_driver_data {
|
|
|
+- u64 quirks;
|
|
|
+- const char *firmware;
|
|
|
+-};
|
|
|
++int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id);
|
|
|
++void xhci_pci_remove(struct pci_dev *dev);
|
|
|
+
|
|
|
+ #endif
|
|
|
+--- a/drivers/usb/host/xhci.h
|
|
|
++++ b/drivers/usb/host/xhci.h
|
|
|
+@@ -1648,7 +1648,7 @@ struct xhci_hcd {
|
|
|
+ #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33)
|
|
|
+ #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
|
|
|
+ #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
|
|
|
+-#define XHCI_RENESAS_FW_QUIRK BIT_ULL(36)
|
|
|
++/* Reserved. It was XHCI_RENESAS_FW_QUIRK */
|
|
|
+ #define XHCI_SKIP_PHY_INIT BIT_ULL(37)
|
|
|
+ #define XHCI_DISABLE_SPARSE BIT_ULL(38)
|
|
|
+ #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39)
|