On Wed, 15 Sep 2010 08:01:24 +0900
Taku YAMAMOTO <[email protected]> wrote:

> On Tue, 14 Sep 2010 11:44:45 +0300
> Andriy Gapon <[email protected]> wrote:
> 
> > Additionally, it seems that we do not currently have any support for 
> > Functional
> > Fixed Hardware (FFH) way of providing C states.  In this case _CST returns 
> > GAS
> > of a register used to enter a C state with address space ID set to
> > ACPI_ADR_SPACE_FIXED_HARDWARE (0x7f/127).  Such addresses should be handled 
> > in a
> > special way:
> > ftp://download.intel.com/technology/IAPC/acpi/downloads/30222305.pdf
> > 
> > Currently we simply (and silently) ignore such _CST entries.
> > I think that this should be useful (if not necessary) with mwait.
> 
> I have a proof-of-concept, quick'n'dirty patch against pre-r212541
> to utilize FFH _CST.
> 
> Unfortunately I have no time to catch up the latest and fantastic work by mav,
> though.

Uh, the patch got eaten by mailman...
Here it is.

-- 
-|-__   YAMAMOTO, Taku
 | __ <     <[email protected]>

      - A chicken is an egg's way of producing more eggs. -
diff -rup /sys/dev/acpica/acpi_cpu.c ./dev/acpica/acpi_cpu.c
--- sys/dev/acpica/acpi_cpu.c   2010-02-11 17:50:21.000000000 +0900
+++ sys/dev/acpica/acpi_cpu.c   2010-05-12 05:21:13.000000000 +0900
@@ -65,6 +65,13 @@ struct acpi_cx {
     uint32_t            trans_lat;     /* Transition latency (usec). */
     uint32_t            power;         /* Power consumed (mW). */
     int                         res_type;      /* Resource type for p_lvlx. */
+#ifdef ACPI_USE_NATIVE_CX
+#define pseudo_BUS_SPACE_FFIXEDHW      -1      /* FFixedHW pseudo resource */
+    uint8_t             vendor;        /* Encoded as BitWidth */
+    uint8_t             classcode;     /* Encoded as BitOffset */
+    uint8_t             arg1;          /* Encoded as AccessWidth */
+    uint64_t            arg0;          /* Encoded as Address */
+#endif /* ACPI_USE_NATIVE_CX */
 };
 #define MAX_CX_STATES   8
 
@@ -336,6 +343,9 @@ acpi_cpu_attach(device_t dev)
      * SMP control where each CPU can have different settings.
      */
     sc->cpu_features = ACPI_CAP_SMP_SAME | ACPI_CAP_SMP_SAME_C3;
+#ifdef ACPI_USE_NATIVE_CX /* XXX */
+    sc->cpu_features |= ACPI_CAP_SMP_C1_NATIVE | ACPI_CAP_SMP_CX_NATIVE;
+#endif
     if (devclass_get_drivers(acpi_cpu_devclass, &drivers, &drv_count) == 0) {
        for (i = 0; i < drv_count; i++) {
            if (ACPI_GET_FEATURES(drivers[i], &features) == 0)
@@ -688,9 +698,13 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *s
        switch (cx_ptr->type) {
        case ACPI_STATE_C1:
            sc->cpu_non_c3 = i;
+#ifdef ACPI_USE_NATIVE_CX
+           break;
+#else
            cx_ptr++;
            sc->cpu_cx_count++;
            continue;
+#endif
        case ACPI_STATE_C2:
            if (cx_ptr->trans_lat > 100) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -721,6 +735,21 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *s
        }
 #endif
 
+#ifdef ACPI_USE_NATIVE_CX
+       /* Check for FFixedHW first. */
+       if (acpi_PkgGasFFH(pkg, 0, &cx_ptr->vendor, &cx_ptr->classcode, 
&cx_ptr->arg1, &cx_ptr->arg0) == 0) {
+           /* We do not increment cpu_rid, because FixedHW isn't a resource. */
+           cx_ptr->res_type = pseudo_BUS_SPACE_FFIXEDHW;
+           ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                            "acpi_cpu%d: Got C%d - %d latency\n",
+                            device_get_unit(sc->cpu_dev), cx_ptr->type,
+                            cx_ptr->trans_lat));
+           cx_ptr++;
+           sc->cpu_cx_count++;
+           continue;
+       }
+#endif
+
        /* Allocate the control register for C2 or C3. */
        acpi_PkgGas(sc->cpu_dev, pkg, 0, &cx_ptr->res_type, &sc->cpu_rid,
            &cx_ptr->p_lvlx, RF_SHAREABLE);
@@ -779,6 +808,8 @@ acpi_cpu_startup(void *arg)
            if (sc->cpu_cx_count < cpu_cx_count)
                cpu_cx_count = sc->cpu_cx_count;
        }
+       if (cpu_cx_count <= 1)
+           return;
     } else {
        /*
         * We are using _CST mode, remove C3 state if necessary.
@@ -859,14 +890,12 @@ acpi_cpu_startup_cx(struct acpi_cpu_soft
                    (void *)sc, 0, acpi_cpu_usage_sysctl, "A",
                    "percent usage for each Cx state");
 
-#ifdef notyet
     /* Signal platform that we can handle _CST notification. */
     if (!cpu_cx_generic && cpu_cst_cnt != 0) {
        ACPI_LOCK(acpi);
        AcpiOsWritePort(cpu_smi_cmd, cpu_cst_cnt, 8);
        ACPI_UNLOCK(acpi);
     }
-#endif
 }
 
 /*
@@ -933,7 +962,11 @@ acpi_cpu_idle()
      * precisely calculate the time spent in C1 since the place we wake up
      * is an ISR.  Assume we slept no more than half of quantum.
      */
-    if (cx_next->type == ACPI_STATE_C1) {
+    if (cx_next->type == ACPI_STATE_C1
+#ifdef ACPI_USE_NATIVE_CX
+       && cx_next->vendor == 0 && cx_next->classcode == 0
+#endif
+           ) {
        AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock);
        acpi_cpu_c1();
        AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
@@ -958,6 +991,12 @@ acpi_cpu_idle()
      * is the only reliable time source.
      */
     AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock);
+#ifdef ACPI_USE_NATIVE_CX
+    if (cx_next->res_type == pseudo_BUS_SPACE_FFIXEDHW) {
+       acpi_cpu_cx_native(cx_next->vendor, cx_next->classcode, cx_next->arg1, 
cx_next->arg0);
+       AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
+    } else {
+#endif
     CPU_GET_REG(cx_next->p_lvlx, 1);
 
     /*
@@ -967,6 +1006,9 @@ acpi_cpu_idle()
      */
     AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
     AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock);
+#ifdef ACPI_USE_NATIVE_CX
+    }
+#endif
 
     /* Enable bus master arbitration and disable bus master wakeup. */
     if (cx_next->type == ACPI_STATE_C3 &&
diff -rup /sys/dev/acpica/acpi_package.c ./dev/acpica/acpi_package.c
--- sys/dev/acpica/acpi_package.c       2010-05-06 21:14:43.080994553 +0900
+++ sys/dev/acpica/acpi_package.c       2010-05-12 05:22:33.000000000 +0900
@@ -103,11 +103,9 @@ acpi_PkgStr(ACPI_OBJECT *res, int idx, v
     return (0);
 }
 
-int
-acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid,
-    struct resource **dst, u_int flags)
+static int
+acpi_get_PkgGas(ACPI_OBJECT *res, int idx, ACPI_GENERIC_ADDRESS *gas)
 {
-    ACPI_GENERIC_ADDRESS gas;
     ACPI_OBJECT *obj;
 
     obj = &res->Package.Elements[idx];
@@ -115,11 +113,46 @@ acpi_PkgGas(device_t dev, ACPI_OBJECT *r
        obj->Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3)
        return (EINVAL);
 
-    memcpy(&gas, obj->Buffer.Pointer + 3, sizeof(gas));
+    memcpy(gas, obj->Buffer.Pointer + 3, sizeof(*gas));
+    return (0);
+}
+
+int
+acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type, int *rid,
+    struct resource **dst, u_int flags)
+{
+    ACPI_GENERIC_ADDRESS gas;
+    int r;
 
+    r = acpi_get_PkgGas(res, idx, &gas);
+    if (r != 0)
+       return (r);
     return (acpi_bus_alloc_gas(dev, type, rid, &gas, dst, flags));
 }
 
+int
+acpi_PkgGasFFH(ACPI_OBJECT *res, int idx, uint8_t *vendor, uint8_t *classcode,
+    uint8_t *arg1, UINT64 *arg0)
+{
+    ACPI_GENERIC_ADDRESS gas;
+    int r;
+
+    r = acpi_get_PkgGas(res, idx, &gas);
+    if (r != 0)
+       return (r);
+
+    if (gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE)
+       return (EOPNOTSUPP);
+
+    /* Extract encoded values. */
+    *vendor = gas.BitWidth;
+    *classcode = gas.BitOffset;
+    *arg1 = gas.AccessWidth;
+    *arg0 = gas.Address;
+
+    return (0);
+}
+
 ACPI_HANDLE
 acpi_GetReference(ACPI_HANDLE scope, ACPI_OBJECT *obj)
 {
diff -rup /sys/dev/acpica/acpivar.h ./dev/acpica/acpivar.h
--- sys/dev/acpica/acpivar.h    2010-05-06 21:14:43.140066765 +0900
+++ sys/dev/acpica/acpivar.h    2010-05-10 05:29:23.000000000 +0900
@@ -201,6 +201,7 @@ extern struct mtx                   acpi_mutex;
 #define ACPI_CAP_SMP_DIFF_CX   (1 << 6) /* MP Cx (different, using _CSD) */
 #define ACPI_CAP_SMP_DIFF_TX   (1 << 7) /* MP Tx (different, using _TSD) */
 #define ACPI_CAP_SMP_C1_NATIVE (1 << 8) /* MP C1 support other than halt */
+#define ACPI_CAP_SMP_CX_NATIVE (1 << 9) /* MP Cx support other than halt */
 
 /*
  * Quirk flags.
@@ -449,6 +450,8 @@ int         acpi_PkgInt32(ACPI_OBJECT *res, int
 int            acpi_PkgStr(ACPI_OBJECT *res, int idx, void *dst, size_t size);
 int            acpi_PkgGas(device_t dev, ACPI_OBJECT *res, int idx, int *type,
                    int *rid, struct resource **dst, u_int flags);
+int            acpi_PkgGasFFH(ACPI_OBJECT *res, int idx, uint8_t *vendor,
+                   uint8_t *classcode, uint8_t *arg1, UINT64 *arg0);
 ACPI_HANDLE    acpi_GetReference(ACPI_HANDLE scope, ACPI_OBJECT *obj);
 
 /*
diff -rup /sys/i386/acpica/acpi_machdep.c ./i386/acpica/acpi_machdep.c
--- sys/i386/acpica/acpi_machdep.c      2010-05-06 21:15:10.955047053 +0900
+++ sys/i386/acpica/acpi_machdep.c      2010-05-11 04:51:27.000000000 +0900
@@ -560,6 +560,47 @@ acpi_cpu_c1()
 }
 
 /*
+ * vendor: ACPI_GENERIC_ADDRESS.BitWidth (8-bit).
+ * classcode: ACPI_GENERIC_ADDRESS.BitOffset (8-bit).
+ * arg1: ACPI_GENERIC_ADDRESS.AccessWidth (8-bit).
+ * arg0: ACPI_GENERIC_ADDRESS.Address (64-bit).
+ */
+void
+acpi_cpu_cx_native(uint8_t vendor, uint8_t classcode, uint8_t arg1, uint64_t 
arg0)
+{
+       switch (vendor) {
+       case 1: /* Intel */
+               switch (classcode) {
+               case 1:
+                       /*
+                        * C1 I/O then HLT.
+                        * arg0: I/O port address to inb.
+                        * arg1: not used (supposed to be 0).
+                        */
+                       inb((u_int)arg0);
+                       break;
+
+               case 2:
+                       /*
+                        * Native C state insn, a.k.a. MWAIT.
+                        * arg0[31:0] : hint for MWAIT (through EAX).
+                        * arg1[0] : H/W-coordinated.
+                        * arg1[1] : Requires bus-master avoidance. (?)
+                        */
+#define        MWAIT_INTR      0x01 /* an INT breaks MWAIT even if it's 
disabled. */
+                       cpu_mwait(MWAIT_INTR, (uint32_t)arg0);
+                       return;
+               }
+               break;
+
+               /* More vendors? */
+       }
+
+       /* Defaults to STI-HLT sequence. */
+       __asm __volatile("sti; hlt");
+}
+
+/*
  * Support for mapping ACPI tables during early boot.  This abuses the
  * crashdump map because the kernel cannot allocate KVA in
  * pmap_mapbios() when this is used.  This makes the following
diff -rup /sys/i386/i386/machdep.c ./i386/i386/machdep.c
--- sys/i386/i386/machdep.c     2010-04-13 19:12:58.000000000 +0900
+++ sys/i386/i386/machdep.c     2010-05-13 05:54:57.941747275 +0900
@@ -1227,6 +1227,23 @@ cpu_idle_acpi(int busy)
                __asm __volatile("sti; hlt");
 }
 
+static int cpu_ident_mwait_ext = 0;
+
+static int
+cpu_probe_mwait_ext(void)
+{
+       u_int regs[4]; /* XXX - should we prefer register_t? */
+
+       if (!(cpu_feature2 & CPUID2_MON))
+               return (0);
+       do_cpuid(5 /* CPUID_MONITOR */, regs);
+       if ((regs[2/*ecx*/] & 0x03/*MON_EXT|MON_INTR*/) == 0x03/*both set*/) {
+               cpu_ident_mwait_ext = 1;
+               return (1);
+       }
+       return (0);
+}
+
 static int cpu_ident_amdc1e = 0;
 
 static int
@@ -1322,6 +1339,14 @@ cpu_idle(int busy)
 #define        MWAIT_C3        0x20
 #define        MWAIT_C4        0x30
 
+/*
+ * mwait extensions.
+ */
+#define MWAIT_INTR     0x01
+
+/*
+ * monitorbuf usage.
+ */
 #define        MWAIT_DISABLED  0x0
 #define        MWAIT_WOKEN     0x1
 #define        MWAIT_WAITING   0x2
@@ -1359,6 +1384,27 @@ cpu_idle_mwait_hlt(int busy)
                cpu_mwait(0, MWAIT_C1);
 }
 
+static void
+cpu_idle_acpi_mwait(int busy)
+{
+       int *mwait;
+
+       disable_intr();
+       mwait = (int *)PCPU_PTR(monitorbuf);
+       *mwait = MWAIT_WAITING;
+       if (sched_runnable())
+               goto done;
+       cpu_monitor(mwait, 0, 0);
+       if (*mwait == MWAIT_WAITING) {
+               if (cpu_idle_hook)
+                       cpu_idle_hook();
+               else
+                       cpu_mwait(MWAIT_INTR, MWAIT_C1);
+       }
+done:
+       enable_intr();
+}
+
 int
 cpu_idle_wakeup(int cpu)
 {
@@ -1367,7 +1413,8 @@ cpu_idle_wakeup(int cpu)
 
        if (cpu_idle_fn == cpu_idle_spin)
                return (1);
-       if (cpu_idle_fn != cpu_idle_mwait && cpu_idle_fn != cpu_idle_mwait_hlt)
+       if (cpu_idle_fn != cpu_idle_mwait && cpu_idle_fn != cpu_idle_mwait_hlt
+           && cpu_idle_fn != cpu_idle_acpi_mwait)
                return (0);
        pcpu = pcpu_find(cpu);
        mwait = (int *)pcpu->pc_monitorbuf;
@@ -1395,6 +1442,7 @@ struct {
        { cpu_idle_amdc1e, "amdc1e" },
        { cpu_idle_hlt, "hlt" },
        { cpu_idle_acpi, "acpi" },
+       { cpu_idle_acpi_mwait, "acpi_mwait" },
        { NULL, NULL }
 };
 
@@ -1414,6 +1462,9 @@ idle_sysctl_available(SYSCTL_HANDLER_ARG
                if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 &&
                    cpu_ident_amdc1e == 0)
                        continue;
+               if (strcmp(idle_tbl[i].id_name, "acpi_mwait") == 0 &&
+                   cpu_ident_mwait_ext == 0)
+                       continue;
                p += sprintf(p, "%s, ", idle_tbl[i].id_name);
        }
        error = sysctl_handle_string(oidp, avail, 0, req);
@@ -1447,6 +1498,9 @@ idle_sysctl(SYSCTL_HANDLER_ARGS)
                if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 &&
                    cpu_ident_amdc1e == 0)
                        continue;
+               if (strcmp(idle_tbl[i].id_name, "acpi_mwait") == 0 &&
+                   cpu_ident_mwait_ext == 0)
+                       continue;
                if (strcmp(idle_tbl[i].id_name, buf))
                        continue;
                cpu_idle_fn = idle_tbl[i].id_fn;
@@ -2954,6 +3008,8 @@ init386(first)
        thread0.td_pcb->pcb_ext = 0;
        thread0.td_frame = &proc0_tf;
 
+       if (cpu_probe_mwait_ext())
+               cpu_idle_fn = cpu_idle_acpi_mwait;
        if (cpu_probe_amdc1e())
                cpu_idle_fn = cpu_idle_amdc1e;
 }
diff -rup /sys/i386/include/acpica_machdep.h ./i386/include/acpica_machdep.h
--- sys/i386/include/acpica_machdep.h   2009-10-07 06:34:28.915016725 +0900
+++ sys/i386/include/acpica_machdep.h   2010-05-11 04:43:31.000000000 +0900
@@ -94,9 +94,11 @@ extern int   acpi_release_global_lock(uint
 #define        COMPILER_DEPENDENT_INT64       long long
 #define        COMPILER_DEPENDENT_UINT64      unsigned long long
 #define        ACPI_USE_NATIVE_DIVIDE
+#define        ACPI_USE_NATIVE_CX
 
 void   acpi_SetDefaultIntrModel(int model);
 void   acpi_cpu_c1(void);
+void   acpi_cpu_cx_native(uint8_t vendor, uint8_t classcode, uint8_t arg1, 
uint64_t arg0);
 void   *acpi_map_table(vm_paddr_t pa, const char *sig);
 void   acpi_unmap_table(void *table);
 vm_paddr_t acpi_find_table(const char *sig);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-acpi
To unsubscribe, send any mail to "[email protected]"

Reply via email to