diff options
Diffstat (limited to 'arch/s390/pci/pci.c')
-rw-r--r-- | arch/s390/pci/pci.c | 83 |
1 files changed, 37 insertions, 46 deletions
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index f1e5be85d592..e2956ad39a4f 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
@@ -82,10 +82,13 @@ struct intr_bucket { | |||
82 | 82 | ||
83 | static struct intr_bucket *bucket; | 83 | static struct intr_bucket *bucket; |
84 | 84 | ||
85 | /* Adapter local summary indicator */ | 85 | /* Adapter interrupt definitions */ |
86 | static u8 *zpci_irq_si; | 86 | static void zpci_irq_handler(struct airq_struct *airq); |
87 | 87 | ||
88 | static atomic_t irq_retries = ATOMIC_INIT(0); | 88 | static struct airq_struct zpci_airq = { |
89 | .handler = zpci_irq_handler, | ||
90 | .isc = PCI_ISC, | ||
91 | }; | ||
89 | 92 | ||
90 | /* I/O Map */ | 93 | /* I/O Map */ |
91 | static DEFINE_SPINLOCK(zpci_iomap_lock); | 94 | static DEFINE_SPINLOCK(zpci_iomap_lock); |
@@ -404,7 +407,7 @@ static struct pci_ops pci_root_ops = { | |||
404 | /* store the last handled bit to implement fair scheduling of devices */ | 407 | /* store the last handled bit to implement fair scheduling of devices */ |
405 | static DEFINE_PER_CPU(unsigned long, next_sbit); | 408 | static DEFINE_PER_CPU(unsigned long, next_sbit); |
406 | 409 | ||
407 | static void zpci_irq_handler(void *dont, void *need) | 410 | static void zpci_irq_handler(struct airq_struct *airq) |
408 | { | 411 | { |
409 | unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit); | 412 | unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit); |
410 | int rescan = 0, max = aisb_max; | 413 | int rescan = 0, max = aisb_max; |
@@ -452,7 +455,6 @@ scan: | |||
452 | max = aisb_max; | 455 | max = aisb_max; |
453 | sbit = find_first_bit_left(bucket->aisb, max); | 456 | sbit = find_first_bit_left(bucket->aisb, max); |
454 | if (sbit != max) { | 457 | if (sbit != max) { |
455 | atomic_inc(&irq_retries); | ||
456 | rescan++; | 458 | rescan++; |
457 | goto scan; | 459 | goto scan; |
458 | } | 460 | } |
@@ -565,7 +567,21 @@ static void zpci_map_resources(struct zpci_dev *zdev) | |||
565 | pr_debug("BAR%i: -> start: %Lx end: %Lx\n", | 567 | pr_debug("BAR%i: -> start: %Lx end: %Lx\n", |
566 | i, pdev->resource[i].start, pdev->resource[i].end); | 568 | i, pdev->resource[i].start, pdev->resource[i].end); |
567 | } | 569 | } |
568 | }; | 570 | } |
571 | |||
572 | static void zpci_unmap_resources(struct zpci_dev *zdev) | ||
573 | { | ||
574 | struct pci_dev *pdev = zdev->pdev; | ||
575 | resource_size_t len; | ||
576 | int i; | ||
577 | |||
578 | for (i = 0; i < PCI_BAR_COUNT; i++) { | ||
579 | len = pci_resource_len(pdev, i); | ||
580 | if (!len) | ||
581 | continue; | ||
582 | pci_iounmap(pdev, (void *) pdev->resource[i].start); | ||
583 | } | ||
584 | } | ||
569 | 585 | ||
570 | struct zpci_dev *zpci_alloc_device(void) | 586 | struct zpci_dev *zpci_alloc_device(void) |
571 | { | 587 | { |
@@ -701,25 +717,20 @@ static int __init zpci_irq_init(void) | |||
701 | goto out_alloc; | 717 | goto out_alloc; |
702 | } | 718 | } |
703 | 719 | ||
704 | isc_register(PCI_ISC); | 720 | rc = register_adapter_interrupt(&zpci_airq); |
705 | zpci_irq_si = s390_register_adapter_interrupt(&zpci_irq_handler, NULL, PCI_ISC); | 721 | if (rc) |
706 | if (IS_ERR(zpci_irq_si)) { | ||
707 | rc = PTR_ERR(zpci_irq_si); | ||
708 | zpci_irq_si = NULL; | ||
709 | goto out_ai; | 722 | goto out_ai; |
710 | } | 723 | /* Set summary to 1 to be called every time for the ISC. */ |
724 | *zpci_airq.lsi_ptr = 1; | ||
711 | 725 | ||
712 | for_each_online_cpu(cpu) | 726 | for_each_online_cpu(cpu) |
713 | per_cpu(next_sbit, cpu) = 0; | 727 | per_cpu(next_sbit, cpu) = 0; |
714 | 728 | ||
715 | spin_lock_init(&bucket->lock); | 729 | spin_lock_init(&bucket->lock); |
716 | /* set summary to 1 to be called every time for the ISC */ | ||
717 | *zpci_irq_si = 1; | ||
718 | set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC); | 730 | set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC); |
719 | return 0; | 731 | return 0; |
720 | 732 | ||
721 | out_ai: | 733 | out_ai: |
722 | isc_unregister(PCI_ISC); | ||
723 | free_page((unsigned long) bucket->alloc); | 734 | free_page((unsigned long) bucket->alloc); |
724 | out_alloc: | 735 | out_alloc: |
725 | free_page((unsigned long) bucket->aisb); | 736 | free_page((unsigned long) bucket->aisb); |
@@ -732,21 +743,10 @@ static void zpci_irq_exit(void) | |||
732 | { | 743 | { |
733 | free_page((unsigned long) bucket->alloc); | 744 | free_page((unsigned long) bucket->alloc); |
734 | free_page((unsigned long) bucket->aisb); | 745 | free_page((unsigned long) bucket->aisb); |
735 | s390_unregister_adapter_interrupt(zpci_irq_si, PCI_ISC); | 746 | unregister_adapter_interrupt(&zpci_airq); |
736 | isc_unregister(PCI_ISC); | ||
737 | kfree(bucket); | 747 | kfree(bucket); |
738 | } | 748 | } |
739 | 749 | ||
740 | void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m) | ||
741 | { | ||
742 | if (!zdev) | ||
743 | return; | ||
744 | |||
745 | seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries)); | ||
746 | seq_printf(m, "aibv[0]:%016lx aibv[1]:%016lx aisb:%016lx\n", | ||
747 | get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb); | ||
748 | } | ||
749 | |||
750 | static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, | 750 | static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, |
751 | unsigned long flags, int domain) | 751 | unsigned long flags, int domain) |
752 | { | 752 | { |
@@ -810,6 +810,16 @@ int pcibios_add_device(struct pci_dev *pdev) | |||
810 | return 0; | 810 | return 0; |
811 | } | 811 | } |
812 | 812 | ||
813 | void pcibios_release_device(struct pci_dev *pdev) | ||
814 | { | ||
815 | struct zpci_dev *zdev = get_zdev(pdev); | ||
816 | |||
817 | zpci_unmap_resources(zdev); | ||
818 | zpci_fmb_disable_device(zdev); | ||
819 | zpci_debug_exit_device(zdev); | ||
820 | zdev->pdev = NULL; | ||
821 | } | ||
822 | |||
813 | static int zpci_scan_bus(struct zpci_dev *zdev) | 823 | static int zpci_scan_bus(struct zpci_dev *zdev) |
814 | { | 824 | { |
815 | struct resource *res; | 825 | struct resource *res; |
@@ -950,25 +960,6 @@ void zpci_stop_device(struct zpci_dev *zdev) | |||
950 | } | 960 | } |
951 | EXPORT_SYMBOL_GPL(zpci_stop_device); | 961 | EXPORT_SYMBOL_GPL(zpci_stop_device); |
952 | 962 | ||
953 | int zpci_scan_device(struct zpci_dev *zdev) | ||
954 | { | ||
955 | zdev->pdev = pci_scan_single_device(zdev->bus, ZPCI_DEVFN); | ||
956 | if (!zdev->pdev) { | ||
957 | pr_err("pci_scan_single_device failed for fid: 0x%x\n", | ||
958 | zdev->fid); | ||
959 | goto out; | ||
960 | } | ||
961 | |||
962 | pci_bus_add_devices(zdev->bus); | ||
963 | |||
964 | return 0; | ||
965 | out: | ||
966 | zpci_dma_exit_device(zdev); | ||
967 | clp_disable_fh(zdev); | ||
968 | return -EIO; | ||
969 | } | ||
970 | EXPORT_SYMBOL_GPL(zpci_scan_device); | ||
971 | |||
972 | static inline int barsize(u8 size) | 963 | static inline int barsize(u8 size) |
973 | { | 964 | { |
974 | return (size) ? (1 << size) >> 10 : 0; | 965 | return (size) ? (1 << size) >> 10 : 0; |