acpi/pstate: Support Integer _PSD
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 31 May 2011 04:37:21 +0000 (12:37 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 31 May 2011 04:57:09 +0000 (12:57 +0800)
Standard _PSD should be package, while some buggy BIOSes will use Integer
for _PSD, e.g. Gigbyte's GA-H67MA-UD2H-B3.

Following template is used for Integer _PSD, after I have fiddled
around with the hw.acpi.cpu sysctl tree a little bit:
- Coordination is set to software all
- The integer of _PSD is taken as the power domain number
- The number of CPUs in the power domain is updated when new CPU in that
  power domain is seen

sys/dev/acpica5/acpi_cpu_pstate.c

index 6fcf086..537eb45 100644 (file)
@@ -92,6 +92,7 @@ LIST_HEAD(acpi_pst_domlist, acpi_pst_domain);
 
 #define ACPI_PSTDOM_FLAG_STUB  0x1     /* stub domain, no _PSD */
 #define ACPI_PSTDOM_FLAG_DEAD  0x2     /* domain can't be started */
+#define ACPI_PSTDOM_FLAG_INT   0x4     /* domain created from Integer _PSD */
 
 struct acpi_pst_softc {
        device_t                pst_dev;
@@ -114,7 +115,9 @@ static int  acpi_pst_attach(device_t dev);
 
 static void    acpi_pst_postattach(void *);
 static struct acpi_pst_domain *
-               acpi_pst_domain_create(device_t, ACPI_OBJECT *);
+               acpi_pst_domain_create_int(device_t, uint32_t);
+static struct acpi_pst_domain *
+               acpi_pst_domain_create_pkg(device_t, ACPI_OBJECT *);
 static struct acpi_pst_domain *
                acpi_pst_domain_find(uint32_t);
 static struct acpi_pst_domain *
@@ -294,16 +297,29 @@ acpi_pst_attach(device_t dev)
        if (!ACPI_FAILURE(status)) {
                obj = (ACPI_OBJECT *)buf.Pointer;
                if (ACPI_PKG_VALID_EQ(obj, 1)) {
-                       dom = acpi_pst_domain_create(dev,
+                       dom = acpi_pst_domain_create_pkg(dev,
                                &obj->Package.Elements[0]);
                        if (dom == NULL) {
                                AcpiOsFree(obj);
                                return ENXIO;
                        }
                } else {
-                       device_printf(dev, "Invalid _PSD package\n");
-                       AcpiOsFree(obj);
-                       return ENXIO;
+                       if (obj->Type != ACPI_TYPE_INTEGER) {
+                               device_printf(dev,
+                                   "Invalid _PSD package, Type 0x%x\n",
+                                   obj->Type);
+                               AcpiOsFree(obj);
+                               return ENXIO;
+                       } else {
+                               device_printf(dev, "Integer _PSD %ju\n",
+                                   (uintmax_t)obj->Integer.Value);
+                               dom = acpi_pst_domain_create_int(dev,
+                                   obj->Integer.Value);
+                               if (dom == NULL) {
+                                       AcpiOsFree(obj);
+                                       return ENXIO;
+                               }
+                       }
                }
 
                /* Free _PSD */
@@ -532,7 +548,7 @@ acpi_pst_attach(device_t dev)
 }
 
 static struct acpi_pst_domain *
-acpi_pst_domain_create(device_t dev, ACPI_OBJECT *obj)
+acpi_pst_domain_create_pkg(device_t dev, ACPI_OBJECT *obj)
 {
        struct acpi_pst_domain *dom;
        uint32_t val, domain, coord, nproc;
@@ -587,6 +603,11 @@ acpi_pst_domain_create(device_t dev, ACPI_OBJECT *obj)
 
        dom = acpi_pst_domain_find(domain);
        if (dom != NULL) {
+               if (dom->pd_flags & ACPI_PSTDOM_FLAG_INT) {
+                       device_printf(dev, "Mixed Integer _PSD and "
+                           "Package _PSD\n");
+                       return NULL;
+               }
                if (dom->pd_coord != coord || dom->pd_nproc != nproc) {
                        device_printf(dev, "Inconsistent _PSD information "
                                      "cross Processor objects\n");
@@ -597,7 +618,34 @@ acpi_pst_domain_create(device_t dev, ACPI_OBJECT *obj)
 
        dom = acpi_pst_domain_alloc(domain, coord, nproc);
        if (bootverbose)
-               device_printf(dev, "create domain%u\n", dom->pd_dom);
+               device_printf(dev, "create pkg domain%u\n", dom->pd_dom);
+
+       return dom;
+}
+
+static struct acpi_pst_domain *
+acpi_pst_domain_create_int(device_t dev, uint32_t domain)
+{
+       struct acpi_pst_domain *dom;
+
+       dom = acpi_pst_domain_find(domain);
+       if (dom != NULL) {
+               if ((dom->pd_flags & ACPI_PSTDOM_FLAG_INT) == 0) {
+                       device_printf(dev, "Mixed Package _PSD and "
+                           "Integer _PSD\n");
+                       return NULL;
+               }
+               KKASSERT(dom->pd_coord == ACPI_PSD_COORD_SWALL);
+
+               dom->pd_nproc++;
+               return dom;
+       }
+
+       dom = acpi_pst_domain_alloc(domain, ACPI_PSD_COORD_SWALL, 1);
+       dom->pd_flags |= ACPI_PSTDOM_FLAG_INT;
+
+       if (bootverbose)
+               device_printf(dev, "create int domain%u\n", dom->pd_dom);
 
        return dom;
 }