s390/pci: improve handling of bus resources

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>
This commit is contained in:
Sebastian Ott 2013-11-12 19:33:06 +01:00 committed by Martin Schwidefsky
parent d1e61fe49f
commit 7a572a3ab1
2 changed files with 86 additions and 65 deletions

View File

@ -63,9 +63,10 @@ enum zpci_state {
}; };
struct zpci_bar_struct { struct zpci_bar_struct {
struct resource *res; /* bus resource */
u32 val; /* bar start & 3 flag bits */ u32 val; /* bar start & 3 flag bits */
u8 size; /* order 2 exponent */
u16 map_idx; /* index into bar mapping array */ u16 map_idx; /* index into bar mapping array */
u8 size; /* order 2 exponent */
}; };
/* Private data per function */ /* Private data per function */
@ -97,6 +98,7 @@ struct zpci_dev {
unsigned long iommu_pages; unsigned long iommu_pages;
unsigned int next_bit; unsigned int next_bit;
char res_name[16];
struct zpci_bar_struct bars[PCI_BAR_COUNT]; struct zpci_bar_struct bars[PCI_BAR_COUNT];
u64 start_dma; /* Start of available DMA addresses */ u64 start_dma; /* Start of available DMA addresses */

View File

@ -579,37 +579,6 @@ static void zpci_irq_exit(void)
unregister_adapter_interrupt(&zpci_airq); 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) static int zpci_alloc_iomap(struct zpci_dev *zdev)
{ {
int entry; int entry;
@ -633,6 +602,82 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry)
spin_unlock(&zpci_iomap_lock); 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) int pcibios_add_device(struct pci_dev *pdev)
{ {
struct zpci_dev *zdev = get_zdev(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) static int zpci_scan_bus(struct zpci_dev *zdev)
{ {
struct resource *res;
LIST_HEAD(resources); LIST_HEAD(resources);
int i; int ret;
/* allocate mapping entry for each used bar */ ret = zpci_setup_bus_resources(zdev, &resources);
for (i = 0; i < PCI_BAR_COUNT; i++) { if (ret)
unsigned long addr, size, flags; return ret;
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;
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);
}
zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
zdev, &resources); zdev, &resources);
if (!zdev->bus) if (!zdev->bus) {
zpci_cleanup_bus_resources(zdev);
return -EIO; return -EIO;
}
zdev->bus->max_bus_speed = zdev->max_bus_speed; zdev->bus->max_bus_speed = zdev->max_bus_speed;
return 0; return 0;