@@ -570,10 +570,55 @@ static struct miscdevice aer_inject_device = {
.fops = &aer_inject_fops,
};
+static void aer_clean_pci_bus_ops(struct pci_dev *dev)
+{
+ unsigned long flags;
+ struct pci_bus_ops *bus_ops, *tmp_ops;
+ struct pci_bus *bus;
+ bus = dev->subordinate;
+ if (!bus)
+ return;
+
+ spin_lock_irqsave(&inject_lock, flags);
+ list_for_each_entry_safe(bus_ops, tmp_ops, &pci_bus_ops_list, list)
+ if (bus_ops->bus == bus) {
+ list_del(&bus_ops->list);
+ kfree(bus_ops);
+ break;
+ }
+ spin_unlock_irqrestore(&inject_lock, flags);
+}
+
+static int aer_hp_notify_fn(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ switch (event) {
+ case BUS_NOTIFY_DEL_DEVICE:
+ aer_clean_pci_bus_ops(to_pci_dev(data));
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block aerinj_hp_notifier = {
+ .notifier_call = &aer_hp_notify_fn,
+};
static int __init aer_inject_init(void)
{
- return misc_register(&aer_inject_device);
+ int ret;
+ ret = misc_register(&aer_inject_device);
+ if (ret)
+ goto out;
+
+ ret = bus_register_notifier(&pci_bus_type, &aerinj_hp_notifier);
+ if (ret)
+ misc_deregister(&aer_inject_device);
+out:
+ return ret;
}
static void __exit aer_inject_exit(void)
@@ -582,6 +627,7 @@ static void __exit aer_inject_exit(void)
unsigned long flags;
struct pci_bus_ops *bus_ops = NULL;
+ bus_unregister_notifier(&pci_bus_type, &aerinj_hp_notifier);
misc_deregister(&aer_inject_device);
/* clean pci_bus_ops tracked in pci_bus_ops_list */