/** * cppc_set_perf - Set a CPUs performance controls. * @cpu: CPU for which to set performance controls. * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h * * Return: 0 for success, -ERRNO otherwise. */ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); struct cpc_register_resource *desired_reg; int ret = 0; if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpu); return -ENODEV; } desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; spin_lock(&pcc_lock); /* If this is PCC reg, check if channel is free before writing */ if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { ret = check_pcc_chan(); if (ret) goto busy_channel; } /* * Skip writing MIN/MAX until Linux knows how to come up with * useful values. */ cpc_write(&desired_reg->cpc_entry.reg, perf_ctrls->desired_perf); /* Is this a PCC reg ?*/ if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { /* Ring doorbell so Remote can get our perf request. */ if (send_pcc_cmd(CMD_WRITE) < 0) ret = -EIO; } busy_channel: spin_unlock(&pcc_lock); return ret; }
/* * This function transfers the ownership of the PCC to the platform * So it must be called while holding write_lock(pcc_lock) */ static int send_pcc_cmd(int pcc_ss_id, u16 cmd) { int ret = -EIO, i; struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; struct acpi_pcct_shared_memory *generic_comm_base = (struct acpi_pcct_shared_memory *)pcc_ss_data->pcc_comm_addr; unsigned int time_delta; /* * For CMD_WRITE we know for a fact the caller should have checked * the channel before writing to PCC space */ if (cmd == CMD_READ) { /* * If there are pending cpc_writes, then we stole the channel * before write completion, so first send a WRITE command to * platform */ if (pcc_ss_data->pending_pcc_write_cmd) send_pcc_cmd(pcc_ss_id, CMD_WRITE); ret = check_pcc_chan(pcc_ss_id, false); if (ret) goto end; } else /* CMD_WRITE */ pcc_ss_data->pending_pcc_write_cmd = FALSE; /* * Handle the Minimum Request Turnaround Time(MRTT) * "The minimum amount of time that OSPM must wait after the completion * of a command before issuing the next command, in microseconds" */ if (pcc_ss_data->pcc_mrtt) { time_delta = ktime_us_delta(ktime_get(), pcc_ss_data->last_cmd_cmpl_time); if (pcc_ss_data->pcc_mrtt > time_delta) udelay(pcc_ss_data->pcc_mrtt - time_delta); } /* * Handle the non-zero Maximum Periodic Access Rate(MPAR) * "The maximum number of periodic requests that the subspace channel can * support, reported in commands per minute. 0 indicates no limitation." * * This parameter should be ideally zero or large enough so that it can * handle maximum number of requests that all the cores in the system can * collectively generate. If it is not, we will follow the spec and just * not send the request to the platform after hitting the MPAR limit in * any 60s window */ if (pcc_ss_data->pcc_mpar) { if (pcc_ss_data->mpar_count == 0) { time_delta = ktime_ms_delta(ktime_get(), pcc_ss_data->last_mpar_reset); if ((time_delta < 60 * MSEC_PER_SEC) && pcc_ss_data->last_mpar_reset) { pr_debug("PCC cmd not sent due to MPAR limit"); ret = -EIO; goto end; } pcc_ss_data->last_mpar_reset = ktime_get(); pcc_ss_data->mpar_count = pcc_ss_data->pcc_mpar; } pcc_ss_data->mpar_count--; } /* Write to the shared comm region. */ writew_relaxed(cmd, &generic_comm_base->command); /* Flip CMD COMPLETE bit */ writew_relaxed(0, &generic_comm_base->status); pcc_ss_data->platform_owns_pcc = true; /* Ring doorbell */ ret = mbox_send_message(pcc_ss_data->pcc_channel, &cmd); if (ret < 0) { pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n", cmd, ret); goto end; } /* wait for completion and check for PCC errro bit */ ret = check_pcc_chan(pcc_ss_id, true); if (pcc_ss_data->pcc_mrtt) pcc_ss_data->last_cmd_cmpl_time = ktime_get(); if (pcc_ss_data->pcc_channel->mbox->txdone_irq) mbox_chan_txdone(pcc_ss_data->pcc_channel, ret); else mbox_client_txdone(pcc_ss_data->pcc_channel, ret); end: if (cmd == CMD_WRITE) { if (unlikely(ret)) { for_each_possible_cpu(i) { struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i); if (!desc) continue; if (desc->write_cmd_id == pcc_ss_data->pcc_write_cnt) desc->write_cmd_status = ret; } } pcc_ss_data->pcc_write_cnt++; wake_up_all(&pcc_ss_data->pcc_write_wait_q); } return ret; }
/** * cppc_set_perf - Set a CPUs performance controls. * @cpu: CPU for which to set performance controls. * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h * * Return: 0 for success, -ERRNO otherwise. */ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); struct cpc_register_resource *desired_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); struct cppc_pcc_data *pcc_ss_data; int ret = 0; if (!cpc_desc || pcc_ss_id < 0) { pr_debug("No CPC descriptor for CPU:%d\n", cpu); return -ENODEV; } pcc_ss_data = pcc_data[pcc_ss_id]; desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; /* * This is Phase-I where we want to write to CPC registers * -> We want all CPUs to be able to execute this phase in parallel * * Since read_lock can be acquired by multiple CPUs simultaneously we * achieve that goal here */ if (CPC_IN_PCC(desired_reg)) { down_read(&pcc_ss_data->pcc_lock); /* BEGIN Phase-I */ if (pcc_ss_data->platform_owns_pcc) { ret = check_pcc_chan(pcc_ss_id, false); if (ret) { up_read(&pcc_ss_data->pcc_lock); return ret; } } /* * Update the pending_write to make sure a PCC CMD_READ will not * arrive and steal the channel during the switch to write lock */ pcc_ss_data->pending_pcc_write_cmd = true; cpc_desc->write_cmd_id = pcc_ss_data->pcc_write_cnt; cpc_desc->write_cmd_status = 0; } /* * Skip writing MIN/MAX until Linux knows how to come up with * useful values. */ cpc_write(cpu, desired_reg, perf_ctrls->desired_perf); if (CPC_IN_PCC(desired_reg)) up_read(&pcc_ss_data->pcc_lock); /* END Phase-I */ /* * This is Phase-II where we transfer the ownership of PCC to Platform * * Short Summary: Basically if we think of a group of cppc_set_perf * requests that happened in short overlapping interval. The last CPU to * come out of Phase-I will enter Phase-II and ring the doorbell. * * We have the following requirements for Phase-II: * 1. We want to execute Phase-II only when there are no CPUs * currently executing in Phase-I * 2. Once we start Phase-II we want to avoid all other CPUs from * entering Phase-I. * 3. We want only one CPU among all those who went through Phase-I * to run phase-II * * If write_trylock fails to get the lock and doesn't transfer the * PCC ownership to the platform, then one of the following will be TRUE * 1. There is at-least one CPU in Phase-I which will later execute * write_trylock, so the CPUs in Phase-I will be responsible for * executing the Phase-II. * 2. Some other CPU has beaten this CPU to successfully execute the * write_trylock and has already acquired the write_lock. We know for a * fact it(other CPU acquiring the write_lock) couldn't have happened * before this CPU's Phase-I as we held the read_lock. * 3. Some other CPU executing pcc CMD_READ has stolen the * down_write, in which case, send_pcc_cmd will check for pending * CMD_WRITE commands by checking the pending_pcc_write_cmd. * So this CPU can be certain that its request will be delivered * So in all cases, this CPU knows that its request will be delivered * by another CPU and can return * * After getting the down_write we still need to check for * pending_pcc_write_cmd to take care of the following scenario * The thread running this code could be scheduled out between * Phase-I and Phase-II. Before it is scheduled back on, another CPU * could have delivered the request to Platform by triggering the * doorbell and transferred the ownership of PCC to platform. So this * avoids triggering an unnecessary doorbell and more importantly before * triggering the doorbell it makes sure that the PCC channel ownership * is still with OSPM. * pending_pcc_write_cmd can also be cleared by a different CPU, if * there was a pcc CMD_READ waiting on down_write and it steals the lock * before the pcc CMD_WRITE is completed. pcc_send_cmd checks for this * case during a CMD_READ and if there are pending writes it delivers * the write command before servicing the read command */ if (CPC_IN_PCC(desired_reg)) { if (down_write_trylock(&pcc_ss_data->pcc_lock)) {/* BEGIN Phase-II */ /* Update only if there are pending write commands */ if (pcc_ss_data->pending_pcc_write_cmd) send_pcc_cmd(pcc_ss_id, CMD_WRITE); up_write(&pcc_ss_data->pcc_lock); /* END Phase-II */ } else /* Wait until pcc_write_cnt is updated by send_pcc_cmd */ wait_event(pcc_ss_data->pcc_write_wait_q, cpc_desc->write_cmd_id != pcc_ss_data->pcc_write_cnt); /* send_pcc_cmd updates the status in case of failure */ ret = cpc_desc->write_cmd_status; } return ret; }
static int send_pcc_cmd(u16 cmd) { int ret = -EIO; struct acpi_pcct_shared_memory *generic_comm_base = (struct acpi_pcct_shared_memory *) pcc_comm_addr; static ktime_t last_cmd_cmpl_time, last_mpar_reset; static int mpar_count; unsigned int time_delta; /* * For CMD_WRITE we know for a fact the caller should have checked * the channel before writing to PCC space */ if (cmd == CMD_READ) { ret = check_pcc_chan(); if (ret) return ret; } /* * Handle the Minimum Request Turnaround Time(MRTT) * "The minimum amount of time that OSPM must wait after the completion * of a command before issuing the next command, in microseconds" */ if (pcc_mrtt) { time_delta = ktime_us_delta(ktime_get(), last_cmd_cmpl_time); if (pcc_mrtt > time_delta) udelay(pcc_mrtt - time_delta); } /* * Handle the non-zero Maximum Periodic Access Rate(MPAR) * "The maximum number of periodic requests that the subspace channel can * support, reported in commands per minute. 0 indicates no limitation." * * This parameter should be ideally zero or large enough so that it can * handle maximum number of requests that all the cores in the system can * collectively generate. If it is not, we will follow the spec and just * not send the request to the platform after hitting the MPAR limit in * any 60s window */ if (pcc_mpar) { if (mpar_count == 0) { time_delta = ktime_ms_delta(ktime_get(), last_mpar_reset); if (time_delta < 60 * MSEC_PER_SEC) { pr_debug("PCC cmd not sent due to MPAR limit"); return -EIO; } last_mpar_reset = ktime_get(); mpar_count = pcc_mpar; } mpar_count--; } /* Write to the shared comm region. */ writew_relaxed(cmd, &generic_comm_base->command); /* Flip CMD COMPLETE bit */ writew_relaxed(0, &generic_comm_base->status); /* Ring doorbell */ ret = mbox_send_message(pcc_channel, &cmd); if (ret < 0) { pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n", cmd, ret); return ret; } /* * For READs we need to ensure the cmd completed to ensure * the ensuing read()s can proceed. For WRITEs we dont care * because the actual write()s are done before coming here * and the next READ or WRITE will check if the channel * is busy/free at the entry of this call. * * If Minimum Request Turnaround Time is non-zero, we need * to record the completion time of both READ and WRITE * command for proper handling of MRTT, so we need to check * for pcc_mrtt in addition to CMD_READ */ if (cmd == CMD_READ || pcc_mrtt) { ret = check_pcc_chan(); if (pcc_mrtt) last_cmd_cmpl_time = ktime_get(); } mbox_client_txdone(pcc_channel, ret); return ret; }