Fixes several issues with amd k8 SSDT P-state generation
authorOskar Enoksson <enok@lysator.liu.se>
Thu, 6 Oct 2011 16:43:43 +0000 (18:43 +0200)
committerMarc Jones <marcj303@gmail.com>
Mon, 17 Oct 2011 07:30:25 +0000 (09:30 +0200)
First issue fixed:
For multi-socket CPU the current implementation emitted
Processor objects for cores in the first CPU only. This
commit fixes the bug by really emitting one Processor
object for each core. However, the unlikely case of mixed
CPU models is still not handled correctly.

Second issue fixed:
One loop was wrong in case a processor in the table declares
no P-states at all. The rewritten loop is safe. Some possibly
dangerous array lengths were also fixed.

Third issue: on MP-boards the recommended ramp-voltage (RVO) is 0mV
according to the BKDG. The current implementation always set it
to 25mV. This commit selects 0 or 25mV depending on CONFIG_MAX_PHYSICAL_CPUS.

Fourth issue: If a processor without PowerNow! support was inserted in a
system with coreboot configured with SET_FIDVID then the boot process hanged
mysteriously and very early. Apparently because init_fidvid_ap tampers with
non-existing registers. This commit fixes the bug by bailing out
from init_fidvid_ap if PowerNow! capability is missing.

Signed-off-by: Oskar Enoksson <enok@lysator.liu.se>
Change-Id: I61f6e2210b84ccba33a36c5efc866447b7134417
Reviewed-on: http://review.coreboot.org/239
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marcj303@gmail.com>
src/cpu/amd/model_fxx/fidvid.c
src/cpu/amd/model_fxx/powernow_acpi.c

index bbafde666227f0973bc5c46e8f5fb7e202f8de17..6395a1e1c65a239904b6ec5cca6f8545600e4626 100644 (file)
@@ -347,13 +347,17 @@ static void init_fidvid_ap(unsigned bsp_apicid, unsigned apicid)
        u32 fid_max;
        int loop;
 
+       if((cpuid_edx(0x80000007)&0x06)!=0x06) {
+               return; /* FID/VID change not supported */
+       }
+
        msr = rdmsr(0xc0010042);
        fid_max = ((msr.lo >> 16) & 0x3f);      /* max fid */
 #if FX_SUPPORT
        if (fid_max >= ((25 - 4) * 2)) {        /* FX max fid is 5G */
                fid_max = ((msr.lo >> 8) & 0x3f) + 5 * 2;       /* maxFID = minFID + 1G */
                if (fid_max >= ((25 - 4) * 2)) {
-                       fid_max = (10 - 4) * 2; // hard set to 2G
+                       fid_max = (10 - 4) * 2; /* hard set to 2G */
                }
        }
 #endif
index bbcf013b1356c74f96598ab713c17b00f3f983c4..83d34f1058811712ddf41c8c2017a0c51b6e430d 100644 (file)
@@ -586,15 +586,27 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
        u8 cmp_cap;
        struct cpuentry *data = NULL;
        uint32_t control;
-       int i = 0, index, len = 0, Pstate_num = 0;
+       int i = 0, index = 0, len = 0, Pstate_num = 0, dev = 0;
        msr_t msr;
-       u8 Pstate_fid[10];
-       u16 Pstate_feq[10];
-       u8 Pstate_vid[10];
-       u32 Pstate_power[10];
+       u8 Pstate_fid[MAXP+1];
+       u16 Pstate_feq[MAXP+1];
+       u8 Pstate_vid[MAXP+1];
+       u32 Pstate_power[MAXP+1];
        u8 Max_fid, Start_fid, Start_vid, Max_vid;
-       struct cpuid_result cpuid1 = cpuid(0x80000001);
+       struct cpuid_result cpuid1;
+
+       /* See if the CPUID(0x80000007) returned EDX[2:1]==11b */
+       cpuid1 = cpuid(0x80000007);
+       if((cpuid1.edx & 0x6)!=0x6) {
+               printk(BIOS_INFO, "Processor not capable of performing P-state transitions\n");
+               return 0;
+       }
 
+       cpuid1 = cpuid(0x80000001);
+
+       /* It has been said that we can safely assume that all CPU's
+        * in the system have the same SYSCONF values
+        */
        msr = rdmsr(0xc0010042);
        Max_fid = (msr.lo & 0x3F0000) >> 16;
        Max_vid = (msr.hi & 0x3F0000) >> 16;
@@ -620,24 +632,51 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
                return 0;
        }
 
-       /* IRT 80us, PLL_LOCK_TIME 2us, MVS 25mv, VST 100us */
-       control = (3 << 30) | (2 << 20) | (0 << 18) | (5 << 11) | (1 << 29);
+#if CONFIG_MAX_PHYSICAL_CPUS==1
+       /* IRT 80us RVO = 50mV PLL_LOCK_TIME 2us, MVS 25mv, VST 100us */
+       control = (3 << 30) | (2 << 28) | (2 << 20) | (0 << 18) | (5 << 11);
+#else
+       /* MP-systems should default to RVO=0mV (no ramp voltage) */
+       /* IRT 80us RVO = 0mV PLL_LOCK_TIME 2us, MVS 25mv, VST 100us */
+
+       control = (3 << 30) | (0 << 28) | (2 << 20) | (0 << 18) | (5 << 11);
+#endif
+       /* RVO (Ramp Voltage Offset)
+        *   00   0mV (default for MP-systems)
+        *   01  25mV
+        *   10  50mV (default)
+        *   11  75mV
+        * IRT (Isochronous Release Time)
+        *   00  10uS
+        *   01  20uS
+        *   10  40uS
+        *   11  80uS (default)
+        * MVS (Maximum Voltage Step)
+        *   00  25mV (default)
+        *   01  50mV (reserved)
+        *   10 100mV (reserved)
+        *   11 200mV (reserved)
+        * VST (Voltage Stabilization Time)
+        *   time = value*20uS  (default value: 5 => 100uS)
+        * PLL_LOCK_TIME
+        *   time = value*1uS (often seen value: 2uS)
+        */
+
        len = 0;
-       Pstate_num = 0;
 
-       Pstate_fid[Pstate_num] = Max_fid;
-       Pstate_feq[Pstate_num] = fid_to_freq(Max_fid);
-       Pstate_vid[Pstate_num] = Max_vid;
-       Pstate_power[Pstate_num] = data->pwr * 100;
-       Pstate_num++;
+       Pstate_fid[0] = Max_fid;
+       Pstate_feq[0] = fid_to_freq(Max_fid);
+       Pstate_vid[0] = Max_vid;
+       Pstate_power[0] = data->pwr * 100;
 
-       do {
+       for(Pstate_num = 1;
+           (Pstate_num <= MAXP) && (data->pstates[Pstate_num - 1].freqMhz != 0);
+           Pstate_num++) {
                Pstate_fid[Pstate_num] = freq_to_fid(data->pstates[Pstate_num - 1].freqMhz) & 0x3f;
                Pstate_feq[Pstate_num] = data->pstates[Pstate_num - 1].freqMhz;
                Pstate_vid[Pstate_num] = vid_to_reg(data->pstates[Pstate_num - 1].voltage);
                Pstate_power[Pstate_num] = data->pstates[Pstate_num - 1].tdp * 100;
-               Pstate_num++;
-       } while ((Pstate_num < MAXP) && (data->pstates[Pstate_num - 1].freqMhz != 0));
+       }
 
        for (i=0;i<Pstate_num;i++)
                printk(BIOS_DEBUG, "P#%d freq %d [MHz] voltage %d [mV] TDP %d [mW]\n", i,
@@ -645,11 +684,19 @@ static int pstates_algorithm(u32 pcontrol_blk, u8 plen, u8 onlyBSP)
                       vid_from_reg(Pstate_vid[i]),
                       Pstate_power[i]);
 
-       for (index = 0; index < (cmp_cap + 1); index++) {
-               len += write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_vid,
-                               Pstate_fid, Pstate_power, index,
-                               pcontrol_blk, plen, onlyBSP, control);
+       /* Loop over all CPU's */
+       for (dev = 0x18; dev < 0x1c; dev++) {
+               if(dev_find_slot(0, PCI_DEVFN(dev, 0)) == NULL)
+                       continue;
+
+               for (i = 0; i < (cmp_cap + 1); i++) {
+                       len += write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_vid,
+                                       Pstate_fid, Pstate_power, index+i,
+                                       pcontrol_blk, plen, onlyBSP, control);
+               }
+               index += i;
        }
+       printk(BIOS_DEBUG,"%d Processor objects emitted to SSDT\n",index);
 
        return len;
 }