Save the PCI driver name into "struct pci_dev_ser" during the PCI prepare callback. After kexec, use driver_set_override() to ensure the device is bound only to the saved driver. Clear the override after the finish callback. Signed-off-by: Chris Li <chrisl@xxxxxxxxxx> --- drivers/pci/liveupdate.c | 36 ++++++++++++++++++++++++++++++++++-- drivers/pci/pci.h | 2 ++ drivers/pci/probe.c | 2 ++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c index 6b85673f4ec20add7e49b04dc44f1bcd868adbdc..189827c6111b2c00ebb24404a205cde3f75d33c3 100644 --- a/drivers/pci/liveupdate.c +++ b/drivers/pci/liveupdate.c @@ -21,6 +21,7 @@ static LIST_HEAD(probe_devices); struct pci_dev_ser { u32 path; /* domain + bus + slot + fn */ u8 requested; + char driver_name[63]; u64 driver_data; /* driver data */ }; @@ -91,6 +92,10 @@ static int build_liveupdate_devices(struct list_head *head) static void dev_cleanup_liveupdate(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); + + if (liveupdate_state_updated()) + WARN_ON(driver_set_override(dev, &pdev->driver_override, "", 0)); dev->lu.depended = 0; dev->lu.dev_state = NULL; list_del_init(&dev->lu.lu_next); @@ -139,7 +144,13 @@ static int pci_get_device_path(struct pci_dev *pdev) static int pci_save_device_state(struct device *dev, struct pci_dev_ser *s) { struct pci_dev *pdev = to_pci_dev(dev); + const char *name = dev->driver->name; + if (!name) + return -ENXIO; + if (strlen(name) > sizeof(s->driver_name) - 1) + return -ENOSPC; + strscpy(s->driver_name, name, sizeof(s->driver_name)); s->path = pci_get_device_path(pdev); s->requested = dev->lu.requested; return 0; @@ -370,9 +381,9 @@ static void pci_dev_do_restore(struct pci_dev *dev, struct pci_dev_ser *s) dev->dev.lu.requested = 1; else dev->dev.lu.depended = 1; - pci_info(dev, "liveupdate restore [%s] data: [%llx]\n", + pci_info(dev, "liveupdate restore [%s] driver: %s data: [%llx]\n", s->requested ? "requested" : "depended", - s->driver_data); + s->driver_name, s->driver_data); list_move_tail(&dev->dev.lu.lu_next, &probe_devices); } @@ -392,6 +403,27 @@ void pci_liveupdate_restore(struct pci_dev *dev) return pci_dev_do_restore(dev, s); } +void pci_liveupdate_override_driver(struct pci_dev *dev) +{ + struct pci_dev_ser *s = dev->dev.lu.dev_state; + int ret; + int len; + + if (!s) + return; + + len = strlen(s->driver_name); + if (!len) + return; + + ret = driver_set_override(&dev->dev, + &dev->driver_override, + s->driver_name, len); + if (ret) + panic("PCI Liveupdate override driver failed: %s", s->driver_name); +} + + static int __init pci_liveupdate_init(void) { int ret; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index c9a7383753949994e031dc362920286a475fe2ab..b79a18c5e948980fe2ef3f0a10e0d795b1eee6d7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1161,8 +1161,10 @@ static inline int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int inde #ifdef CONFIG_LIVEUPDATE void pci_liveupdate_restore(struct pci_dev *dev); +void pci_liveupdate_override_driver(struct pci_dev *dev); #else static inline void pci_liveupdate_restore(struct pci_dev *dev) {} +static inline void pci_liveupdate_override_driver(struct pci_dev *dev) {} #endif #endif /* DRIVERS_PCI_H */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a0605af1a699cd07b09897172803dcba1d2da9f9..e41a1bef2083aa9184fd1c894d5de964f19d5c01 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2714,6 +2714,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) /* Set up MSI IRQ domain */ pci_set_msi_domain(dev); + pci_liveupdate_override_driver(dev); + /* Notifier could use PCI capabilities */ ret = device_add(&dev->dev); WARN_ON(ret < 0); -- 2.50.1.487.gc89ff58d15-goog