Thread (86 messages) 86 messages, 11 authors, 2014-01-27

[PATCH 10/20] ARM64 / ACPI: Enumerate possible/present CPU set and map logical cpu id to APIC id

From: Hanjun Guo <hidden>
Date: 2014-01-24 14:37:40
Also in: linux-acpi, lkml

Hi Lorenzo,

On 2014?01?22? 23:53, Lorenzo Pieralisi wrote:
On Fri, Jan 17, 2014 at 12:25:04PM +0000, Hanjun Guo wrote:

[...]
quoted
+/* map logic cpu id to physical GIC id */
+extern int arm_cpu_to_apicid[NR_CPUS];
+#define cpu_physical_id(cpu) arm_cpu_to_apicid[cpu]
Sudeep already commented on this, please update it accordingly.
Actually after some careful review of the ACPI code, I can't
update it as MPIDR here.

MPIDR can be the ACPI uid and NOT the GIC id, the mapping
of them are something like this in ACPI driver now:

logic cpu id <---> APIC Id (GIC ID) <---> ACPI uid (MPIDR on ARM)
but not logic cpu id <---> ACPI uid directly, you can refer to
the code of processor_core.c

So here I can only map GIC id to logical cpu id.
quoted
+
  #else	/* !CONFIG_ACPI */
  #define acpi_disabled 1		/* ACPI sometimes enabled on ARM */
  #define acpi_noirq 1		/* ACPI sometimes enabled on ARM */
diff --git a/drivers/acpi/plat/arm-core.c b/drivers/acpi/plat/arm-core.c
index 8ba3e6f..1d9b789 100644
--- a/drivers/acpi/plat/arm-core.c
+++ b/drivers/acpi/plat/arm-core.c
@@ -31,6 +31,7 @@
  #include <linux/smp.h>
  
  #include <asm/pgtable.h>
+#include <asm/cputype.h>
  
  /*
   * We never plan to use RSDT on arm/arm64 as its deprecated in spec but this
@@ -52,6 +53,13 @@ EXPORT_SYMBOL(acpi_pci_disabled);
   */
  static u64 acpi_lapic_addr __initdata;
Is this variable actually needed ?
Yes, needed for GIC initialization.
quoted
  
+/* available_cpus here means enabled cpu in MADT */
+static int available_cpus;
Ditto.
quoted
+
+/* Map logic cpu id to physical GIC id (physical CPU id). */
+int arm_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
+static int boot_cpu_apic_id = -1;
Do we need all these variables ? I think we should reuse cpu_logical_map
data structures for that, it looks suspiciously familiar.
MPIDR is the different part. if we use MPIDR as GIC id, i think
we can reuse cpu_logical_map, but Sudeep suggested not
use MPIDR as GIC id.
quoted
  #define BAD_MADT_ENTRY(entry, end) (					\
  	(!entry) || (unsigned long)entry + sizeof(*entry) > end ||	\
  	((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
@@ -132,6 +140,55 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
   * Please refer to chapter5.2.12.14/15 of ACPI 5.0
   */
  
+/**
+ * acpi_register_gic_cpu_interface - register a gic cpu interface and
+ * generates a logic cpu number
+ * @id: gic cpu interface id to register
+ * @enabled: this cpu is enabled or not
+ *
+ * Returns the logic cpu number which maps to the gic cpu interface
+ */
+static int acpi_register_gic_cpu_interface(int id, u8 enabled)
+{
+	int cpu;
+
+	if (id >= MAX_GIC_CPU_INTERFACE) {
+		pr_info(PREFIX "skipped apicid that is too big\n");
+		return -EINVAL;
+	}
+
+	total_cpus++;
+	if (!enabled)
+		return -EINVAL;
+
+	if (available_cpus >=  NR_CPUS) {
+		pr_warn(PREFIX "NR_CPUS limit of %d reached,"
+		" Processor %d/0x%x ignored.\n", NR_CPUS, total_cpus, id);
+		return -EINVAL;
+	}
Hmm...what if you are missing the boot CPU ? It is a worthy check.
Have a look at smp_init_cpus(), it does not bail out on cpu>= NR_CPUS
because you do want to make sure that the DT contains the boot CPU
node. Same logic applies.
Thanks, I will review he code you mentioned and find a solution
for ACPI part.
quoted
+
+	available_cpus++;
+
Is available_cpus != num_possible_cpus() ? It does not look like hence
available_cpus can go.
No, possible cpus include available cpus and disabled cpus
this is useful for ACPI based CPU hot-plug features.
quoted
+	/* allocate a logic cpu id for the new comer */
+	if (boot_cpu_apic_id == id) {
+		/*
+		 * boot_cpu_init() already hold bit 0 in cpu_present_mask
+		 * for BSP, no need to allocte again.
+		 */
+		cpu = 0;
+	} else {
+		cpu = cpumask_next_zero(-1, cpu_present_mask);
+	}
+
+	/* map the logic cpu id to APIC id */
+	arm_cpu_to_apicid[cpu] = id;
+
+	set_cpu_present(cpu, true);
+	set_cpu_possible(cpu, true);
This is getting nasty. Before adding this patch and previous ones we
need to put in place a method for the kernel to make a definite choice between
ACPI and DT and stick to that. We can't initialize the logical map twice
(which will happen if your DT has valid cpu nodes and a chosen node pointing
to proper ACPI tables) or even having some entries initialized from DT and
others by ACPI. It is a big fat no-no, please update the series accordingly.
really good catch here :)
so the problem here is that should we use both ACPI and DT in one system?

quoted
+
+	return cpu;
+}
+
  static int __init
  acpi_parse_gic(struct acpi_subtable_header *header, const unsigned long end)
  {
@@ -144,6 +201,16 @@ acpi_parse_gic(struct acpi_subtable_header *header, const unsigned long end)
  
  	acpi_table_print_madt_entry(header);
  
+	/*
+	 * We need to register disabled CPU as well to permit
+	 * counting disabled CPUs. This allows us to size
+	 * cpus_possible_map more accurately, to permit
+	 * to not preallocating memory for all NR_CPUS
+	 * when we use CPU hotplug.
+	 */
+	acpi_register_gic_cpu_interface(processor->gic_id,
+			processor->flags & ACPI_MADT_ENABLED);
+
  	return 0;
  }
  
@@ -186,6 +253,19 @@ static int __init acpi_parse_madt_gic_entries(void)
  		return count;
  	}
  
+#ifdef CONFIG_SMP
+	if (available_cpus == 0) {
+		pr_info(PREFIX "Found 0 CPUs; assuming 1\n");
+		arm_cpu_to_apicid[available_cpus] =
+			read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+		available_cpus = 1;	/* We've got at least one of these */
+	}
I'd rather check the MADT for at least the boot cpu to present, if it is
not ACPI tables are horribly buggy and the kernel should barf on that.
quoted
+#endif
+
+	/* Make boot-up look pretty */
+	pr_info("%d CPUs available, %d CPUs total\n", available_cpus,
+		total_cpus);
Ok, now, how can we use the "disabled" CPUs == (total_cpus - available_cpus) ?
For cpus can be hot-added later when system is running.
Are we keeping track of them in the kernel at all ? It does not look
like, so I wonder whether we need this bit of info. I do not see why it
is pretty to know that there are disabled, aka unusable CPUs.
quoted
  	return 0;
  }
  
@@ -321,6 +401,9 @@ int __init early_acpi_boot_init(void)
  	if (acpi_disabled)
  		return -ENODEV;
  
+	/* Get the boot CPU's GIC cpu interface id before MADT parsing */
+	boot_cpu_apic_id = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
See Sudeep's comment.
I will rework this part to get the GIC cpu interface id, not the MPIDR here.

Thanks
Hanjun
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help