s390/pci: remove pdev pointer from arch data
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Fri, 29 Jan 2016 14:13:30 +0000 (15:13 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 23 Feb 2016 07:56:16 +0000 (08:56 +0100)
For each PCI function we need to maintain arch specific data in
struct zpci_dev which also contains a pointer to struct pci_dev.

When a function is registered or deregistered (which is triggered by PCI
common code) we need to adjust that pointer which could interfere with
the machine check handler (triggered by FW) using zpci_dev->pdev.

Since multiple instances of the same pdev could exist at a time this can't
be solved with locking.

Fix that by ditching the pdev pointer and use a bus walk to reach
struct pci_dev (only one instance of a pdev can be registered at the bus
at a time).

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/pci.h
arch/s390/pci/pci.c
arch/s390/pci/pci_debug.c
arch/s390/pci/pci_dma.c
arch/s390/pci/pci_event.c
drivers/pci/hotplug/s390_pci_hpc.c

index c873e682b67f8e4063628a1726a896a167a9d8c4..dc763eae7c493381ccf8976b1a08ff9091696e87 100644 (file)
@@ -66,7 +66,6 @@ struct s390_domain;
 
 /* Private data per function */
 struct zpci_dev {
-       struct pci_dev  *pdev;
        struct pci_bus  *bus;
        struct list_head entry;         /* list of all zpci_devices, needed for hotplug, etc. */
 
@@ -192,7 +191,7 @@ int zpci_fmb_disable_device(struct zpci_dev *);
 /* Debug */
 int zpci_debug_init(void);
 void zpci_debug_exit(void);
-void zpci_debug_init_device(struct zpci_dev *);
+void zpci_debug_init_device(struct zpci_dev *, const char *);
 void zpci_debug_exit_device(struct zpci_dev *);
 void zpci_debug_info(struct zpci_dev *, struct seq_file *);
 
index 8f19c8f9d660570839a69f60477f855181ba4e7c..f76d01e69fb8f220a1c1bd7f849d381c71076348 100644 (file)
@@ -637,11 +637,9 @@ static void zpci_cleanup_bus_resources(struct zpci_dev *zdev)
 
 int pcibios_add_device(struct pci_dev *pdev)
 {
-       struct zpci_dev *zdev = to_zpci(pdev);
        struct resource *res;
        int i;
 
-       zdev->pdev = pdev;
        pdev->dev.groups = zpci_attr_groups;
        zpci_map_resources(pdev);
 
@@ -664,8 +662,7 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
        struct zpci_dev *zdev = to_zpci(pdev);
 
-       zdev->pdev = pdev;
-       zpci_debug_init_device(zdev);
+       zpci_debug_init_device(zdev, dev_name(&pdev->dev));
        zpci_fmb_enable_device(zdev);
 
        return pci_enable_resources(pdev, mask);
@@ -677,7 +674,6 @@ void pcibios_disable_device(struct pci_dev *pdev)
 
        zpci_fmb_disable_device(zdev);
        zpci_debug_exit_device(zdev);
-       zdev->pdev = NULL;
 }
 
 #ifdef CONFIG_HIBERNATE_CALLBACKS
index 4129b0a5fd780f1f1b74260ee6be656ff93d91c1..c555de3d12d6b987842a31f77f201c53f779a368 100644 (file)
@@ -128,10 +128,9 @@ static const struct file_operations debugfs_pci_perf_fops = {
        .release = single_release,
 };
 
-void zpci_debug_init_device(struct zpci_dev *zdev)
+void zpci_debug_init_device(struct zpci_dev *zdev, const char *name)
 {
-       zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev),
-                                              debugfs_root);
+       zdev->debugfs_dev = debugfs_create_dir(name, debugfs_root);
        if (IS_ERR(zdev->debugfs_dev))
                zdev->debugfs_dev = NULL;
 
index 4638b93c763243908ae8bfe61816aed2c8761816..a06ce8037cec0257f805dd211d7ea4cfecbb5fd2 100644 (file)
@@ -217,27 +217,29 @@ void dma_cleanup_tables(unsigned long *table)
        dma_free_cpu_table(table);
 }
 
-static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev,
+static unsigned long __dma_alloc_iommu(struct device *dev,
                                       unsigned long start, int size)
 {
+       struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
        unsigned long boundary_size;
 
-       boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1,
+       boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
                              PAGE_SIZE) >> PAGE_SHIFT;
        return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,
                                start, size, 0, boundary_size, 0);
 }
 
-static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size)
+static unsigned long dma_alloc_iommu(struct device *dev, int size)
 {
+       struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
        unsigned long offset, flags;
        int wrap = 0;
 
        spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
-       offset = __dma_alloc_iommu(zdev, zdev->next_bit, size);
+       offset = __dma_alloc_iommu(dev, zdev->next_bit, size);
        if (offset == -1) {
                /* wrap-around */
-               offset = __dma_alloc_iommu(zdev, 0, size);
+               offset = __dma_alloc_iommu(dev, 0, size);
                wrap = 1;
        }
 
@@ -251,8 +253,9 @@ static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size)
        return offset;
 }
 
-static void dma_free_iommu(struct zpci_dev *zdev, unsigned long offset, int size)
+static void dma_free_iommu(struct device *dev, unsigned long offset, int size)
 {
+       struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
        unsigned long flags;
 
        spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags);
@@ -293,7 +296,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
 
        /* This rounds up number of pages based on size and offset */
        nr_pages = iommu_num_pages(pa, size, PAGE_SIZE);
-       iommu_page_index = dma_alloc_iommu(zdev, nr_pages);
+       iommu_page_index = dma_alloc_iommu(dev, nr_pages);
        if (iommu_page_index == -1) {
                ret = -ENOSPC;
                goto out_err;
@@ -319,7 +322,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
        return dma_addr + (offset & ~PAGE_MASK);
 
 out_free:
-       dma_free_iommu(zdev, iommu_page_index, nr_pages);
+       dma_free_iommu(dev, iommu_page_index, nr_pages);
 out_err:
        zpci_err("map error:\n");
        zpci_err_dma(ret, pa);
@@ -346,7 +349,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
 
        atomic64_add(npages, &zdev->unmapped_pages);
        iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT;
-       dma_free_iommu(zdev, iommu_page_index, npages);
+       dma_free_iommu(dev, iommu_page_index, npages);
 }
 
 static void *s390_dma_alloc(struct device *dev, size_t size,
index b0e04751c5d599fbdbb4bdb68fdbed5dcb4039d5..fb2a9a560fdcfc1e414e823563d436a4ebdc90af 100644 (file)
@@ -46,11 +46,14 @@ struct zpci_ccdf_avail {
 static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
 {
        struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
-       struct pci_dev *pdev = zdev ? zdev->pdev : NULL;
+       struct pci_dev *pdev = NULL;
 
        zpci_err("error CCDF:\n");
        zpci_err_hex(ccdf, sizeof(*ccdf));
 
+       if (zdev)
+               pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN);
+
        pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n",
               pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
 
@@ -58,6 +61,7 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
                return;
 
        pdev->error_state = pci_channel_io_perm_failure;
+       pci_dev_put(pdev);
 }
 
 void zpci_event_error(void *data)
@@ -69,9 +73,12 @@ void zpci_event_error(void *data)
 static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
 {
        struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
-       struct pci_dev *pdev = zdev ? zdev->pdev : NULL;
+       struct pci_dev *pdev = NULL;
        int ret;
 
+       if (zdev)
+               pdev = pci_get_slot(zdev->bus, ZPCI_DEVFN);
+
        pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n",
                pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
        zpci_err("avail CCDF:\n");
@@ -138,6 +145,8 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
        default:
                break;
        }
+       if (pdev)
+               pci_dev_put(pdev);
 }
 
 void zpci_event_availability(void *data)
index eb5efaef06ea5572b339d2aa3cead268e57722cc..50b8b7d54416dfe1fb773103fa52516e9690155b 100644 (file)
@@ -93,13 +93,17 @@ out_deconfigure:
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
        struct slot *slot = hotplug_slot->private;
+       struct pci_dev *pdev;
        int rc;
 
        if (!zpci_fn_configured(slot->zdev->state))
                return -EIO;
 
-       if (slot->zdev->pdev)
-               pci_stop_and_remove_bus_device_locked(slot->zdev->pdev);
+       pdev = pci_get_slot(slot->zdev->bus, ZPCI_DEVFN);
+       if (pdev) {
+               pci_stop_and_remove_bus_device_locked(pdev);
+               pci_dev_put(pdev);
+       }
 
        rc = zpci_disable_device(slot->zdev);
        if (rc)