On Friday, September 07, 2007 8:54 PM, Mark.Haywood at Sun.COM wrote:

> Hi Aubrey,
> 
> See comments inline ...
> 
> Li, Aubrey wrote:
>> Hi,
>> 
>> You may noticed this issue was reported many times on the mailing
>> list. 
>> 
>> I recently work on the speedstep driver and found the root cause.
>> 
>> 1) Processor supports SpeedStep feature, and the ACPI table offered
>> by BIOS has already included SSDT table, which includes processor
>> configuration objects like _PSS as well. The currect driver works
>> properly on this kind of machine. 
>> 
>> 2) Processor supports SpeedStep feature, and the ACPI table offered
>> by BIOS has included SSDT table, but this table doesn't include
>> processor configuration objects. This causes _PSS not found warning.
>> Actually, _PSS object exists in the processor configuration table,
>> which will be loaded by evaluating _PDC methods. The current driver
>> DOES call _PDC Methods, but the passed parameter is wrong. The
>> following patch fixed this issue. ( the patch is attached in case of
>> whitespace coding style issue).  
>> 
> 
> You aren't looking at the latest source. I've recently
> implemented this
> fix (about 2 weeks ago), sans the OR'ing of the ESS_PDC_C1_FFH
> bit which
> I don't think makes any sense for P-states since it's described in the
> Intel Processor Vendor-Specific ACPI Interface Specification this way:
> 
> "If set, OSPM supports the C1 "I/O then Halt" FFH sequence for
> multi-processor configurations"
> 
> Can you explain why that bit should be enabled? If it really does need
> to be enabled, then I think we should request that Intel should
> update the Interface Specification. 

Yes, I got the latest source now. I should update my working copy from
time to time.
As for this fix, I thnk the following patch is better to explain my
thoughts.

In case we support C state driver in future, It's better we call _PDC
method in cpu_acpi driver.
And IMHO, we should try to enable the all available capability when
evaluating _PDC.

Rename "cpu_acpi_write_pdc" to "cpu_acpi_init_pdc" is another change. 
According to the spec, initialize PDC may be better, ;-)

At least, we should put the PDC bits definitions into cpu_acpi.h. It
shouldn't belong to speedstep only.

What's your thoughts?

------------------------------------------------------------------------
--
diff -r 304eb1332eef usr/src/uts/i86pc/io/cpu_acpi.c
--- a/usr/src/uts/i86pc/io/cpu_acpi.c   Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/uts/i86pc/io/cpu_acpi.c   Mon Sep 10 03:35:54 2007 +0800
@@ -37,6 +37,7 @@ cpu_acpi_init(dev_info_t *dip)
 cpu_acpi_init(dev_info_t *dip)
 {
        cpu_acpi_handle_t handle;
+       uint32_t pdc_cap;
 
        handle = kmem_zalloc(sizeof (cpu_acpi_state_t), KM_SLEEP);
 
@@ -45,6 +46,13 @@ cpu_acpi_init(dev_info_t *dip)
                return (NULL);
        }
        handle->cs_dip = dip;
+
+       pdc_cap = CPU_ACPI_PDC_MSR | CPU_ACPI_PDC_MP_C1_FFH |
+                       CPU_ACPI_PDC_MP_C1PT | CPU_ACPI_PDC_MP_PSD |
+                       CPU_ACPI_PDC_MP_CSD | CPU_ACPI_PDC_MP_C1;
+
+       if (cpu_acpi_init_pdc(handle, CPU_ACPI_PDC_REVISION, 1,
&pdc_cap) != 0)
+                cmn_err(CE_NOTE,"Failed to write PDC");
        return (handle);
 }
 
@@ -416,7 +424,7 @@ cpu_acpi_install_ppc_handler(cpu_acpi_ha
  * Write _PDC.
  */
 int
-cpu_acpi_write_pdc(cpu_acpi_handle_t handle, uint32_t revision,
uint32_t count,
+cpu_acpi_init_pdc(cpu_acpi_handle_t handle, uint32_t revision, uint32_t
count,
     uint32_t *capabilities)
 {
        ACPI_OBJECT obj;
diff -r 304eb1332eef usr/src/uts/i86pc/io/speedstep.c
--- a/usr/src/uts/i86pc/io/speedstep.c  Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/uts/i86pc/io/speedstep.c  Mon Sep 10 03:29:30 2007 +0800
@@ -51,16 +51,6 @@
 #define        ESS_LATENCY_WAIT                100
 
 /*
- * The SpeedStep related Processor Driver Capabilities (_PDC).
- * See Intel Processor Vendor-Specific ACPI Interface Specification
- * for details.
- */
-#define        ESS_PDC_REVISION                0x1
-#define        ESS_PDC_PS_MSR                  (1<<0)
-#define        ESS_PDC_MP                      (1<<3)
-#define        ESS_PDC_PSD                     (1<<5)
-
-/*
  * MSR registers for changing and reading processor power state.
  */
 #define        IA32_PERF_STATCPUDRV_MSR                0x198
@@ -83,8 +73,6 @@ typedef struct speedstep_state {
 typedef struct speedstep_state {
        uint32_t ss_state;
 } speedstep_state_t;
-
-uint32_t ess_pdccap = ESS_PDC_PS_MSR | ESS_PDC_MP | ESS_PDC_PSD;
 
 /*
  * Read the status register. How it is read, depends upon the _PCT
@@ -202,7 +190,6 @@ speedstep_pstate_transition(int *ret, cp
        if (i >= ESS_MAX_LATENCY_MICROSECS) {
                DTRACE_PROBE(ess_transition_incomplete);
        }
-
        speedstep_state->ss_state = req_state;
        CPU->cpu_curr_clock =
            (((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000));
@@ -296,14 +283,6 @@ speedstep_init(cpudrv_devstate_t *cpudsp
                return (ESS_RET_NO_PM);
        }
 
-       /*
-        * _PDC support is optional and the driver should
-        * function even if the _PDC write fails.
-        */
-       if (cpu_acpi_write_pdc(handle, ESS_PDC_REVISION, 1,
-           &ess_pdccap) != 0)
-               ESSDEBUG(("Failed to write PDC\n"));
-
        if (cpu_acpi_cache_data(handle) != 0) {
                ESSDEBUG(("Failed to cache ACPI data\n"));
                cpu_acpi_fini(handle);
diff -r 304eb1332eef usr/src/uts/i86pc/sys/cpu_acpi.h
--- a/usr/src/uts/i86pc/sys/cpu_acpi.h  Thu Sep 06 19:30:39 2007 -0700
+++ b/usr/src/uts/i86pc/sys/cpu_acpi.h  Mon Sep 10 03:36:29 2007 +0800
@@ -59,6 +59,21 @@ extern "C" {
 #define        CPU_ACPI_IS_OBJ_CACHED(sp, obj) (sp->cpu_acpi_cached &
obj)
 #define        CPU_ACPI_OBJ_IS_CACHED(sp, obj) (sp->cpu_acpi_cached |=
obj)
 #define        CPU_ACPI_OBJ_IS_NOT_CACHED(sp, obj) (sp->cpu_acpi_cached
&= ~obj)
+
+/*
+ * Bit and revision definitions for _PDC
+ */
+#define        CPU_ACPI_PDC_REVISION           0x1
+
+#define        CPU_ACPI_PDC_MSR                (1 << 0)
+#define        CPU_ACPI_PDC_MP_C1_FFH          (1 << 1)
+#define        CPU_ACPI_PDC_T                  (1 << 2)
+#define        CPU_ACPI_PDC_MP_C1PT            (1 << 3)
+#define        CPU_ACPI_PDC_MP_C2C3            (1 << 4)
+#define        CPU_ACPI_PDC_MP_PSD             (1 << 5)
+#define        CPU_ACPI_PDC_MP_CSD             (1 << 6)
+#define        CPU_ACPI_PDC_MP_TSD             (1 << 7)
+#define        CPU_ACPI_PDC_MP_C1              (1 << 8)
 
 /*
  * Container for _PSD information
@@ -128,7 +143,7 @@ extern int cpu_acpi_cache_data(cpu_acpi_
 extern int cpu_acpi_cache_data(cpu_acpi_handle_t);
 extern void cpu_acpi_install_ppc_handler(cpu_acpi_handle_t,
     ACPI_NOTIFY_HANDLER, dev_info_t *);
-extern int cpu_acpi_write_pdc(cpu_acpi_handle_t, uint32_t, uint32_t,
+extern int cpu_acpi_init_pdc(cpu_acpi_handle_t, uint32_t, uint32_t,
     uint32_t *);
 extern int cpu_acpi_write_port(ACPI_IO_ADDRESS, uint32_t, uint32_t);
 extern int cpu_acpi_read_port(ACPI_IO_ADDRESS, uint32_t *, uint32_t);
------------------------------------------------------------------------
--------------------------

> 
>> 
> ---------------------------------------------------------------
> ---------
>> ----------
>> In addition, acpica building cpu map function assumes there is only
>> one processor type object under _PR_ object. That causes the
>> processor handler is always mapped to the last Processor Type
>> object. This is not correct on case 2) machine, it will cause to
>> give a wrong handler to evaluate _PDC object. That's another reason
>> that _PSS not found. Here is the patch(it's attached as well in case
>> of whitespace coding style issue),  
>> 
> 
> I'll have to look at this one some more. I don't understand you
> explanation and I don't understand the proposed fix. Are you sure
> that you didn't mean 
> 
> if (cpu_map[cpu_id]->obj != NULL)
>       cpu_map[cpu_id]->obj = obj;
> 

Two kinds of processor configuration machines in my hand.

1) _PR_ has only one child CPU0, which is ok.
CPU0 is _PDC's parent, and it will be mapped to the cpu acpi handler.
So when passed the handler to evaluate _PDC, it will be sucessful.

Level = 1, parent = \___ child = _PR_
Level = 2, parent = _PR_ child = CPU0
Level = 3, parent = CPU0 child = _PPC
Level = 3, parent = CPU0 child = _PCT
Level = 3, parent = CPU0 child = _PSS
Level = 3, parent = CPU0 child = SPSS
Level = 3, parent = CPU0 child = NPSS
Level = 3, parent = CPU0 child = _PDC

2) _PR_ has two child: P001 and CPU1. and the last object CPU1 is always
mapped to be the cpu acpi handler.
   However, P001 which is the parent of _PDC, should be the cpu acpi
handler.
We should always use the first one. So when **cpu_map[cpu_id]->obj ==
NULL **, we can assign **obj** to it.
Otherwise the first matched handler will be overwrite by the last one.
And the wrong parent parameter will be passed to evaluate _PDC.
So we run into failure.

Level = 1, parent = \___ child = _PR_
Level = 2, parent = _PR_ child = P001
Level = 3, parent = P001 child = HI0_
Level = 3, parent = P001 child = _PDC
Level = 3, parent = P001 child = _OSC
Level = 3, parent = P001 child = _CST
Level = 3, parent = P001 child = _PPC
Level = 3, parent = P001 child = _PCT
Level = 3, parent = P001 child = _PSD
Level = 3, parent = P001 child = _PSS
Level = 3, parent = P001 child = SPSS
Level = 3, parent = P001 child = NPSS
Level = 2, parent = _PR_ child = CPU1
------------------------------------------------------------------

Did you see the same problem on Toshiba Tecra M5?

Thanks,
-Aubrey

Reply via email to