s390/pci: improve handling of bus resources
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Tue, 12 Nov 2013 18:33:06 +0000 (19:33 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 15 Nov 2013 13:08:37 +0000 (14:08 +0100)
Cleanup the functions for allocation and setup of bus resources. Do
not allocate the same name for each resource but use a per-bus name.
Also provide means to cleanup all resources allocated by a bus.

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

index 1cc185d..b9315c4 100644 (file)
@@ -63,9 +63,10 @@ enum zpci_state {
 };
 
 struct zpci_bar_struct {
+       struct resource *res;           /* bus resource */
        u32             val;            /* bar start & 3 flag bits */
-       u8              size;           /* order 2 exponent */
        u16             map_idx;        /* index into bar mapping array */
+       u8              size;           /* order 2 exponent */
 };
 
 /* Private data per function */
@@ -97,6 +98,7 @@ struct zpci_dev {
        unsigned long   iommu_pages;
        unsigned int    next_bit;
 
+       char res_name[16];
        struct zpci_bar_struct bars[PCI_BAR_COUNT];
 
        u64             start_dma;      /* Start of available DMA addresses */
index 0c9a177..63a0860 100644 (file)
@@ -579,37 +579,6 @@ static void zpci_irq_exit(void)
        unregister_adapter_interrupt(&zpci_airq);
 }
 
-static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
-                                               unsigned long flags, int domain)
-{
-       struct resource *r;
-       char *name;
-       int rc;
-
-       r = kzalloc(sizeof(*r), GFP_KERNEL);
-       if (!r)
-               return ERR_PTR(-ENOMEM);
-       r->start = start;
-       r->end = r->start + size - 1;
-       r->flags = flags;
-       r->parent = &iomem_resource;
-       name = kmalloc(18, GFP_KERNEL);
-       if (!name) {
-               kfree(r);
-               return ERR_PTR(-ENOMEM);
-       }
-       sprintf(name, "PCI Bus: %04x:%02x", domain, ZPCI_BUS_NR);
-       r->name = name;
-
-       rc = request_resource(&iomem_resource, r);
-       if (rc) {
-               kfree(r->name);
-               kfree(r);
-               return ERR_PTR(-ENOMEM);
-       }
-       return r;
-}
-
 static int zpci_alloc_iomap(struct zpci_dev *zdev)
 {
        int entry;
@@ -633,6 +602,82 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry)
        spin_unlock(&zpci_iomap_lock);
 }
 
+static struct resource *__alloc_res(struct zpci_dev *zdev, unsigned long start,
+                                   unsigned long size, unsigned long flags)
+{
+       struct resource *r;
+
+       r = kzalloc(sizeof(*r), GFP_KERNEL);
+       if (!r)
+               return NULL;
+
+       r->start = start;
+       r->end = r->start + size - 1;
+       r->flags = flags;
+       r->name = zdev->res_name;
+
+       if (request_resource(&iomem_resource, r)) {
+               kfree(r);
+               return NULL;
+       }
+       return r;
+}
+
+static int zpci_setup_bus_resources(struct zpci_dev *zdev,
+                                   struct list_head *resources)
+{
+       unsigned long addr, size, flags;
+       struct resource *res;
+       int i, entry;
+
+       snprintf(zdev->res_name, sizeof(zdev->res_name),
+                "PCI Bus %04x:%02x", zdev->domain, ZPCI_BUS_NR);
+
+       for (i = 0; i < PCI_BAR_COUNT; i++) {
+               if (!zdev->bars[i].size)
+                       continue;
+               entry = zpci_alloc_iomap(zdev);
+               if (entry < 0)
+                       return entry;
+               zdev->bars[i].map_idx = entry;
+
+               /* only MMIO is supported */
+               flags = IORESOURCE_MEM;
+               if (zdev->bars[i].val & 8)
+                       flags |= IORESOURCE_PREFETCH;
+               if (zdev->bars[i].val & 4)
+                       flags |= IORESOURCE_MEM_64;
+
+               addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48);
+
+               size = 1UL << zdev->bars[i].size;
+
+               res = __alloc_res(zdev, addr, size, flags);
+               if (!res) {
+                       zpci_free_iomap(zdev, entry);
+                       return -ENOMEM;
+               }
+               zdev->bars[i].res = res;
+               pci_add_resource(resources, res);
+       }
+
+       return 0;
+}
+
+static void zpci_cleanup_bus_resources(struct zpci_dev *zdev)
+{
+       int i;
+
+       for (i = 0; i < PCI_BAR_COUNT; i++) {
+               if (!zdev->bars[i].size)
+                       continue;
+
+               zpci_free_iomap(zdev, zdev->bars[i].map_idx);
+               release_resource(zdev->bars[i].res);
+               kfree(zdev->bars[i].res);
+       }
+}
+
 int pcibios_add_device(struct pci_dev *pdev)
 {
        struct zpci_dev *zdev = get_zdev(pdev);
@@ -731,45 +776,19 @@ struct dev_pm_ops pcibios_pm_ops = {
 
 static int zpci_scan_bus(struct zpci_dev *zdev)
 {
-       struct resource *res;
        LIST_HEAD(resources);
-       int i;
-
-       /* allocate mapping entry for each used bar */
-       for (i = 0; i < PCI_BAR_COUNT; i++) {
-               unsigned long addr, size, flags;
-               int entry;
-
-               if (!zdev->bars[i].size)
-                       continue;
-               entry = zpci_alloc_iomap(zdev);
-               if (entry < 0)
-                       return entry;
-               zdev->bars[i].map_idx = entry;
-
-               /* only MMIO is supported */
-               flags = IORESOURCE_MEM;
-               if (zdev->bars[i].val & 8)
-                       flags |= IORESOURCE_PREFETCH;
-               if (zdev->bars[i].val & 4)
-                       flags |= IORESOURCE_MEM_64;
-
-               addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48);
-
-               size = 1UL << zdev->bars[i].size;
+       int ret;
 
-               res = zpci_alloc_bus_resource(addr, size, flags, zdev->domain);
-               if (IS_ERR(res)) {
-                       zpci_free_iomap(zdev, entry);
-                       return PTR_ERR(res);
-               }
-               pci_add_resource(&resources, res);
-       }
+       ret = zpci_setup_bus_resources(zdev, &resources);
+       if (ret)
+               return ret;
 
        zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
                                      zdev, &resources);
-       if (!zdev->bus)
+       if (!zdev->bus) {
+               zpci_cleanup_bus_resources(zdev);
                return -EIO;
+       }
 
        zdev->bus->max_bus_speed = zdev->max_bus_speed;
        return 0;