From d427da2323b093a65d8317783e76ab8fad2e2ef0 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Fri, 25 Aug 2023 14:27:10 +0800 Subject: [PATCH 01/13] PCI: Add pci_get_base_class() helper There is no function to get all PCI devices in a system by matching against the base class code only, ignoring the sub-class code and the programming interface. Add pci_get_base_class() to suit the need. For example, if a driver wants to process all PCI display devices in a system, it can do so like this: pdev = NULL; while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) { do_something_for_pci_display_device(pdev); } Link: https://lore.kernel.org/r/20230825062714.6325-2-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng [bhelgaas: reword commit log] Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher --- drivers/pci/search.c | 31 +++++++++++++++++++++++++++++++ include/linux/pci.h | 5 +++++ 2 files changed, 36 insertions(+) diff --git a/drivers/pci/search.c b/drivers/pci/search.c index b4c138a6ec02..53840634fbfc 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -363,6 +363,37 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) } EXPORT_SYMBOL(pci_get_class); +/** + * pci_get_base_class - searching for a PCI device by matching against the base class code only + * @class: search for a PCI device with this base class code + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is found + * with a matching base class code, the reference count to the device is + * incremented. See pci_match_one_device() to figure out how does this works. + * A new search is initiated by passing %NULL as the @from argument. + * Otherwise if @from is not %NULL, searches continue from next device on the + * global list. The reference count for @from is always decremented if it is + * not %NULL. + * + * Returns: + * A pointer to a matched PCI device, %NULL Otherwise. + */ +struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from) +{ + struct pci_device_id id = { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class_mask = 0xFF0000, + .class = class << 16, + }; + + return pci_get_dev_by_id(&id, from); +} +EXPORT_SYMBOL(pci_get_base_class); + /** * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not. * @ids: A pointer to a null terminated list of struct pci_device_id structures diff --git a/include/linux/pci.h b/include/linux/pci.h index 8c7c2c3c6c65..40ac1288a2cc 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1181,6 +1181,8 @@ struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn); struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, unsigned int devfn); struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from); +struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from); + int pci_dev_present(const struct pci_device_id *ids); int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, @@ -1924,6 +1926,9 @@ static inline struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) { return NULL; } +static inline struct pci_dev *pci_get_base_class(unsigned int class, + struct pci_dev *from) +{ return NULL; } static inline int pci_dev_present(const struct pci_device_id *ids) { return 0; } From 9ed8fcfd7f17152e6ff5711bb3ddca82f75a38d4 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Fri, 25 Aug 2023 14:27:11 +0800 Subject: [PATCH 02/13] ALSA: hda: Use pci_get_base_class() to reduce duplicated code Use pci_get_base_class() to reduce duplicated code. No functional change intended. Link: https://lore.kernel.org/r/20230825062714.6325-3-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas Reviewed-by: Takashi Iwai Reviewed-by: Alex Deucher Cc: Jaroslav Kysela Cc: Fred Oh Cc: Pierre-Louis Bossart Cc: Kai Vehmanen --- sound/pci/hda/hda_intel.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 765d95e79861..0b5136fddbca 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1417,17 +1417,11 @@ static bool atpx_present(void) acpi_handle dhandle, atpx_handle; acpi_status status; - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { - dhandle = ACPI_HANDLE(&pdev->dev); - if (dhandle) { - status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); - if (ACPI_SUCCESS(status)) { - pci_dev_put(pdev); - return true; - } - } - } - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { + while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) { + if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) && + (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8)) + continue; + dhandle = ACPI_HANDLE(&pdev->dev); if (dhandle) { status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); From c213ed390cf1352f954164bad71275d6a095200c Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Fri, 25 Aug 2023 14:27:12 +0800 Subject: [PATCH 03/13] drm/nouveau: Use pci_get_base_class() to reduce duplicated code Use pci_get_base_class() to reduce duplicated code. No functional change intended. Link: https://lore.kernel.org/r/20230825062714.6325-4-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher Cc: Ben Skeggs Cc: Karol Herbst Cc: Lyude Paul Cc: David Airlie Cc: Daniel Vetter --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index a2ae8c21e4dc..8f0c69aad248 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -284,14 +284,11 @@ static bool nouveau_dsm_detect(void) printk("MXM: GUID detected in BIOS\n"); /* now do DSM detection */ - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { - vga_count++; + while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) { + if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) && + (pdev->class != PCI_CLASS_DISPLAY_3D << 8)) + continue; - nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus, - &has_optimus_flags, &has_power_resources); - } - - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) { vga_count++; nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus, From 18bf400530ca06e4bffcc9ce4741cf7a3526b85f Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Fri, 25 Aug 2023 14:27:13 +0800 Subject: [PATCH 04/13] drm/amdgpu: Use pci_get_base_class() to reduce duplicated code Use pci_get_base_class() to reduce duplicated code. No functional change intended. Link: https://lore.kernel.org/r/20230825062714.6325-5-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher Cc: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 11 ++++------- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 20 +++++--------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 2bca37044ad0..327e2fd2401f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1389,14 +1389,11 @@ void amdgpu_acpi_detect(void) struct pci_dev *pdev = NULL; int ret; - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { - if (!atif->handle) - amdgpu_atif_pci_probe_handle(pdev); - if (!atcs->handle) - amdgpu_atcs_pci_probe_handle(pdev); - } + while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) { + if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) && + (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8)) + continue; - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { if (!atif->handle) amdgpu_atif_pci_probe_handle(pdev); if (!atcs->handle) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index 38ccec913f00..5bbb23e102ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -287,7 +287,11 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev) if (adev->flags & AMD_IS_APU) return false; - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { + while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) { + if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) && + (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8)) + continue; + dhandle = ACPI_HANDLE(&pdev->dev); if (!dhandle) continue; @@ -299,20 +303,6 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev) } } - if (!found) { - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { - dhandle = ACPI_HANDLE(&pdev->dev); - if (!dhandle) - continue; - - status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); - if (ACPI_SUCCESS(status)) { - found = true; - break; - } - } - } - if (!found) return false; pci_dev_put(pdev); From b5fc04039b9578d8bcc46bf70bcfe6b137340aeb Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Fri, 25 Aug 2023 14:27:14 +0800 Subject: [PATCH 05/13] drm/radeon: Use pci_get_base_class() to reduce duplicated code Use pci_get_base_class() to reduce duplicated code. No functional change intended. Link: https://lore.kernel.org/r/20230825062714.6325-6-sui.jingfeng@linux.dev Signed-off-by: Sui Jingfeng Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher Cc: Alex Deucher --- drivers/gpu/drm/radeon/radeon_bios.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 63bdc9f6fc24..3a8c5199a0fe 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -199,7 +199,11 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_IGP) return false; - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { + while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) { + if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) && + (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8)) + continue; + dhandle = ACPI_HANDLE(&pdev->dev); if (!dhandle) continue; @@ -211,20 +215,6 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) } } - if (!found) { - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { - dhandle = ACPI_HANDLE(&pdev->dev); - if (!dhandle) - continue; - - status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); - if (ACPI_SUCCESS(status)) { - found = true; - break; - } - } - } - if (!found) return false; pci_dev_put(pdev); From 5827e17d0555b566c32044b0632b46f9f95054fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 3 Oct 2023 15:52:58 +0300 Subject: [PATCH 06/13] PCI: vmd: Correct PCI Header Type Register's multi-function check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vmd_domain_reset() attempts to find whether the device may contain multiple functions by checking 0x80 (Multi-Function Device), however, the hdr_type variable has already been masked with PCI_HEADER_TYPE_MASK so the check can never true. To fix the issue, don't mask the read with PCI_HEADER_TYPE_MASK. Fixes: 6aab5622296b ("PCI: vmd: Clean up domain before enumeration") Link: https://lore.kernel.org/r/20231003125300.5541-2-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Cc: Nirmal Patel --- drivers/pci/controller/vmd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index ad56df98b8e6..1c1c1aa940a5 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -525,8 +525,7 @@ static void vmd_domain_reset(struct vmd_dev *vmd) base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus, PCI_DEVFN(dev, 0), 0); - hdr_type = readb(base + PCI_HEADER_TYPE) & - PCI_HEADER_TYPE_MASK; + hdr_type = readb(base + PCI_HEADER_TYPE); functions = (hdr_type & 0x80) ? 8 : 1; for (fn = 0; fn < functions; fn++) { From bdca03a271f2de2c24ea56756fd9bbcff35173fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 3 Oct 2023 15:52:59 +0300 Subject: [PATCH 07/13] PCI: Add PCI_HEADER_TYPE_MFD definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add PCI_HEADER_TYPE_MFD so we can replace literals in the code. Link: https://lore.kernel.org/r/20231003125300.5541-3-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas --- include/uapi/linux/pci_regs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index e5f558d96493..06df65f11c39 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -80,6 +80,7 @@ #define PCI_HEADER_TYPE_NORMAL 0 #define PCI_HEADER_TYPE_BRIDGE 1 #define PCI_HEADER_TYPE_CARDBUS 2 +#define PCI_HEADER_TYPE_MFD 0x80 /* Multi-Function Device (possible) */ #define PCI_BIST 0x0f /* 8 bits */ #define PCI_BIST_CODE_MASK 0x0f /* Return result */ From 83c088148c8e5c439eec6c7651692f797547e1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Tue, 3 Oct 2023 15:53:00 +0300 Subject: [PATCH 08/13] PCI: Use PCI_HEADER_TYPE_* instead of literals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace literals under drivers/pci/ with PCI_HEADER_TYPE_MASK, PCI_HEADER_TYPE_NORMAL, and PCI_HEADER_TYPE_MFD. Also replace !! boolean conversions with FIELD_GET(). Link: https://lore.kernel.org/r/20231003125300.5541-4-ilpo.jarvinen@linux.intel.com Signed-off-by: Ilpo Järvinen Signed-off-by: Bjorn Helgaas Reviewed-by: Wolfram Sang # for Renesas R-Car --- drivers/pci/controller/dwc/pci-layerscape.c | 2 +- .../controller/mobiveil/pcie-mobiveil-host.c | 2 +- drivers/pci/controller/pcie-iproc.c | 2 +- drivers/pci/controller/pcie-rcar-ep.c | 2 +- drivers/pci/controller/pcie-rcar-host.c | 2 +- drivers/pci/controller/vmd.c | 2 +- drivers/pci/hotplug/cpqphp_ctrl.c | 6 ++--- drivers/pci/hotplug/cpqphp_pci.c | 22 +++++++++---------- drivers/pci/hotplug/ibmphp.h | 5 +++-- drivers/pci/hotplug/ibmphp_pci.c | 2 +- drivers/pci/pci.c | 2 +- drivers/pci/quirks.c | 6 ++--- 12 files changed, 28 insertions(+), 27 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c index b931d597656f..37956e09c65b 100644 --- a/drivers/pci/controller/dwc/pci-layerscape.c +++ b/drivers/pci/controller/dwc/pci-layerscape.c @@ -58,7 +58,7 @@ static bool ls_pcie_is_bridge(struct ls_pcie *pcie) u32 header_type; header_type = ioread8(pci->dbi_base + PCI_HEADER_TYPE); - header_type &= 0x7f; + header_type &= PCI_HEADER_TYPE_MASK; return header_type == PCI_HEADER_TYPE_BRIDGE; } diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c index 45b97a4b14db..32951f7d6d6d 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c @@ -539,7 +539,7 @@ static bool mobiveil_pcie_is_bridge(struct mobiveil_pcie *pcie) u32 header_type; header_type = mobiveil_csr_readb(pcie, PCI_HEADER_TYPE); - header_type &= 0x7f; + header_type &= PCI_HEADER_TYPE_MASK; return header_type == PCI_HEADER_TYPE_BRIDGE; } diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index bd1c98b68851..97f739a2c9f8 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -783,7 +783,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie) /* make sure we are not in EP mode */ iproc_pci_raw_config_read32(pcie, 0, PCI_HEADER_TYPE, 1, &hdr_type); - if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) { + if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) { dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type); return -EFAULT; } diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c index f9682df1da61..7034c0ff23d0 100644 --- a/drivers/pci/controller/pcie-rcar-ep.c +++ b/drivers/pci/controller/pcie-rcar-ep.c @@ -43,7 +43,7 @@ static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie) rcar_rmw32(pcie, REXPCAP(0), 0xff, PCI_CAP_ID_EXP); rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS), PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ENDPOINT << 4); - rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f, + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), PCI_HEADER_TYPE_MASK, PCI_HEADER_TYPE_NORMAL); /* Write out the physical slot number = 0 */ diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index 88975e40ee2f..bf7cc0b6a695 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -460,7 +460,7 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie) rcar_rmw32(pcie, REXPCAP(0), 0xff, PCI_CAP_ID_EXP); rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS), PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4); - rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f, + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), PCI_HEADER_TYPE_MASK, PCI_HEADER_TYPE_BRIDGE); /* Enable data link layer active state reporting */ diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 1c1c1aa940a5..566721c41f3e 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -527,7 +527,7 @@ static void vmd_domain_reset(struct vmd_dev *vmd) hdr_type = readb(base + PCI_HEADER_TYPE); - functions = (hdr_type & 0x80) ? 8 : 1; + functions = (hdr_type & PCI_HEADER_TYPE_MFD) ? 8 : 1; for (fn = 0; fn < functions; fn++) { base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus, PCI_DEVFN(dev, fn), 0); diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index e429ecddc8fe..c01968ef0bd7 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -2059,7 +2059,7 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func) return rc; /* If it's a bridge, check the VGA Enable bit */ - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { rc = pci_bus_read_config_byte(pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); if (rc) return rc; @@ -2342,7 +2342,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func if (rc) return rc; - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((temp_byte & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* set Primary bus */ dbg("set Primary bus = %d\n", func->bus); rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); @@ -2739,7 +2739,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func * PCI_BRIDGE_CTL_SERR | * PCI_BRIDGE_CTL_NO_ISA */ rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); - } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + } else if ((temp_byte & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) { /* Standard device */ rc = pci_bus_read_config_byte(pci_bus, devfn, 0x0B, &class_code); diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 3b248426a9f4..e9f1fb333a71 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -363,7 +363,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) return rc; /* If multi-function device, set max_functions to 8 */ - if (header_type & 0x80) + if (header_type & PCI_HEADER_TYPE_MFD) max_functions = 8; else max_functions = 1; @@ -372,7 +372,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) do { DevError = 0; - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* Recurse the subordinate bus * get the subordinate bus number */ @@ -487,13 +487,13 @@ int cpqhp_save_slot_config(struct controller *ctrl, struct pci_func *new_slot) pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - if (header_type & 0x80) /* Multi-function device */ + if (header_type & PCI_HEADER_TYPE_MFD) max_functions = 8; else max_functions = 1; while (function < max_functions) { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* Recurse the subordinate bus */ pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); @@ -571,7 +571,7 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func) /* Check for Bridge */ pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -625,7 +625,7 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func) } /* End of base register loop */ - } else if ((header_type & 0x7F) == 0x00) { + } else if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) { /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { temp_register = 0xFFFFFFFF; @@ -723,7 +723,7 @@ int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func) /* Check for Bridge */ pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* Clear Bridge Control Register */ command = 0x00; pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); @@ -858,7 +858,7 @@ int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func) } } /* End of base register loop */ /* Standard header */ - } else if ((header_type & 0x7F) == 0x00) { + } else if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) { /* Figure out IO and memory base lengths */ for (cloop = 0x10; cloop <= 0x24; cloop += 4) { pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); @@ -975,7 +975,7 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func) pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); /* If this is a bridge device, restore subordinate devices */ - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); sub_bus = (int) secondary_bus; @@ -1067,7 +1067,7 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func) /* Check for Bridge */ pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* In order to continue checking, we must program the * bus registers in the bridge to respond to accesses * for its subordinate bus(es) @@ -1090,7 +1090,7 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func) } /* Check to see if it is a standard config header */ - else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + else if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) { /* Check subsystem vendor and ID */ pci_bus_read_config_dword(pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index 41eafe511210..c248a09be7b5 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -17,6 +17,7 @@ */ #include +#include extern int ibmphp_debug; @@ -286,8 +287,8 @@ int ibmphp_register_pci(void); /* pci specific defines */ #define PCI_VENDOR_ID_NOTVALID 0xFFFF -#define PCI_HEADER_TYPE_MULTIDEVICE 0x80 -#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81 +#define PCI_HEADER_TYPE_MULTIDEVICE (PCI_HEADER_TYPE_MFD|PCI_HEADER_TYPE_NORMAL) +#define PCI_HEADER_TYPE_MULTIBRIDGE (PCI_HEADER_TYPE_MFD|PCI_HEADER_TYPE_BRIDGE) #define LATENCY 0x64 #define CACHE 64 diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c index 50038e5f9ca4..eeb412cbd9fe 100644 --- a/drivers/pci/hotplug/ibmphp_pci.c +++ b/drivers/pci/hotplug/ibmphp_pci.c @@ -1087,7 +1087,7 @@ static struct res_needed *scan_behind_bridge(struct pci_func *func, u8 busno) pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); debug("hdr_type behind the bridge is %x\n", hdr_type); - if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + if ((hdr_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { err("embedded bridges not supported for hot-plugging.\n"); amount->not_correct = 1; return amount; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 59c01d68c6d5..33946ff5c6bd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -534,7 +534,7 @@ u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap) pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type); - pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & 0x7f); + pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & PCI_HEADER_TYPE_MASK); if (pos) pos = __pci_find_next_cap(bus, devfn, pos, cap); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index eeec1d6f9023..b16e6168e89b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1844,8 +1844,8 @@ static void quirk_jmicron_ata(struct pci_dev *pdev) /* Update pdev accordingly */ pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr); - pdev->hdr_type = hdr & 0x7f; - pdev->multifunction = !!(hdr & 0x80); + pdev->hdr_type = hdr & PCI_HEADER_TYPE_MASK; + pdev->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr); pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class); pdev->class = class >> 8; @@ -5666,7 +5666,7 @@ static void quirk_nvidia_hda(struct pci_dev *gpu) /* The GPU becomes a multi-function device when the HDA is enabled */ pci_read_config_byte(gpu, PCI_HEADER_TYPE, &hdr_type); - gpu->multifunction = !!(hdr_type & 0x80); + gpu->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr_type); } DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, 16, quirk_nvidia_hda); From 8624ebc300b2418b498cb85463682afc9bde5d54 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Oct 2023 16:53:52 +0300 Subject: [PATCH 09/13] PCI/ACPI: Use acpi_evaluate_dsm_typed() The acpi_evaluate_dsm_typed() provides a way to check the type of the object evaluated by _DSM call. Use it instead of open coded variant. Link: https://lore.kernel.org/r/20231002135352.2603096-1-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Bjorn Helgaas Acked-by: "Rafael J. Wysocki" --- drivers/pci/pci-acpi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a05350a4e49c..cf108259aef6 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -1215,12 +1215,12 @@ void acpi_pci_add_bus(struct pci_bus *bus) if (!pci_is_root_bus(bus)) return; - obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3, - DSM_PCI_POWER_ON_RESET_DELAY, NULL); + obj = acpi_evaluate_dsm_typed(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3, + DSM_PCI_POWER_ON_RESET_DELAY, NULL, ACPI_TYPE_INTEGER); if (!obj) return; - if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) { + if (obj->integer.value == 1) { bridge = pci_find_host_bridge(bus); bridge->ignore_reset_delay = 1; } @@ -1376,12 +1376,13 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev, if (bridge->ignore_reset_delay) pdev->d3cold_delay = 0; - obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 3, - DSM_PCI_DEVICE_READINESS_DURATIONS, NULL); + obj = acpi_evaluate_dsm_typed(handle, &pci_acpi_dsm_guid, 3, + DSM_PCI_DEVICE_READINESS_DURATIONS, NULL, + ACPI_TYPE_PACKAGE); if (!obj) return; - if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) { + if (obj->package.count == 5) { elements = obj->package.elements; if (elements[0].type == ACPI_TYPE_INTEGER) { value = (int)elements[0].integer.value / 1000; From 83a939f0fdc208ff3639dd3d42ac9b3c35607fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 1 Oct 2023 19:02:51 +0200 Subject: [PATCH 10/13] PCI: exynos: Don't discard .remove() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_PCI_EXYNOS=y and exynos_pcie_remove() marked with __exit, the function is discarded from the driver. In this case a bound device can still get unbound, e.g via sysfs. Then no cleanup code is run resulting in resource leaks or worse. The right thing to do is do always have the remove callback available. This fixes the following warning by modpost: WARNING: modpost: drivers/pci/controller/dwc/pci-exynos: section mismatch in reference: exynos_pcie_driver+0x8 (section: .data) -> exynos_pcie_remove (section: .exit.text) (with ARCH=x86_64 W=1 allmodconfig). Fixes: 340cba6092c2 ("pci: Add PCIe driver for Samsung Exynos") Link: https://lore.kernel.org/r/20231001170254.2506508-2-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Bjorn Helgaas Reviewed-by: Alim Akhtar Cc: stable@vger.kernel.org --- drivers/pci/controller/dwc/pci-exynos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 6319082301d6..c6bede346932 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -375,7 +375,7 @@ static int exynos_pcie_probe(struct platform_device *pdev) return ret; } -static int __exit exynos_pcie_remove(struct platform_device *pdev) +static int exynos_pcie_remove(struct platform_device *pdev) { struct exynos_pcie *ep = platform_get_drvdata(pdev); @@ -431,7 +431,7 @@ static const struct of_device_id exynos_pcie_of_match[] = { static struct platform_driver exynos_pcie_driver = { .probe = exynos_pcie_probe, - .remove = __exit_p(exynos_pcie_remove), + .remove = exynos_pcie_remove, .driver = { .name = "exynos-pcie", .of_match_table = exynos_pcie_of_match, From 3064ef2e88c1629c1e67a77d7bc20020b35846f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 1 Oct 2023 19:02:52 +0200 Subject: [PATCH 11/13] PCI: kirin: Don't discard .remove() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_PCIE_KIRIN=y and kirin_pcie_remove() marked with __exit, the function is discarded from the driver. In this case a bound device can still get unbound, e.g via sysfs. Then no cleanup code is run resulting in resource leaks or worse. The right thing to do is do always have the remove callback available. This fixes the following warning by modpost: drivers/pci/controller/dwc/pcie-kirin: section mismatch in reference: kirin_pcie_driver+0x8 (section: .data) -> kirin_pcie_remove (section: .exit.text) (with ARCH=x86_64 W=1 allmodconfig). Fixes: 000f60db784b ("PCI: kirin: Add support for a PHY layer") Link: https://lore.kernel.org/r/20231001170254.2506508-3-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org --- drivers/pci/controller/dwc/pcie-kirin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index d93bc2906950..2ee146767971 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -741,7 +741,7 @@ static int kirin_pcie_power_on(struct platform_device *pdev, return ret; } -static int __exit kirin_pcie_remove(struct platform_device *pdev) +static int kirin_pcie_remove(struct platform_device *pdev) { struct kirin_pcie *kirin_pcie = platform_get_drvdata(pdev); @@ -818,7 +818,7 @@ static int kirin_pcie_probe(struct platform_device *pdev) static struct platform_driver kirin_pcie_driver = { .probe = kirin_pcie_probe, - .remove = __exit_p(kirin_pcie_remove), + .remove = kirin_pcie_remove, .driver = { .name = "kirin-pcie", .of_match_table = kirin_pcie_match, From 200bddbb3f5202bbce96444fdc416305de14f547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 1 Oct 2023 19:02:53 +0200 Subject: [PATCH 12/13] PCI: keystone: Don't discard .remove() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_PCIE_KEYSTONE=y and ks_pcie_remove() marked with __exit, the function is discarded from the driver. In this case a bound device can still get unbound, e.g via sysfs. Then no cleanup code is run resulting in resource leaks or worse. The right thing to do is do always have the remove callback available. Note that this driver cannot be compiled as a module, so ks_pcie_remove() was always discarded before this change and modpost couldn't warn about this issue. Furthermore the __ref annotation also prevents a warning. Fixes: 0c4ffcfe1fbc ("PCI: keystone: Add TI Keystone PCIe driver") Link: https://lore.kernel.org/r/20231001170254.2506508-4-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 49aea6ce3e87..eb3fa17b243f 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1302,7 +1302,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) return ret; } -static int __exit ks_pcie_remove(struct platform_device *pdev) +static int ks_pcie_remove(struct platform_device *pdev) { struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev); struct device_link **link = ks_pcie->link; @@ -1320,7 +1320,7 @@ static int __exit ks_pcie_remove(struct platform_device *pdev) static struct platform_driver ks_pcie_driver __refdata = { .probe = ks_pcie_probe, - .remove = __exit_p(ks_pcie_remove), + .remove = ks_pcie_remove, .driver = { .name = "keystone-pcie", .of_match_table = ks_pcie_of_match, From 7994db905c0fd692cf04c527585f08a91b560144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 1 Oct 2023 19:02:54 +0200 Subject: [PATCH 13/13] PCI: keystone: Don't discard .probe() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The __init annotation makes the ks_pcie_probe() function disappear after booting completes. However a device can also be bound later. In that case, we try to call ks_pcie_probe(), but the backing memory is likely already overwritten. The right thing to do is do always have the probe callback available. Note that the (wrong) __refdata annotation prevented this issue to be noticed by modpost. Fixes: 0c4ffcfe1fbc ("PCI: keystone: Add TI Keystone PCIe driver") Link: https://lore.kernel.org/r/20231001170254.2506508-5-u.kleine-koenig@pengutronix.de Signed-off-by: Uwe Kleine-König Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org --- drivers/pci/controller/dwc/pci-keystone.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index eb3fa17b243f..0def919f89fa 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1100,7 +1100,7 @@ static const struct of_device_id ks_pcie_of_match[] = { { }, }; -static int __init ks_pcie_probe(struct platform_device *pdev) +static int ks_pcie_probe(struct platform_device *pdev) { const struct dw_pcie_host_ops *host_ops; const struct dw_pcie_ep_ops *ep_ops; @@ -1318,7 +1318,7 @@ static int ks_pcie_remove(struct platform_device *pdev) return 0; } -static struct platform_driver ks_pcie_driver __refdata = { +static struct platform_driver ks_pcie_driver = { .probe = ks_pcie_probe, .remove = ks_pcie_remove, .driver = {