[coreboot] New patch to review for coreboot: af6f38b Fixes several issues with amd k8 SSDT P-state generation
Oskar Enoksson (enok@lysator.liu.se)
gerrit at coreboot.org
Thu Oct 6 18:58:31 CEST 2011
Oskar Enoksson (enok at lysator.liu.se) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/239
-gerrit
commit af6f38bbfbf7702a5c432a6275e58dd13ce318bd
Author: Oskar Enoksson <enok at lysator.liu.se>
Date: Thu Oct 6 18:43:43 2011 +0200
Fixes several issues with amd k8 SSDT P-state generation
For multi-socket CPU the current implementation emitted
Processor objects for cores in the first CPU only. This
commit fixes the bug. One caveat though: the unlikely case
of CPU's with different FID/VID capabilities mixed in the
same system is not handled correctly.
Second issue fixed: processors not supporting P-state
transitions got no Processor objects at all. It's probably
better to give them a Processor object with one single P-state.
The old loop also looked wrong in case a processor
in the table doesn't have any declared 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 if the
number of populated CPU sockets is >1 or not.
Signed-off-by: Oskar Enoksson <enok at lysator.liu.se>
Change-Id: I61f6e2210b84ccba33a36c5efc866447b7134417
---
src/cpu/amd/model_fxx/powernow_acpi.c | 155 ++++++++++++++++++++++-----------
1 files changed, 103 insertions(+), 52 deletions(-)
diff --git a/src/cpu/amd/model_fxx/powernow_acpi.c b/src/cpu/amd/model_fxx/powernow_acpi.c
index bbcf013..65bbd90 100644
--- a/src/cpu/amd/model_fxx/powernow_acpi.c
+++ b/src/cpu/amd/model_fxx/powernow_acpi.c
@@ -586,70 +586,121 @@ 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, isock = 0, nsock = 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);
+ unsigned sockets[] = { 0x18, 0x19, 0x1a, 0x1b };
+ struct cpuentry entr_dummy = {.pstates[0].freqMhz = 0 };
- msr = rdmsr(0xc0010042);
- Max_fid = (msr.lo & 0x3F0000) >> 16;
- Max_vid = (msr.hi & 0x3F0000) >> 16;
- Start_fid = (msr.lo & 0x3F00) >> 8;
- Start_vid = (msr.hi & 0x3F00) >> 8;
-
- cmp_cap =
- (pci_read_config16(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xE8) &
- 0x3000) >> 12;
+ // Count number of populated sockets
+ for (isock = 0,nsock = 0; isock < ARRAY_SIZE(sockets); isock++) {
+ if(dev_find_slot(0, PCI_DEVFN(sockets[isock], 0))!=NULL)
+ nsock++;
+ }
+
+ for (isock = 0; isock < ARRAY_SIZE(sockets); isock++) {
+ if(dev_find_slot(0, PCI_DEVFN(sockets[isock], 0))==NULL)
+ continue;
+ // TODO: We should read msr from the right CPU here
+ // The following only works if fid/vid values are identical on
+ // all CPU's
+ msr = rdmsr(0xc0010042);
+ Max_fid = (msr.lo & 0x3F0000) >> 16;
+ Max_vid = (msr.hi & 0x3F0000) >> 16;
+ Start_fid = (msr.lo & 0x3F00) >> 8;
+ Start_vid = (msr.hi & 0x3F00) >> 8;
+
+ cmp_cap =
+ (pci_read_config16(dev_find_slot(0, PCI_DEVFN(sockets[isock], 3)), 0xE8) &
+ 0x3000) >> 12;
+
+ for (i = 0; i < ARRAY_SIZE(entr); i++) {
+ if ((entr[i].cpuid == cpuid1.eax)
+ && (entr[i].startFID == Start_fid)
+ && (entr[i].maxFID == Max_fid)
+ && (entr[i].brandID == ((u8 )((cpuid1.ebx >> 6) & 0xff)))) {
+ data = &entr[i];
+ break;
+ }
+ }
- for (i = 0; i < ARRAY_SIZE(entr); i++) {
- if ((entr[i].cpuid == cpuid1.eax)
- && (entr[i].startFID == Start_fid)
- && (entr[i].maxFID == Max_fid)
- && (entr[i].brandID == ((u8 )((cpuid1.ebx >> 6) & 0xff)))) {
- data = &entr[i];
+ if (data == NULL) {
+ printk(BIOS_WARNING, "Unknown CPU in socket %d, please update powernow_acpi.c\n",isock);
+ data = &entr_dummy;
+ }
+ /* See if the CPUID(0x80000007) returned EDX[2:1]==11b */
+ cpuid1 = cpuid(0x80000007);
+ switch ((cpuid1.edx & 0x6)) {
+ case 0x6:
+ break;
+ case 0x0:
+ printk(BIOS_INFO, "Processor not capable of performing P-state transitions\n");
+ data = &entr_dummy;
+ break;
+ default:
+ printk(BIOS_WARNING, "Capability of performing P-state transitions unknown\n");
break;
}
- }
-
- if (data == NULL) {
- printk(BIOS_WARNING, "Unknown CPU, please update the powernow_acpi.c\n");
- return 0;
- }
-
- /* IRT 80us, PLL_LOCK_TIME 2us, MVS 25mv, VST 100us */
- control = (3 << 30) | (2 << 20) | (0 << 18) | (5 << 11) | (1 << 29);
- 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++;
-
- do {
- 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;
+ if(nsock==1)
+ // IRT 80us, PLL_LOCK_TIME 2us, MVS 25mv, VST 100us RVO = 50mV
+ control = (3 << 30) | (2 << 20) | (0 << 18) | (5 << 11) | (1 << 29);
+ else
+ // MP-systems should default to RVO=0mV (no ramp voltage)
+ // IRT 80us, PLL_LOCK_TIME 2us, MVS 25mv, VST 100us RVO = 0mV
+ control = (3 << 30) | (2 << 20) | (0 << 18) | (5 << 11) | (0 << 29);
+ // RVO: 00 0mV (default for MP-systems)
+ // 01 25mV
+ // 10 50mV (default)
+ // 11 75mV
+ // IRT: 00 10uS
+ // 01 20uS
+ // 10 40uS
+ // 11 80uS (default)
+ // MVS: 00 25mV (default)
+ // 01 50mV (reserved)
+ // 10 100mV (reserved)
+ // 11 200mV (reserved)
+ // VST: time is value*20uS (default value: 5 => 100uS)
+ // PLL_LOCK_TIME: time is 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++;
- } 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,
- Pstate_feq[i],
- vid_from_reg(Pstate_vid[i]),
- Pstate_power[i]);
+ while ((Pstate_num <= MAXP) && (data->pstates[Pstate_num - 1].freqMhz != 0)) {
+ 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++;
+ }
- 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);
+ for (i=0;i<Pstate_num;i++)
+ printk(BIOS_DEBUG, "P#%d freq %d [MHz] voltage %d [mV] TDP %d [mW]\n", i,
+ Pstate_feq[i],
+ vid_from_reg(Pstate_vid[i]),
+ Pstate_power[i]);
+
+ 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 will be emitted to SSDT\n",index);
return len;
}
More information about the coreboot
mailing list