x86, ACPI: add support for x2apic ACPI extensions
Suresh Siddha [Mon, 30 Mar 2009 21:55:30 +0000 (13:55 -0800)]
All logical processors with APIC ID values of 255 and greater will have their
APIC reported through Processor X2APIC structure (type-9 entry type) and all
logical processors with APIC ID less than 255 will have their APIC reported
through legacy Processor Local APIC (type-0 entry type) only. This is the
same case even for NMI structure reporting.

The Processor X2APIC Affinity structure provides the association between the
X2APIC ID of a logical processor and the proximity domain to which the logical
processor belongs.

For OSPM, Procssor IDs outside the 0-254 range are to be declared as Device()
objects in the ACPI namespace.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>

arch/x86/kernel/acpi/boot.c
arch/x86/mm/srat_64.c
drivers/acpi/numa.c
drivers/acpi/processor_core.c
drivers/acpi/tables.c
include/linux/acpi.h

index 7678f10..565e70c 100644 (file)
@@ -260,6 +260,35 @@ static void __cpuinit acpi_register_lapic(int id, u8 enabled)
 }
 
 static int __init
+acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end)
+{
+       struct acpi_madt_local_x2apic *processor = NULL;
+
+       processor = (struct acpi_madt_local_x2apic *)header;
+
+       if (BAD_MADT_ENTRY(processor, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+#ifdef CONFIG_X86_X2APIC
+       /*
+        * 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_lapic(processor->local_apic_id,   /* APIC ID */
+                           processor->lapic_flags & ACPI_MADT_ENABLED);
+#else
+       printk(KERN_WARNING PREFIX "x2apic entry ignored\n");
+#endif
+
+       return 0;
+}
+
+static int __init
 acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
 {
        struct acpi_madt_local_apic *processor = NULL;
@@ -319,6 +348,25 @@ acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
 }
 
 static int __init
+acpi_parse_x2apic_nmi(struct acpi_subtable_header *header,
+                     const unsigned long end)
+{
+       struct acpi_madt_local_x2apic_nmi *x2apic_nmi = NULL;
+
+       x2apic_nmi = (struct acpi_madt_local_x2apic_nmi *)header;
+
+       if (BAD_MADT_ENTRY(x2apic_nmi, end))
+               return -EINVAL;
+
+       acpi_table_print_madt_entry(header);
+
+       if (x2apic_nmi->lint != 1)
+               printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
+
+       return 0;
+}
+
+static int __init
 acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
 {
        struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
@@ -823,6 +871,7 @@ static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
 static int __init acpi_parse_madt_lapic_entries(void)
 {
        int count;
+       int x2count = 0;
 
        if (!cpu_has_apic)
                return -ENODEV;
@@ -846,22 +895,28 @@ static int __init acpi_parse_madt_lapic_entries(void)
        count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC,
                                      acpi_parse_sapic, MAX_APICS);
 
-       if (!count)
+       if (!count) {
+               x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC,
+                                               acpi_parse_x2apic, MAX_APICS);
                count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC,
                                              acpi_parse_lapic, MAX_APICS);
-       if (!count) {
+       }
+       if (!count && !x2count) {
                printk(KERN_ERR PREFIX "No LAPIC entries present\n");
                /* TBD: Cleanup to allow fallback to MPS */
                return -ENODEV;
-       } else if (count < 0) {
+       } else if (count < 0 || x2count < 0) {
                printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
                /* TBD: Cleanup to allow fallback to MPS */
                return count;
        }
 
+       x2count =
+           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC_NMI,
+                                 acpi_parse_x2apic_nmi, 0);
        count =
            acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
-       if (count < 0) {
+       if (count < 0 || x2count < 0) {
                printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
                /* TBD: Cleanup to allow fallback to MPS */
                return count;
index 09737c8..13d56f5 100644 (file)
@@ -115,6 +115,36 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
        reserve_early(phys, phys + length, "ACPI SLIT");
 }
 
+/* Callback for Proximity Domain -> x2APIC mapping */
+void __init
+acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
+{
+       int pxm, node;
+       int apic_id;
+
+       if (srat_disabled())
+               return;
+       if (pa->header.length < sizeof(struct acpi_srat_x2apic_cpu_affinity)) {
+               bad_srat();
+               return;
+       }
+       if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
+               return;
+       pxm = pa->proximity_domain;
+       node = setup_node(pxm);
+       if (node < 0) {
+               printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
+               bad_srat();
+               return;
+       }
+
+       apic_id = pa->apic_id;
+       apicid_to_node[apic_id] = node;
+       acpi_numa = 1;
+       printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
+              pxm, apic_id, node);
+}
+
 /* Callback for Proximity Domain -> LAPIC mapping */
 void __init
 acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
index 3a0d8ef..d440ccd 100644 (file)
@@ -131,6 +131,21 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header)
 #endif                         /* ACPI_DEBUG_OUTPUT */
                break;
 
+       case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
+#ifdef ACPI_DEBUG_OUTPUT
+               {
+                       struct acpi_srat_x2apic_cpu_affinity *p =
+                           (struct acpi_srat_x2apic_cpu_affinity *)header;
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                         "SRAT Processor (x2apicid[0x%08x]) in"
+                                         " proximity domain %d %s\n",
+                                         p->apic_id,
+                                         p->proximity_domain,
+                                         (p->flags & ACPI_SRAT_CPU_ENABLED) ?
+                                         "enabled" : "disabled"));
+               }
+#endif                         /* ACPI_DEBUG_OUTPUT */
+               break;
        default:
                printk(KERN_WARNING PREFIX
                       "Found unsupported SRAT entry (type = 0x%x)\n",
@@ -180,8 +195,35 @@ static int __init acpi_parse_slit(struct acpi_table_header *table)
        return 0;
 }
 
+void __init __attribute__ ((weak))
+acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
+{
+       printk(KERN_WARNING PREFIX
+              "Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id);
+       return;
+}
+
+
+static int __init
+acpi_parse_x2apic_affinity(struct acpi_subtable_header *header,
+                          const unsigned long end)
+{
+       struct acpi_srat_x2apic_cpu_affinity *processor_affinity;
+
+       processor_affinity = (struct acpi_srat_x2apic_cpu_affinity *)header;
+       if (!processor_affinity)
+               return -EINVAL;
+
+       acpi_table_print_srat_entry(header);
+
+       /* let architecture-dependent part to do it */
+       acpi_numa_x2apic_affinity_init(processor_affinity);
+
+       return 0;
+}
+
 static int __init
-acpi_parse_processor_affinity(struct acpi_subtable_header * header,
+acpi_parse_processor_affinity(struct acpi_subtable_header *header,
                              const unsigned long end)
 {
        struct acpi_srat_cpu_affinity *processor_affinity;
@@ -241,6 +283,8 @@ int __init acpi_numa_init(void)
 {
        /* SRAT: Static Resource Affinity Table */
        if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
+               acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
+                                     acpi_parse_x2apic_affinity, NR_CPUS);
                acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
                                      acpi_parse_processor_affinity, NR_CPUS);
                acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
index 0cc2fd3..775324e 100644 (file)
@@ -427,6 +427,29 @@ static int map_lapic_id(struct acpi_subtable_header *entry,
        return 0;
 }
 
+static int map_x2apic_id(struct acpi_subtable_header *entry,
+                        int device_declaration, u32 acpi_id, int *apic_id)
+{
+       struct acpi_madt_local_x2apic *apic =
+               (struct acpi_madt_local_x2apic *)entry;
+       u32 tmp = apic->local_apic_id;
+
+       /* Only check enabled APICs*/
+       if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
+               return 0;
+
+       /* Device statement declaration type */
+       if (device_declaration) {
+               if (apic->uid == acpi_id)
+                       goto found;
+       }
+
+       return 0;
+found:
+       *apic_id = tmp;
+       return 1;
+}
+
 static int map_lsapic_id(struct acpi_subtable_header *entry,
                int device_declaration, u32 acpi_id, int *apic_id)
 {
@@ -476,6 +499,9 @@ static int map_madt_entry(int type, u32 acpi_id)
                if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
                        if (map_lapic_id(header, acpi_id, &apic_id))
                                break;
+               } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
+                       if (map_x2apic_id(header, type, acpi_id, &apic_id))
+                               break;
                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
                        if (map_lsapic_id(header, type, acpi_id, &apic_id))
                                break;
index a885295..991c006 100644 (file)
@@ -62,6 +62,18 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                }
                break;
 
+       case ACPI_MADT_TYPE_LOCAL_X2APIC:
+               {
+                       struct acpi_madt_local_x2apic *p =
+                           (struct acpi_madt_local_x2apic *)header;
+                       printk(KERN_INFO PREFIX
+                              "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n",
+                              p->local_apic_id, p->uid,
+                              (p->lapic_flags & ACPI_MADT_ENABLED) ?
+                              "enabled" : "disabled");
+               }
+               break;
+
        case ACPI_MADT_TYPE_IO_APIC:
                {
                        struct acpi_madt_io_apic *p =
@@ -116,6 +128,24 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
                }
                break;
 
+       case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
+               {
+                       u16 polarity, trigger;
+                       struct acpi_madt_local_x2apic_nmi *p =
+                           (struct acpi_madt_local_x2apic_nmi *)header;
+
+                       polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK;
+                       trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
+
+                       printk(KERN_INFO PREFIX
+                              "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n",
+                              p->uid,
+                              mps_inti_flags_polarity[polarity],
+                              mps_inti_flags_trigger[trigger],
+                              p->lint);
+               }
+               break;
+
        case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
                {
                        struct acpi_madt_local_apic_override *p =
index 6fce2fc..a6989e5 100644 (file)
@@ -96,6 +96,7 @@ void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
 /* the following four functions are architecture-dependent */
 void acpi_numa_slit_init (struct acpi_table_slit *slit);
 void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
+void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa);
 void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
 void acpi_numa_arch_fixup(void);