diff options
| author | Bjorn Helgaas <bhelgaas@google.com> | 2026-08-21 16:40:34 -0500 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-08-21 16:40:34 -0500 |
| commit | cc6fa623ca8d33e2ce561ad294ac4bb478a3acd9 (patch) | |
| tree | e0f86cf060306cc33389e66d5ee64f0cb9fdf1d2 /drivers | |
| parent | ea55835bc53825bd3486a2eaa59af4b326baa4cd (diff) | |
| parent | 3ffc4c9690c33ee28cdb3d0182b12f9c623e3acc (diff) | |
| download | linux-cc6fa623ca8d33e2ce561ad294ac4bb478a3acd9.tar.gz linux-cc6fa623ca8d33e2ce561ad294ac4bb478a3acd9.zip | |
Merge branch 'pci/enumeration'
- Don't store pci_device_id in agp amd-k7 and via, ata, scsi nsp32, ipack
tpci200, mlxsw since the dynamic ID feature means the ID is only
guaranteed to live during probe (Gary Guo)
- Add pci_match_one_id() to match an ID directly so dynamic ID insertion
doesn't need to make a temporary device for matching (Gary Guo)
- Check for existing ID inside the dynamic ID addition critical section to
avoid a time-of-check vs time-of-use race (Gary Guo)
- Copy device ID to avoid use-after-free when match races with sysfs
dynamic ID removal (Gary Guo)
* pci/enumeration:
PCI: Fix UAF when probe runs concurrent to dyn ID removal
PCI: Fix dyn_id add TOCTOU
PCI: Make pci_match_one_device() match on ID instead of device
agp/amd-k7: Don't rely on address of pci_device_id
agp/via: Don't rely on address of pci_device_id
mlxsw: pci: Don't store pci_device_id
ipack: tpci200: Don't store pci_device_id
scsi: nsp32: Don't store pci_device_id
ata: ata_generic: Don't store pci_device_id
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/ata/ata_generic.c | 6 | ||||
| -rw-r--r-- | drivers/char/agp/amd-k7-agp.c | 26 | ||||
| -rw-r--r-- | drivers/char/agp/via-agp.c | 308 | ||||
| -rw-r--r-- | drivers/ipack/carriers/tpci200.c | 1 | ||||
| -rw-r--r-- | drivers/ipack/carriers/tpci200.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/pci.c | 11 | ||||
| -rw-r--r-- | drivers/pci/pci-driver.c | 194 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 43 | ||||
| -rw-r--r-- | drivers/pci/search.c | 8 | ||||
| -rw-r--r-- | drivers/scsi/nsp32.c | 8 | ||||
| -rw-r--r-- | drivers/scsi/nsp32.h | 8 |
11 files changed, 236 insertions, 378 deletions
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index e70b6c089cf1..18ea740ca582 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -51,11 +51,11 @@ enum { static int generic_set_mode(struct ata_link *link, struct ata_device **unused) { struct ata_port *ap = link->ap; - const struct pci_device_id *id = ap->host->private_data; + unsigned long driver_data = (unsigned long)ap->host->private_data; int dma_enabled = 0; struct ata_device *dev; - if (id->driver_data & ATA_GEN_FORCE_DMA) { + if (driver_data & ATA_GEN_FORCE_DMA) { dma_enabled = 0xff; } else if (ap->ioaddr.bmdma_addr) { /* Bits 5 and 6 indicate if DMA is active on master/slave */ @@ -206,7 +206,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id return rc; pcim_pin_device(dev); } - return ata_pci_bmdma_init_one(dev, ppi, &generic_sht, (void *)id, 0); + return ata_pci_bmdma_init_one(dev, ppi, &generic_sht, (void *)id->driver_data, 0); } static const struct pci_device_id ata_generic[] = { diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 898ff30ffd46..4d201e71c517 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -387,37 +387,17 @@ static const struct agp_bridge_driver amd_irongate_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids amd_agp_device_ids[] = -{ - { - .device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006, - .chipset_name = "Irongate", - }, - { - .device_id = PCI_DEVICE_ID_AMD_FE_GATE_700E, - .chipset_name = "761", - }, - { - .device_id = PCI_DEVICE_ID_AMD_FE_GATE_700C, - .chipset_name = "760MP", - }, - { }, /* dummy final entry, always present */ -}; - static int agp_amdk7_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct agp_bridge_data *bridge; u8 cap_ptr; - int j; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; - j = ent - agp_amdk7_pci_table; - dev_info(&pdev->dev, "AMD %s chipset\n", - amd_agp_device_ids[j].chipset_name); + dev_info(&pdev->dev, "AMD %s chipset\n", (const char *)ent->driver_data); bridge = agp_alloc_bridge(); if (!bridge) @@ -492,7 +472,6 @@ static int agp_amdk7_resume(struct device *dev) return amd_irongate_driver.configure(); } -/* must be the same order as name table above */ static const struct pci_device_id agp_amdk7_pci_table[] = { { .class = (PCI_CLASS_BRIDGE_HOST << 8), @@ -501,6 +480,7 @@ static const struct pci_device_id agp_amdk7_pci_table[] = { .device = PCI_DEVICE_ID_AMD_FE_GATE_7006, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)"Irongate", }, { .class = (PCI_CLASS_BRIDGE_HOST << 8), @@ -509,6 +489,7 @@ static const struct pci_device_id agp_amdk7_pci_table[] = { .device = PCI_DEVICE_ID_AMD_FE_GATE_700E, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)"761", }, { .class = (PCI_CLASS_BRIDGE_HOST << 8), @@ -517,6 +498,7 @@ static const struct pci_device_id agp_amdk7_pci_table[] = { .device = PCI_DEVICE_ID_AMD_FE_GATE_700C, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)"760MP", }, { } }; diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 8b19a5d1a09b..ab3b73dd080a 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -221,204 +221,6 @@ static const struct agp_bridge_driver via_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids via_agp_device_ids[] = -{ - { - .device_id = PCI_DEVICE_ID_VIA_82C597_0, - .chipset_name = "Apollo VP3", - }, - - { - .device_id = PCI_DEVICE_ID_VIA_82C598_0, - .chipset_name = "Apollo MVP3", - }, - - { - .device_id = PCI_DEVICE_ID_VIA_8501_0, - .chipset_name = "Apollo MVP4", - }, - - /* VT8601 */ - { - .device_id = PCI_DEVICE_ID_VIA_8601_0, - .chipset_name = "Apollo ProMedia/PLE133Ta", - }, - - /* VT82C693A / VT28C694T */ - { - .device_id = PCI_DEVICE_ID_VIA_82C691_0, - .chipset_name = "Apollo Pro 133", - }, - - { - .device_id = PCI_DEVICE_ID_VIA_8371_0, - .chipset_name = "KX133", - }, - - /* VT8633 */ - { - .device_id = PCI_DEVICE_ID_VIA_8633_0, - .chipset_name = "Pro 266", - }, - - { - .device_id = PCI_DEVICE_ID_VIA_XN266, - .chipset_name = "Apollo Pro266", - }, - - /* VT8361 */ - { - .device_id = PCI_DEVICE_ID_VIA_8361, - .chipset_name = "KLE133", - }, - - /* VT8365 / VT8362 */ - { - .device_id = PCI_DEVICE_ID_VIA_8363_0, - .chipset_name = "Twister-K/KT133x/KM133", - }, - - /* VT8753A */ - { - .device_id = PCI_DEVICE_ID_VIA_8753_0, - .chipset_name = "P4X266", - }, - - /* VT8366 */ - { - .device_id = PCI_DEVICE_ID_VIA_8367_0, - .chipset_name = "KT266/KY266x/KT333", - }, - - /* VT8633 (for CuMine/ Celeron) */ - { - .device_id = PCI_DEVICE_ID_VIA_8653_0, - .chipset_name = "Pro266T", - }, - - /* KM266 / PM266 */ - { - .device_id = PCI_DEVICE_ID_VIA_XM266, - .chipset_name = "PM266/KM266", - }, - - /* CLE266 */ - { - .device_id = PCI_DEVICE_ID_VIA_862X_0, - .chipset_name = "CLE266", - }, - - { - .device_id = PCI_DEVICE_ID_VIA_8377_0, - .chipset_name = "KT400/KT400A/KT600", - }, - - /* VT8604 / VT8605 / VT8603 - * (Apollo Pro133A chipset with S3 Savage4) */ - { - .device_id = PCI_DEVICE_ID_VIA_8605_0, - .chipset_name = "ProSavage PM133/PL133/PN133" - }, - - /* P4M266x/P4N266 */ - { - .device_id = PCI_DEVICE_ID_VIA_8703_51_0, - .chipset_name = "P4M266x/P4N266", - }, - - /* VT8754 */ - { - .device_id = PCI_DEVICE_ID_VIA_8754C_0, - .chipset_name = "PT800", - }, - - /* P4X600 */ - { - .device_id = PCI_DEVICE_ID_VIA_8763_0, - .chipset_name = "P4X600" - }, - - /* KM400 */ - { - .device_id = PCI_DEVICE_ID_VIA_8378_0, - .chipset_name = "KM400/KM400A", - }, - - /* PT880 */ - { - .device_id = PCI_DEVICE_ID_VIA_PT880, - .chipset_name = "PT880", - }, - - /* PT880 Ultra */ - { - .device_id = PCI_DEVICE_ID_VIA_PT880ULTRA, - .chipset_name = "PT880 Ultra", - }, - - /* PT890 */ - { - .device_id = PCI_DEVICE_ID_VIA_8783_0, - .chipset_name = "PT890", - }, - - /* PM800/PN800/PM880/PN880 */ - { - .device_id = PCI_DEVICE_ID_VIA_PX8X0_0, - .chipset_name = "PM800/PN800/PM880/PN880", - }, - /* KT880 */ - { - .device_id = PCI_DEVICE_ID_VIA_3269_0, - .chipset_name = "KT880", - }, - /* KTxxx/Px8xx */ - { - .device_id = PCI_DEVICE_ID_VIA_83_87XX_1, - .chipset_name = "VT83xx/VT87xx/KTxxx/Px8xx", - }, - /* P4M800 */ - { - .device_id = PCI_DEVICE_ID_VIA_3296_0, - .chipset_name = "P4M800", - }, - /* P4M800CE */ - { - .device_id = PCI_DEVICE_ID_VIA_P4M800CE, - .chipset_name = "VT3314", - }, - /* VT3324 / CX700 */ - { - .device_id = PCI_DEVICE_ID_VIA_VT3324, - .chipset_name = "CX700", - }, - /* VT3336 - this is a chipset for AMD Athlon/K8 CPU. Due to K8's unique - * architecture, the AGP resource and behavior are different from - * the traditional AGP which resides only in chipset. AGP is used - * by 3D driver which wasn't available for the VT3336 and VT3364 - * generation until now. Unfortunately, by testing, VT3364 works - * but VT3336 doesn't. - explanation from via, just leave this as - * as a placeholder to avoid future patches adding it back in. - */ -#if 0 - { - .device_id = PCI_DEVICE_ID_VIA_VT3336, - .chipset_name = "VT3336", - }, -#endif - /* P4M890 */ - { - .device_id = PCI_DEVICE_ID_VIA_P4M890, - .chipset_name = "P4M890", - }, - /* P4M900 */ - { - .device_id = PCI_DEVICE_ID_VIA_VT3364, - .chipset_name = "P4M900", - }, - { }, /* dummy final entry, always present */ -}; - /* * VIA's AGP3 chipsets do magick to put the AGP bridge compliant @@ -437,17 +239,14 @@ static void check_via_agp3 (struct agp_bridge_data *bridge) static int agp_via_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct agp_device_ids *devs = via_agp_device_ids; struct agp_bridge_data *bridge; - int j = 0; u8 cap_ptr; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; - j = ent - agp_via_pci_table; - printk (KERN_INFO PFX "Detected VIA %s chipset\n", devs[j].chipset_name); + dev_info(&pdev->dev, "Detected VIA %s chipset\n", (const char *)ent->driver_data); bridge = agp_alloc_bridge(); if (!bridge) @@ -501,9 +300,8 @@ static int agp_via_resume(struct device *dev) return 0; } -/* must be the same order as name table above */ static const struct pci_device_id agp_via_pci_table[] = { -#define ID(x) \ +#define ID(x, name) \ { \ .class = (PCI_CLASS_BRIDGE_HOST << 8), \ .class_mask = ~0, \ @@ -511,39 +309,77 @@ static const struct pci_device_id agp_via_pci_table[] = { .device = x, \ .subvendor = PCI_ANY_ID, \ .subdevice = PCI_ANY_ID, \ + .driver_data = (kernel_ulong_t)name, \ } - ID(PCI_DEVICE_ID_VIA_82C597_0), - ID(PCI_DEVICE_ID_VIA_82C598_0), - ID(PCI_DEVICE_ID_VIA_8501_0), - ID(PCI_DEVICE_ID_VIA_8601_0), - ID(PCI_DEVICE_ID_VIA_82C691_0), - ID(PCI_DEVICE_ID_VIA_8371_0), - ID(PCI_DEVICE_ID_VIA_8633_0), - ID(PCI_DEVICE_ID_VIA_XN266), - ID(PCI_DEVICE_ID_VIA_8361), - ID(PCI_DEVICE_ID_VIA_8363_0), - ID(PCI_DEVICE_ID_VIA_8753_0), - ID(PCI_DEVICE_ID_VIA_8367_0), - ID(PCI_DEVICE_ID_VIA_8653_0), - ID(PCI_DEVICE_ID_VIA_XM266), - ID(PCI_DEVICE_ID_VIA_862X_0), - ID(PCI_DEVICE_ID_VIA_8377_0), - ID(PCI_DEVICE_ID_VIA_8605_0), - ID(PCI_DEVICE_ID_VIA_8703_51_0), - ID(PCI_DEVICE_ID_VIA_8754C_0), - ID(PCI_DEVICE_ID_VIA_8763_0), - ID(PCI_DEVICE_ID_VIA_8378_0), - ID(PCI_DEVICE_ID_VIA_PT880), - ID(PCI_DEVICE_ID_VIA_PT880ULTRA), - ID(PCI_DEVICE_ID_VIA_8783_0), - ID(PCI_DEVICE_ID_VIA_PX8X0_0), - ID(PCI_DEVICE_ID_VIA_3269_0), - ID(PCI_DEVICE_ID_VIA_83_87XX_1), - ID(PCI_DEVICE_ID_VIA_3296_0), - ID(PCI_DEVICE_ID_VIA_P4M800CE), - ID(PCI_DEVICE_ID_VIA_VT3324), - ID(PCI_DEVICE_ID_VIA_P4M890), - ID(PCI_DEVICE_ID_VIA_VT3364), + ID(PCI_DEVICE_ID_VIA_82C597_0, "Apollo VP3"), + ID(PCI_DEVICE_ID_VIA_82C598_0, "Apollo MVP3"), + ID(PCI_DEVICE_ID_VIA_8501_0, "Apollo MVP4"), + /* VT8601 */ + ID(PCI_DEVICE_ID_VIA_8601_0, "Apollo ProMedia/PLE133Ta"), + /* VT82C693A / VT28C694T */ + ID(PCI_DEVICE_ID_VIA_82C691_0, "Apollo Pro 133"), + ID(PCI_DEVICE_ID_VIA_8371_0, "KX133"), + /* VT8633 */ + ID(PCI_DEVICE_ID_VIA_8633_0, "Pro 266"), + ID(PCI_DEVICE_ID_VIA_XN266, "Apollo Pro266"), + /* VT8361 */ + ID(PCI_DEVICE_ID_VIA_8361, "KLE133"), + /* VT8365 / VT8362 */ + ID(PCI_DEVICE_ID_VIA_8363_0, "Twister-K/KT133x/KM133"), + /* VT8753A */ + ID(PCI_DEVICE_ID_VIA_8753_0, "P4X266"), + /* VT8366 */ + ID(PCI_DEVICE_ID_VIA_8367_0, "KT266/KY266x/KT333"), + /* VT8633 (for CuMine/ Celeron) */ + ID(PCI_DEVICE_ID_VIA_8653_0, "Pro266T"), + /* KM266 / PM266 */ + ID(PCI_DEVICE_ID_VIA_XM266, "PM266/KM266"), + /* CLE266 */ + ID(PCI_DEVICE_ID_VIA_862X_0, "CLE266"), + ID(PCI_DEVICE_ID_VIA_8377_0, "KT400/KT400A/KT600"), + /* VT8604 / VT8605 / VT8603 (Apollo Pro133A chipset with S3 Savage4) */ + ID(PCI_DEVICE_ID_VIA_8605_0, "ProSavage PM133/PL133/PN133"), + /* P4M266x/P4N266 */ + ID(PCI_DEVICE_ID_VIA_8703_51_0, "P4M266x/P4N266"), + /* VT8754 */ + ID(PCI_DEVICE_ID_VIA_8754C_0, "PT800"), + /* P4X600 */ + ID(PCI_DEVICE_ID_VIA_8763_0, "P4X600"), + /* KM400 */ + ID(PCI_DEVICE_ID_VIA_8378_0, "KM400/KM400A"), + /* PT880 */ + ID(PCI_DEVICE_ID_VIA_PT880, "PT880"), + /* PT880 Ultra */ + ID(PCI_DEVICE_ID_VIA_PT880ULTRA, "PT880 Ultra"), + /* PT890 */ + ID(PCI_DEVICE_ID_VIA_8783_0, "PT890"), + /* PM800/PN800/PM880/PN880 */ + ID(PCI_DEVICE_ID_VIA_PX8X0_0, "PM800/PN800/PM880/PN880"), + /* KT880 */ + ID(PCI_DEVICE_ID_VIA_3269_0, "KT880"), + /* KTxxx/Px8xx */ + ID(PCI_DEVICE_ID_VIA_83_87XX_1, "VT83xx/VT87xx/KTxxx/Px8xx"), + /* P4M800 */ + ID(PCI_DEVICE_ID_VIA_3296_0, "P4M800"), + /* P4M800CE */ + ID(PCI_DEVICE_ID_VIA_P4M800CE, "VT3314"), + /* VT3324 / CX700 */ + ID(PCI_DEVICE_ID_VIA_VT3324, "CX700"), + /* VT3336 - this is a chipset for AMD Athlon/K8 CPU. Due to K8's unique + * architecture, the AGP resource and behavior are different from + * the traditional AGP which resides only in chipset. AGP is used + * by 3D driver which wasn't available for the VT3336 and VT3364 + * generation until now. Unfortunately, by testing, VT3364 works + * but VT3336 doesn't. - explanation from via, just leave this as + * a placeholder to avoid future patches adding it back in. + */ +#if 0 + ID(PCI_DEVICE_ID_VIA_VT3336, "VT3336"), +#endif + /* P4M890 */ + ID(PCI_DEVICE_ID_VIA_P4M890, "P4M890"), + /* P4M900 */ + ID(PCI_DEVICE_ID_VIA_VT3364, "P4M900"), { } }; diff --git a/drivers/ipack/carriers/tpci200.c b/drivers/ipack/carriers/tpci200.c index 05dcb6675cd6..1cf51f763293 100644 --- a/drivers/ipack/carriers/tpci200.c +++ b/drivers/ipack/carriers/tpci200.c @@ -562,7 +562,6 @@ static int tpci200_pci_probe(struct pci_dev *pdev, /* Save struct pci_dev pointer */ tpci200->info->pdev = pdev; - tpci200->info->id_table = (struct pci_device_id *)id; /* register the device and initialize it */ ret = tpci200_install(tpci200); diff --git a/drivers/ipack/carriers/tpci200.h b/drivers/ipack/carriers/tpci200.h index e79ac64abcff..a2bf3125794b 100644 --- a/drivers/ipack/carriers/tpci200.h +++ b/drivers/ipack/carriers/tpci200.h @@ -145,7 +145,6 @@ struct tpci200_slot { */ struct tpci200_infos { struct pci_dev *pdev; - struct pci_device_id *id_table; struct tpci200_regs __iomem *interface_regs; void __iomem *cfg_regs; struct ipack_bus_device *ipack_bus; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 0da85d36647d..bfe3268dfdc1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -130,7 +130,6 @@ struct mlxsw_pci { } comp; } cmd; struct mlxsw_bus_info bus_info; - const struct pci_device_id *id; enum mlxsw_pci_cqe_v max_cqe_ver; /* Maximal supported CQE version */ u8 num_cqs; /* Number of CQs */ u8 num_sdqs; /* Number of SDQs */ @@ -1768,7 +1767,6 @@ static void mlxsw_pci_mbox_free(struct mlxsw_pci *mlxsw_pci, } static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci, - const struct pci_device_id *id, u32 *p_sys_status) { unsigned long end; @@ -1839,7 +1837,7 @@ static int mlxsw_pci_reset_sw(struct mlxsw_pci *mlxsw_pci) } static int -mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) +mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci) { struct pci_dev *pdev = mlxsw_pci->pdev; bool pci_reset_sbr_supported = false; @@ -1848,7 +1846,7 @@ mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) u32 sys_status; int err; - err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); + err = mlxsw_pci_sys_ready_wait(mlxsw_pci, &sys_status); if (err) { dev_err(&pdev->dev, "Failed to reach system ready status before reset. Status is 0x%x\n", sys_status); @@ -1880,7 +1878,7 @@ mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id) if (err) return err; - err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status); + err = mlxsw_pci_sys_ready_wait(mlxsw_pci, &sys_status); if (err) { dev_err(&pdev->dev, "Failed to reach system ready status after reset. Status is 0x%x\n", sys_status); @@ -1932,7 +1930,7 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, if (!mbox) return -ENOMEM; - err = mlxsw_pci_reset(mlxsw_pci, mlxsw_pci->id); + err = mlxsw_pci_reset(mlxsw_pci); if (err) goto err_reset; @@ -2464,7 +2462,6 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); mlxsw_pci->bus_info.dev = &pdev->dev; mlxsw_pci->bus_info.read_clock_capable = true; - mlxsw_pci->id = id; err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, &mlxsw_pci_bus, mlxsw_pci, false, diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f36778e62ac1..e16aa59dd7ac 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -30,6 +30,47 @@ struct pci_dynid { }; /** + * do_pci_add_dynid - Add a new PCI device ID to this driver and re-probe + * @drv: target PCI driver + * @id: ID to be added + * @check_dup: whether to check if matching ID is already present + * + * Add a new dynamic PCI device ID to this driver and causes the driver to + * probe for all devices again. @drv must have been registered prior to calling + * this function. + * + * Context: Does GFP_KERNEL allocation. + * + * Return: 0 on success, -errno on failure. + */ +static int do_pci_add_dynid(struct pci_driver *drv, + const struct pci_device_id *id, + bool check_dup) +{ + struct pci_dynid *dynid, *existing_dynid; + + dynid = kzalloc_obj(*dynid); + if (!dynid) + return -ENOMEM; + + dynid->id = *id; + + scoped_guard(spinlock, &drv->dynids.lock) { + if (check_dup) { + list_for_each_entry(existing_dynid, &drv->dynids.list, node) { + if (pci_match_one_id(&existing_dynid->id, id)) { + kfree(dynid); + return -EEXIST; + } + } + } + list_add_tail(&dynid->node, &drv->dynids.list); + } + + return driver_attach(&drv->driver); +} + +/** * pci_add_dynid - add a new PCI device ID to this driver and re-probe devices * @drv: target pci driver * @vendor: PCI vendor ID @@ -56,25 +97,17 @@ int pci_add_dynid(struct pci_driver *drv, unsigned int class, unsigned int class_mask, unsigned long driver_data) { - struct pci_dynid *dynid; - - dynid = kzalloc_obj(*dynid); - if (!dynid) - return -ENOMEM; - - dynid->id.vendor = vendor; - dynid->id.device = device; - dynid->id.subvendor = subvendor; - dynid->id.subdevice = subdevice; - dynid->id.class = class; - dynid->id.class_mask = class_mask; - dynid->id.driver_data = driver_data; - - spin_lock(&drv->dynids.lock); - list_add_tail(&dynid->node, &drv->dynids.list); - spin_unlock(&drv->dynids.lock); - - return driver_attach(&drv->driver); + struct pci_device_id id = { + .vendor = vendor, + .device = device, + .subvendor = subvendor, + .subdevice = subdevice, + .class = class, + .class_mask = class_mask, + .driver_data = driver_data, + }; + + return do_pci_add_dynid(drv, &id, false); } EXPORT_SYMBOL_GPL(pci_add_dynid); @@ -91,6 +124,31 @@ static void pci_free_dynids(struct pci_driver *drv) } /** + * do_pci_match_id - See if a PCI ID matches a given pci_id table + * @ids: array of PCI device ID structures to search in + * @dev_id: the actual PCI device ID structure to match against. + * @include_override_only: also match against device ID entries marked as + * override only. + * + * Return: the matching pci_device_id structure or %NULL if there is no match. + */ +static const struct pci_device_id * +do_pci_match_id(const struct pci_device_id *ids, + const struct pci_device_id *dev_id, + bool include_override_only) +{ + if (ids) { + while (ids->vendor || ids->subvendor || ids->class_mask) { + if ((!ids->override_only || include_override_only) && + pci_match_one_id(ids, dev_id)) + return ids; + ids++; + } + } + return NULL; +} + +/** * pci_match_id - See if a PCI device matches a given pci_id table * @ids: array of PCI device ID structures to search in * @dev: the PCI device structure to match against. @@ -105,14 +163,9 @@ static void pci_free_dynids(struct pci_driver *drv) const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev) { - if (ids) { - while (ids->vendor || ids->subvendor || ids->class_mask) { - if (pci_match_one_device(ids, dev)) - return ids; - ids++; - } - } - return NULL; + struct pci_device_id dev_id = pci_id_from_device(dev); + + return do_pci_match_id(ids, &dev_id, true); } EXPORT_SYMBOL(pci_match_id); @@ -127,6 +180,7 @@ static const struct pci_device_id pci_device_id_any = { * pci_match_device - See if a device matches a driver's list of IDs * @drv: the PCI driver to match against * @dev: the PCI device structure to match against + * @id_copy: place to store copy of pci_device_id for dynamic ID * * Used by a driver to check whether a PCI device is in its list of * supported devices or in the dynids list, which may have been augmented @@ -134,10 +188,11 @@ static const struct pci_device_id pci_device_id_any = { * structure or %NULL if there is no match. */ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, - struct pci_dev *dev) + struct pci_dev *dev, + struct pci_device_id *id_copy) { - struct pci_dynid *dynid; - const struct pci_device_id *found_id = NULL, *ids; + const struct pci_device_id *found_id = NULL; + struct pci_device_id dev_id; int ret; /* When driver_override is set, only bind to the matching driver */ @@ -145,45 +200,29 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, if (ret == 0) return NULL; + dev_id = pci_id_from_device(dev); /* Look at the dynamic ids first, before the static ones */ - spin_lock(&drv->dynids.lock); - list_for_each_entry(dynid, &drv->dynids.list, node) { - if (pci_match_one_device(&dynid->id, dev)) { - found_id = &dynid->id; - break; + scoped_guard(spinlock, &drv->dynids.lock) { + struct pci_dynid *dynid; + + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (pci_match_one_id(&dynid->id, &dev_id)) { + *id_copy = dynid->id; + return id_copy; + } } } - spin_unlock(&drv->dynids.lock); + found_id = do_pci_match_id(drv->id_table, &dev_id, ret > 0); if (found_id) return found_id; - for (ids = drv->id_table; (found_id = pci_match_id(ids, dev)); - ids = found_id + 1) { - /* - * The match table is split based on driver_override. - * In case override_only was set, enforce driver_override - * matching. - */ - if (found_id->override_only) { - if (ret > 0) - return found_id; - } else { - return found_id; - } - } - /* driver_override will always match, send a dummy id */ if (ret > 0) return &pci_device_id_any; return NULL; } -static void _pci_free_device(struct device *dev) -{ - kfree(to_pci_dev(dev)); -} - /** * new_id_store - sysfs frontend to pci_add_dynid() * @driver: target device driver @@ -197,38 +236,22 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, { struct pci_driver *pdrv = to_pci_driver(driver); const struct pci_device_id *ids = pdrv->id_table; - u32 vendor, device, subvendor = PCI_ANY_ID, - subdevice = PCI_ANY_ID, class = 0, class_mask = 0; - unsigned long driver_data = 0; + struct pci_device_id id = { + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID + }; int fields; int retval = 0; fields = sscanf(buf, "%x %x %x %x %x %x %lx", - &vendor, &device, &subvendor, &subdevice, - &class, &class_mask, &driver_data); + &id.vendor, &id.device, &id.subvendor, &id.subdevice, + &id.class, &id.class_mask, &id.driver_data); if (fields < 2) return -EINVAL; if (fields != 7) { - struct pci_dev *pdev = kzalloc_obj(*pdev); - if (!pdev) - return -ENOMEM; - - pdev->vendor = vendor; - pdev->device = device; - pdev->subsystem_vendor = subvendor; - pdev->subsystem_device = subdevice; - pdev->class = class; - pdev->dev.release = _pci_free_device; - - device_initialize(&pdev->dev); - if (pci_match_device(pdrv, pdev)) - retval = -EEXIST; - - put_device(&pdev->dev); - - if (retval) - return retval; + if (do_pci_match_id(pdrv->id_table, &id, false)) + return -EEXIST; } /* Only accept driver_data values that match an existing id_table @@ -236,7 +259,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, if (ids) { retval = -EINVAL; while (ids->vendor || ids->subvendor || ids->class_mask) { - if (driver_data == ids->driver_data) { + if (id.driver_data == ids->driver_data) { retval = 0; break; } @@ -246,8 +269,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, return retval; } - retval = pci_add_dynid(pdrv, vendor, device, subvendor, subdevice, - class, class_mask, driver_data); + retval = do_pci_add_dynid(pdrv, &id, fields != 7); if (retval) return retval; return count; @@ -445,12 +467,13 @@ void pci_probe_flush_workqueue(void) static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) { const struct pci_device_id *id; + struct pci_device_id id_copy; int error = 0; if (drv->probe) { error = -ENODEV; - id = pci_match_device(drv, pci_dev); + id = pci_match_device(drv, pci_dev, &id_copy); if (id) error = pci_call_probe(drv, pci_dev, id); } @@ -1538,12 +1561,13 @@ static int pci_bus_match(struct device *dev, const struct device_driver *drv) struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *pci_drv; const struct pci_device_id *found_id; + struct pci_device_id id_copy; if (pci_dev_binding_disallowed(pci_dev)) return 0; pci_drv = (struct pci_driver *)to_pci_driver(drv); - found_id = pci_match_device(pci_drv, pci_dev); + found_id = pci_match_device(pci_drv, pci_dev, &id_copy); if (found_id) return 1; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 02ee26ee9206..b845b9b2758e 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -442,21 +442,40 @@ static inline int pci_setup_cardbus(char *str) { return -ENOENT; } #endif /* CONFIG_CARDBUS */ /** - * pci_match_one_device - Tell if a PCI device structure has a matching - * PCI device id structure - * @id: single PCI device id structure to match - * @dev: the PCI device structure to match against + * pci_id_from_device - Obtain a pci_device_id from a PCI device + * @dev: the PCI device * - * Returns the matching pci_device_id structure or %NULL if there is no match. + * Return: a pci_device_id filled. */ -static inline const struct pci_device_id * -pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) +static inline struct pci_device_id pci_id_from_device(const struct pci_dev *dev) { - if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && - (id->device == PCI_ANY_ID || id->device == dev->device) && - (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) && - (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) && - !((id->class ^ dev->class) & id->class_mask)) + return (struct pci_device_id) { + .vendor = dev->vendor, + .device = dev->device, + .subvendor = dev->subsystem_vendor, + .subdevice = dev->subsystem_device, + .class = dev->class, + }; +} + +/** + * pci_match_one_id - Tell if a PCI device ID matches a needle PCI device ID + * @id: single PCI device id structure to match against (needle) + * @dev_id: the actual ID from the PCI device + * + * ID can be retrieved from device using pci_id_from_device(). + * + * Return: the matching pci_device_id structure or %NULL if there is no match. + */ +static inline const struct pci_device_id * +pci_match_one_id(const struct pci_device_id *id, + const struct pci_device_id *dev_id) +{ + if ((id->vendor == PCI_ANY_ID || id->vendor == dev_id->vendor) && + (id->device == PCI_ANY_ID || id->device == dev_id->device) && + (id->subvendor == PCI_ANY_ID || id->subvendor == dev_id->subvendor) && + (id->subdevice == PCI_ANY_ID || id->subdevice == dev_id->subdevice) && + !((id->class ^ dev_id->class) & id->class_mask)) return id; return NULL; } diff --git a/drivers/pci/search.c b/drivers/pci/search.c index e3d3177fce54..34f8de551d58 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -245,8 +245,10 @@ static int match_pci_dev_by_id(struct device *dev, const void *data) { struct pci_dev *pdev = to_pci_dev(dev); const struct pci_device_id *id = data; + struct pci_device_id dev_id; - if (pci_match_one_device(id, pdev)) + dev_id = pci_id_from_device(pdev); + if (pci_match_one_id(id, &dev_id)) return 1; return 0; } @@ -416,9 +418,9 @@ EXPORT_SYMBOL(pci_get_class); * @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 + * Iterate 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. + * incremented. See pci_match_one_id() to figure out how 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 diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index e893d5677241..9c9281222a0a 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -1470,7 +1470,7 @@ static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host) (nsp32_read2(base, INDEX_REG) >> 8) & 0xff); mode_reg = nsp32_index_read1(base, CHIP_MODE); - model = data->pci_devid->driver_data; + model = data->model; #ifdef CONFIG_PM seq_printf(m, "Power Management: %s\n", @@ -2907,8 +2907,8 @@ static int nsp32_eh_host_reset(struct scsi_cmnd *SCpnt) */ static int nsp32_getprom_param(nsp32_hw_data *data) { - int vendor = data->pci_devid->vendor; - int device = data->pci_devid->device; + int vendor = data->Pci->vendor; + int device = data->Pci->device; int ret, i; int __maybe_unused val; @@ -3340,7 +3340,7 @@ static int nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id) } data->Pci = pdev; - data->pci_devid = id; + data->model = id->driver_data; data->IrqNumber = pdev->irq; data->BaseAddress = pci_resource_start(pdev, 0); data->NumAddress = pci_resource_len (pdev, 0); diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h index 924889f8bd37..9e65771cb592 100644 --- a/drivers/scsi/nsp32.h +++ b/drivers/scsi/nsp32.h @@ -564,10 +564,10 @@ typedef struct _nsp32_hw_data { struct scsi_cmnd *CurrentSC; - struct pci_dev *Pci; - const struct pci_device_id *pci_devid; - struct Scsi_Host *Host; - spinlock_t Lock; + struct pci_dev *Pci; + int model; + struct Scsi_Host *Host; + spinlock_t Lock; char info_str[100]; |
