diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-05-08 02:06:27 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-05-08 19:41:24 -0400 |
commit | 34768bc8329194b14e42ee408a84edfa40059046 (patch) | |
tree | 3fff53138966f3a58e796a71c19a3b75de86fbf7 /arch/sparc64/kernel/pci_psycho.c | |
parent | 5a4a3e592d0d66653297049373caa7ac5b4febe0 (diff) |
[SPARC64] PCI: Use root list of pbm's instead of pci_controller_info's
The idea is to move more and more things into the pbm,
with the eventual goal of eliminating the pci_controller_info
entirely as there really isn't any need for it.
This stage of the transformations requires some reworking of
the PCI error interrupt handling.
It might be tricky to get rid of the pci_controller_info parenting for
a few reasons:
1) When we get an uncorrectable or correctable error we want
to interrogate the IOMMU and streaming cache of both
PBMs for error status. These errors come from the UPA
front-end which is shared between the two PBM PCI bus
segments.
Historically speaking this is why I choose the datastructure
hierarchy of pci_controller_info-->pci_pbm_info
2) The probing does a portid/devhandle match to look for the
'other' pbm, but this is entirely an artifact and can be
eliminated trivially.
What we could do to solve #1 is to have a "buddy" pointer from one pbm
to another.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci_psycho.c')
-rw-r--r-- | arch/sparc64/kernel/pci_psycho.c | 107 |
1 files changed, 49 insertions, 58 deletions
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 0f35135a40c5..4801eb441236 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c | |||
@@ -265,12 +265,12 @@ static unsigned long stc_error_buf[128]; | |||
265 | static unsigned long stc_tag_buf[16]; | 265 | static unsigned long stc_tag_buf[16]; |
266 | static unsigned long stc_line_buf[16]; | 266 | static unsigned long stc_line_buf[16]; |
267 | 267 | ||
268 | static void __psycho_check_one_stc(struct pci_controller_info *p, | 268 | static void __psycho_check_one_stc(struct pci_pbm_info *pbm, |
269 | struct pci_pbm_info *pbm, | ||
270 | int is_pbm_a) | 269 | int is_pbm_a) |
271 | { | 270 | { |
271 | struct pci_controller_info *p = pbm->parent; | ||
272 | struct strbuf *strbuf = &pbm->stc; | 272 | struct strbuf *strbuf = &pbm->stc; |
273 | unsigned long regbase = p->pbm_A.controller_regs; | 273 | unsigned long regbase = pbm->controller_regs; |
274 | unsigned long err_base, tag_base, line_base; | 274 | unsigned long err_base, tag_base, line_base; |
275 | u64 control; | 275 | u64 control; |
276 | int i; | 276 | int i; |
@@ -362,20 +362,13 @@ static void __psycho_check_one_stc(struct pci_controller_info *p, | |||
362 | spin_unlock(&stc_buf_lock); | 362 | spin_unlock(&stc_buf_lock); |
363 | } | 363 | } |
364 | 364 | ||
365 | static void __psycho_check_stc_error(struct pci_controller_info *p, | 365 | static void __psycho_check_stc_error(struct pci_pbm_info *pbm, |
366 | unsigned long afsr, | 366 | unsigned long afsr, |
367 | unsigned long afar, | 367 | unsigned long afar, |
368 | enum psycho_error_type type) | 368 | enum psycho_error_type type) |
369 | { | 369 | { |
370 | struct pci_pbm_info *pbm; | 370 | __psycho_check_one_stc(pbm, |
371 | 371 | (pbm == &pbm->parent->pbm_A)); | |
372 | pbm = &p->pbm_A; | ||
373 | if (pbm->stc.strbuf_enabled) | ||
374 | __psycho_check_one_stc(p, pbm, 1); | ||
375 | |||
376 | pbm = &p->pbm_B; | ||
377 | if (pbm->stc.strbuf_enabled) | ||
378 | __psycho_check_one_stc(p, pbm, 0); | ||
379 | } | 372 | } |
380 | 373 | ||
381 | /* When an Uncorrectable Error or a PCI Error happens, we | 374 | /* When an Uncorrectable Error or a PCI Error happens, we |
@@ -413,12 +406,13 @@ static void __psycho_check_stc_error(struct pci_controller_info *p, | |||
413 | #define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL) | 406 | #define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL) |
414 | #define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL) | 407 | #define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL) |
415 | #define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL | 408 | #define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL |
416 | static void psycho_check_iommu_error(struct pci_controller_info *p, | 409 | static void psycho_check_iommu_error(struct pci_pbm_info *pbm, |
417 | unsigned long afsr, | 410 | unsigned long afsr, |
418 | unsigned long afar, | 411 | unsigned long afar, |
419 | enum psycho_error_type type) | 412 | enum psycho_error_type type) |
420 | { | 413 | { |
421 | struct iommu *iommu = p->pbm_A.iommu; | 414 | struct pci_controller_info *p = pbm->parent; |
415 | struct iommu *iommu = pbm->iommu; | ||
422 | unsigned long iommu_tag[16]; | 416 | unsigned long iommu_tag[16]; |
423 | unsigned long iommu_data[16]; | 417 | unsigned long iommu_data[16]; |
424 | unsigned long flags; | 418 | unsigned long flags; |
@@ -465,7 +459,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p, | |||
465 | psycho_write(iommu->iommu_control, | 459 | psycho_write(iommu->iommu_control, |
466 | control | PSYCHO_IOMMU_CTRL_DENAB); | 460 | control | PSYCHO_IOMMU_CTRL_DENAB); |
467 | for (i = 0; i < 16; i++) { | 461 | for (i = 0; i < 16; i++) { |
468 | unsigned long base = p->pbm_A.controller_regs; | 462 | unsigned long base = pbm->controller_regs; |
469 | 463 | ||
470 | iommu_tag[i] = | 464 | iommu_tag[i] = |
471 | psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL)); | 465 | psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL)); |
@@ -516,7 +510,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p, | |||
516 | (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); | 510 | (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); |
517 | } | 511 | } |
518 | } | 512 | } |
519 | __psycho_check_stc_error(p, afsr, afar, type); | 513 | __psycho_check_stc_error(pbm, afsr, afar, type); |
520 | spin_unlock_irqrestore(&iommu->lock, flags); | 514 | spin_unlock_irqrestore(&iommu->lock, flags); |
521 | } | 515 | } |
522 | 516 | ||
@@ -541,9 +535,10 @@ static void psycho_check_iommu_error(struct pci_controller_info *p, | |||
541 | 535 | ||
542 | static irqreturn_t psycho_ue_intr(int irq, void *dev_id) | 536 | static irqreturn_t psycho_ue_intr(int irq, void *dev_id) |
543 | { | 537 | { |
544 | struct pci_controller_info *p = dev_id; | 538 | struct pci_pbm_info *pbm = dev_id; |
545 | unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR; | 539 | struct pci_controller_info *p = pbm->parent; |
546 | unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR; | 540 | unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR; |
541 | unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR; | ||
547 | unsigned long afsr, afar, error_bits; | 542 | unsigned long afsr, afar, error_bits; |
548 | int reported; | 543 | int reported; |
549 | 544 | ||
@@ -593,8 +588,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id) | |||
593 | printk("(none)"); | 588 | printk("(none)"); |
594 | printk("]\n"); | 589 | printk("]\n"); |
595 | 590 | ||
596 | /* Interrogate IOMMU for error status. */ | 591 | /* Interrogate both IOMMUs for error status. */ |
597 | psycho_check_iommu_error(p, afsr, afar, UE_ERR); | 592 | psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR); |
593 | psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR); | ||
598 | 594 | ||
599 | return IRQ_HANDLED; | 595 | return IRQ_HANDLED; |
600 | } | 596 | } |
@@ -618,9 +614,10 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id) | |||
618 | 614 | ||
619 | static irqreturn_t psycho_ce_intr(int irq, void *dev_id) | 615 | static irqreturn_t psycho_ce_intr(int irq, void *dev_id) |
620 | { | 616 | { |
621 | struct pci_controller_info *p = dev_id; | 617 | struct pci_pbm_info *pbm = dev_id; |
622 | unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR; | 618 | struct pci_controller_info *p = pbm->parent; |
623 | unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR; | 619 | unsigned long afsr_reg = pbm->controller_regs + PSYCHO_CE_AFSR; |
620 | unsigned long afar_reg = pbm->controller_regs + PSYCHO_CE_AFAR; | ||
624 | unsigned long afsr, afar, error_bits; | 621 | unsigned long afsr, afar, error_bits; |
625 | int reported; | 622 | int reported; |
626 | 623 | ||
@@ -823,11 +820,11 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) | |||
823 | * a bug in the IOMMU support code or a PCI device driver. | 820 | * a bug in the IOMMU support code or a PCI device driver. |
824 | */ | 821 | */ |
825 | if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) { | 822 | if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) { |
826 | psycho_check_iommu_error(p, afsr, afar, PCI_ERR); | 823 | psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR); |
827 | pci_scan_for_target_abort(p, pbm, pbm->pci_bus); | 824 | pci_scan_for_target_abort(pbm->parent, pbm, pbm->pci_bus); |
828 | } | 825 | } |
829 | if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA)) | 826 | if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA)) |
830 | pci_scan_for_master_abort(p, pbm, pbm->pci_bus); | 827 | pci_scan_for_master_abort(pbm->parent, pbm, pbm->pci_bus); |
831 | 828 | ||
832 | /* For excessive retries, PSYCHO/PBM will abort the device | 829 | /* For excessive retries, PSYCHO/PBM will abort the device |
833 | * and there is no way to specifically check for excessive | 830 | * and there is no way to specifically check for excessive |
@@ -837,7 +834,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) | |||
837 | */ | 834 | */ |
838 | 835 | ||
839 | if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR)) | 836 | if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR)) |
840 | pci_scan_for_parity_error(p, pbm, pbm->pci_bus); | 837 | pci_scan_for_parity_error(pbm->parent, pbm, pbm->pci_bus); |
841 | 838 | ||
842 | return IRQ_HANDLED; | 839 | return IRQ_HANDLED; |
843 | } | 840 | } |
@@ -847,34 +844,33 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id) | |||
847 | #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ | 844 | #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ |
848 | #define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */ | 845 | #define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */ |
849 | #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ | 846 | #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ |
850 | static void psycho_register_error_handlers(struct pci_controller_info *p) | 847 | static void psycho_register_error_handlers(struct pci_pbm_info *pbm) |
851 | { | 848 | { |
852 | struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ | ||
853 | struct of_device *op = of_find_device_by_node(pbm->prom_node); | 849 | struct of_device *op = of_find_device_by_node(pbm->prom_node); |
854 | unsigned long base = p->pbm_A.controller_regs; | 850 | unsigned long base = pbm->controller_regs; |
855 | u64 tmp; | 851 | u64 tmp; |
856 | 852 | ||
857 | if (!op) | 853 | if (!op) |
858 | return; | 854 | return; |
859 | 855 | ||
860 | /* Psycho interrupt property order is: | 856 | /* Psycho interrupt property order is: |
861 | * 0: PCIERR PBM B INO | 857 | * 0: PCIERR INO for this PBM |
862 | * 1: UE ERR | 858 | * 1: UE ERR |
863 | * 2: CE ERR | 859 | * 2: CE ERR |
864 | * 3: POWER FAIL | 860 | * 3: POWER FAIL |
865 | * 4: SPARE HARDWARE | 861 | * 4: SPARE HARDWARE |
866 | * 5: PCIERR PBM A INO | 862 | * 5: POWER MANAGEMENT |
867 | */ | 863 | */ |
868 | 864 | ||
869 | if (op->num_irqs < 6) | 865 | if (op->num_irqs < 6) |
870 | return; | 866 | return; |
871 | 867 | ||
872 | request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p); | 868 | request_irq(op->irqs[1], psycho_ue_intr, 0, |
873 | request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p); | 869 | "PSYCHO_UE", pbm); |
874 | request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED, | 870 | request_irq(op->irqs[2], psycho_ce_intr, 0, |
875 | "PSYCHO PCIERR-A", &p->pbm_A); | 871 | "PSYCHO_CE", pbm); |
876 | request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED, | 872 | request_irq(op->irqs[0], psycho_pcierr_intr, 0, |
877 | "PSYCHO PCIERR-B", &p->pbm_B); | 873 | "PSYCHO_PCIERR", pbm); |
878 | 874 | ||
879 | /* Enable UE and CE interrupts for controller. */ | 875 | /* Enable UE and CE interrupts for controller. */ |
880 | psycho_write(base + PSYCHO_ECC_CTRL, | 876 | psycho_write(base + PSYCHO_ECC_CTRL, |
@@ -918,25 +914,16 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm) | |||
918 | pci_config_write8(addr, 64); | 914 | pci_config_write8(addr, 64); |
919 | } | 915 | } |
920 | 916 | ||
921 | static void pbm_scan_bus(struct pci_controller_info *p, | 917 | static void psycho_scan_bus(struct pci_pbm_info *pbm) |
922 | struct pci_pbm_info *pbm) | ||
923 | { | 918 | { |
919 | pbm_config_busmastering(pbm); | ||
920 | pbm->is_66mhz_capable = 0; | ||
924 | pbm->pci_bus = pci_scan_one_pbm(pbm); | 921 | pbm->pci_bus = pci_scan_one_pbm(pbm); |
925 | } | ||
926 | |||
927 | static void psycho_scan_bus(struct pci_controller_info *p) | ||
928 | { | ||
929 | pbm_config_busmastering(&p->pbm_B); | ||
930 | p->pbm_B.is_66mhz_capable = 0; | ||
931 | pbm_config_busmastering(&p->pbm_A); | ||
932 | p->pbm_A.is_66mhz_capable = 1; | ||
933 | pbm_scan_bus(p, &p->pbm_B); | ||
934 | pbm_scan_bus(p, &p->pbm_A); | ||
935 | 922 | ||
936 | /* After the PCI bus scan is complete, we can register | 923 | /* After the PCI bus scan is complete, we can register |
937 | * the error interrupt handlers. | 924 | * the error interrupt handlers. |
938 | */ | 925 | */ |
939 | psycho_register_error_handlers(p); | 926 | psycho_register_error_handlers(pbm); |
940 | } | 927 | } |
941 | 928 | ||
942 | static void psycho_iommu_init(struct pci_controller_info *p) | 929 | static void psycho_iommu_init(struct pci_controller_info *p) |
@@ -1096,6 +1083,11 @@ static void psycho_pbm_init(struct pci_controller_info *p, | |||
1096 | else | 1083 | else |
1097 | pbm = &p->pbm_B; | 1084 | pbm = &p->pbm_B; |
1098 | 1085 | ||
1086 | pbm->next = pci_pbm_root; | ||
1087 | pci_pbm_root = pbm; | ||
1088 | |||
1089 | pbm->scan_bus = psycho_scan_bus; | ||
1090 | |||
1099 | pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; | 1091 | pbm->chip_type = PBM_CHIP_TYPE_PSYCHO; |
1100 | pbm->chip_version = 0; | 1092 | pbm->chip_version = 0; |
1101 | prop = of_find_property(dp, "version#", NULL); | 1093 | prop = of_find_property(dp, "version#", NULL); |
@@ -1127,6 +1119,7 @@ void psycho_init(struct device_node *dp, char *model_name) | |||
1127 | { | 1119 | { |
1128 | struct linux_prom64_registers *pr_regs; | 1120 | struct linux_prom64_registers *pr_regs; |
1129 | struct pci_controller_info *p; | 1121 | struct pci_controller_info *p; |
1122 | struct pci_pbm_info *pbm; | ||
1130 | struct iommu *iommu; | 1123 | struct iommu *iommu; |
1131 | struct property *prop; | 1124 | struct property *prop; |
1132 | u32 upa_portid; | 1125 | u32 upa_portid; |
@@ -1137,7 +1130,9 @@ void psycho_init(struct device_node *dp, char *model_name) | |||
1137 | if (prop) | 1130 | if (prop) |
1138 | upa_portid = *(u32 *) prop->value; | 1131 | upa_portid = *(u32 *) prop->value; |
1139 | 1132 | ||
1140 | for(p = pci_controller_root; p; p = p->next) { | 1133 | for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { |
1134 | struct pci_controller_info *p = pbm->parent; | ||
1135 | |||
1141 | if (p->pbm_A.portid == upa_portid) { | 1136 | if (p->pbm_A.portid == upa_portid) { |
1142 | is_pbm_a = (p->pbm_A.prom_node == NULL); | 1137 | is_pbm_a = (p->pbm_A.prom_node == NULL); |
1143 | psycho_pbm_init(p, dp, is_pbm_a); | 1138 | psycho_pbm_init(p, dp, is_pbm_a); |
@@ -1157,13 +1152,9 @@ void psycho_init(struct device_node *dp, char *model_name) | |||
1157 | } | 1152 | } |
1158 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; | 1153 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; |
1159 | 1154 | ||
1160 | p->next = pci_controller_root; | ||
1161 | pci_controller_root = p; | ||
1162 | |||
1163 | p->pbm_A.portid = upa_portid; | 1155 | p->pbm_A.portid = upa_portid; |
1164 | p->pbm_B.portid = upa_portid; | 1156 | p->pbm_B.portid = upa_portid; |
1165 | p->index = pci_num_controllers++; | 1157 | p->index = pci_num_controllers++; |
1166 | p->scan_bus = psycho_scan_bus; | ||
1167 | p->pci_ops = &psycho_ops; | 1158 | p->pci_ops = &psycho_ops; |
1168 | 1159 | ||
1169 | prop = of_find_property(dp, "reg", NULL); | 1160 | prop = of_find_property(dp, "reg", NULL); |