From: Jihong Min Date: Tue, 19 May 2026 00:07:31 +0000 (+0900) Subject: usb: xhci-pci: add AMD Promontory 21 PCI glue X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e896b4a48c4e815956d28961448041c80ad5a19;p=thirdparty%2Fkernel%2Fstable.git usb: xhci-pci: add AMD Promontory 21 PCI glue AMD Promontory 21 (PROM21) xHCI PCI functions use the common xhci-pci core for USB operation, but also expose controller-specific sensor data. Add a small PROM21 PCI glue driver for AMD 1022:43fc and 1022:43fd controllers. The glue delegates USB host operation to the common xhci-pci core and publishes a "hwmon" auxiliary device with parent-provided MMIO data. Auxiliary device creation failure is logged but does not fail the xHCI probe. Make the PROM21 glue a hidden Kconfig tristate driven by the user-visible SENSORS_PROM21_XHCI option. If sensor support is disabled, generic xhci-pci binds PROM21 controllers normally. If sensor support is enabled, the glue follows USB_XHCI_PCI. This keeps the auxiliary device available for a modular sensor driver while avoiding a built-in xhci-pci core handing PROM21 controllers to a glue driver that is only available as a module during initramfs. Assisted-by: Codex:gpt-5.5 Signed-off-by: Jihong Min Reviewed-by: Mario Limonciello (AMD) Tested-by: Yaroslav Isakov Acked-by: Guenter Roeck Link: https://patch.msgid.link/20260519000732.2334711-2-hurryman2212@gmail.com Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0a277a07cf70..43f30cd867e4 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -42,6 +42,12 @@ config USB_XHCI_PCI depends on USB_PCI default y +config USB_XHCI_PCI_PROM21 + tristate + depends on USB_XHCI_PCI + default USB_XHCI_PCI if SENSORS_PROM21_XHCI != n + select AUXILIARY_BUS + config USB_XHCI_PCI_RENESAS tristate "Support for additional Renesas xHCI controller with firmware" depends on USB_XHCI_PCI diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index a07e7ba9cd53..174580c1281a 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o +obj-$(CONFIG_USB_XHCI_PCI_PROM21) += xhci-pci-prom21.o obj-$(CONFIG_USB_XHCI_PCI_RENESAS) += xhci-pci-renesas.o obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o diff --git a/drivers/usb/host/xhci-pci-prom21.c b/drivers/usb/host/xhci-pci-prom21.c new file mode 100644 index 000000000000..6486f4a09345 --- /dev/null +++ b/drivers/usb/host/xhci-pci-prom21.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Promontory 21 xHCI host controller PCI Bus Glue. + * + * This does not add any PROM21-specific USB or xHCI operation. It exists only + * to publish an auxiliary device for integrated temperature sensor support. + * + * Copyright (C) 2026 Jihong Min + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xhci-pci.h" + +struct prom21_xhci_auxdev { + struct auxiliary_device *auxdev; + struct prom21_xhci_pdata pdata; + int id; +}; + +static DEFINE_IDA(prom21_xhci_auxdev_ida); + +static void prom21_xhci_auxdev_release(struct device *dev, void *res) +{ + struct prom21_xhci_auxdev *prom21_auxdev = res; + + auxiliary_device_destroy(prom21_auxdev->auxdev); + ida_free(&prom21_xhci_auxdev_ida, prom21_auxdev->id); +} + +static int prom21_xhci_create_auxdev(struct pci_dev *pdev) +{ + struct prom21_xhci_auxdev *prom21_auxdev; + struct usb_hcd *hcd = pci_get_drvdata(pdev); + int ret; + + prom21_auxdev = devres_alloc(prom21_xhci_auxdev_release, + sizeof(*prom21_auxdev), GFP_KERNEL); + if (!prom21_auxdev) + return -ENOMEM; + + prom21_auxdev->pdata.pdev = pdev; + prom21_auxdev->pdata.regs = hcd->regs; + prom21_auxdev->pdata.rsrc_len = hcd->rsrc_len; + + prom21_auxdev->id = ida_alloc(&prom21_xhci_auxdev_ida, GFP_KERNEL); + if (prom21_auxdev->id < 0) { + ret = prom21_auxdev->id; + goto err_free_devres; + } + + prom21_auxdev->auxdev = auxiliary_device_create(&pdev->dev, + KBUILD_MODNAME, "hwmon", + &prom21_auxdev->pdata, + prom21_auxdev->id); + if (!prom21_auxdev->auxdev) { + ret = -ENOMEM; + goto err_free_ida; + } + + devres_add(&pdev->dev, prom21_auxdev); + return 0; + +err_free_ida: + ida_free(&prom21_xhci_auxdev_ida, prom21_auxdev->id); +err_free_devres: + devres_free(prom21_auxdev); + return ret; +} + +static void prom21_xhci_destroy_auxdev(struct pci_dev *pdev) +{ + devres_release(&pdev->dev, prom21_xhci_auxdev_release, NULL, NULL); +} + +static int prom21_xhci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + int retval; + + retval = xhci_pci_common_probe(dev, id); + if (retval) + return retval; + + retval = prom21_xhci_create_auxdev(dev); + if (retval) { + /* + * The auxiliary device only provides optional temperature sensor + * support. Keep the xHCI controller usable if it fails. + */ + dev_err(&dev->dev, + "failed to create PROM21 hwmon auxiliary device: %d\n", + retval); + } + + return 0; +} + +static void prom21_xhci_remove(struct pci_dev *dev) +{ + prom21_xhci_destroy_auxdev(dev); + xhci_pci_remove(dev); +} + +static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FC) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FD) }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver prom21_xhci_driver = { + .name = "xhci-pci-prom21", + .id_table = pci_ids, + + .probe = prom21_xhci_probe, + .remove = prom21_xhci_remove, + + .shutdown = usb_hcd_pci_shutdown, + .driver = { + .pm = pm_ptr(&usb_hcd_pci_pm_ops), + }, +}; +module_pci_driver(prom21_xhci_driver); + +MODULE_AUTHOR("Jihong Min "); +MODULE_DESCRIPTION("AMD Promontory 21 xHCI PCI Host Controller Driver"); +MODULE_IMPORT_NS("xhci"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 585b2f3117b0..039c26b241d0 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -696,12 +696,23 @@ static const struct pci_device_id pci_ids_renesas[] = { { /* end: all zeroes */ } }; +/* handled by xhci-pci-prom21 if enabled */ +static const struct pci_device_id pci_ids_prom21[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FC) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FD) }, + { /* end: all zeroes */ } +}; + static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { if (IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS) && pci_match_id(pci_ids_renesas, dev)) return -ENODEV; + if (IS_ENABLED(CONFIG_USB_XHCI_PCI_PROM21) && + pci_match_id(pci_ids_prom21, dev)) + return -ENODEV; + return xhci_pci_common_probe(dev, id); } diff --git a/drivers/usb/host/xhci-pci.h b/drivers/usb/host/xhci-pci.h index e87c7d9d76b8..11f435f94322 100644 --- a/drivers/usb/host/xhci-pci.h +++ b/drivers/usb/host/xhci-pci.h @@ -4,6 +4,9 @@ #ifndef XHCI_PCI_H #define XHCI_PCI_H +#define PCI_DEVICE_ID_AMD_PROM21_XHCI_43FC 0x43fc +#define PCI_DEVICE_ID_AMD_PROM21_XHCI_43FD 0x43fd + int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id); void xhci_pci_remove(struct pci_dev *dev); diff --git a/include/linux/platform_data/usb-xhci-prom21.h b/include/linux/platform_data/usb-xhci-prom21.h new file mode 100644 index 000000000000..ee672ad452a8 --- /dev/null +++ b/include/linux/platform_data/usb-xhci-prom21.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AMD Promontory 21 xHCI auxiliary device platform data. + * + * Copyright (C) 2026 Jihong Min + */ + +#ifndef _LINUX_PLATFORM_DATA_USB_XHCI_PROM21_H +#define _LINUX_PLATFORM_DATA_USB_XHCI_PROM21_H + +#include +#include + +struct pci_dev; + +struct prom21_xhci_pdata { + struct pci_dev *pdev; + void __iomem *regs; + resource_size_t rsrc_len; +}; + +#endif