diff options
Diffstat (limited to 'arch/sparc64/kernel/prom.c')
-rw-r--r-- | arch/sparc64/kernel/prom.c | 112 |
1 files changed, 95 insertions, 17 deletions
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 5e1fcd05160d..c54d4d8af014 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c | |||
@@ -386,11 +386,9 @@ static unsigned int psycho_irq_build(struct device_node *dp, | |||
386 | 386 | ||
387 | /* Now build the IRQ bucket. */ | 387 | /* Now build the IRQ bucket. */ |
388 | imap = controller_regs + imap_off; | 388 | imap = controller_regs + imap_off; |
389 | imap += 4; | ||
390 | 389 | ||
391 | iclr_off = psycho_iclr_offset(ino); | 390 | iclr_off = psycho_iclr_offset(ino); |
392 | iclr = controller_regs + iclr_off; | 391 | iclr = controller_regs + iclr_off; |
393 | iclr += 4; | ||
394 | 392 | ||
395 | if ((ino & 0x20) == 0) | 393 | if ((ino & 0x20) == 0) |
396 | inofixup = ino & 0x03; | 394 | inofixup = ino & 0x03; |
@@ -398,7 +396,7 @@ static unsigned int psycho_irq_build(struct device_node *dp, | |||
398 | return build_irq(inofixup, iclr, imap); | 396 | return build_irq(inofixup, iclr, imap); |
399 | } | 397 | } |
400 | 398 | ||
401 | static void psycho_irq_trans_init(struct device_node *dp) | 399 | static void __init psycho_irq_trans_init(struct device_node *dp) |
402 | { | 400 | { |
403 | const struct linux_prom64_registers *regs; | 401 | const struct linux_prom64_registers *regs; |
404 | 402 | ||
@@ -613,11 +611,9 @@ static unsigned int sabre_irq_build(struct device_node *dp, | |||
613 | 611 | ||
614 | /* Now build the IRQ bucket. */ | 612 | /* Now build the IRQ bucket. */ |
615 | imap = controller_regs + imap_off; | 613 | imap = controller_regs + imap_off; |
616 | imap += 4; | ||
617 | 614 | ||
618 | iclr_off = sabre_iclr_offset(ino); | 615 | iclr_off = sabre_iclr_offset(ino); |
619 | iclr = controller_regs + iclr_off; | 616 | iclr = controller_regs + iclr_off; |
620 | iclr += 4; | ||
621 | 617 | ||
622 | if ((ino & 0x20) == 0) | 618 | if ((ino & 0x20) == 0) |
623 | inofixup = ino & 0x03; | 619 | inofixup = ino & 0x03; |
@@ -640,7 +636,7 @@ static unsigned int sabre_irq_build(struct device_node *dp, | |||
640 | return virt_irq; | 636 | return virt_irq; |
641 | } | 637 | } |
642 | 638 | ||
643 | static void sabre_irq_trans_init(struct device_node *dp) | 639 | static void __init sabre_irq_trans_init(struct device_node *dp) |
644 | { | 640 | { |
645 | const struct linux_prom64_registers *regs; | 641 | const struct linux_prom64_registers *regs; |
646 | struct sabre_irq_data *irq_data; | 642 | struct sabre_irq_data *irq_data; |
@@ -679,13 +675,14 @@ static unsigned long schizo_iclr_offset(unsigned long ino) | |||
679 | static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, | 675 | static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, |
680 | unsigned int ino) | 676 | unsigned int ino) |
681 | { | 677 | { |
682 | return pbm_regs + schizo_iclr_offset(ino) + 4; | 678 | |
679 | return pbm_regs + schizo_iclr_offset(ino); | ||
683 | } | 680 | } |
684 | 681 | ||
685 | static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, | 682 | static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, |
686 | unsigned int ino) | 683 | unsigned int ino) |
687 | { | 684 | { |
688 | return pbm_regs + schizo_imap_offset(ino) + 4; | 685 | return pbm_regs + schizo_imap_offset(ino); |
689 | } | 686 | } |
690 | 687 | ||
691 | #define schizo_read(__reg) \ | 688 | #define schizo_read(__reg) \ |
@@ -796,7 +793,8 @@ static unsigned int schizo_irq_build(struct device_node *dp, | |||
796 | return virt_irq; | 793 | return virt_irq; |
797 | } | 794 | } |
798 | 795 | ||
799 | static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo) | 796 | static void __init __schizo_irq_trans_init(struct device_node *dp, |
797 | int is_tomatillo) | ||
800 | { | 798 | { |
801 | const struct linux_prom64_registers *regs; | 799 | const struct linux_prom64_registers *regs; |
802 | struct schizo_irq_data *irq_data; | 800 | struct schizo_irq_data *irq_data; |
@@ -818,12 +816,12 @@ static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo) | |||
818 | irq_data->chip_version = of_getintprop_default(dp, "version#", 0); | 816 | irq_data->chip_version = of_getintprop_default(dp, "version#", 0); |
819 | } | 817 | } |
820 | 818 | ||
821 | static void schizo_irq_trans_init(struct device_node *dp) | 819 | static void __init schizo_irq_trans_init(struct device_node *dp) |
822 | { | 820 | { |
823 | __schizo_irq_trans_init(dp, 0); | 821 | __schizo_irq_trans_init(dp, 0); |
824 | } | 822 | } |
825 | 823 | ||
826 | static void tomatillo_irq_trans_init(struct device_node *dp) | 824 | static void __init tomatillo_irq_trans_init(struct device_node *dp) |
827 | { | 825 | { |
828 | __schizo_irq_trans_init(dp, 1); | 826 | __schizo_irq_trans_init(dp, 1); |
829 | } | 827 | } |
@@ -837,7 +835,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp, | |||
837 | return sun4v_build_irq(devhandle, devino); | 835 | return sun4v_build_irq(devhandle, devino); |
838 | } | 836 | } |
839 | 837 | ||
840 | static void pci_sun4v_irq_trans_init(struct device_node *dp) | 838 | static void __init pci_sun4v_irq_trans_init(struct device_node *dp) |
841 | { | 839 | { |
842 | const struct linux_prom64_registers *regs; | 840 | const struct linux_prom64_registers *regs; |
843 | 841 | ||
@@ -848,6 +846,85 @@ static void pci_sun4v_irq_trans_init(struct device_node *dp) | |||
848 | dp->irq_trans->data = (void *) (unsigned long) | 846 | dp->irq_trans->data = (void *) (unsigned long) |
849 | ((regs->phys_addr >> 32UL) & 0x0fffffff); | 847 | ((regs->phys_addr >> 32UL) & 0x0fffffff); |
850 | } | 848 | } |
849 | |||
850 | struct fire_irq_data { | ||
851 | unsigned long pbm_regs; | ||
852 | u32 portid; | ||
853 | }; | ||
854 | |||
855 | #define FIRE_IMAP_BASE 0x001000 | ||
856 | #define FIRE_ICLR_BASE 0x001400 | ||
857 | |||
858 | static unsigned long fire_imap_offset(unsigned long ino) | ||
859 | { | ||
860 | return FIRE_IMAP_BASE + (ino * 8UL); | ||
861 | } | ||
862 | |||
863 | static unsigned long fire_iclr_offset(unsigned long ino) | ||
864 | { | ||
865 | return FIRE_ICLR_BASE + (ino * 8UL); | ||
866 | } | ||
867 | |||
868 | static unsigned long fire_ino_to_iclr(unsigned long pbm_regs, | ||
869 | unsigned int ino) | ||
870 | { | ||
871 | return pbm_regs + fire_iclr_offset(ino); | ||
872 | } | ||
873 | |||
874 | static unsigned long fire_ino_to_imap(unsigned long pbm_regs, | ||
875 | unsigned int ino) | ||
876 | { | ||
877 | return pbm_regs + fire_imap_offset(ino); | ||
878 | } | ||
879 | |||
880 | static unsigned int fire_irq_build(struct device_node *dp, | ||
881 | unsigned int ino, | ||
882 | void *_data) | ||
883 | { | ||
884 | struct fire_irq_data *irq_data = _data; | ||
885 | unsigned long pbm_regs = irq_data->pbm_regs; | ||
886 | unsigned long imap, iclr; | ||
887 | unsigned long int_ctrlr; | ||
888 | |||
889 | ino &= 0x3f; | ||
890 | |||
891 | /* Now build the IRQ bucket. */ | ||
892 | imap = fire_ino_to_imap(pbm_regs, ino); | ||
893 | iclr = fire_ino_to_iclr(pbm_regs, ino); | ||
894 | |||
895 | /* Set the interrupt controller number. */ | ||
896 | int_ctrlr = 1 << 6; | ||
897 | upa_writeq(int_ctrlr, imap); | ||
898 | |||
899 | /* The interrupt map registers do not have an INO field | ||
900 | * like other chips do. They return zero in the INO | ||
901 | * field, and the interrupt controller number is controlled | ||
902 | * in bits 6 thru 9. So in order for build_irq() to get | ||
903 | * the INO right we pass it in as part of the fixup | ||
904 | * which will get added to the map register zero value | ||
905 | * read by build_irq(). | ||
906 | */ | ||
907 | ino |= (irq_data->portid << 6); | ||
908 | ino -= int_ctrlr; | ||
909 | return build_irq(ino, iclr, imap); | ||
910 | } | ||
911 | |||
912 | static void __init fire_irq_trans_init(struct device_node *dp) | ||
913 | { | ||
914 | const struct linux_prom64_registers *regs; | ||
915 | struct fire_irq_data *irq_data; | ||
916 | |||
917 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | ||
918 | dp->irq_trans->irq_build = fire_irq_build; | ||
919 | |||
920 | irq_data = prom_early_alloc(sizeof(struct fire_irq_data)); | ||
921 | |||
922 | regs = of_get_property(dp, "reg", NULL); | ||
923 | dp->irq_trans->data = irq_data; | ||
924 | |||
925 | irq_data->pbm_regs = regs[0].phys_addr; | ||
926 | irq_data->portid = of_getintprop_default(dp, "portid", 0); | ||
927 | } | ||
851 | #endif /* CONFIG_PCI */ | 928 | #endif /* CONFIG_PCI */ |
852 | 929 | ||
853 | #ifdef CONFIG_SBUS | 930 | #ifdef CONFIG_SBUS |
@@ -995,7 +1072,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp, | |||
995 | return build_irq(sbus_level, iclr, imap); | 1072 | return build_irq(sbus_level, iclr, imap); |
996 | } | 1073 | } |
997 | 1074 | ||
998 | static void sbus_irq_trans_init(struct device_node *dp) | 1075 | static void __init sbus_irq_trans_init(struct device_node *dp) |
999 | { | 1076 | { |
1000 | const struct linux_prom64_registers *regs; | 1077 | const struct linux_prom64_registers *regs; |
1001 | 1078 | ||
@@ -1042,7 +1119,7 @@ static unsigned int central_build_irq(struct device_node *dp, | |||
1042 | return build_irq(0, iclr, imap); | 1119 | return build_irq(0, iclr, imap); |
1043 | } | 1120 | } |
1044 | 1121 | ||
1045 | static void central_irq_trans_init(struct device_node *dp) | 1122 | static void __init central_irq_trans_init(struct device_node *dp) |
1046 | { | 1123 | { |
1047 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); | 1124 | dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); |
1048 | dp->irq_trans->irq_build = central_build_irq; | 1125 | dp->irq_trans->irq_build = central_build_irq; |
@@ -1056,7 +1133,7 @@ struct irq_trans { | |||
1056 | }; | 1133 | }; |
1057 | 1134 | ||
1058 | #ifdef CONFIG_PCI | 1135 | #ifdef CONFIG_PCI |
1059 | static struct irq_trans pci_irq_trans_table[] = { | 1136 | static struct irq_trans __initdata pci_irq_trans_table[] = { |
1060 | { "SUNW,sabre", sabre_irq_trans_init }, | 1137 | { "SUNW,sabre", sabre_irq_trans_init }, |
1061 | { "pci108e,a000", sabre_irq_trans_init }, | 1138 | { "pci108e,a000", sabre_irq_trans_init }, |
1062 | { "pci108e,a001", sabre_irq_trans_init }, | 1139 | { "pci108e,a001", sabre_irq_trans_init }, |
@@ -1069,6 +1146,7 @@ static struct irq_trans pci_irq_trans_table[] = { | |||
1069 | { "SUNW,tomatillo", tomatillo_irq_trans_init }, | 1146 | { "SUNW,tomatillo", tomatillo_irq_trans_init }, |
1070 | { "pci108e,a801", tomatillo_irq_trans_init }, | 1147 | { "pci108e,a801", tomatillo_irq_trans_init }, |
1071 | { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, | 1148 | { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, |
1149 | { "pciex108e,80f0", fire_irq_trans_init }, | ||
1072 | }; | 1150 | }; |
1073 | #endif | 1151 | #endif |
1074 | 1152 | ||
@@ -1081,7 +1159,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp, | |||
1081 | return sun4v_build_irq(devhandle, devino); | 1159 | return sun4v_build_irq(devhandle, devino); |
1082 | } | 1160 | } |
1083 | 1161 | ||
1084 | static void sun4v_vdev_irq_trans_init(struct device_node *dp) | 1162 | static void __init sun4v_vdev_irq_trans_init(struct device_node *dp) |
1085 | { | 1163 | { |
1086 | const struct linux_prom64_registers *regs; | 1164 | const struct linux_prom64_registers *regs; |
1087 | 1165 | ||
@@ -1093,7 +1171,7 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp) | |||
1093 | ((regs->phys_addr >> 32UL) & 0x0fffffff); | 1171 | ((regs->phys_addr >> 32UL) & 0x0fffffff); |
1094 | } | 1172 | } |
1095 | 1173 | ||
1096 | static void irq_trans_init(struct device_node *dp) | 1174 | static void __init irq_trans_init(struct device_node *dp) |
1097 | { | 1175 | { |
1098 | #ifdef CONFIG_PCI | 1176 | #ifdef CONFIG_PCI |
1099 | const char *model; | 1177 | const char *model; |