diff options
-rw-r--r-- | arch/mips/include/asm/mips-cps.h | 39 | ||||
-rw-r--r-- | arch/mips/kernel/mips-cm.c | 37 |
2 files changed, 76 insertions, 0 deletions
diff --git a/arch/mips/include/asm/mips-cps.h b/arch/mips/include/asm/mips-cps.h index c077e8d100f5..917009b80e69 100644 --- a/arch/mips/include/asm/mips-cps.h +++ b/arch/mips/include/asm/mips-cps.h @@ -8,6 +8,7 @@ #define __MIPS_ASM_MIPS_CPS_H__ #include <linux/bitfield.h> +#include <linux/cpumask.h> #include <linux/io.h> #include <linux/types.h> @@ -228,4 +229,42 @@ static inline unsigned int mips_cps_numvps(unsigned int cluster, unsigned int co return FIELD_GET(CM_GCR_Cx_CONFIG_PVPE, cfg + 1); } +/** + * mips_cps_multicluster_cpus() - Detect whether CPUs are in multiple clusters + * + * Determine whether the system includes CPUs in multiple clusters - ie. + * whether we can treat the system as single or multi-cluster as far as CPUs + * are concerned. Note that this is slightly different to simply checking + * whether multiple clusters are present - it is possible for there to be + * clusters which contain no CPUs, which this function will effectively ignore. + * + * Returns true if CPUs are spread across multiple clusters, else false. + */ +static inline bool mips_cps_multicluster_cpus(void) +{ + unsigned int first_cl, last_cl; + + /* + * CPUs are numbered sequentially by cluster - ie. CPUs 0..X will be in + * cluster 0, CPUs X+1..Y in cluster 1, CPUs Y+1..Z in cluster 2 etc. + * + * Thus we can detect multiple clusters trivially by checking whether + * the first & last CPUs belong to the same cluster. + */ + first_cl = cpu_cluster(&boot_cpu_data); + last_cl = cpu_cluster(&cpu_data[nr_cpu_ids - 1]); + return first_cl != last_cl; +} + +/** + * mips_cps_first_online_in_cluster() - Detect if CPU is first online in cluster + * + * Determine whether the local CPU is the first to be brought online in its + * cluster - that is, whether there are any other online CPUs in the local + * cluster. + * + * Returns true if this CPU is first online, else false. + */ +extern unsigned int mips_cps_first_online_in_cluster(void); + #endif /* __MIPS_ASM_MIPS_CPS_H__ */ diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 3a115fab5573..3eb2cfb893e1 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -512,3 +512,40 @@ void mips_cm_error_report(void) /* reprime cause register */ write_gcr_error_cause(cm_error); } + +unsigned int mips_cps_first_online_in_cluster(void) +{ + unsigned int local_cl; + int i; + + local_cl = cpu_cluster(¤t_cpu_data); + + /* + * We rely upon knowledge that CPUs are numbered sequentially by + * cluster - ie. CPUs 0..X will be in cluster 0, CPUs X+1..Y in cluster + * 1, CPUs Y+1..Z in cluster 2 etc. This means that CPUs in the same + * cluster will immediately precede or follow one another. + * + * First we scan backwards, until we find an online CPU in the cluster + * or we move on to another cluster. + */ + for (i = smp_processor_id() - 1; i >= 0; i--) { + if (cpu_cluster(&cpu_data[i]) != local_cl) + break; + if (!cpu_online(i)) + continue; + return false; + } + + /* Then do the same for higher numbered CPUs */ + for (i = smp_processor_id() + 1; i < nr_cpu_ids; i++) { + if (cpu_cluster(&cpu_data[i]) != local_cl) + break; + if (!cpu_online(i)) + continue; + return false; + } + + /* We found no online CPUs in the local cluster */ + return true; +} |