// SPDX-License-Identifier: GPL-2.0-only /* * AMD K7 Powernow driver. * (C) 2003 Dave Jones on behalf of SuSE Labs. * * Based upon datasheets & sample CPUs kindly provided by AMD. * * Errata 5: * CPU may fail to execute a FID/VID change in presence of interrupt. * - We cli/sti on stepping A0 CPUs around the FID/VID transition. * Errata 15: * CPU with half frequency multipliers may hang upon wakeup from disconnect. * - We disable half multipliers if ACPI is used on A0 stepping CPUs.
*/
if (have_a0 == 1) /* A0 errata 5 */
local_irq_disable();
if (freqs.old > freqs.new) { /* Going down, so change FID first */
change_FID(fid);
change_VID(vid);
} else { /* Going up, so change VID first */
change_VID(vid);
change_FID(fid);
}
/* processor_perflib will multiply the MHz value by 1000 to * get a KHz value (e.g. 1266000). However, powernow-k7 works * with true KHz values (e.g. 1266768). To ensure that all * powernow frequencies are available, we must ensure that * ACPI doesn't restrict them, so we round up the MHz value * to ensure that perflib's computed KHz value is greater than * or equal to powernow's KHz value.
*/ if (speed % 1000 > 0)
speed_mhz++;
if ((fid_codes[fid] % 10) == 5) { if (have_a0 == 1)
invalidate_entry(i);
}
/* notify BIOS that we exist */
acpi_processor_notify_smm(THIS_MODULE);
return 0;
err2:
acpi_processor_unregister_performance(0);
err1:
free_cpumask_var(acpi_processor_perf->shared_cpu_map);
err05:
kfree(acpi_processor_perf);
err0:
pr_warn("ACPI perflib can not be used on this platform\n");
acpi_processor_perf = NULL; return retval;
} #else staticint powernow_acpi_init(void)
{
pr_info("no support for ACPI processor found - please recompile your kernel with ACPI processor\n"); return -EINVAL;
} #endif
if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
pr_debug("Found PSB header at %p\n", p);
psb = (struct psb_s *) p;
pr_debug("Table version: 0x%x\n", psb->tableversion); if (psb->tableversion != 0x12) {
pr_info("Sorry, only v1.2 tables supported right now\n"); return -ENODEV;
}
pr_debug("Flags: 0x%x\n", psb->flags); if ((psb->flags & 1) == 0)
pr_debug("Mobile voltage regulator\n"); else
pr_debug("Desktop voltage regulator\n");
latency = psb->settlingtime; if (latency < 100) {
pr_info("BIOS set settling time to %d microseconds. Should be at least 100. Correcting.\n",
latency);
latency = 100;
}
pr_debug("Settling Time: %d microseconds.\n",
psb->settlingtime);
pr_debug("Has %d PST tables. (Only dumping ones " "relevant to this CPU).\n",
psb->numpst);
if ((etuple == pst->cpuid) &&
check_fsb(pst->fsbspeed) &&
(maxfid == pst->maxfid) &&
(startvid == pst->startvid)) {
print_pst_entry(pst, j);
p = (char *)pst + sizeof(*pst);
ret = get_ranges(p); return ret;
} else { unsignedint k;
p = (char *)pst + sizeof(*pst); for (k = 0; k < number_scales; k++)
p += 2;
}
}
pr_info("No PST tables match this cpuid (0x%x)\n",
etuple);
pr_info("This is indicative of a broken BIOS\n");
return -EINVAL;
}
p++;
}
return -ENODEV;
}
/* * We use the fact that the bus frequency is somehow * a multiple of 100000/3 khz, then we compute sgtc according * to this multiple. * That way, we match more how AMD thinks all of that work. * We will then get the same kind of behaviour already tested under * the "well-known" other OS.
*/ staticint fixup_sgtc(void)
{ unsignedint sgtc; unsignedint m;
m = fsb / 3333; if ((m % 10) >= 5)
m += 5;
m /= 10;
sgtc = 100 * m * latency;
sgtc = sgtc / 3; if (sgtc > 0xfffff) {
pr_warn("SGTC too large %d\n", sgtc);
sgtc = 0xfffff;
} return sgtc;
}
staticunsignedint powernow_get(unsignedint cpu)
{ union msr_fidvidstatus fidvidstatus; unsignedint cfid;
if (cpu) return 0;
rdmsrq(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
cfid = fidvidstatus.bits.CFID;
return fsb * fid_codes[cfid] / 10;
}
staticint acer_cpufreq_pst(conststruct dmi_system_id *d)
{
pr_warn("%s laptop with broken PST tables in BIOS detected\n",
d->ident);
pr_warn("You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
pr_warn("cpufreq scaling has been disabled as a result of this\n"); return 0;
}
/* * Some Athlon laptops have really fucked PST tables. * A BIOS update is all that can save them. * Mention this, and disable cpufreq.
*/ staticconststruct dmi_system_id powernow_dmi_table[] = {
{
.callback = acer_cpufreq_pst,
.ident = "Acer Aspire",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde Software"),
DMI_MATCH(DMI_BIOS_VERSION, "3A71"),
},
},
{ }
};
staticint powernow_cpu_init(struct cpufreq_policy *policy)
{ union msr_fidvidstatus fidvidstatus; int result;
if (policy->cpu != 0) return -ENODEV;
rdmsrq(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
recalibrate_cpu_khz();
fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; if (!fsb) {
pr_warn("can not determine bus frequency\n"); return -EINVAL;
}
pr_debug("FSB: %3dMHz\n", fsb/1000);
if (dmi_check_system(powernow_dmi_table) || acpi_force) {
pr_info("PSB/PST known to be broken - trying ACPI instead\n");
result = powernow_acpi_init();
} else {
result = powernow_decode_bios(fidvidstatus.bits.MFID,
fidvidstatus.bits.SVID); if (result) {
pr_info("Trying ACPI perflib\n");
maximum_speed = 0;
minimum_speed = -1;
latency = 0;
result = powernow_acpi_init(); if (result) {
pr_info("ACPI and legacy methods failed\n");
}
} else { /* SGTC use the bus clock as timer */
latency = fixup_sgtc();
pr_info("SGTC: %d\n", latency);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.