diff options
Diffstat (limited to 'arch/s390/pci')
-rw-r--r-- | arch/s390/pci/pci.c | 202 | ||||
-rw-r--r-- | arch/s390/pci/pci_clp.c | 8 | ||||
-rw-r--r-- | arch/s390/pci/pci_event.c | 79 |
3 files changed, 169 insertions, 120 deletions
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 0c9a17780e4b..bf7c73d71eef 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
@@ -530,20 +530,6 @@ static void zpci_unmap_resources(struct zpci_dev *zdev) | |||
530 | } | 530 | } |
531 | } | 531 | } |
532 | 532 | ||
533 | struct zpci_dev *zpci_alloc_device(void) | ||
534 | { | ||
535 | struct zpci_dev *zdev; | ||
536 | |||
537 | /* Alloc memory for our private pci device data */ | ||
538 | zdev = kzalloc(sizeof(*zdev), GFP_KERNEL); | ||
539 | return zdev ? : ERR_PTR(-ENOMEM); | ||
540 | } | ||
541 | |||
542 | void zpci_free_device(struct zpci_dev *zdev) | ||
543 | { | ||
544 | kfree(zdev); | ||
545 | } | ||
546 | |||
547 | int pcibios_add_platform_entries(struct pci_dev *pdev) | 533 | int pcibios_add_platform_entries(struct pci_dev *pdev) |
548 | { | 534 | { |
549 | return zpci_sysfs_add_device(&pdev->dev); | 535 | return zpci_sysfs_add_device(&pdev->dev); |
@@ -579,37 +565,6 @@ static void zpci_irq_exit(void) | |||
579 | unregister_adapter_interrupt(&zpci_airq); | 565 | unregister_adapter_interrupt(&zpci_airq); |
580 | } | 566 | } |
581 | 567 | ||
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) | 568 | static int zpci_alloc_iomap(struct zpci_dev *zdev) |
614 | { | 569 | { |
615 | int entry; | 570 | int entry; |
@@ -633,6 +588,82 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry) | |||
633 | spin_unlock(&zpci_iomap_lock); | 588 | spin_unlock(&zpci_iomap_lock); |
634 | } | 589 | } |
635 | 590 | ||
591 | static struct resource *__alloc_res(struct zpci_dev *zdev, unsigned long start, | ||
592 | unsigned long size, unsigned long flags) | ||
593 | { | ||
594 | struct resource *r; | ||
595 | |||
596 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
597 | if (!r) | ||
598 | return NULL; | ||
599 | |||
600 | r->start = start; | ||
601 | r->end = r->start + size - 1; | ||
602 | r->flags = flags; | ||
603 | r->name = zdev->res_name; | ||
604 | |||
605 | if (request_resource(&iomem_resource, r)) { | ||
606 | kfree(r); | ||
607 | return NULL; | ||
608 | } | ||
609 | return r; | ||
610 | } | ||
611 | |||
612 | static int zpci_setup_bus_resources(struct zpci_dev *zdev, | ||
613 | struct list_head *resources) | ||
614 | { | ||
615 | unsigned long addr, size, flags; | ||
616 | struct resource *res; | ||
617 | int i, entry; | ||
618 | |||
619 | snprintf(zdev->res_name, sizeof(zdev->res_name), | ||
620 | "PCI Bus %04x:%02x", zdev->domain, ZPCI_BUS_NR); | ||
621 | |||
622 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
623 | if (!zdev->bars[i].size) | ||
624 | continue; | ||
625 | entry = zpci_alloc_iomap(zdev); | ||
626 | if (entry < 0) | ||
627 | return entry; | ||
628 | zdev->bars[i].map_idx = entry; | ||
629 | |||
630 | /* only MMIO is supported */ | ||
631 | flags = IORESOURCE_MEM; | ||
632 | if (zdev->bars[i].val & 8) | ||
633 | flags |= IORESOURCE_PREFETCH; | ||
634 | if (zdev->bars[i].val & 4) | ||
635 | flags |= IORESOURCE_MEM_64; | ||
636 | |||
637 | addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48); | ||
638 | |||
639 | size = 1UL << zdev->bars[i].size; | ||
640 | |||
641 | res = __alloc_res(zdev, addr, size, flags); | ||
642 | if (!res) { | ||
643 | zpci_free_iomap(zdev, entry); | ||
644 | return -ENOMEM; | ||
645 | } | ||
646 | zdev->bars[i].res = res; | ||
647 | pci_add_resource(resources, res); | ||
648 | } | ||
649 | |||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static void zpci_cleanup_bus_resources(struct zpci_dev *zdev) | ||
654 | { | ||
655 | int i; | ||
656 | |||
657 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
658 | if (!zdev->bars[i].size) | ||
659 | continue; | ||
660 | |||
661 | zpci_free_iomap(zdev, zdev->bars[i].map_idx); | ||
662 | release_resource(zdev->bars[i].res); | ||
663 | kfree(zdev->bars[i].res); | ||
664 | } | ||
665 | } | ||
666 | |||
636 | int pcibios_add_device(struct pci_dev *pdev) | 667 | int pcibios_add_device(struct pci_dev *pdev) |
637 | { | 668 | { |
638 | struct zpci_dev *zdev = get_zdev(pdev); | 669 | struct zpci_dev *zdev = get_zdev(pdev); |
@@ -729,52 +760,6 @@ struct dev_pm_ops pcibios_pm_ops = { | |||
729 | }; | 760 | }; |
730 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ | 761 | #endif /* CONFIG_HIBERNATE_CALLBACKS */ |
731 | 762 | ||
732 | static int zpci_scan_bus(struct zpci_dev *zdev) | ||
733 | { | ||
734 | struct resource *res; | ||
735 | LIST_HEAD(resources); | ||
736 | int i; | ||
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 | |||
761 | res = zpci_alloc_bus_resource(addr, size, flags, zdev->domain); | ||
762 | if (IS_ERR(res)) { | ||
763 | zpci_free_iomap(zdev, entry); | ||
764 | return PTR_ERR(res); | ||
765 | } | ||
766 | pci_add_resource(&resources, res); | ||
767 | } | ||
768 | |||
769 | zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, | ||
770 | zdev, &resources); | ||
771 | if (!zdev->bus) | ||
772 | return -EIO; | ||
773 | |||
774 | zdev->bus->max_bus_speed = zdev->max_bus_speed; | ||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | static int zpci_alloc_domain(struct zpci_dev *zdev) | 763 | static int zpci_alloc_domain(struct zpci_dev *zdev) |
779 | { | 764 | { |
780 | spin_lock(&zpci_domain_lock); | 765 | spin_lock(&zpci_domain_lock); |
@@ -795,6 +780,41 @@ static void zpci_free_domain(struct zpci_dev *zdev) | |||
795 | spin_unlock(&zpci_domain_lock); | 780 | spin_unlock(&zpci_domain_lock); |
796 | } | 781 | } |
797 | 782 | ||
783 | void pcibios_remove_bus(struct pci_bus *bus) | ||
784 | { | ||
785 | struct zpci_dev *zdev = get_zdev_by_bus(bus); | ||
786 | |||
787 | zpci_exit_slot(zdev); | ||
788 | zpci_cleanup_bus_resources(zdev); | ||
789 | zpci_free_domain(zdev); | ||
790 | |||
791 | spin_lock(&zpci_list_lock); | ||
792 | list_del(&zdev->entry); | ||
793 | spin_unlock(&zpci_list_lock); | ||
794 | |||
795 | kfree(zdev); | ||
796 | } | ||
797 | |||
798 | static int zpci_scan_bus(struct zpci_dev *zdev) | ||
799 | { | ||
800 | LIST_HEAD(resources); | ||
801 | int ret; | ||
802 | |||
803 | ret = zpci_setup_bus_resources(zdev, &resources); | ||
804 | if (ret) | ||
805 | return ret; | ||
806 | |||
807 | zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, | ||
808 | zdev, &resources); | ||
809 | if (!zdev->bus) { | ||
810 | zpci_cleanup_bus_resources(zdev); | ||
811 | return -EIO; | ||
812 | } | ||
813 | |||
814 | zdev->bus->max_bus_speed = zdev->max_bus_speed; | ||
815 | return 0; | ||
816 | } | ||
817 | |||
798 | int zpci_enable_device(struct zpci_dev *zdev) | 818 | int zpci_enable_device(struct zpci_dev *zdev) |
799 | { | 819 | { |
800 | int rc; | 820 | int rc; |
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 84147984224a..c747394029ee 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c | |||
@@ -155,9 +155,9 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured) | |||
155 | int rc; | 155 | int rc; |
156 | 156 | ||
157 | zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, configured); | 157 | zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, configured); |
158 | zdev = zpci_alloc_device(); | 158 | zdev = kzalloc(sizeof(*zdev), GFP_KERNEL); |
159 | if (IS_ERR(zdev)) | 159 | if (!zdev) |
160 | return PTR_ERR(zdev); | 160 | return -ENOMEM; |
161 | 161 | ||
162 | zdev->fh = fh; | 162 | zdev->fh = fh; |
163 | zdev->fid = fid; | 163 | zdev->fid = fid; |
@@ -178,7 +178,7 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured) | |||
178 | return 0; | 178 | return 0; |
179 | 179 | ||
180 | error: | 180 | error: |
181 | zpci_free_device(zdev); | 181 | kfree(zdev); |
182 | return rc; | 182 | return rc; |
183 | } | 183 | } |
184 | 184 | ||
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index 278e671ec9ac..800f064b0da7 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
13 | #include <asm/pci_debug.h> | 13 | #include <asm/pci_debug.h> |
14 | #include <asm/sclp.h> | ||
14 | 15 | ||
15 | /* Content Code Description for PCI Function Error */ | 16 | /* Content Code Description for PCI Function Error */ |
16 | struct zpci_ccdf_err { | 17 | struct zpci_ccdf_err { |
@@ -42,10 +43,27 @@ struct zpci_ccdf_avail { | |||
42 | u16 pec; /* PCI event code */ | 43 | u16 pec; /* PCI event code */ |
43 | } __packed; | 44 | } __packed; |
44 | 45 | ||
45 | static void zpci_event_log_avail(struct zpci_ccdf_avail *ccdf) | 46 | void zpci_event_error(void *data) |
46 | { | 47 | { |
48 | struct zpci_ccdf_err *ccdf = data; | ||
49 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); | ||
50 | |||
51 | zpci_err("error CCDF:\n"); | ||
52 | zpci_err_hex(ccdf, sizeof(*ccdf)); | ||
53 | |||
54 | if (!zdev) | ||
55 | return; | ||
56 | |||
57 | pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n", | ||
58 | pci_name(zdev->pdev), ccdf->pec, ccdf->fid); | ||
59 | } | ||
60 | |||
61 | void zpci_event_availability(void *data) | ||
62 | { | ||
63 | struct zpci_ccdf_avail *ccdf = data; | ||
47 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); | 64 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); |
48 | struct pci_dev *pdev = zdev ? zdev->pdev : NULL; | 65 | struct pci_dev *pdev = zdev ? zdev->pdev : NULL; |
66 | int ret; | ||
49 | 67 | ||
50 | pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n", | 68 | pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n", |
51 | pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); | 69 | pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); |
@@ -53,36 +71,47 @@ static void zpci_event_log_avail(struct zpci_ccdf_avail *ccdf) | |||
53 | zpci_err_hex(ccdf, sizeof(*ccdf)); | 71 | zpci_err_hex(ccdf, sizeof(*ccdf)); |
54 | 72 | ||
55 | switch (ccdf->pec) { | 73 | switch (ccdf->pec) { |
56 | case 0x0301: | 74 | case 0x0301: /* Standby -> Configured */ |
57 | zpci_enable_device(zdev); | 75 | if (!zdev || zdev->state == ZPCI_FN_STATE_CONFIGURED) |
76 | break; | ||
77 | zdev->state = ZPCI_FN_STATE_CONFIGURED; | ||
78 | ret = zpci_enable_device(zdev); | ||
79 | if (ret) | ||
80 | break; | ||
81 | pci_rescan_bus(zdev->bus); | ||
58 | break; | 82 | break; |
59 | case 0x0302: | 83 | case 0x0302: /* Reserved -> Standby */ |
60 | clp_add_pci_device(ccdf->fid, ccdf->fh, 0); | 84 | clp_add_pci_device(ccdf->fid, ccdf->fh, 0); |
61 | break; | 85 | break; |
62 | case 0x0306: | 86 | case 0x0303: /* Deconfiguration requested */ |
87 | if (pdev) | ||
88 | pci_stop_and_remove_bus_device(pdev); | ||
89 | |||
90 | ret = zpci_disable_device(zdev); | ||
91 | if (ret) | ||
92 | break; | ||
93 | |||
94 | ret = sclp_pci_deconfigure(zdev->fid); | ||
95 | zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret); | ||
96 | if (!ret) | ||
97 | zdev->state = ZPCI_FN_STATE_STANDBY; | ||
98 | |||
99 | break; | ||
100 | case 0x0304: /* Configured -> Standby */ | ||
101 | if (pdev) | ||
102 | pci_stop_and_remove_bus_device(pdev); | ||
103 | |||
104 | zpci_disable_device(zdev); | ||
105 | zdev->state = ZPCI_FN_STATE_STANDBY; | ||
106 | break; | ||
107 | case 0x0306: /* 0x308 or 0x302 for multiple devices */ | ||
63 | clp_rescan_pci_devices(); | 108 | clp_rescan_pci_devices(); |
64 | break; | 109 | break; |
110 | case 0x0308: /* Standby -> Reserved */ | ||
111 | pci_stop_root_bus(zdev->bus); | ||
112 | pci_remove_root_bus(zdev->bus); | ||
113 | break; | ||
65 | default: | 114 | default: |
66 | break; | 115 | break; |
67 | } | 116 | } |
68 | } | 117 | } |
69 | |||
70 | void zpci_event_error(void *data) | ||
71 | { | ||
72 | struct zpci_ccdf_err *ccdf = data; | ||
73 | struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); | ||
74 | |||
75 | zpci_err("error CCDF:\n"); | ||
76 | zpci_err_hex(ccdf, sizeof(*ccdf)); | ||
77 | |||
78 | if (!zdev) | ||
79 | return; | ||
80 | |||
81 | pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n", | ||
82 | pci_name(zdev->pdev), ccdf->pec, ccdf->fid); | ||
83 | } | ||
84 | |||
85 | void zpci_event_availability(void *data) | ||
86 | { | ||
87 | zpci_event_log_avail(data); | ||
88 | } | ||