uncore->chan_id = -1;
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
hisi_uncore_pcc_reg_scan, uncore); if (ACPI_FAILURE(status) || uncore->chan_id < 0) return dev_err_probe(uncore->dev, -ENODEV, "Failed to get a PCC channel\n");
rc = devm_mutex_init(uncore->dev, &uncore->pcc_lock); if (rc) return rc;
if (WARN_ON(!uncore || !uncore->pchan)) return -ENODEV;
opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(opp)) {
dev_err(dev, "Failed to get opp for freq %lu hz\n", *freq); return PTR_ERR(opp);
}
dev_pm_opp_put(opp);
data = (u32)(dev_pm_opp_get_freq(opp) / HZ_PER_MHZ);
/* * Upon a failure, 'data' remains 0 and 'freq' is set to 0 rather than a * random value. devfreq shouldn't use 'freq' in that case though.
*/
*freq = data * HZ_PER_MHZ;
rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_GET_PLAT_FREQ_NUM,
&data); if (rc) return dev_err_probe(dev, rc, "Failed to get plat freq num\n");
num = data;
for (index = 0; index < num; index++) {
data = index;
rc = hisi_uncore_cmd_send(uncore,
HUCF_PCC_CMD_GET_PLAT_FREQ_BY_IDX,
&data); if (rc) {
dev_pm_opp_remove_all_dynamic(dev); return dev_err_probe(dev, rc, "Failed to get plat freq at index %u\n", index);
}
freq_mhz = data;
/* Don't care OPP voltage, take 1V as default */
rc = dev_pm_opp_add(dev, freq_mhz * HZ_PER_MHZ, 1000000); if (rc) {
dev_pm_opp_remove_all_dynamic(dev); return dev_err_probe(dev, rc, "Add OPP %lu failed\n", freq_mhz);
}
}
staticint hisi_platform_gov_func(struct devfreq *df, unsignedlong *freq)
{ /* * Platform-controlled mode doesn't care the frequency issued from * devfreq, so just pick the max freq.
*/
*freq = DEVFREQ_MAX_FREQ;
if (WARN_ON(!uncore || !uncore->pchan)) return -ENODEV;
switch (event) { case DEVFREQ_GOV_START:
data = HUCF_MODE_PLATFORM;
rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_MODE, &data); if (rc)
dev_err(uncore->dev, "Failed to set platform mode (%d)\n", rc); break; case DEVFREQ_GOV_STOP:
data = HUCF_MODE_OS;
rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_MODE, &data); if (rc)
dev_err(uncore->dev, "Failed to set os mode (%d)\n", rc); break; default: break;
}
return rc;
}
/* * In the platform-controlled mode, the platform decides the uncore frequency * and ignores the frequency issued from the driver. * Thus, create a pseudo 'hisi_platform' governor that stops devfreq monitor * from working so as to save meaningless overhead.
*/ staticstruct devfreq_governor hisi_platform_governor = {
.name = "hisi_platform", /* * Set interrupt_driven to skip the devfreq monitor mechanism, though * this governor is not interrupt-driven.
*/
.flags = DEVFREQ_GOV_FLAG_IRQ_DRIVEN,
.get_target_freq = hisi_platform_gov_func,
.event_handler = hisi_platform_gov_handler,
};
staticvoid hisi_uncore_remove_platform_gov(struct hisi_uncore_freq *uncore)
{
u32 data = HUCF_MODE_PLATFORM; int rc;
if (!(uncore->cap & HUCF_CAP_PLATFORM_CTRL)) return;
guard(mutex)(&hisi_platform_gov_usage_lock);
if (--hisi_platform_gov_usage == 0) {
rc = devfreq_remove_governor(&hisi_platform_governor); if (rc)
dev_err(uncore->dev, "Failed to remove hisi_platform gov (%d)\n", rc);
}
/* * Set to the platform-controlled mode on exit if supported, so as to * have a certain behaviour when the driver is detached.
*/
rc = hisi_uncore_cmd_send(uncore, HUCF_PCC_CMD_SET_MODE, &data); if (rc)
dev_err(uncore->dev, "Failed to set platform mode on exit (%d)\n", rc);
}
/* * Returns: * 0 if success, uncore->related_cpus is set. * -EINVAL if property not found, or property found but without elements in it, * or invalid arguments received in any of the subroutine. * Other error codes if it goes wrong.
*/ staticint hisi_uncore_mark_related_cpus(struct hisi_uncore_freq *uncore, char *property, int (*get_topo_id)(int cpu), conststruct cpumask *(*get_cpumask)(int cpu))
{ unsignedint i, cpu;
size_t len; int rc;
rc = device_property_count_u32(uncore->dev, property); if (rc < 0) return rc; if (rc == 0) return -EINVAL;
len = rc;
u32 *num __free(kfree) = kcalloc(len, sizeof(*num), GFP_KERNEL); if (!num) return -ENOMEM;
rc = device_property_read_u32_array(uncore->dev, property, num, len); if (rc) return rc;
for (i = 0; i < len; i++) {
for_each_possible_cpu(cpu) { if (get_topo_id(cpu) != num[i]) continue;
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.