Commit 77e3d86f authored by Prakash, Prashanth's avatar Prakash, Prashanth Committed by Rafael J. Wysocki

ACPI / CPPC: optimized cpc_read and cpc_write

cpc_read and cpc_write are used while holding the pcc_lock spin_lock,
so they need to be as fast as possible. acpi_os_read/write_memory
APIs linearly search through a list for cached mapping which is
quite expensive. Since the PCC subspace is already mapped into
virtual address space during initialization, we can just add the
offset and access the necessary CPPC registers.

This patch + similar changes to PCC driver reduce the time per freq.
transition from around 200us to about 20us for the CPPC cpufreq
driver.
Signed-off-by: default avatarPrashanth Prakash <pprakash@codeaurora.org>
Acked-by: default avatarAshwin Chaugule <ashwin.chaugule@linaro.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent ad62e1e6
...@@ -67,6 +67,9 @@ static int pcc_subspace_idx = -1; ...@@ -67,6 +67,9 @@ static int pcc_subspace_idx = -1;
static bool pcc_channel_acquired; static bool pcc_channel_acquired;
static ktime_t deadline; static ktime_t deadline;
/* pcc mapped address + header size + offset within PCC subspace */
#define GET_PCC_VADDR(offs) (pcc_comm_addr + 0x8 + (offs))
/* /*
* Arbitrary Retries in case the remote processor is slow to respond * Arbitrary Retries in case the remote processor is slow to respond
* to PCC commands. Keeping it high enough to cover emulators where * to PCC commands. Keeping it high enough to cover emulators where
...@@ -582,29 +585,74 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr) ...@@ -582,29 +585,74 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
} }
EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit); EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
static u64 get_phys_addr(struct cpc_reg *reg) /*
{ * Since cpc_read and cpc_write are called while holding pcc_lock, it should be
/* PCC communication addr space begins at byte offset 0x8. */ * as fast as possible. We have already mapped the PCC subspace during init, so
if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) * we can directly write to it.
return (u64)comm_base_addr + 0x8 + reg->address; */
else
return reg->address;
}
static void cpc_read(struct cpc_reg *reg, u64 *val) static int cpc_read(struct cpc_reg *reg, u64 *val)
{ {
u64 addr = get_phys_addr(reg); int ret_val = 0;
*val = 0;
if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
void __iomem *vaddr = GET_PCC_VADDR(reg->address);
acpi_os_read_memory((acpi_physical_address)addr, switch (reg->bit_width) {
case 8:
*val = readb(vaddr);
break;
case 16:
*val = readw(vaddr);
break;
case 32:
*val = readl(vaddr);
break;
case 64:
*val = readq(vaddr);
break;
default:
pr_debug("Error: Cannot read %u bit width from PCC\n",
reg->bit_width);
ret_val = -EFAULT;
}
} else
ret_val = acpi_os_read_memory((acpi_physical_address)reg->address,
val, reg->bit_width); val, reg->bit_width);
return ret_val;
} }
static void cpc_write(struct cpc_reg *reg, u64 val) static int cpc_write(struct cpc_reg *reg, u64 val)
{ {
u64 addr = get_phys_addr(reg); int ret_val = 0;
if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
void __iomem *vaddr = GET_PCC_VADDR(reg->address);
acpi_os_write_memory((acpi_physical_address)addr, switch (reg->bit_width) {
case 8:
writeb(val, vaddr);
break;
case 16:
writew(val, vaddr);
break;
case 32:
writel(val, vaddr);
break;
case 64:
writeq(val, vaddr);
break;
default:
pr_debug("Error: Cannot write %u bit width to PCC\n",
reg->bit_width);
ret_val = -EFAULT;
break;
}
} else
ret_val = acpi_os_write_memory((acpi_physical_address)reg->address,
val, reg->bit_width); val, reg->bit_width);
return ret_val;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment