mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 09:43:59 +08:00
ACPI / CPPC: restructure read/writes for efficient sys mapped reg ops
For cases where sys mapped CPC registers need to be accessed frequently, it helps immensly to pre-map them rather than map and unmap for each operation. e.g. case where feedback counters are sys mem map registers. Restructure cpc_read/write and the cpc_regs structure to allow pre-mapping the system addresses and unmap them when the CPU exits. Signed-off-by: Ashwin Chaugule <ashwin.chaugule@linaro.org> Signed-off-by: Prashanth Prakash <pprakash@codeaurora.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
aca314efb1
commit
5bbb86aa4b
@ -62,7 +62,6 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
|
|||||||
/* This layer handles all the PCC specifics for CPPC. */
|
/* This layer handles all the PCC specifics for CPPC. */
|
||||||
static struct mbox_chan *pcc_channel;
|
static struct mbox_chan *pcc_channel;
|
||||||
static void __iomem *pcc_comm_addr;
|
static void __iomem *pcc_comm_addr;
|
||||||
static u64 comm_base_addr;
|
|
||||||
static int pcc_subspace_idx = -1;
|
static int pcc_subspace_idx = -1;
|
||||||
static bool pcc_channel_acquired;
|
static bool pcc_channel_acquired;
|
||||||
static ktime_t deadline;
|
static ktime_t deadline;
|
||||||
@ -394,7 +393,6 @@ EXPORT_SYMBOL_GPL(acpi_get_psd_map);
|
|||||||
static int register_pcc_channel(int pcc_subspace_idx)
|
static int register_pcc_channel(int pcc_subspace_idx)
|
||||||
{
|
{
|
||||||
struct acpi_pcct_hw_reduced *cppc_ss;
|
struct acpi_pcct_hw_reduced *cppc_ss;
|
||||||
unsigned int len;
|
|
||||||
u64 usecs_lat;
|
u64 usecs_lat;
|
||||||
|
|
||||||
if (pcc_subspace_idx >= 0) {
|
if (pcc_subspace_idx >= 0) {
|
||||||
@ -419,12 +417,6 @@ static int register_pcc_channel(int pcc_subspace_idx)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the shared communication region
|
|
||||||
* for the OS and Platform to communicate over.
|
|
||||||
*/
|
|
||||||
comm_base_addr = cppc_ss->base_address;
|
|
||||||
len = cppc_ss->length;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cppc_ss->latency is just a Nominal value. In reality
|
* cppc_ss->latency is just a Nominal value. In reality
|
||||||
@ -436,7 +428,7 @@ static int register_pcc_channel(int pcc_subspace_idx)
|
|||||||
pcc_mrtt = cppc_ss->min_turnaround_time;
|
pcc_mrtt = cppc_ss->min_turnaround_time;
|
||||||
pcc_mpar = cppc_ss->max_access_rate;
|
pcc_mpar = cppc_ss->max_access_rate;
|
||||||
|
|
||||||
pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len);
|
pcc_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length);
|
||||||
if (!pcc_comm_addr) {
|
if (!pcc_comm_addr) {
|
||||||
pr_err("Failed to ioremap PCC comm region mem\n");
|
pr_err("Failed to ioremap PCC comm region mem\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -545,6 +537,8 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
|
|||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpc_ptr->num_entries = num_ent;
|
||||||
|
|
||||||
/* Second entry should be revision. */
|
/* Second entry should be revision. */
|
||||||
cpc_obj = &out_obj->package.elements[1];
|
cpc_obj = &out_obj->package.elements[1];
|
||||||
if (cpc_obj->type == ACPI_TYPE_INTEGER) {
|
if (cpc_obj->type == ACPI_TYPE_INTEGER) {
|
||||||
@ -585,7 +579,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
|
|||||||
pr_debug("Mismatched PCC ids.\n");
|
pr_debug("Mismatched PCC ids.\n");
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
} else if (gas_t->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
|
} else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
|
||||||
|
if (gas_t->address) {
|
||||||
|
void __iomem *addr;
|
||||||
|
|
||||||
|
addr = ioremap(gas_t->address, gas_t->bit_width/8);
|
||||||
|
if (!addr)
|
||||||
|
goto out_free;
|
||||||
|
cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
/* Support only PCC and SYS MEM type regs */
|
/* Support only PCC and SYS MEM type regs */
|
||||||
pr_debug("Unsupported register type: %d\n", gas_t->space_id);
|
pr_debug("Unsupported register type: %d\n", gas_t->space_id);
|
||||||
goto out_free;
|
goto out_free;
|
||||||
@ -623,6 +626,13 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
|
/* Free all the mapped sys mem areas for this CPU */
|
||||||
|
for (i = 2; i < cpc_ptr->num_entries; i++) {
|
||||||
|
void __iomem *addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr;
|
||||||
|
|
||||||
|
if (addr)
|
||||||
|
iounmap(addr);
|
||||||
|
}
|
||||||
kfree(cpc_ptr);
|
kfree(cpc_ptr);
|
||||||
|
|
||||||
out_buf_free:
|
out_buf_free:
|
||||||
@ -640,7 +650,17 @@ EXPORT_SYMBOL_GPL(acpi_cppc_processor_probe);
|
|||||||
void acpi_cppc_processor_exit(struct acpi_processor *pr)
|
void acpi_cppc_processor_exit(struct acpi_processor *pr)
|
||||||
{
|
{
|
||||||
struct cpc_desc *cpc_ptr;
|
struct cpc_desc *cpc_ptr;
|
||||||
|
unsigned int i;
|
||||||
|
void __iomem *addr;
|
||||||
cpc_ptr = per_cpu(cpc_desc_ptr, pr->id);
|
cpc_ptr = per_cpu(cpc_desc_ptr, pr->id);
|
||||||
|
|
||||||
|
/* Free all the mapped sys mem areas for this CPU */
|
||||||
|
for (i = 2; i < cpc_ptr->num_entries; i++) {
|
||||||
|
addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr;
|
||||||
|
if (addr)
|
||||||
|
iounmap(addr);
|
||||||
|
}
|
||||||
|
|
||||||
kfree(cpc_ptr);
|
kfree(cpc_ptr);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
|
EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
|
||||||
@ -651,15 +671,27 @@ EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
|
|||||||
* we can directly write to it.
|
* we can directly write to it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int cpc_read(struct cpc_reg *reg, u64 *val)
|
static int cpc_read(struct cpc_register_resource *reg_res, u64 *val)
|
||||||
{
|
{
|
||||||
int ret_val = 0;
|
int ret_val = 0;
|
||||||
|
void __iomem *vaddr = 0;
|
||||||
|
struct cpc_reg *reg = ®_res->cpc_entry.reg;
|
||||||
|
|
||||||
|
if (reg_res->type == ACPI_TYPE_INTEGER) {
|
||||||
|
*val = reg_res->cpc_entry.int_value;
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
*val = 0;
|
*val = 0;
|
||||||
if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
|
if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
|
||||||
void __iomem *vaddr = GET_PCC_VADDR(reg->address);
|
vaddr = GET_PCC_VADDR(reg->address);
|
||||||
|
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
||||||
|
vaddr = reg_res->sys_mem_vaddr;
|
||||||
|
else
|
||||||
|
return acpi_os_read_memory((acpi_physical_address)reg->address,
|
||||||
|
val, reg->bit_width);
|
||||||
|
|
||||||
switch (reg->bit_width) {
|
switch (reg->bit_width) {
|
||||||
case 8:
|
case 8:
|
||||||
*val = readb_relaxed(vaddr);
|
*val = readb_relaxed(vaddr);
|
||||||
break;
|
break;
|
||||||
@ -674,23 +706,28 @@ static int cpc_read(struct cpc_reg *reg, u64 *val)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_debug("Error: Cannot read %u bit width from PCC\n",
|
pr_debug("Error: Cannot read %u bit width from PCC\n",
|
||||||
reg->bit_width);
|
reg->bit_width);
|
||||||
ret_val = -EFAULT;
|
ret_val = -EFAULT;
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
ret_val = acpi_os_read_memory((acpi_physical_address)reg->address,
|
|
||||||
val, reg->bit_width);
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpc_write(struct cpc_reg *reg, u64 val)
|
static int cpc_write(struct cpc_register_resource *reg_res, u64 val)
|
||||||
{
|
{
|
||||||
int ret_val = 0;
|
int ret_val = 0;
|
||||||
|
void __iomem *vaddr = 0;
|
||||||
|
struct cpc_reg *reg = ®_res->cpc_entry.reg;
|
||||||
|
|
||||||
if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
|
if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
|
||||||
void __iomem *vaddr = GET_PCC_VADDR(reg->address);
|
vaddr = GET_PCC_VADDR(reg->address);
|
||||||
|
else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
||||||
|
vaddr = reg_res->sys_mem_vaddr;
|
||||||
|
else
|
||||||
|
return acpi_os_write_memory((acpi_physical_address)reg->address,
|
||||||
|
val, reg->bit_width);
|
||||||
|
|
||||||
switch (reg->bit_width) {
|
switch (reg->bit_width) {
|
||||||
case 8:
|
case 8:
|
||||||
writeb_relaxed(val, vaddr);
|
writeb_relaxed(val, vaddr);
|
||||||
break;
|
break;
|
||||||
@ -705,13 +742,11 @@ static int cpc_write(struct cpc_reg *reg, u64 val)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pr_debug("Error: Cannot write %u bit width to PCC\n",
|
pr_debug("Error: Cannot write %u bit width to PCC\n",
|
||||||
reg->bit_width);
|
reg->bit_width);
|
||||||
ret_val = -EFAULT;
|
ret_val = -EFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
ret_val = acpi_os_write_memory((acpi_physical_address)reg->address,
|
|
||||||
val, reg->bit_width);
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,16 +789,16 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpc_read(&highest_reg->cpc_entry.reg, &high);
|
cpc_read(highest_reg, &high);
|
||||||
perf_caps->highest_perf = high;
|
perf_caps->highest_perf = high;
|
||||||
|
|
||||||
cpc_read(&lowest_reg->cpc_entry.reg, &low);
|
cpc_read(lowest_reg, &low);
|
||||||
perf_caps->lowest_perf = low;
|
perf_caps->lowest_perf = low;
|
||||||
|
|
||||||
cpc_read(&ref_perf->cpc_entry.reg, &ref);
|
cpc_read(ref_perf, &ref);
|
||||||
perf_caps->reference_perf = ref;
|
perf_caps->reference_perf = ref;
|
||||||
|
|
||||||
cpc_read(&nom_perf->cpc_entry.reg, &nom);
|
cpc_read(nom_perf, &nom);
|
||||||
perf_caps->nominal_perf = nom;
|
perf_caps->nominal_perf = nom;
|
||||||
|
|
||||||
if (!ref)
|
if (!ref)
|
||||||
@ -804,7 +839,7 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
|
|||||||
|
|
||||||
/* Are any of the regs PCC ?*/
|
/* Are any of the regs PCC ?*/
|
||||||
if ((delivered_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
|
if ((delivered_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) ||
|
||||||
(reference_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
|
(reference_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) {
|
||||||
/* Ring doorbell once to update PCC subspace */
|
/* Ring doorbell once to update PCC subspace */
|
||||||
if (send_pcc_cmd(CMD_READ) < 0) {
|
if (send_pcc_cmd(CMD_READ) < 0) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
@ -812,8 +847,8 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpc_read(&delivered_reg->cpc_entry.reg, &delivered);
|
cpc_read(delivered_reg, &delivered);
|
||||||
cpc_read(&reference_reg->cpc_entry.reg, &reference);
|
cpc_read(reference_reg, &reference);
|
||||||
|
|
||||||
if (!delivered || !reference) {
|
if (!delivered || !reference) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
@ -868,7 +903,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
|
|||||||
* Skip writing MIN/MAX until Linux knows how to come up with
|
* Skip writing MIN/MAX until Linux knows how to come up with
|
||||||
* useful values.
|
* useful values.
|
||||||
*/
|
*/
|
||||||
cpc_write(&desired_reg->cpc_entry.reg, perf_ctrls->desired_perf);
|
cpc_write(desired_reg, perf_ctrls->desired_perf);
|
||||||
|
|
||||||
/* Is this a PCC reg ?*/
|
/* Is this a PCC reg ?*/
|
||||||
if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
|
if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
|
||||||
@ -878,7 +913,6 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
|
|||||||
}
|
}
|
||||||
busy_channel:
|
busy_channel:
|
||||||
spin_unlock(&pcc_lock);
|
spin_unlock(&pcc_lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cppc_set_perf);
|
EXPORT_SYMBOL_GPL(cppc_set_perf);
|
||||||
|
@ -49,6 +49,7 @@ struct cpc_reg {
|
|||||||
*/
|
*/
|
||||||
struct cpc_register_resource {
|
struct cpc_register_resource {
|
||||||
acpi_object_type type;
|
acpi_object_type type;
|
||||||
|
u64 __iomem *sys_mem_vaddr;
|
||||||
union {
|
union {
|
||||||
struct cpc_reg reg;
|
struct cpc_reg reg;
|
||||||
u64 int_value;
|
u64 int_value;
|
||||||
|
Loading…
Reference in New Issue
Block a user