mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-18 19:05:39 +00:00
Merge branches 'acpi-cppc', 'acpi-pcc', 'acpi-apei' and 'acpi-osi'
Merge new material related to CPPC, PCC, APEI and OSI strings handling for 6.1-rc1: - Disable frequency invariance in the CPPC library if registers used by cppc_get_perf_ctrs() are accessed via PCC (Jeremy Linton). - Add ACPI disabled check to acpi_cpc_valid() (Perry Yuan). - Fix Tx acknowledge in the PCC address space handler (Huisong Li). - Use wait_for_completion_timeout() for PCC mailbox operations (Huisong Li). - Release resources on PCC address space setup failure path (Rafael Mendonca). - Remove unneeded result variables from APEI code (ye xingchen). - Print total number of records found during BERT log parsing (Dmitry Monakhov). - Drop support for 3 _OSI strings that should not be necessary any more and update documentation on custom _OSI strings so that adding new ones is not encouraged any more (Mario Limonciello). * acpi-cppc: ACPI: CPPC: Disable FIE if registers in PCC regions ACPI: CPPC: Add ACPI disabled check to acpi_cpc_valid() * acpi-pcc: ACPI: PCC: Fix Tx acknowledge in the PCC address space handler ACPI: PCC: replace wait_for_completion() ACPI: PCC: Release resources on address space setup failure path * acpi-apei: ACPI: APEI: Remove unneeded result variables ACPI: APEI: Add BERT error log footer * acpi-osi: ACPI: OSI: Update Documentation on custom _OSI strings ACPI: OSI: Remove Linux-HPI-Hybrid-Graphics _OSI string ACPI: OSI: Remove Linux-Lenovo-NV-HDMI-Audio _OSI string ACPI: OSI: Remove Linux-Dell-Video _OSI string
This commit is contained in:
commit
b1d03b7ec7
@ -41,26 +41,23 @@ But it is likely that they will all eventually be added.
|
||||
What should an OEM do if they want to support Linux and Windows
|
||||
using the same BIOS image? Often they need to do something different
|
||||
for Linux to deal with how Linux is different from Windows.
|
||||
Here the BIOS should ask exactly what it wants to know:
|
||||
|
||||
In this case, the OEM should create custom ASL to be executed by the
|
||||
Linux kernel and changes to Linux kernel drivers to execute this custom
|
||||
ASL. The easiest way to accomplish this is to introduce a device specific
|
||||
method (_DSM) that is called from the Linux kernel.
|
||||
|
||||
In the past the kernel used to support something like:
|
||||
_OSI("Linux-OEM-my_interface_name")
|
||||
where 'OEM' is needed if this is an OEM-specific hook,
|
||||
and 'my_interface_name' describes the hook, which could be a
|
||||
quirk, a bug, or a bug-fix.
|
||||
|
||||
In addition, the OEM should send a patch to upstream Linux
|
||||
via the linux-acpi@vger.kernel.org mailing list. When that patch
|
||||
is checked into Linux, the OS will answer "YES" when the BIOS
|
||||
on the OEM's system uses _OSI to ask if the interface is supported
|
||||
by the OS. Linux distributors can back-port that patch for Linux
|
||||
pre-installs, and it will be included by all distributions that
|
||||
re-base to upstream. If the distribution can not update the kernel binary,
|
||||
they can also add an acpi_osi=Linux-OEM-my_interface_name
|
||||
cmdline parameter to the boot loader, as needed.
|
||||
|
||||
If the string refers to a feature where the upstream kernel
|
||||
eventually grows support, a patch should be sent to remove
|
||||
the string when that support is added to the kernel.
|
||||
However this was discovered to be abused by other BIOS vendors to change
|
||||
completely unrelated code on completely unrelated systems. This prompted
|
||||
an evaluation of all of it's uses. This uncovered that they aren't needed
|
||||
for any of the original reasons. As such, the kernel will not respond to
|
||||
any custom Linux-* strings by default.
|
||||
|
||||
That was easy. Read on, to find out how to do it wrong.
|
||||
|
||||
|
@ -23,6 +23,12 @@
|
||||
|
||||
#include <acpi/pcc.h>
|
||||
|
||||
/*
|
||||
* Arbitrary retries in case the remote processor is slow to respond
|
||||
* to PCC commands
|
||||
*/
|
||||
#define PCC_CMD_WAIT_RETRIES_NUM 500
|
||||
|
||||
struct pcc_data {
|
||||
struct pcc_mbox_chan *pcc_chan;
|
||||
void __iomem *pcc_comm_addr;
|
||||
@ -63,6 +69,7 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
|
||||
if (IS_ERR(data->pcc_chan)) {
|
||||
pr_err("Failed to find PCC channel for subspace %d\n",
|
||||
ctx->subspace_id);
|
||||
kfree(data);
|
||||
return AE_NOT_FOUND;
|
||||
}
|
||||
|
||||
@ -72,6 +79,8 @@ acpi_pcc_address_space_setup(acpi_handle region_handle, u32 function,
|
||||
if (!data->pcc_comm_addr) {
|
||||
pr_err("Failed to ioremap PCC comm region mem for %d\n",
|
||||
ctx->subspace_id);
|
||||
pcc_mbox_free_channel(data->pcc_chan);
|
||||
kfree(data);
|
||||
return AE_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -86,6 +95,7 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
|
||||
{
|
||||
int ret;
|
||||
struct pcc_data *data = region_context;
|
||||
u64 usecs_lat;
|
||||
|
||||
reinit_completion(&data->done);
|
||||
|
||||
@ -96,10 +106,22 @@ acpi_pcc_address_space_handler(u32 function, acpi_physical_address addr,
|
||||
if (ret < 0)
|
||||
return AE_ERROR;
|
||||
|
||||
if (data->pcc_chan->mchan->mbox->txdone_irq)
|
||||
wait_for_completion(&data->done);
|
||||
if (data->pcc_chan->mchan->mbox->txdone_irq) {
|
||||
/*
|
||||
* pcc_chan->latency is just a Nominal value. In reality the remote
|
||||
* processor could be much slower to reply. So add an arbitrary
|
||||
* amount of wait on top of Nominal.
|
||||
*/
|
||||
usecs_lat = PCC_CMD_WAIT_RETRIES_NUM * data->pcc_chan->latency;
|
||||
ret = wait_for_completion_timeout(&data->done,
|
||||
usecs_to_jiffies(usecs_lat));
|
||||
if (ret == 0) {
|
||||
pr_err("PCC command executed timeout!\n");
|
||||
return AE_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
mbox_client_txdone(data->pcc_chan->mchan, ret);
|
||||
mbox_chan_txdone(data->pcc_chan->mchan, ret);
|
||||
|
||||
memcpy_fromio(value, data->pcc_comm_addr, data->ctx.length);
|
||||
|
||||
|
@ -125,12 +125,9 @@ EXPORT_SYMBOL_GPL(apei_exec_write_register);
|
||||
int apei_exec_write_register_value(struct apei_exec_context *ctx,
|
||||
struct acpi_whea_header *entry)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ctx->value = entry->value;
|
||||
rc = apei_exec_write_register(ctx, entry);
|
||||
|
||||
return rc;
|
||||
return apei_exec_write_register(ctx, entry);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(apei_exec_write_register_value);
|
||||
|
||||
|
@ -90,6 +90,9 @@ static void __init bert_print_all(struct acpi_bert_region *region,
|
||||
|
||||
if (skipped)
|
||||
pr_info(HW_ERR "Skipped %d error records\n", skipped);
|
||||
|
||||
if (printed + skipped)
|
||||
pr_info("Total records found: %d\n", printed + skipped);
|
||||
}
|
||||
|
||||
static int __init setup_bert_disable(char *str)
|
||||
|
@ -1020,14 +1020,10 @@ static int reader_pos;
|
||||
|
||||
static int erst_open_pstore(struct pstore_info *psi)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (erst_disable)
|
||||
return -ENODEV;
|
||||
|
||||
rc = erst_get_record_id_begin(&reader_pos);
|
||||
|
||||
return rc;
|
||||
return erst_get_record_id_begin(&reader_pos);
|
||||
}
|
||||
|
||||
static int erst_close_pstore(struct pstore_info *psi)
|
||||
|
@ -424,6 +424,9 @@ bool acpi_cpc_valid(void)
|
||||
struct cpc_desc *cpc_ptr;
|
||||
int cpu;
|
||||
|
||||
if (acpi_disabled)
|
||||
return false;
|
||||
|
||||
for_each_present_cpu(cpu) {
|
||||
cpc_ptr = per_cpu(cpc_desc_ptr, cpu);
|
||||
if (!cpc_ptr)
|
||||
@ -1240,6 +1243,48 @@ out_err:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
|
||||
|
||||
/**
|
||||
* cppc_perf_ctrs_in_pcc - Check if any perf counters are in a PCC region.
|
||||
*
|
||||
* CPPC has flexibility about how CPU performance counters are accessed.
|
||||
* One of the choices is PCC regions, which can have a high access latency. This
|
||||
* routine allows callers of cppc_get_perf_ctrs() to know this ahead of time.
|
||||
*
|
||||
* Return: true if any of the counters are in PCC regions, false otherwise
|
||||
*/
|
||||
bool cppc_perf_ctrs_in_pcc(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_present_cpu(cpu) {
|
||||
struct cpc_register_resource *ref_perf_reg;
|
||||
struct cpc_desc *cpc_desc;
|
||||
|
||||
cpc_desc = per_cpu(cpc_desc_ptr, cpu);
|
||||
|
||||
if (CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
|
||||
CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
|
||||
CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]))
|
||||
return true;
|
||||
|
||||
|
||||
ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
|
||||
|
||||
/*
|
||||
* If reference perf register is not supported then we should
|
||||
* use the nominal perf value
|
||||
*/
|
||||
if (!CPC_SUPPORTED(ref_perf_reg))
|
||||
ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
|
||||
|
||||
if (CPC_IN_PCC(ref_perf_reg))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc);
|
||||
|
||||
/**
|
||||
* cppc_get_perf_ctrs - Read a CPU's performance feedback counters.
|
||||
* @cpunum: CPU from which to read counters.
|
||||
|
@ -44,30 +44,6 @@ osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
|
||||
{"Processor Device", true},
|
||||
{"3.0 _SCP Extensions", true},
|
||||
{"Processor Aggregator Device", true},
|
||||
/*
|
||||
* Linux-Dell-Video is used by BIOS to disable RTD3 for NVidia graphics
|
||||
* cards as RTD3 is not supported by drivers now. Systems with NVidia
|
||||
* cards will hang without RTD3 disabled.
|
||||
*
|
||||
* Once NVidia drivers officially support RTD3, this _OSI strings can
|
||||
* be removed if both new and old graphics cards are supported.
|
||||
*/
|
||||
{"Linux-Dell-Video", true},
|
||||
/*
|
||||
* Linux-Lenovo-NV-HDMI-Audio is used by BIOS to power on NVidia's HDMI
|
||||
* audio device which is turned off for power-saving in Windows OS.
|
||||
* This power management feature observed on some Lenovo Thinkpad
|
||||
* systems which will not be able to output audio via HDMI without
|
||||
* a BIOS workaround.
|
||||
*/
|
||||
{"Linux-Lenovo-NV-HDMI-Audio", true},
|
||||
/*
|
||||
* Linux-HPI-Hybrid-Graphics is used by BIOS to enable dGPU to
|
||||
* output video directly to external monitors on HP Inc. mobile
|
||||
* workstations as Nvidia and AMD VGA drivers provide limited
|
||||
* hybrid graphics supports.
|
||||
*/
|
||||
{"Linux-HPI-Hybrid-Graphics", true},
|
||||
};
|
||||
|
||||
static u32 acpi_osi_handler(acpi_string interface, u32 supported)
|
||||
|
@ -353,7 +353,7 @@ void topology_init_cpu_capacity_cppc(void)
|
||||
struct cppc_perf_caps perf_caps;
|
||||
int cpu;
|
||||
|
||||
if (likely(acpi_disabled || !acpi_cpc_valid()))
|
||||
if (likely(!acpi_cpc_valid()))
|
||||
return;
|
||||
|
||||
raw_capacity = kcalloc(num_possible_cpus(), sizeof(*raw_capacity),
|
||||
|
@ -673,7 +673,7 @@ static int __init amd_pstate_init(void)
|
||||
return -ENODEV;
|
||||
|
||||
if (!acpi_cpc_valid()) {
|
||||
pr_debug("the _CPC object is not present in SBIOS\n");
|
||||
pr_warn_once("the _CPC object is not present in SBIOS or ACPI disabled\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,15 @@ static struct cppc_workaround_oem_info wa_info[] = {
|
||||
|
||||
static struct cpufreq_driver cppc_cpufreq_driver;
|
||||
|
||||
static enum {
|
||||
FIE_UNSET = -1,
|
||||
FIE_ENABLED,
|
||||
FIE_DISABLED
|
||||
} fie_disabled = FIE_UNSET;
|
||||
|
||||
#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
|
||||
module_param(fie_disabled, int, 0444);
|
||||
MODULE_PARM_DESC(fie_disabled, "Disable Frequency Invariance Engine (FIE)");
|
||||
|
||||
/* Frequency invariance support */
|
||||
struct cppc_freq_invariance {
|
||||
@ -158,7 +166,7 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
|
||||
struct cppc_freq_invariance *cppc_fi;
|
||||
int cpu, ret;
|
||||
|
||||
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
|
||||
if (fie_disabled)
|
||||
return;
|
||||
|
||||
for_each_cpu(cpu, policy->cpus) {
|
||||
@ -199,7 +207,7 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
|
||||
struct cppc_freq_invariance *cppc_fi;
|
||||
int cpu;
|
||||
|
||||
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
|
||||
if (fie_disabled)
|
||||
return;
|
||||
|
||||
/* policy->cpus will be empty here, use related_cpus instead */
|
||||
@ -229,7 +237,15 @@ static void __init cppc_freq_invariance_init(void)
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
|
||||
if (fie_disabled != FIE_ENABLED && fie_disabled != FIE_DISABLED) {
|
||||
fie_disabled = FIE_ENABLED;
|
||||
if (cppc_perf_ctrs_in_pcc()) {
|
||||
pr_info("FIE not enabled on systems with registers in PCC\n");
|
||||
fie_disabled = FIE_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fie_disabled)
|
||||
return;
|
||||
|
||||
kworker_fie = kthread_create_worker(0, "cppc_fie");
|
||||
@ -247,7 +263,7 @@ static void __init cppc_freq_invariance_init(void)
|
||||
|
||||
static void cppc_freq_invariance_exit(void)
|
||||
{
|
||||
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
|
||||
if (fie_disabled)
|
||||
return;
|
||||
|
||||
kthread_destroy_worker(kworker_fie);
|
||||
@ -936,6 +952,7 @@ static void cppc_check_hisi_workaround(void)
|
||||
wa_info[i].oem_revision == tbl->oem_revision) {
|
||||
/* Overwrite the get() callback */
|
||||
cppc_cpufreq_driver.get = hisi_cppc_cpufreq_get_rate;
|
||||
fie_disabled = FIE_DISABLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -947,7 +964,7 @@ static int __init cppc_cpufreq_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((acpi_disabled) || !acpi_cpc_valid())
|
||||
if (!acpi_cpc_valid())
|
||||
return -ENODEV;
|
||||
|
||||
cppc_check_hisi_workaround();
|
||||
|
@ -140,6 +140,7 @@ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
|
||||
extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
|
||||
extern int cppc_set_enable(int cpu, bool enable);
|
||||
extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
|
||||
extern bool cppc_perf_ctrs_in_pcc(void);
|
||||
extern bool acpi_cpc_valid(void);
|
||||
extern bool cppc_allow_fast_switch(void);
|
||||
extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
|
||||
@ -173,6 +174,10 @@ static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
static inline bool cppc_perf_ctrs_in_pcc(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool acpi_cpc_valid(void)
|
||||
{
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user