diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-30 05:50:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-30 05:50:29 -0400 |
commit | 3822b50964d6702b7d8ba18ffd132d4bf786a17e (patch) | |
tree | 577c4234ddb62b0805793c5707a54196c0c2d47b /arch/sparc64/kernel/pci_sun4v.c | |
parent | 6d19c88f53bb3471a15152ea4fbdbebd36c0046c (diff) |
sparc64: Convert SUN4V PCI controller driver into a real driver.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci_sun4v.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 123 |
1 files changed, 83 insertions, 40 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index a104c80d319d..c1e72beade2b 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
@@ -13,12 +13,10 @@ | |||
13 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
14 | #include <linux/msi.h> | 14 | #include <linux/msi.h> |
15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
16 | #include <linux/of_device.h> | ||
16 | 17 | ||
17 | #include <asm/iommu.h> | 18 | #include <asm/iommu.h> |
18 | #include <asm/irq.h> | 19 | #include <asm/irq.h> |
19 | #include <asm/upa.h> | ||
20 | #include <asm/pstate.h> | ||
21 | #include <asm/oplib.h> | ||
22 | #include <asm/hypervisor.h> | 20 | #include <asm/hypervisor.h> |
23 | #include <asm/prom.h> | 21 | #include <asm/prom.h> |
24 | 22 | ||
@@ -27,6 +25,9 @@ | |||
27 | 25 | ||
28 | #include "pci_sun4v.h" | 26 | #include "pci_sun4v.h" |
29 | 27 | ||
28 | #define DRIVER_NAME "pci_sun4v" | ||
29 | #define PFX DRIVER_NAME ": " | ||
30 | |||
30 | static unsigned long vpci_major = 1; | 31 | static unsigned long vpci_major = 1; |
31 | static unsigned long vpci_minor = 1; | 32 | static unsigned long vpci_minor = 1; |
32 | 33 | ||
@@ -583,7 +584,7 @@ static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm, | |||
583 | return cnt; | 584 | return cnt; |
584 | } | 585 | } |
585 | 586 | ||
586 | static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | 587 | static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) |
587 | { | 588 | { |
588 | struct iommu *iommu = pbm->iommu; | 589 | struct iommu *iommu = pbm->iommu; |
589 | struct property *prop; | 590 | struct property *prop; |
@@ -603,9 +604,9 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | |||
603 | } | 604 | } |
604 | 605 | ||
605 | if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) { | 606 | if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) { |
606 | prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n", | 607 | printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n", |
607 | vdma[0], vdma[1]); | 608 | vdma[0], vdma[1]); |
608 | prom_halt(); | 609 | return -EINVAL; |
609 | }; | 610 | }; |
610 | 611 | ||
611 | dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL); | 612 | dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL); |
@@ -625,8 +626,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | |||
625 | sz = (sz + 7UL) & ~7UL; | 626 | sz = (sz + 7UL) & ~7UL; |
626 | iommu->arena.map = kzalloc(sz, GFP_KERNEL); | 627 | iommu->arena.map = kzalloc(sz, GFP_KERNEL); |
627 | if (!iommu->arena.map) { | 628 | if (!iommu->arena.map) { |
628 | prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); | 629 | printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n"); |
629 | prom_halt(); | 630 | return -ENOMEM; |
630 | } | 631 | } |
631 | iommu->arena.limit = num_tsb_entries; | 632 | iommu->arena.limit = num_tsb_entries; |
632 | 633 | ||
@@ -634,6 +635,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | |||
634 | if (sz) | 635 | if (sz) |
635 | printk("%s: Imported %lu TSB entries from OBP\n", | 636 | printk("%s: Imported %lu TSB entries from OBP\n", |
636 | pbm->name, sz); | 637 | pbm->name, sz); |
638 | |||
639 | return 0; | ||
637 | } | 640 | } |
638 | 641 | ||
639 | #ifdef CONFIG_PCI_MSI | 642 | #ifdef CONFIG_PCI_MSI |
@@ -890,10 +893,11 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm) | |||
890 | } | 893 | } |
891 | #endif /* !(CONFIG_PCI_MSI) */ | 894 | #endif /* !(CONFIG_PCI_MSI) */ |
892 | 895 | ||
893 | static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, | 896 | static int __init pci_sun4v_pbm_init(struct pci_controller_info *p, |
894 | struct device_node *dp, u32 devhandle) | 897 | struct device_node *dp, u32 devhandle) |
895 | { | 898 | { |
896 | struct pci_pbm_info *pbm; | 899 | struct pci_pbm_info *pbm; |
900 | int err; | ||
897 | 901 | ||
898 | if (devhandle & 0x40) | 902 | if (devhandle & 0x40) |
899 | pbm = &p->pbm_B; | 903 | pbm = &p->pbm_B; |
@@ -905,7 +909,6 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, | |||
905 | 909 | ||
906 | pbm->numa_node = of_node_to_nid(dp); | 910 | pbm->numa_node = of_node_to_nid(dp); |
907 | 911 | ||
908 | pbm->scan_bus = pci_sun4v_scan_bus; | ||
909 | pbm->pci_ops = &sun4v_pci_ops; | 912 | pbm->pci_ops = &sun4v_pci_ops; |
910 | pbm->config_space_reg_bits = 12; | 913 | pbm->config_space_reg_bits = 12; |
911 | 914 | ||
@@ -924,50 +927,58 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, | |||
924 | pci_determine_mem_io_space(pbm); | 927 | pci_determine_mem_io_space(pbm); |
925 | 928 | ||
926 | pci_get_pbm_props(pbm); | 929 | pci_get_pbm_props(pbm); |
927 | pci_sun4v_iommu_init(pbm); | 930 | |
931 | err = pci_sun4v_iommu_init(pbm); | ||
932 | if (err) | ||
933 | return err; | ||
934 | |||
928 | pci_sun4v_msi_init(pbm); | 935 | pci_sun4v_msi_init(pbm); |
936 | |||
937 | pci_sun4v_scan_bus(pbm); | ||
938 | |||
939 | return 0; | ||
929 | } | 940 | } |
930 | 941 | ||
931 | void __init sun4v_pci_init(struct device_node *dp, char *model_name) | 942 | static int __devinit pci_sun4v_probe(struct of_device *op, |
943 | const struct of_device_id *match) | ||
932 | { | 944 | { |
945 | const struct linux_prom64_registers *regs; | ||
933 | static int hvapi_negotiated = 0; | 946 | static int hvapi_negotiated = 0; |
934 | struct pci_controller_info *p; | 947 | struct pci_controller_info *p; |
935 | struct pci_pbm_info *pbm; | 948 | struct pci_pbm_info *pbm; |
949 | struct device_node *dp; | ||
936 | struct iommu *iommu; | 950 | struct iommu *iommu; |
937 | struct property *prop; | ||
938 | struct linux_prom64_registers *regs; | ||
939 | u32 devhandle; | 951 | u32 devhandle; |
940 | int i; | 952 | int i; |
941 | 953 | ||
954 | dp = op->node; | ||
955 | |||
942 | if (!hvapi_negotiated++) { | 956 | if (!hvapi_negotiated++) { |
943 | int err = sun4v_hvapi_register(HV_GRP_PCI, | 957 | int err = sun4v_hvapi_register(HV_GRP_PCI, |
944 | vpci_major, | 958 | vpci_major, |
945 | &vpci_minor); | 959 | &vpci_minor); |
946 | 960 | ||
947 | if (err) { | 961 | if (err) { |
948 | prom_printf("SUN4V_PCI: Could not register hvapi, " | 962 | printk(KERN_ERR PFX "Could not register hvapi, " |
949 | "err=%d\n", err); | 963 | "err=%d\n", err); |
950 | prom_halt(); | 964 | return err; |
951 | } | 965 | } |
952 | printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n", | 966 | printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n", |
953 | vpci_major, vpci_minor); | 967 | vpci_major, vpci_minor); |
954 | 968 | ||
955 | dma_ops = &sun4v_dma_ops; | 969 | dma_ops = &sun4v_dma_ops; |
956 | } | 970 | } |
957 | 971 | ||
958 | prop = of_find_property(dp, "reg", NULL); | 972 | regs = of_get_property(dp, "reg", NULL); |
959 | if (!prop) { | 973 | if (!regs) { |
960 | prom_printf("SUN4V_PCI: Could not find config registers\n"); | 974 | printk(KERN_ERR PFX "Could not find config registers\n"); |
961 | prom_halt(); | 975 | return -ENODEV; |
962 | } | 976 | } |
963 | regs = prop->value; | ||
964 | |||
965 | devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; | 977 | devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; |
966 | 978 | ||
967 | for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { | 979 | for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { |
968 | if (pbm->devhandle == (devhandle ^ 0x40)) { | 980 | if (pbm->devhandle == (devhandle ^ 0x40)) { |
969 | pci_sun4v_pbm_init(pbm->parent, dp, devhandle); | 981 | return pci_sun4v_pbm_init(pbm->parent, dp, devhandle); |
970 | return; | ||
971 | } | 982 | } |
972 | } | 983 | } |
973 | 984 | ||
@@ -975,31 +986,63 @@ void __init sun4v_pci_init(struct device_node *dp, char *model_name) | |||
975 | unsigned long page = get_zeroed_page(GFP_ATOMIC); | 986 | unsigned long page = get_zeroed_page(GFP_ATOMIC); |
976 | 987 | ||
977 | if (!page) | 988 | if (!page) |
978 | goto fatal_memory_error; | 989 | return -ENOMEM; |
979 | 990 | ||
980 | per_cpu(iommu_batch, i).pglist = (u64 *) page; | 991 | per_cpu(iommu_batch, i).pglist = (u64 *) page; |
981 | } | 992 | } |
982 | 993 | ||
983 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | 994 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); |
984 | if (!p) | 995 | if (!p) { |
985 | goto fatal_memory_error; | 996 | printk(KERN_ERR PFX "Could not allocate pci_controller_info\n"); |
997 | goto out_free; | ||
998 | } | ||
986 | 999 | ||
987 | iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); | 1000 | iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); |
988 | if (!iommu) | 1001 | if (!iommu) { |
989 | goto fatal_memory_error; | 1002 | printk(KERN_ERR PFX "Could not allocate pbm A iommu\n"); |
1003 | goto out_free; | ||
1004 | } | ||
990 | 1005 | ||
991 | p->pbm_A.iommu = iommu; | 1006 | p->pbm_A.iommu = iommu; |
992 | 1007 | ||
993 | iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); | 1008 | iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); |
994 | if (!iommu) | 1009 | if (!iommu) { |
995 | goto fatal_memory_error; | 1010 | printk(KERN_ERR PFX "Could not allocate pbm B iommu\n"); |
1011 | goto out_free; | ||
1012 | } | ||
996 | 1013 | ||
997 | p->pbm_B.iommu = iommu; | 1014 | p->pbm_B.iommu = iommu; |
998 | 1015 | ||
999 | pci_sun4v_pbm_init(p, dp, devhandle); | 1016 | return pci_sun4v_pbm_init(p, dp, devhandle); |
1000 | return; | ||
1001 | 1017 | ||
1002 | fatal_memory_error: | 1018 | out_free: |
1003 | prom_printf("SUN4V_PCI: Fatal memory allocation error.\n"); | 1019 | if (p) { |
1004 | prom_halt(); | 1020 | if (p->pbm_A.iommu) |
1021 | kfree(p->pbm_A.iommu); | ||
1022 | if (p->pbm_B.iommu) | ||
1023 | kfree(p->pbm_B.iommu); | ||
1024 | kfree(p); | ||
1025 | } | ||
1026 | return -ENOMEM; | ||
1005 | } | 1027 | } |
1028 | |||
1029 | static struct of_device_id pci_sun4v_match[] = { | ||
1030 | { | ||
1031 | .name = "pci", | ||
1032 | .compatible = "SUNW,sun4v-pci", | ||
1033 | }, | ||
1034 | {}, | ||
1035 | }; | ||
1036 | |||
1037 | static struct of_platform_driver pci_sun4v_driver = { | ||
1038 | .name = DRIVER_NAME, | ||
1039 | .match_table = pci_sun4v_match, | ||
1040 | .probe = pci_sun4v_probe, | ||
1041 | }; | ||
1042 | |||
1043 | static int __init pci_sun4v_init(void) | ||
1044 | { | ||
1045 | return of_register_driver(&pci_sun4v_driver, &of_bus_type); | ||
1046 | } | ||
1047 | |||
1048 | subsys_initcall(pci_sun4v_init); | ||