diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-30 06:13:20 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-30 06:13:20 -0400 |
commit | b20bfe41badcbf38512fbe1118fe2e0817098e77 (patch) | |
tree | dd4e8aa8de3113af6c265c58f6f015870ed84ddd /arch/sparc64/kernel/pci_psycho.c | |
parent | 3822b50964d6702b7d8ba18ffd132d4bf786a17e (diff) |
sparc64: Convert PSYCHO PCI controller driver into a real driver.
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 | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index ef5fe29202c2..4e8f87aad205 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c | |||
@@ -17,11 +17,13 @@ | |||
17 | #include <asm/irq.h> | 17 | #include <asm/irq.h> |
18 | #include <asm/starfire.h> | 18 | #include <asm/starfire.h> |
19 | #include <asm/prom.h> | 19 | #include <asm/prom.h> |
20 | #include <asm/oplib.h> | ||
21 | 20 | ||
22 | #include "pci_impl.h" | 21 | #include "pci_impl.h" |
23 | #include "iommu_common.h" | 22 | #include "iommu_common.h" |
24 | 23 | ||
24 | #define DRIVER_NAME "psycho" | ||
25 | #define PFX DRIVER_NAME ": " | ||
26 | |||
25 | /* All PSYCHO registers are 64-bits. The following accessor | 27 | /* All PSYCHO registers are 64-bits. The following accessor |
26 | * routines are how they are accessed. The REG parameter | 28 | * routines are how they are accessed. The REG parameter |
27 | * is a physical address. | 29 | * is a physical address. |
@@ -840,7 +842,7 @@ static int psycho_iommu_init(struct pci_pbm_info *pbm) | |||
840 | control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL); | 842 | control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL); |
841 | control |= PSYCHO_IOMMU_CTRL_DENAB; | 843 | control |= PSYCHO_IOMMU_CTRL_DENAB; |
842 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control); | 844 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control); |
843 | for(i = 0; i < 16; i++) { | 845 | for (i = 0; i < 16; i++) { |
844 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0); | 846 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0); |
845 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0); | 847 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0); |
846 | } | 848 | } |
@@ -850,8 +852,10 @@ static int psycho_iommu_init(struct pci_pbm_info *pbm) | |||
850 | */ | 852 | */ |
851 | err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff, | 853 | err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff, |
852 | pbm->numa_node); | 854 | pbm->numa_node); |
853 | if (err) | 855 | if (err) { |
856 | printk(KERN_ERR PFX "iommu_table_init() fails\n"); | ||
854 | return err; | 857 | return err; |
858 | } | ||
855 | 859 | ||
856 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE, | 860 | psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE, |
857 | __pa(iommu->page_table)); | 861 | __pa(iommu->page_table)); |
@@ -982,7 +986,6 @@ static void __init psycho_pbm_init(struct pci_controller_info *p, | |||
982 | 986 | ||
983 | pbm->numa_node = -1; | 987 | pbm->numa_node = -1; |
984 | 988 | ||
985 | pbm->scan_bus = psycho_scan_bus; | ||
986 | pbm->pci_ops = &sun4u_pci_ops; | 989 | pbm->pci_ops = &sun4u_pci_ops; |
987 | pbm->config_space_reg_bits = 8; | 990 | pbm->config_space_reg_bits = 8; |
988 | 991 | ||
@@ -1002,7 +1005,7 @@ static void __init psycho_pbm_init(struct pci_controller_info *p, | |||
1002 | pbm->prom_node = dp; | 1005 | pbm->prom_node = dp; |
1003 | pbm->name = dp->full_name; | 1006 | pbm->name = dp->full_name; |
1004 | 1007 | ||
1005 | printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n", | 1008 | printk(KERN_INFO "%s: PSYCHO PCI Bus Module ver[%x:%x]\n", |
1006 | pbm->name, | 1009 | pbm->name, |
1007 | pbm->chip_version, pbm->chip_revision); | 1010 | pbm->chip_version, pbm->chip_revision); |
1008 | 1011 | ||
@@ -1011,24 +1014,28 @@ static void __init psycho_pbm_init(struct pci_controller_info *p, | |||
1011 | pci_get_pbm_props(pbm); | 1014 | pci_get_pbm_props(pbm); |
1012 | 1015 | ||
1013 | psycho_pbm_strbuf_init(pbm, is_pbm_a); | 1016 | psycho_pbm_strbuf_init(pbm, is_pbm_a); |
1017 | |||
1018 | psycho_scan_bus(pbm); | ||
1014 | } | 1019 | } |
1015 | 1020 | ||
1016 | #define PSYCHO_CONFIGSPACE 0x001000000UL | 1021 | #define PSYCHO_CONFIGSPACE 0x001000000UL |
1017 | 1022 | ||
1018 | void __init psycho_init(struct device_node *dp, char *model_name) | 1023 | static int __devinit psycho_probe(struct of_device *op, |
1024 | const struct of_device_id *match) | ||
1019 | { | 1025 | { |
1020 | struct linux_prom64_registers *pr_regs; | 1026 | const struct linux_prom64_registers *pr_regs; |
1027 | struct device_node *dp = op->node; | ||
1021 | struct pci_controller_info *p; | 1028 | struct pci_controller_info *p; |
1022 | struct pci_pbm_info *pbm; | 1029 | struct pci_pbm_info *pbm; |
1023 | struct iommu *iommu; | 1030 | struct iommu *iommu; |
1024 | struct property *prop; | 1031 | int is_pbm_a, err; |
1032 | const u32 *p32; | ||
1025 | u32 upa_portid; | 1033 | u32 upa_portid; |
1026 | int is_pbm_a; | ||
1027 | 1034 | ||
1028 | upa_portid = 0xff; | 1035 | upa_portid = 0xff; |
1029 | prop = of_find_property(dp, "upa-portid", NULL); | 1036 | p32 = of_get_property(dp, "upa-portid", NULL); |
1030 | if (prop) | 1037 | if (p32) |
1031 | upa_portid = *(u32 *) prop->value; | 1038 | upa_portid = *p32; |
1032 | 1039 | ||
1033 | for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { | 1040 | for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { |
1034 | struct pci_controller_info *p = pbm->parent; | 1041 | struct pci_controller_info *p = pbm->parent; |
@@ -1036,24 +1043,34 @@ void __init psycho_init(struct device_node *dp, char *model_name) | |||
1036 | if (p->pbm_A.portid == upa_portid) { | 1043 | if (p->pbm_A.portid == upa_portid) { |
1037 | is_pbm_a = (p->pbm_A.prom_node == NULL); | 1044 | is_pbm_a = (p->pbm_A.prom_node == NULL); |
1038 | psycho_pbm_init(p, dp, is_pbm_a); | 1045 | psycho_pbm_init(p, dp, is_pbm_a); |
1039 | return; | 1046 | return 0; |
1040 | } | 1047 | } |
1041 | } | 1048 | } |
1042 | 1049 | ||
1050 | err = -ENOMEM; | ||
1043 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | 1051 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); |
1044 | if (!p) | 1052 | if (!p) { |
1045 | goto fatal_memory_error; | 1053 | printk(KERN_ERR PFX "Cannot allocate controller info.\n"); |
1054 | goto out_free; | ||
1055 | } | ||
1056 | |||
1046 | iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); | 1057 | iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); |
1047 | if (!iommu) | 1058 | if (!iommu) { |
1048 | goto fatal_memory_error; | 1059 | printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); |
1060 | goto out_free; | ||
1061 | } | ||
1049 | 1062 | ||
1050 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; | 1063 | p->pbm_A.iommu = p->pbm_B.iommu = iommu; |
1051 | 1064 | ||
1052 | p->pbm_A.portid = upa_portid; | 1065 | p->pbm_A.portid = upa_portid; |
1053 | p->pbm_B.portid = upa_portid; | 1066 | p->pbm_B.portid = upa_portid; |
1054 | 1067 | ||
1055 | prop = of_find_property(dp, "reg", NULL); | 1068 | pr_regs = of_get_property(dp, "reg", NULL); |
1056 | pr_regs = prop->value; | 1069 | err = -ENODEV; |
1070 | if (!pr_regs) { | ||
1071 | printk(KERN_ERR PFX "No reg property.\n"); | ||
1072 | goto out_free; | ||
1073 | } | ||
1057 | 1074 | ||
1058 | p->pbm_A.controller_regs = pr_regs[2].phys_addr; | 1075 | p->pbm_A.controller_regs = pr_regs[2].phys_addr; |
1059 | p->pbm_B.controller_regs = pr_regs[2].phys_addr; | 1076 | p->pbm_B.controller_regs = pr_regs[2].phys_addr; |
@@ -1063,14 +1080,42 @@ void __init psycho_init(struct device_node *dp, char *model_name) | |||
1063 | 1080 | ||
1064 | psycho_controller_hwinit(&p->pbm_A); | 1081 | psycho_controller_hwinit(&p->pbm_A); |
1065 | 1082 | ||
1066 | if (psycho_iommu_init(&p->pbm_A)) | 1083 | err = psycho_iommu_init(&p->pbm_A); |
1067 | goto fatal_memory_error; | 1084 | if (err) |
1085 | goto out_free; | ||
1068 | 1086 | ||
1069 | is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); | 1087 | is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); |
1088 | |||
1070 | psycho_pbm_init(p, dp, is_pbm_a); | 1089 | psycho_pbm_init(p, dp, is_pbm_a); |
1071 | return; | ||
1072 | 1090 | ||
1073 | fatal_memory_error: | 1091 | return 0; |
1074 | prom_printf("PSYCHO: Fatal memory allocation error.\n"); | 1092 | |
1075 | prom_halt(); | 1093 | out_free: |
1094 | if (p) { | ||
1095 | if (p->pbm_A.iommu) | ||
1096 | kfree(p->pbm_A.iommu); | ||
1097 | kfree(p); | ||
1098 | } | ||
1099 | return err; | ||
1100 | } | ||
1101 | |||
1102 | static struct of_device_id psycho_match[] = { | ||
1103 | { | ||
1104 | .name = "pci", | ||
1105 | .compatible = "pci108e,8000", | ||
1106 | }, | ||
1107 | {}, | ||
1108 | }; | ||
1109 | |||
1110 | static struct of_platform_driver psycho_driver = { | ||
1111 | .name = DRIVER_NAME, | ||
1112 | .match_table = psycho_match, | ||
1113 | .probe = psycho_probe, | ||
1114 | }; | ||
1115 | |||
1116 | static int __init psycho_init(void) | ||
1117 | { | ||
1118 | return of_register_driver(&psycho_driver, &of_bus_type); | ||
1076 | } | 1119 | } |
1120 | |||
1121 | subsys_initcall(psycho_init); | ||