diff options
Diffstat (limited to 'arch/sparc64/kernel/pci_psycho.c')
-rw-r--r-- | arch/sparc64/kernel/pci_psycho.c | 161 |
1 files changed, 74 insertions, 87 deletions
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 0be850e6e580..70a7af092be2 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c | |||
@@ -146,24 +146,16 @@ static unsigned long stc_error_buf[128]; | |||
146 | static unsigned long stc_tag_buf[16]; | 146 | static unsigned long stc_tag_buf[16]; |
147 | static unsigned long stc_line_buf[16]; | 147 | static unsigned long stc_line_buf[16]; |
148 | 148 | ||
149 | static void __psycho_check_one_stc(struct pci_pbm_info *pbm, | 149 | static void psycho_check_stc_error(struct pci_pbm_info *pbm) |
150 | int is_pbm_a) | ||
151 | { | 150 | { |
152 | struct strbuf *strbuf = &pbm->stc; | 151 | struct strbuf *strbuf = &pbm->stc; |
153 | unsigned long regbase = pbm->controller_regs; | ||
154 | unsigned long err_base, tag_base, line_base; | 152 | unsigned long err_base, tag_base, line_base; |
155 | u64 control; | 153 | u64 control; |
156 | int i; | 154 | int i; |
157 | 155 | ||
158 | if (is_pbm_a) { | 156 | err_base = strbuf->strbuf_err_stat; |
159 | err_base = regbase + PSYCHO_STC_ERR_A; | 157 | tag_base = strbuf->strbuf_tag_diag; |
160 | tag_base = regbase + PSYCHO_STC_TAG_A; | 158 | line_base = strbuf->strbuf_line_diag; |
161 | line_base = regbase + PSYCHO_STC_LINE_A; | ||
162 | } else { | ||
163 | err_base = regbase + PSYCHO_STC_ERR_B; | ||
164 | tag_base = regbase + PSYCHO_STC_TAG_B; | ||
165 | line_base = regbase + PSYCHO_STC_LINE_B; | ||
166 | } | ||
167 | 159 | ||
168 | spin_lock(&stc_buf_lock); | 160 | spin_lock(&stc_buf_lock); |
169 | 161 | ||
@@ -239,15 +231,6 @@ static void __psycho_check_one_stc(struct pci_pbm_info *pbm, | |||
239 | spin_unlock(&stc_buf_lock); | 231 | spin_unlock(&stc_buf_lock); |
240 | } | 232 | } |
241 | 233 | ||
242 | static void __psycho_check_stc_error(struct pci_pbm_info *pbm, | ||
243 | unsigned long afsr, | ||
244 | unsigned long afar, | ||
245 | enum psycho_error_type type) | ||
246 | { | ||
247 | __psycho_check_one_stc(pbm, | ||
248 | (pbm == &pbm->parent->pbm_A)); | ||
249 | } | ||
250 | |||
251 | /* When an Uncorrectable Error or a PCI Error happens, we | 234 | /* When an Uncorrectable Error or a PCI Error happens, we |
252 | * interrogate the IOMMU state to see if it is the cause. | 235 | * interrogate the IOMMU state to see if it is the cause. |
253 | */ | 236 | */ |
@@ -386,7 +369,7 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm, | |||
386 | (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); | 369 | (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); |
387 | } | 370 | } |
388 | } | 371 | } |
389 | __psycho_check_stc_error(pbm, afsr, afar, type); | 372 | psycho_check_stc_error(pbm); |
390 | spin_unlock_irqrestore(&iommu->lock, flags); | 373 | spin_unlock_irqrestore(&iommu->lock, flags); |
391 | } | 374 | } |
392 | 375 | ||
@@ -412,7 +395,6 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm, | |||
412 | static irqreturn_t psycho_ue_intr(int irq, void *dev_id) | 395 | static irqreturn_t psycho_ue_intr(int irq, void *dev_id) |
413 | { | 396 | { |
414 | struct pci_pbm_info *pbm = dev_id; | 397 | struct pci_pbm_info *pbm = dev_id; |
415 | struct pci_controller_info *p = pbm->parent; | ||
416 | unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR; | 398 | unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR; |
417 | unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR; | 399 | unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR; |
418 | unsigned long afsr, afar, error_bits; | 400 | unsigned long afsr, afar, error_bits; |
@@ -465,8 +447,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id) | |||
465 | printk("]\n"); | 447 | printk("]\n"); |
466 | 448 | ||
467 | /* Interrogate both IOMMUs for error status. */ | 449 | /* Interrogate both IOMMUs for error status. */ |
468 | psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR); | 450 | psycho_check_iommu_error(pbm, afsr, afar, UE_ERR); |
469 | psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR); | 451 | if (pbm->sibling) |
452 | psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR); | ||
470 | 453 | ||
471 | return IRQ_HANDLED; | 454 | return IRQ_HANDLED; |
472 | } | 455 | } |
@@ -573,23 +556,18 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id) | |||
573 | #define PSYCHO_PCI_AFAR_A 0x2018UL | 556 | #define PSYCHO_PCI_AFAR_A 0x2018UL |
574 | #define PSYCHO_PCI_AFAR_B 0x4018UL | 557 | #define PSYCHO_PCI_AFAR_B 0x4018UL |
575 | 558 | ||
576 | static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a) | 559 | static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm) |
577 | { | 560 | { |
578 | unsigned long csr_reg, csr, csr_error_bits; | 561 | unsigned long csr, csr_error_bits; |
579 | irqreturn_t ret = IRQ_NONE; | 562 | irqreturn_t ret = IRQ_NONE; |
580 | u16 stat; | 563 | u16 stat; |
581 | 564 | ||
582 | if (is_pbm_a) { | 565 | csr = psycho_read(pbm->pci_csr); |
583 | csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL; | ||
584 | } else { | ||
585 | csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL; | ||
586 | } | ||
587 | csr = psycho_read(csr_reg); | ||
588 | csr_error_bits = | 566 | csr_error_bits = |
589 | csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR); | 567 | csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR); |
590 | if (csr_error_bits) { | 568 | if (csr_error_bits) { |
591 | /* Clear the errors. */ | 569 | /* Clear the errors. */ |
592 | psycho_write(csr_reg, csr); | 570 | psycho_write(pbm->pci_csr, csr); |
593 | 571 | ||
594 | /* Log 'em. */ | 572 | /* Log 'em. */ |
595 | if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR) | 573 | if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR) |
@@ -616,19 +594,12 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm | |||
616 | static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) | 594 | static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) |
617 | { | 595 | { |
618 | struct pci_pbm_info *pbm = dev_id; | 596 | struct pci_pbm_info *pbm = dev_id; |
619 | struct pci_controller_info *p = pbm->parent; | ||
620 | unsigned long afsr_reg, afar_reg; | 597 | unsigned long afsr_reg, afar_reg; |
621 | unsigned long afsr, afar, error_bits; | 598 | unsigned long afsr, afar, error_bits; |
622 | int is_pbm_a, reported; | 599 | int reported; |
623 | 600 | ||
624 | is_pbm_a = (pbm == &pbm->parent->pbm_A); | 601 | afsr_reg = pbm->pci_afsr; |
625 | if (is_pbm_a) { | 602 | afar_reg = pbm->pci_afar; |
626 | afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A; | ||
627 | afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A; | ||
628 | } else { | ||
629 | afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B; | ||
630 | afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B; | ||
631 | } | ||
632 | 603 | ||
633 | /* Latch error status. */ | 604 | /* Latch error status. */ |
634 | afar = psycho_read(afar_reg); | 605 | afar = psycho_read(afar_reg); |
@@ -641,7 +612,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) | |||
641 | PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA | | 612 | PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA | |
642 | PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR); | 613 | PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR); |
643 | if (!error_bits) | 614 | if (!error_bits) |
644 | return psycho_pcierr_intr_other(pbm, is_pbm_a); | 615 | return psycho_pcierr_intr_other(pbm); |
645 | psycho_write(afsr_reg, error_bits); | 616 | psycho_write(afsr_reg, error_bits); |
646 | 617 | ||
647 | /* Log the error. */ | 618 | /* Log the error. */ |
@@ -923,10 +894,16 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, | |||
923 | pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; | 894 | pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; |
924 | pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; | 895 | pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; |
925 | pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A; | 896 | pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A; |
897 | pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A; | ||
898 | pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A; | ||
899 | pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A; | ||
926 | } else { | 900 | } else { |
927 | pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B; | 901 | pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B; |
928 | pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; | 902 | pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; |
929 | pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; | 903 | pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; |
904 | pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B; | ||
905 | pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B; | ||
906 | pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B; | ||
930 | } | 907 | } |
931 | /* PSYCHO's streaming buffer lacks ctx flushing. */ | 908 | /* PSYCHO's streaming buffer lacks ctx flushing. */ |
932 | pbm->stc.strbuf_ctxflush = 0; | 909 | pbm->stc.strbuf_ctxflush = 0; |
@@ -971,16 +948,10 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, | |||
971 | #define PSYCHO_MEMSPACE_B 0x180000000UL | 948 | #define PSYCHO_MEMSPACE_B 0x180000000UL |
972 | #define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL | 949 | #define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL |
973 | 950 | ||
974 | static void __init psycho_pbm_init(struct pci_controller_info *p, | 951 | static void __init psycho_pbm_init(struct pci_pbm_info *pbm, |
975 | struct of_device *op, int is_pbm_a) | 952 | struct of_device *op, int is_pbm_a) |
976 | { | 953 | { |
977 | struct device_node *dp = op->node; | 954 | struct device_node *dp = op->node; |
978 | struct pci_pbm_info *pbm; | ||
979 | |||
980 | if (is_pbm_a) | ||
981 | pbm = &p->pbm_A; | ||
982 | else | ||
983 | pbm = &p->pbm_B; | ||
984 | 955 | ||
985 | pbm->next = pci_pbm_root; | 956 | pbm->next = pci_pbm_root; |
986 | pci_pbm_root = pbm; | 957 | pci_pbm_root = pbm; |
@@ -996,7 +967,6 @@ static void __init psycho_pbm_init(struct pci_controller_info *p, | |||
996 | pbm->chip_version = of_getintprop_default(dp, "version#", 0); | 967 | pbm->chip_version = of_getintprop_default(dp, "version#", 0); |
997 | pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0); | 968 | pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0); |
998 | 969 | ||
999 | pbm->parent = p; | ||
1000 | pbm->prom_node = dp; | 970 | pbm->prom_node = dp; |
1001 | pbm->name = dp->full_name; | 971 | pbm->name = dp->full_name; |
1002 | 972 | ||
@@ -1013,6 +983,17 @@ static void __init psycho_pbm_init(struct pci_controller_info *p, | |||
1013 | psycho_scan_bus(pbm, &op->dev); | 983 | psycho_scan_bus(pbm, &op->dev); |
1014 | } | 984 | } |
1015 | 985 | ||
986 | static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid) | ||
987 | { | ||
988 | struct pci_pbm_info *pbm; | ||
989 | |||
990 | for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { | ||
991 | if (pbm->portid == upa_portid) | ||
992 | return pbm; | ||
993 | } | ||
994 | return NULL; | ||
995 | } | ||
996 | |||
1016 | #define PSYCHO_CONFIGSPACE 0x001000000UL | 997 | #define PSYCHO_CONFIGSPACE 0x001000000UL |
1017 | 998 | ||
1018 | static int __devinit psycho_probe(struct of_device *op, | 999 | static int __devinit psycho_probe(struct of_device *op, |
@@ -1020,7 +1001,6 @@ static int __devinit psycho_probe(struct of_device *op, | |||
1020 | { | 1001 | { |
1021 | const struct linux_prom64_registers *pr_regs; | 1002 | const struct linux_prom64_registers *pr_regs; |
1022 | struct device_node *dp = op->node; | 1003 | struct device_node *dp = op->node; |
1023 | struct pci_controller_info *p; | ||
1024 | struct pci_pbm_info *pbm; | 1004 | struct pci_pbm_info *pbm; |
1025 | struct iommu *iommu; | 1005 | struct iommu *iommu; |
1026 | int is_pbm_a, err; | 1006 | int is_pbm_a, err; |
@@ -1028,33 +1008,26 @@ static int __devinit psycho_probe(struct of_device *op, | |||
1028 | 1008 | ||
1029 | upa_portid = of_getintprop_default(dp, "upa-portid", 0xff); | 1009 | upa_portid = of_getintprop_default(dp, "upa-portid", 0xff); |
1030 | 1010 | ||
1031 | for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { | ||
1032 | struct pci_controller_info *p = pbm->parent; | ||
1033 | |||
1034 | if (p->pbm_A.portid == upa_portid) { | ||
1035 | is_pbm_a = (p->pbm_A.prom_node == NULL); | ||
1036 | psycho_pbm_init(p, op, is_pbm_a); | ||
1037 | return 0; | ||
1038 | } | ||
1039 | } | ||
1040 | |||
1041 | err = -ENOMEM; | 1011 | err = -ENOMEM; |
1042 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | 1012 | pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); |
1043 | if (!p) { | 1013 | if (!pbm) { |
1044 | printk(KERN_ERR PFX "Cannot allocate controller info.\n"); | 1014 | printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n"); |
1045 | goto out_err; | 1015 | goto out_err; |
1046 | } | 1016 | } |
1047 | 1017 | ||
1048 | iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); | 1018 | pbm->sibling = psycho_find_sibling(upa_portid); |
1049 | if (!iommu) { | 1019 | if (pbm->sibling) { |
1050 | printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); | 1020 | iommu = pbm->sibling->iommu; |
1051 | goto out_free_controller; | 1021 | } else { |
1022 | iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL); | ||
1023 | if (!iommu) { | ||
1024 | printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); | ||
1025 | goto out_free_controller; | ||
1026 | } | ||
1052 | } | 1027 | } |
1053 | 1028 | ||
1054 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; | 1029 | pbm->iommu = iommu; |
1055 | 1030 | pbm->portid = upa_portid; | |
1056 | p->pbm_A.portid = upa_portid; | ||
1057 | p->pbm_B.portid = upa_portid; | ||
1058 | 1031 | ||
1059 | pr_regs = of_get_property(dp, "reg", NULL); | 1032 | pr_regs = of_get_property(dp, "reg", NULL); |
1060 | err = -ENODEV; | 1033 | err = -ENODEV; |
@@ -1063,29 +1036,43 @@ static int __devinit psycho_probe(struct of_device *op, | |||
1063 | goto out_free_iommu; | 1036 | goto out_free_iommu; |
1064 | } | 1037 | } |
1065 | 1038 | ||
1066 | p->pbm_A.controller_regs = pr_regs[2].phys_addr; | 1039 | is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); |
1067 | p->pbm_B.controller_regs = pr_regs[2].phys_addr; | 1040 | |
1041 | pbm->controller_regs = pr_regs[2].phys_addr; | ||
1042 | pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE); | ||
1068 | 1043 | ||
1069 | p->pbm_A.config_space = p->pbm_B.config_space = | 1044 | if (is_pbm_a) { |
1070 | (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE); | 1045 | pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A; |
1046 | pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A; | ||
1047 | pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIA_CTRL; | ||
1048 | } else { | ||
1049 | pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B; | ||
1050 | pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B; | ||
1051 | pbm->pci_csr = pbm->controller_regs + PSYCHO_PCIB_CTRL; | ||
1052 | } | ||
1071 | 1053 | ||
1072 | psycho_controller_hwinit(&p->pbm_A); | 1054 | psycho_controller_hwinit(pbm); |
1055 | if (!pbm->sibling) { | ||
1056 | err = psycho_iommu_init(pbm); | ||
1057 | if (err) | ||
1058 | goto out_free_iommu; | ||
1059 | } | ||
1073 | 1060 | ||
1074 | err = psycho_iommu_init(&p->pbm_A); | 1061 | psycho_pbm_init(pbm, op, is_pbm_a); |
1075 | if (err) | ||
1076 | goto out_free_iommu; | ||
1077 | 1062 | ||
1078 | is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); | 1063 | if (pbm->sibling) |
1064 | pbm->sibling->sibling = pbm; | ||
1079 | 1065 | ||
1080 | psycho_pbm_init(p, op, is_pbm_a); | 1066 | dev_set_drvdata(&op->dev, pbm); |
1081 | 1067 | ||
1082 | return 0; | 1068 | return 0; |
1083 | 1069 | ||
1084 | out_free_iommu: | 1070 | out_free_iommu: |
1085 | kfree(p->pbm_A.iommu); | 1071 | if (!pbm->sibling) |
1072 | kfree(pbm->iommu); | ||
1086 | 1073 | ||
1087 | out_free_controller: | 1074 | out_free_controller: |
1088 | kfree(p); | 1075 | kfree(pbm); |
1089 | 1076 | ||
1090 | out_err: | 1077 | out_err: |
1091 | return err; | 1078 | return err; |