From e054cac74acbb7c869357e6a743af3e684fbd995 Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Tue, 19 Dec 2017 02:49:11 +0000 Subject: [PATCH] Implement ACPI CPU support when Processor object is not present By the ACPI standard (ACPI 5 chapter 8.4 Declaring Processors) Processors can be implemented in 2 distinct ways: * Through a Processor object type (which provides P_BLK) * Through a Device object type Prior to this change, the FreeBSD driver only supported the former. AMD Epyc / Poweredge systems we are testing both implement the latter only. Add the missing support. Because P_BLK is not defined in the device object case, C-states entering must be completely controlled via _CST methods rather than P_LVL2/3. John Baldwin points out that ACPI 6.0 formally deprecates the Processor keyword, so eventually processors will only be enumerated as Device objects. Submitted by: attilio Reviewed by: jhb, markj, Anton Rang Relnotes: maybe Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D13457 --- sys/dev/acpica/acpi_cpu.c | 104 +++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 36 deletions(-) diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c index 855e57b45d2..2be10d3ea83 100644 --- a/sys/dev/acpica/acpi_cpu.c +++ b/sys/dev/acpica/acpi_cpu.c @@ -140,6 +140,8 @@ struct acpi_cpu_device { #define CST_FFH_MWAIT_HW_COORD 0x0001 #define CST_FFH_MWAIT_BM_AVOID 0x0002 +#define CPUDEV_DEVICE_ID "ACPI0007" + /* Allow users to ignore processor orders in MADT. */ static int cpu_unordered; SYSCTL_INT(_debug_acpi, OID_AUTO, cpu_unordered, CTLFLAG_RDTUN, @@ -236,14 +238,21 @@ MODULE_DEPEND(cpu, acpi, 1, 1, 1); static int acpi_cpu_probe(device_t dev) { + static char *cpudev_ids[] = { CPUDEV_DEVICE_ID, NULL }; int acpi_id, cpu_id; ACPI_BUFFER buf; ACPI_HANDLE handle; ACPI_OBJECT *obj; ACPI_STATUS status; + ACPI_OBJECT_TYPE type; - if (acpi_disabled("cpu") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR || - acpi_cpu_disabled) + if (acpi_disabled("cpu") || acpi_cpu_disabled) + return (ENXIO); + type = acpi_get_type(dev); + if (type != ACPI_TYPE_PROCESSOR && type != ACPI_TYPE_DEVICE) + return (ENXIO); + if (type == ACPI_TYPE_DEVICE && + ACPI_ID_PROBE(device_get_parent(dev), dev, cpudev_ids) == NULL) return (ENXIO); handle = acpi_get_handle(dev); @@ -251,29 +260,39 @@ acpi_cpu_probe(device_t dev) cpu_softc = malloc(sizeof(struct acpi_cpu_softc *) * (mp_maxid + 1), M_TEMP /* XXX */, M_WAITOK | M_ZERO); - /* Get our Processor object. */ - buf.Pointer = NULL; - buf.Length = ACPI_ALLOCATE_BUFFER; - status = AcpiEvaluateObject(handle, NULL, NULL, &buf); - if (ACPI_FAILURE(status)) { - device_printf(dev, "probe failed to get Processor obj - %s\n", - AcpiFormatException(status)); - return (ENXIO); - } - obj = (ACPI_OBJECT *)buf.Pointer; - if (obj->Type != ACPI_TYPE_PROCESSOR) { - device_printf(dev, "Processor object has bad type %d\n", obj->Type); - AcpiOsFree(obj); - return (ENXIO); - } + if (type == ACPI_TYPE_PROCESSOR) { + /* Get our Processor object. */ + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_BUFFER; + status = AcpiEvaluateObject(handle, NULL, NULL, &buf); + if (ACPI_FAILURE(status)) { + device_printf(dev, "probe failed to get Processor obj - %s\n", + AcpiFormatException(status)); + return (ENXIO); + } + obj = (ACPI_OBJECT *)buf.Pointer; + if (obj->Type != ACPI_TYPE_PROCESSOR) { + device_printf(dev, "Processor object has bad type %d\n", + obj->Type); + AcpiOsFree(obj); + return (ENXIO); + } - /* - * Find the processor associated with our unit. We could use the - * ProcId as a key, however, some boxes do not have the same values - * in their Processor object as the ProcId values in the MADT. - */ - acpi_id = obj->Processor.ProcId; - AcpiOsFree(obj); + /* + * Find the processor associated with our unit. We could use the + * ProcId as a key, however, some boxes do not have the same values + * in their Processor object as the ProcId values in the MADT. + */ + acpi_id = obj->Processor.ProcId; + AcpiOsFree(obj); + } else { + status = acpi_GetInteger(handle, "_UID", &acpi_id); + if (ACPI_FAILURE(status)) { + device_printf(dev, "Device object has bad value - %s\n", + AcpiFormatException(status)); + return (ENXIO); + } + } if (acpi_pcpu_get_id(dev, &acpi_id, &cpu_id) != 0) return (ENXIO); @@ -325,19 +344,32 @@ acpi_cpu_attach(device_t dev) cpu_smi_cmd = AcpiGbl_FADT.SmiCommand; cpu_cst_cnt = AcpiGbl_FADT.CstControl; - buf.Pointer = NULL; - buf.Length = ACPI_ALLOCATE_BUFFER; - status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf); - if (ACPI_FAILURE(status)) { - device_printf(dev, "attach failed to get Processor obj - %s\n", - AcpiFormatException(status)); - return (ENXIO); + if (acpi_get_type(dev) == ACPI_TYPE_PROCESSOR) { + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_BUFFER; + status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf); + if (ACPI_FAILURE(status)) { + device_printf(dev, "attach failed to get Processor obj - %s\n", + AcpiFormatException(status)); + return (ENXIO); + } + obj = (ACPI_OBJECT *)buf.Pointer; + sc->cpu_p_blk = obj->Processor.PblkAddress; + sc->cpu_p_blk_len = obj->Processor.PblkLength; + sc->cpu_acpi_id = obj->Processor.ProcId; + AcpiOsFree(obj); + } else { + KASSERT(acpi_get_type(dev) == ACPI_TYPE_DEVICE, + ("Unexpected ACPI object")); + status = acpi_GetInteger(sc->cpu_handle, "_UID", &sc->cpu_acpi_id); + if (ACPI_FAILURE(status)) { + device_printf(dev, "Device object has bad value - %s\n", + AcpiFormatException(status)); + return (ENXIO); + } + sc->cpu_p_blk = 0; + sc->cpu_p_blk_len = 0; } - obj = (ACPI_OBJECT *)buf.Pointer; - sc->cpu_p_blk = obj->Processor.PblkAddress; - sc->cpu_p_blk_len = obj->Processor.PblkLength; - sc->cpu_acpi_id = obj->Processor.ProcId; - AcpiOsFree(obj); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "acpi_cpu%d: P_BLK at %#x/%d\n", device_get_unit(dev), sc->cpu_p_blk, sc->cpu_p_blk_len));