@@ -114,6 +114,7 @@ struct nvme_dev {
unsigned int num_vecs;
int q_depth;
u32 db_stride;
+ resource_size_t current_phys_bar;
void __iomem *bar;
unsigned long bar_mapped_size;
struct work_struct remove_work;
@@ -1678,13 +1679,16 @@ static int nvme_remap_bar(struct nvme_dev *dev, unsigned long size)
{
struct pci_dev *pdev = to_pci_dev(dev->dev);
- if (size <= dev->bar_mapped_size)
+ if (dev->bar &&
+ dev->current_phys_bar == pci_resource_start(pdev, 0) &&
+ size <= dev->bar_mapped_size)
return 0;
if (size > pci_resource_len(pdev, 0))
return -ENOMEM;
if (dev->bar)
iounmap(dev->bar);
- dev->bar = ioremap(pci_resource_start(pdev, 0), size);
+ dev->current_phys_bar = pci_resource_start(pdev, 0);
+ dev->bar = ioremap(dev->current_phys_bar, size);
if (!dev->bar) {
dev->bar_mapped_size = 0;
return -ENOMEM;
@@ -2550,6 +2554,8 @@ static void nvme_reset_work(struct work_struct *work)
if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING))
goto out;
+ nvme_remap_bar(dev, db_bar_size(dev, 0));
+
/*
* If we're called to reset a live controller first shut it down before
* moving on.
@@ -2952,6 +2958,23 @@ static void nvme_error_resume(struct pci_dev *pdev)
flush_work(&dev->ctrl.reset_work);
}
+void nvme_rescan_prepare(struct pci_dev *pdev)
+{
+ struct nvme_dev *dev = pci_get_drvdata(pdev);
+
+ nvme_dev_disable(dev, false);
+ nvme_dev_unmap(dev);
+ dev->bar = NULL;
+}
+
+void nvme_rescan_done(struct pci_dev *pdev)
+{
+ struct nvme_dev *dev = pci_get_drvdata(pdev);
+
+ nvme_dev_map(dev);
+ nvme_reset_ctrl_sync(&dev->ctrl);
+}
+
static const struct pci_error_handlers nvme_err_handler = {
.error_detected = nvme_error_detected,
.slot_reset = nvme_slot_reset,
@@ -3016,6 +3039,8 @@ static struct pci_driver nvme_driver = {
},
.sriov_configure = pci_sriov_configure_simple,
.err_handler = &nvme_err_handler,
+ .rescan_prepare = nvme_rescan_prepare,
+ .rescan_done = nvme_rescan_done,
};
static int __init nvme_init(void)
Hotplugged devices can affect the existing ones by moving their BARs. PCI subsystem will inform the NVME driver about this by invoking reset_prepare()+reset_done(), then iounmap()+ioremap() must be called. Signed-off-by: Sergey Miroshnichenko <s.miroshnichenko@yadro.com> --- drivers/nvme/host/pci.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-)