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 <rang AT acm.org>
Relnotes:	maybe
Sponsored by:	Dell EMC Isilon
Differential Revision:	https://reviews.freebsd.org/D13457
This commit is contained in:
Conrad Meyer 2017-12-19 02:49:11 +00:00
parent 22cf6021fc
commit e054cac74a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=326956

View File

@ -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));