mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 22:50:41 +00:00
Merge branch 'cluster-boot-protocol' of git://linux-arm.org/linux-2.6-lp into devel-stable
This commit is contained in:
commit
e38eb34aab
77
Documentation/devicetree/bindings/arm/cpus.txt
Normal file
77
Documentation/devicetree/bindings/arm/cpus.txt
Normal file
@ -0,0 +1,77 @@
|
||||
* ARM CPUs binding description
|
||||
|
||||
The device tree allows to describe the layout of CPUs in a system through
|
||||
the "cpus" node, which in turn contains a number of subnodes (ie "cpu")
|
||||
defining properties for every cpu.
|
||||
|
||||
Bindings for CPU nodes follow the ePAPR standard, available from:
|
||||
|
||||
http://devicetree.org
|
||||
|
||||
For the ARM architecture every CPU node must contain the following properties:
|
||||
|
||||
- device_type: must be "cpu"
|
||||
- reg: property matching the CPU MPIDR[23:0] register bits
|
||||
reg[31:24] bits must be set to 0
|
||||
- compatible: should be one of:
|
||||
"arm,arm1020"
|
||||
"arm,arm1020e"
|
||||
"arm,arm1022"
|
||||
"arm,arm1026"
|
||||
"arm,arm720"
|
||||
"arm,arm740"
|
||||
"arm,arm7tdmi"
|
||||
"arm,arm920"
|
||||
"arm,arm922"
|
||||
"arm,arm925"
|
||||
"arm,arm926"
|
||||
"arm,arm940"
|
||||
"arm,arm946"
|
||||
"arm,arm9tdmi"
|
||||
"arm,cortex-a5"
|
||||
"arm,cortex-a7"
|
||||
"arm,cortex-a8"
|
||||
"arm,cortex-a9"
|
||||
"arm,cortex-a15"
|
||||
"arm,arm1136"
|
||||
"arm,arm1156"
|
||||
"arm,arm1176"
|
||||
"arm,arm11mpcore"
|
||||
"faraday,fa526"
|
||||
"intel,sa110"
|
||||
"intel,sa1100"
|
||||
"marvell,feroceon"
|
||||
"marvell,mohawk"
|
||||
"marvell,xsc3"
|
||||
"marvell,xscale"
|
||||
|
||||
Example:
|
||||
|
||||
cpus {
|
||||
#size-cells = <0>;
|
||||
#address-cells = <1>;
|
||||
|
||||
CPU0: cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a15";
|
||||
reg = <0x0>;
|
||||
};
|
||||
|
||||
CPU1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a15";
|
||||
reg = <0x1>;
|
||||
};
|
||||
|
||||
CPU2: cpu@100 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a7";
|
||||
reg = <0x100>;
|
||||
};
|
||||
|
||||
CPU3: cpu@101 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,cortex-a7";
|
||||
reg = <0x101>;
|
||||
};
|
||||
};
|
@ -69,6 +69,14 @@ struct gic_chip_data {
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
|
||||
|
||||
/*
|
||||
* The GIC mapping of CPU interfaces does not necessarily match
|
||||
* the logical CPU numbering. Let's use a mapping as returned
|
||||
* by the GIC itself.
|
||||
*/
|
||||
#define NR_GIC_CPU_IF 8
|
||||
static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
|
||||
|
||||
/*
|
||||
* Supported arch specific GIC irq extension.
|
||||
* Default make them NULL.
|
||||
@ -238,11 +246,11 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
|
||||
unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
|
||||
u32 val, mask, bit;
|
||||
|
||||
if (cpu >= 8 || cpu >= nr_cpu_ids)
|
||||
if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
|
||||
return -EINVAL;
|
||||
|
||||
mask = 0xff << shift;
|
||||
bit = 1 << (cpu_logical_map(cpu) + shift);
|
||||
bit = gic_cpu_map[cpu] << shift;
|
||||
|
||||
raw_spin_lock(&irq_controller_lock);
|
||||
val = readl_relaxed(reg) & ~mask;
|
||||
@ -349,11 +357,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
|
||||
u32 cpumask;
|
||||
unsigned int gic_irqs = gic->gic_irqs;
|
||||
void __iomem *base = gic_data_dist_base(gic);
|
||||
u32 cpu = cpu_logical_map(smp_processor_id());
|
||||
|
||||
cpumask = 1 << cpu;
|
||||
cpumask |= cpumask << 8;
|
||||
cpumask |= cpumask << 16;
|
||||
|
||||
writel_relaxed(0, base + GIC_DIST_CTRL);
|
||||
|
||||
@ -366,6 +369,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
|
||||
/*
|
||||
* Set all global interrupts to this CPU only.
|
||||
*/
|
||||
cpumask = readl_relaxed(base + GIC_DIST_TARGET + 0);
|
||||
for (i = 32; i < gic_irqs; i += 4)
|
||||
writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
|
||||
|
||||
@ -389,8 +393,24 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
|
||||
{
|
||||
void __iomem *dist_base = gic_data_dist_base(gic);
|
||||
void __iomem *base = gic_data_cpu_base(gic);
|
||||
unsigned int cpu_mask, cpu = smp_processor_id();
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Get what the GIC says our CPU mask is.
|
||||
*/
|
||||
BUG_ON(cpu >= NR_GIC_CPU_IF);
|
||||
cpu_mask = readl_relaxed(dist_base + GIC_DIST_TARGET + 0);
|
||||
gic_cpu_map[cpu] = cpu_mask;
|
||||
|
||||
/*
|
||||
* Clear our mask from the other map entries in case they're
|
||||
* still undefined.
|
||||
*/
|
||||
for (i = 0; i < NR_GIC_CPU_IF; i++)
|
||||
if (i != cpu)
|
||||
gic_cpu_map[i] &= ~cpu_mask;
|
||||
|
||||
/*
|
||||
* Deal with the banked PPI and SGI interrupts - disable all
|
||||
* PPI interrupts, ensure all SGI interrupts are enabled.
|
||||
@ -646,7 +666,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
||||
{
|
||||
irq_hw_number_t hwirq_base;
|
||||
struct gic_chip_data *gic;
|
||||
int gic_irqs, irq_base;
|
||||
int gic_irqs, irq_base, i;
|
||||
|
||||
BUG_ON(gic_nr >= MAX_GIC_NR);
|
||||
|
||||
@ -682,6 +702,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
||||
gic_set_base_accessor(gic, gic_get_common_base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the CPU interface map to all CPUs.
|
||||
* It will be refined as each CPU probes its ID.
|
||||
*/
|
||||
for (i = 0; i < NR_GIC_CPU_IF; i++)
|
||||
gic_cpu_map[i] = 0xff;
|
||||
|
||||
/*
|
||||
* For primary GICs, skip over SGIs.
|
||||
* For secondary GICs, skip over PPIs, too.
|
||||
@ -737,7 +764,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
|
||||
|
||||
/* Convert our logical CPU mask into a physical one. */
|
||||
for_each_cpu(cpu, mask)
|
||||
map |= 1 << cpu_logical_map(cpu);
|
||||
map |= gic_cpu_map[cpu];
|
||||
|
||||
/*
|
||||
* Ensure that stores to Normal memory are visible to the
|
||||
|
@ -25,6 +25,19 @@
|
||||
#define CPUID_EXT_ISAR4 "c2, 4"
|
||||
#define CPUID_EXT_ISAR5 "c2, 5"
|
||||
|
||||
#define MPIDR_SMP_BITMASK (0x3 << 30)
|
||||
#define MPIDR_SMP_VALUE (0x2 << 30)
|
||||
|
||||
#define MPIDR_MT_BITMASK (0x1 << 24)
|
||||
|
||||
#define MPIDR_HWID_BITMASK 0xFFFFFF
|
||||
|
||||
#define MPIDR_LEVEL_BITS 8
|
||||
#define MPIDR_LEVEL_MASK ((1 << MPIDR_LEVEL_BITS) - 1)
|
||||
|
||||
#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
|
||||
((mpidr >> (MPIDR_LEVEL_BITS * level)) & MPIDR_LEVEL_MASK)
|
||||
|
||||
extern unsigned int processor_id;
|
||||
|
||||
#ifdef CONFIG_CPU_CP15
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
|
||||
extern void arm_dt_memblock_reserve(void);
|
||||
extern void __init arm_dt_init_cpu_maps(void);
|
||||
|
||||
#else /* CONFIG_OF */
|
||||
|
||||
@ -24,6 +25,7 @@ static inline struct machine_desc *setup_machine_fdt(unsigned int dt_phys)
|
||||
}
|
||||
|
||||
static inline void arm_dt_memblock_reserve(void) { }
|
||||
static inline void arm_dt_init_cpu_maps(void) { }
|
||||
|
||||
#endif /* CONFIG_OF */
|
||||
#endif /* ASMARM_PROM_H */
|
||||
|
@ -5,6 +5,9 @@
|
||||
#ifndef __ASMARM_SMP_PLAT_H
|
||||
#define __ASMARM_SMP_PLAT_H
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
|
||||
/*
|
||||
@ -48,5 +51,19 @@ static inline int cache_ops_need_broadcast(void)
|
||||
*/
|
||||
extern int __cpu_logical_map[];
|
||||
#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
|
||||
/*
|
||||
* Retrieve logical cpu index corresponding to a given MPIDR[23:0]
|
||||
* - mpidr: MPIDR[23:0] to be used for the look-up
|
||||
*
|
||||
* Returns the cpu logical index or -EINVAL on look-up error
|
||||
*/
|
||||
static inline int get_logical_index(u32 mpidr)
|
||||
{
|
||||
int cpu;
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
|
||||
if (cpu_logical_map(cpu) == mpidr)
|
||||
return cpu;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -19,8 +19,10 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
@ -61,6 +63,104 @@ void __init arm_dt_memblock_reserve(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* arm_dt_init_cpu_maps - Function retrieves cpu nodes from the device tree
|
||||
* and builds the cpu logical map array containing MPIDR values related to
|
||||
* logical cpus
|
||||
*
|
||||
* Updates the cpu possible mask with the number of parsed cpu nodes
|
||||
*/
|
||||
void __init arm_dt_init_cpu_maps(void)
|
||||
{
|
||||
/*
|
||||
* Temp logical map is initialized with UINT_MAX values that are
|
||||
* considered invalid logical map entries since the logical map must
|
||||
* contain a list of MPIDR[23:0] values where MPIDR[31:24] must
|
||||
* read as 0.
|
||||
*/
|
||||
struct device_node *cpu, *cpus;
|
||||
u32 i, j, cpuidx = 1;
|
||||
u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
|
||||
|
||||
u32 tmp_map[NR_CPUS] = { [0 ... NR_CPUS-1] = UINT_MAX };
|
||||
bool bootcpu_valid = false;
|
||||
cpus = of_find_node_by_path("/cpus");
|
||||
|
||||
if (!cpus)
|
||||
return;
|
||||
|
||||
for_each_child_of_node(cpus, cpu) {
|
||||
u32 hwid;
|
||||
|
||||
pr_debug(" * %s...\n", cpu->full_name);
|
||||
/*
|
||||
* A device tree containing CPU nodes with missing "reg"
|
||||
* properties is considered invalid to build the
|
||||
* cpu_logical_map.
|
||||
*/
|
||||
if (of_property_read_u32(cpu, "reg", &hwid)) {
|
||||
pr_debug(" * %s missing reg property\n",
|
||||
cpu->full_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 8 MSBs must be set to 0 in the DT since the reg property
|
||||
* defines the MPIDR[23:0].
|
||||
*/
|
||||
if (hwid & ~MPIDR_HWID_BITMASK)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Duplicate MPIDRs are a recipe for disaster.
|
||||
* Scan all initialized entries and check for
|
||||
* duplicates. If any is found just bail out.
|
||||
* temp values were initialized to UINT_MAX
|
||||
* to avoid matching valid MPIDR[23:0] values.
|
||||
*/
|
||||
for (j = 0; j < cpuidx; j++)
|
||||
if (WARN(tmp_map[j] == hwid, "Duplicate /cpu reg "
|
||||
"properties in the DT\n"))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Build a stashed array of MPIDR values. Numbering scheme
|
||||
* requires that if detected the boot CPU must be assigned
|
||||
* logical id 0. Other CPUs get sequential indexes starting
|
||||
* from 1. If a CPU node with a reg property matching the
|
||||
* boot CPU MPIDR is detected, this is recorded so that the
|
||||
* logical map built from DT is validated and can be used
|
||||
* to override the map created in smp_setup_processor_id().
|
||||
*/
|
||||
if (hwid == mpidr) {
|
||||
i = 0;
|
||||
bootcpu_valid = true;
|
||||
} else {
|
||||
i = cpuidx++;
|
||||
}
|
||||
|
||||
tmp_map[i] = hwid;
|
||||
|
||||
if (cpuidx > nr_cpu_ids)
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN(!bootcpu_valid, "DT missing boot CPU MPIDR[23:0], "
|
||||
"fall back to default cpu_logical_map\n"))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Since the boot CPU node contains proper data, and all nodes have
|
||||
* a reg property, the DT CPU list can be considered valid and the
|
||||
* logical map created in smp_setup_processor_id() can be overridden
|
||||
*/
|
||||
for (i = 0; i < cpuidx; i++) {
|
||||
set_cpu_possible(i, true);
|
||||
cpu_logical_map(i) = tmp_map[i];
|
||||
pr_debug("cpu logical map 0x%x\n", cpu_logical_map(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setup_machine_fdt - Machine setup when an dtb was passed to the kernel
|
||||
* @dt_phys: physical address of dt blob
|
||||
|
@ -426,13 +426,14 @@ int __cpu_logical_map[NR_CPUS];
|
||||
void __init smp_setup_processor_id(void)
|
||||
{
|
||||
int i;
|
||||
u32 cpu = is_smp() ? read_cpuid_mpidr() & 0xff : 0;
|
||||
u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
|
||||
u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
|
||||
|
||||
cpu_logical_map(0) = cpu;
|
||||
for (i = 1; i < NR_CPUS; ++i)
|
||||
for (i = 1; i < nr_cpu_ids; ++i)
|
||||
cpu_logical_map(i) = i == cpu ? 0 : i;
|
||||
|
||||
printk(KERN_INFO "Booting Linux on physical CPU %d\n", cpu);
|
||||
printk(KERN_INFO "Booting Linux on physical CPU 0x%x\n", mpidr);
|
||||
}
|
||||
|
||||
static void __init setup_processor(void)
|
||||
@ -758,6 +759,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
unflatten_device_tree();
|
||||
|
||||
arm_dt_init_cpu_maps();
|
||||
#ifdef CONFIG_SMP
|
||||
if (is_smp()) {
|
||||
smp_set_ops(mdesc->smp);
|
||||
|
@ -196,32 +196,7 @@ static inline void parse_dt_topology(void) {}
|
||||
static inline void update_cpu_power(unsigned int cpuid, unsigned int mpidr) {}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* cpu topology management
|
||||
*/
|
||||
|
||||
#define MPIDR_SMP_BITMASK (0x3 << 30)
|
||||
#define MPIDR_SMP_VALUE (0x2 << 30)
|
||||
|
||||
#define MPIDR_MT_BITMASK (0x1 << 24)
|
||||
|
||||
/*
|
||||
* These masks reflect the current use of the affinity levels.
|
||||
* The affinity level can be up to 16 bits according to ARM ARM
|
||||
*/
|
||||
#define MPIDR_HWID_BITMASK 0xFFFFFF
|
||||
|
||||
#define MPIDR_LEVEL0_MASK 0x3
|
||||
#define MPIDR_LEVEL0_SHIFT 0
|
||||
|
||||
#define MPIDR_LEVEL1_MASK 0xF
|
||||
#define MPIDR_LEVEL1_SHIFT 8
|
||||
|
||||
#define MPIDR_LEVEL2_MASK 0xFF
|
||||
#define MPIDR_LEVEL2_SHIFT 16
|
||||
|
||||
/*
|
||||
/*
|
||||
* cpu topology table
|
||||
*/
|
||||
struct cputopo_arm cpu_topology[NR_CPUS];
|
||||
@ -282,19 +257,14 @@ void store_cpu_topology(unsigned int cpuid)
|
||||
|
||||
if (mpidr & MPIDR_MT_BITMASK) {
|
||||
/* core performance interdependency */
|
||||
cpuid_topo->thread_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
|
||||
& MPIDR_LEVEL0_MASK;
|
||||
cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
|
||||
& MPIDR_LEVEL1_MASK;
|
||||
cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL2_SHIFT)
|
||||
& MPIDR_LEVEL2_MASK;
|
||||
cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
|
||||
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
|
||||
cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
|
||||
} else {
|
||||
/* largely independent cores */
|
||||
cpuid_topo->thread_id = -1;
|
||||
cpuid_topo->core_id = (mpidr >> MPIDR_LEVEL0_SHIFT)
|
||||
& MPIDR_LEVEL0_MASK;
|
||||
cpuid_topo->socket_id = (mpidr >> MPIDR_LEVEL1_SHIFT)
|
||||
& MPIDR_LEVEL1_MASK;
|
||||
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
|
||||
cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user