summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 148a301a6b3c..79a5e112711a 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -188,7 +188,9 @@ static int aer_inj_read_config(struct pci_bus *bus, unsigned int devfn,
struct aer_error *err;
unsigned long flags;
struct pci_ops *ops;
+ struct pci_ops *my_ops;
int domain;
+ int rv;
spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32))
@@ -208,8 +210,19 @@ static int aer_inj_read_config(struct pci_bus *bus, unsigned int devfn,
}
out:
ops = __find_pci_bus_ops(bus);
+ /*
+ * pci_lock must already be held, so we can directly
+ * manipulate bus->ops. Many config access functions,
+ * including pci_generic_config_read() require the original
+ * bus->ops be installed to function, so temporarily put them
+ * back.
+ */
+ my_ops = bus->ops;
+ bus->ops = ops;
+ rv = ops->read(bus, devfn, where, size, val);
+ bus->ops = my_ops;
spin_unlock_irqrestore(&inject_lock, flags);
- return ops->read(bus, devfn, where, size, val);
+ return rv;
}
static int aer_inj_write_config(struct pci_bus *bus, unsigned int devfn,
@@ -220,7 +233,9 @@ static int aer_inj_write_config(struct pci_bus *bus, unsigned int devfn,
unsigned long flags;
int rw1cs;
struct pci_ops *ops;
+ struct pci_ops *my_ops;
int domain;
+ int rv;
spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32))
@@ -243,8 +258,19 @@ static int aer_inj_write_config(struct pci_bus *bus, unsigned int devfn,
}
out:
ops = __find_pci_bus_ops(bus);
+ /*
+ * pci_lock must already be held, so we can directly
+ * manipulate bus->ops. Many config access functions,
+ * including pci_generic_config_write() require the original
+ * bus->ops be installed to function, so temporarily put them
+ * back.
+ */
+ my_ops = bus->ops;
+ bus->ops = ops;
+ rv = ops->write(bus, devfn, where, size, val);
+ bus->ops = my_ops;
spin_unlock_irqrestore(&inject_lock, flags);
- return ops->write(bus, devfn, where, size, val);
+ return rv;
}
static struct pci_ops aer_inj_pci_ops = {