diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kernel/prom.c | 76 |
1 files changed, 47 insertions, 29 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index eb23ac92abb9..f7b8c0be982e 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -865,45 +865,63 @@ static int __init prom_reconfig_setup(void) | |||
865 | __initcall(prom_reconfig_setup); | 865 | __initcall(prom_reconfig_setup); |
866 | #endif | 866 | #endif |
867 | 867 | ||
868 | bool arch_match_cpu_phys_id(int cpu, u64 phys_id) | ||
869 | { | ||
870 | return (int)phys_id == get_hard_smp_processor_id(cpu); | ||
871 | } | ||
872 | |||
873 | static bool __of_find_n_match_cpu_property(struct device_node *cpun, | ||
874 | const char *prop_name, int cpu, unsigned int *thread) | ||
875 | { | ||
876 | const __be32 *cell; | ||
877 | int ac, prop_len, tid; | ||
878 | u64 hwid; | ||
879 | |||
880 | ac = of_n_addr_cells(cpun); | ||
881 | cell = of_get_property(cpun, prop_name, &prop_len); | ||
882 | if (!cell) | ||
883 | return false; | ||
884 | prop_len /= sizeof(*cell); | ||
885 | for (tid = 0; tid < prop_len; tid++) { | ||
886 | hwid = of_read_number(cell, ac); | ||
887 | if (arch_match_cpu_phys_id(cpu, hwid)) { | ||
888 | if (thread) | ||
889 | *thread = tid; | ||
890 | return true; | ||
891 | } | ||
892 | cell += ac; | ||
893 | } | ||
894 | return false; | ||
895 | } | ||
896 | |||
868 | /* Find the device node for a given logical cpu number, also returns the cpu | 897 | /* Find the device node for a given logical cpu number, also returns the cpu |
869 | * local thread number (index in ibm,interrupt-server#s) if relevant and | 898 | * local thread number (index in ibm,interrupt-server#s) if relevant and |
870 | * asked for (non NULL) | 899 | * asked for (non NULL) |
871 | */ | 900 | */ |
872 | struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) | 901 | struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) |
873 | { | 902 | { |
874 | int hardid; | 903 | struct device_node *cpun, *cpus; |
875 | struct device_node *np; | ||
876 | 904 | ||
877 | hardid = get_hard_smp_processor_id(cpu); | 905 | cpus = of_find_node_by_path("/cpus"); |
906 | if (!cpus) { | ||
907 | pr_warn("Missing cpus node, bailing out\n"); | ||
908 | return NULL; | ||
909 | } | ||
878 | 910 | ||
879 | for_each_node_by_type(np, "cpu") { | 911 | for_each_child_of_node(cpus, cpun) { |
880 | const u32 *intserv; | 912 | if (of_node_cmp(cpun->type, "cpu")) |
881 | unsigned int plen, t; | 913 | continue; |
882 | 914 | ||
883 | /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist | 915 | /* Check for non-standard "ibm,ppc-interrupt-server#s" property |
884 | * fallback to "reg" property and assume no threads | 916 | * for thread ids on PowerPC. If it doesn't exist fallback to |
917 | * standard "reg" property. | ||
885 | */ | 918 | */ |
886 | intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", | 919 | if (__of_find_n_match_cpu_property(cpun, |
887 | &plen); | 920 | "ibm,ppc-interrupt-server#s", cpu, thread)) |
888 | if (intserv == NULL) { | 921 | return cpun; |
889 | const u32 *reg = of_get_property(np, "reg", NULL); | 922 | |
890 | if (reg == NULL) | 923 | if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread)) |
891 | continue; | 924 | return cpun; |
892 | if (*reg == hardid) { | ||
893 | if (thread) | ||
894 | *thread = 0; | ||
895 | return np; | ||
896 | } | ||
897 | } else { | ||
898 | plen /= sizeof(u32); | ||
899 | for (t = 0; t < plen; t++) { | ||
900 | if (hardid == intserv[t]) { | ||
901 | if (thread) | ||
902 | *thread = t; | ||
903 | return np; | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | } | 925 | } |
908 | return NULL; | 926 | return NULL; |
909 | } | 927 | } |