diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2013-11-12 13:33:06 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-11-15 08:08:37 -0500 |
commit | 7a572a3ab1d1d346fcde5243914a18b0218780e9 (patch) | |
tree | 35fc7fdac2f24256204467609a3c0455fe51e836 /arch/s390/pci/pci.c | |
parent | d1e61fe49fd450be15d402ac353784f5ba8a624e (diff) |
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>
Diffstat (limited to 'arch/s390/pci/pci.c')
-rw-r--r-- | arch/s390/pci/pci.c | 147 |
1 files changed, 83 insertions, 64 deletions
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 0c9a17780e4b..63a086072edb 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
@@ -579,37 +579,6 @@ static void zpci_irq_exit(void) | |||
579 | unregister_adapter_interrupt(&zpci_airq); | 579 | unregister_adapter_interrupt(&zpci_airq); |
580 | } | 580 | } |
581 | 581 | ||
582 | static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, | ||
583 | unsigned long flags, int domain) | ||
584 | { | ||
585 | struct resource *r; | ||
586 | char *name; | ||
587 | int rc; | ||
588 | |||
589 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
590 | if (!r) | ||
591 | return ERR_PTR(-ENOMEM); | ||
592 | r->start = start; | ||
593 | r->end = r->start + size - 1; | ||
594 | r->flags = flags; | ||
595 | r->parent = &iomem_resource; | ||
596 | name = kmalloc(18, GFP_KERNEL); | ||
597 | if (!name) { | ||
598 | kfree(r); | ||
599 | return ERR_PTR(-ENOMEM); | ||
600 | } | ||
601 | sprintf(name, "PCI Bus: %04x:%02x", domain, ZPCI_BUS_NR); | ||
602 | r->name = name; | ||
603 | |||
604 | rc = request_resource(&iomem_resource, r); | ||
605 | if (rc) { | ||
606 | kfree(r->name); | ||
607 | kfree(r); | ||
608 | return ERR_PTR(-ENOMEM); | ||
609 | } | ||
610 | return r; | ||
611 | } | ||
612 | |||
613 | static int zpci_alloc_iomap(struct zpci_dev *zdev) | 582 | static int zpci_alloc_iomap(struct zpci_dev *zdev) |
614 | { | 583 | { |
615 | int entry; | 584 | int entry; |
@@ -633,6 +602,82 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry) | |||
633 | spin_unlock(&zpci_iomap_lock); | 602 | spin_unlock(&zpci_iomap_lock); |
634 | } | 603 | } |
635 | 604 | ||
605 | static struct resource *__alloc_res(struct zpci_dev *zdev, unsigned long start, | ||
606 | unsigned long size, unsigned long flags) | ||
607 | { | ||
608 | struct resource *r; | ||
609 | |||
610 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
611 | if (!r) | ||
612 | return NULL; | ||
613 | |||
614 | r->start = start; | ||
615 | r->end = r->start + size - 1; | ||
616 | r->flags = flags; | ||
617 | r->name = zdev->res_name; | ||
618 | |||
619 | if (request_resource(&iomem_resource, r)) { | ||
620 | kfree(r); | ||
621 | return NULL; | ||
622 | } | ||
623 | return r; | ||
624 | } | ||
625 | |||
626 | static int zpci_setup_bus_resources(struct zpci_dev *zdev, | ||
627 | struct list_head *resources) | ||
628 | { | ||
629 | unsigned long addr, size, flags; | ||
630 | struct resource *res; | ||
631 | int i, entry; | ||
632 | |||
633 | snprintf(zdev->res_name, sizeof(zdev->res_name), | ||
634 | "PCI Bus %04x:%02x", zdev->domain, ZPCI_BUS_NR); | ||
635 | |||
636 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
637 | if (!zdev->bars[i].size) | ||
638 | continue; | ||
639 | entry = zpci_alloc_iomap(zdev); | ||
640 | if (entry < 0) | ||
641 | return entry; | ||
642 | zdev->bars[i].map_idx = entry; | ||
643 | |||
644 | /* only MMIO is supported */ | ||
645 | flags = IORESOURCE_MEM; | ||
646 | if (zdev->bars[i].val & 8) | ||
647 | flags |= IORESOURCE_PREFETCH; | ||
648 | if (zdev->bars[i].val & 4) | ||
649 | flags |= IORESOURCE_MEM_64; | ||
650 | |||
651 | addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48); | ||
652 | |||
653 | size = 1UL << zdev->bars[i].size; | ||
654 | |||
655 | res = __alloc_res(zdev, addr, size, flags); | ||
656 | if (!res) { | ||
657 | zpci_free_iomap(zdev, entry); | ||
658 | return -ENOMEM; | ||
659 | } | ||
660 | zdev->bars[i].res = res; | ||
661 | pci_add_resource(resources, res); | ||
662 | } | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static void zpci_cleanup_bus_resources(struct zpci_dev *zdev) | ||
668 | { | ||
669 | int i; | ||
670 | |||
671 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
672 | if (!zdev->bars[i].size) | ||
673 | continue; | ||
674 | |||
675 | zpci_free_iomap(zdev, zdev->bars[i].map_idx); | ||
676 | release_resource(zdev->bars[i].res); | ||
677 | kfree(zdev->bars[i].res); | ||
678 | } | ||
679 | } | ||
680 | |||
636 | int pcibios_add_device(struct pci_dev *pdev) | 681 | int pcibios_add_device(struct pci_dev *pdev) |
637 | { | 682 | { |
638 | struct zpci_dev *zdev = get_zdev(pdev); | 683 | struct zpci_dev *zdev = get_zdev(pdev); |
@@ -731,45 +776,19 @@ struct dev_pm_ops pcibios_pm_ops = { | |||
731 | 776 | ||
732 | static int zpci_scan_bus(struct zpci_dev *zdev) | 777 | static int zpci_scan_bus(struct zpci_dev *zdev) |
733 | { | 778 | { |
734 | struct resource *res; | ||
735 | LIST_HEAD(resources); | 779 | LIST_HEAD(resources); |
736 | int i; | 780 | int ret; |
737 | |||
738 | /* allocate mapping entry for each used bar */ | ||
739 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
740 | unsigned long addr, size, flags; | ||
741 | int entry; | ||
742 | |||
743 | if (!zdev->bars[i].size) | ||
744 | continue; | ||
745 | entry = zpci_alloc_iomap(zdev); | ||
746 | if (entry < 0) | ||
747 | return entry; | ||
748 | zdev->bars[i].map_idx = entry; | ||
749 | |||
750 | /* only MMIO is supported */ | ||
751 | flags = IORESOURCE_MEM; | ||
752 | if (zdev->bars[i].val & 8) | ||
753 | flags |= IORESOURCE_PREFETCH; | ||
754 | if (zdev->bars[i].val & 4) | ||
755 | flags |= IORESOURCE_MEM_64; | ||
756 | |||
757 | addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48); | ||
758 | |||
759 | size = 1UL << zdev->bars[i].size; | ||
760 | 781 | ||
761 | res = zpci_alloc_bus_resource(addr, size, flags, zdev->domain); | 782 | ret = zpci_setup_bus_resources(zdev, &resources); |
762 | if (IS_ERR(res)) { | 783 | if (ret) |
763 | zpci_free_iomap(zdev, entry); | 784 | return ret; |
764 | return PTR_ERR(res); | ||
765 | } | ||
766 | pci_add_resource(&resources, res); | ||
767 | } | ||
768 | 785 | ||
769 | zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, | 786 | zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, |
770 | zdev, &resources); | 787 | zdev, &resources); |
771 | if (!zdev->bus) | 788 | if (!zdev->bus) { |
789 | zpci_cleanup_bus_resources(zdev); | ||
772 | return -EIO; | 790 | return -EIO; |
791 | } | ||
773 | 792 | ||
774 | zdev->bus->max_bus_speed = zdev->max_bus_speed; | 793 | zdev->bus->max_bus_speed = zdev->max_bus_speed; |
775 | return 0; | 794 | return 0; |