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
This commit is contained in:
Bjorn Helgaas
2026-08-21 16:40:34 -05:00
12 changed files with 235 additions and 376 deletions

View File

@@ -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[] = {

View File

@@ -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",
},
{ }
};

View File

@@ -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"),
{ }
};

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -29,6 +29,47 @@ struct pci_dynid {
struct pci_device_id id;
};
/**
* 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
@@ -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;
struct pci_device_id id = {
.vendor = vendor,
.device = device,
.subvendor = subvendor,
.subdevice = subdevice,
.class = class,
.class_mask = class_mask,
.driver_data = driver_data,
};
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);
return do_pci_add_dynid(drv, &id, false);
}
EXPORT_SYMBOL_GPL(pci_add_dynid);
@@ -90,6 +123,31 @@ static void pci_free_dynids(struct pci_driver *drv)
spin_unlock(&drv->dynids.lock);
}
/**
* 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
@@ -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;

View File

@@ -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 struct pci_device_id pci_id_from_device(const struct pci_dev *dev)
{
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_device(const struct pci_device_id *id, const struct pci_dev *dev)
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->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))
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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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];

View File

@@ -979,6 +979,7 @@ struct module;
* function returns zero when the driver chooses to
* take "ownership" of the device or an error code
* (negative number) otherwise.
* The pci_device_id parameter is only valid during probe.
* The probe function always gets called from process
* context, so it can sleep.
* @remove: The remove() function gets called whenever a device