/** * struct amd_shmem_info - Shared memory table for AMD HFI * * @header: The PCCT table header including signature, length flags and command. * @version_number: Version number of the table * @n_logical_processors: Number of logical processors * @n_capabilities: Number of ranking dimensions (performance, efficiency, etc) * @table_update_context: Command being sent over the subspace * @n_bitmaps: Number of 32-bit bitmaps to enumerate all the APIC IDs * This is based on the maximum APIC ID enumerated in the system * @reserved: 24 bit spare * @table_data: Bit Map(s) of enabled logical processors * Followed by the ranking data for each logical processor
*/ struct amd_shmem_info { struct acpi_pcct_ext_pcc_shared_memory header;
u32 version_number :8,
n_logical_processors :8,
n_capabilities :8,
table_update_context :8;
u32 n_bitmaps :8,
reserved :24;
u32 table_data[];
};
/** * struct amd_hfi_classes - HFI class capabilities per CPU * @perf: Performance capability * @eff: Power efficiency capability * * Capabilities of a logical processor in the ranking table. These capabilities * are unitless and specific to each HFI class.
*/ struct amd_hfi_classes {
u32 perf;
u32 eff;
};
/** * struct amd_hfi_cpuinfo - HFI workload class info per CPU * @cpu: CPU index * @apic_id: APIC id of the current CPU * @cpus: mask of CPUs associated with amd_hfi_cpuinfo * @class_index: workload class ID index * @nr_class: max number of workload class supported * @ipcc_scores: ipcc scores for each class * @amd_hfi_classes: current CPU workload class ranking data * * Parameters of a logical processor linked with hardware feedback class.
*/ struct amd_hfi_cpuinfo { int cpu;
u32 apic_id;
cpumask_var_t cpus;
s16 class_index;
u8 nr_class; int *ipcc_scores; struct amd_hfi_classes *amd_hfi_classes;
};
pcc_comm_addr = acpi_os_ioremap(amd_hfi_data->pcc_chan->shmem_base_addr,
amd_hfi_data->pcc_chan->shmem_size); if (!pcc_comm_addr) {
dev_err(amd_hfi_data->dev, "failed to ioremap PCC common region mem\n"); return -ENOMEM;
}
if (amd_hfi_data->shmem->header.signature != PCC_SIGNATURE) {
dev_err(amd_hfi_data->dev, "invalid signature in shared memory\n"); return -EINVAL;
} if (amd_hfi_data->shmem->version_number != AMD_HETERO_RANKING_TABLE_VER) {
dev_err(amd_hfi_data->dev, "invalid version %d\n",
amd_hfi_data->shmem->version_number); return -EINVAL;
}
for (unsignedint i = 0; i < amd_hfi_data->shmem->n_bitmaps; i++) {
u32 bitmap = amd_hfi_data->shmem->table_data[i];
for (unsignedint j = 0; j < BITS_PER_TYPE(u32); j++) {
u32 apic_id = i * BITS_PER_TYPE(u32) + j; struct amd_hfi_cpuinfo *info; int cpu_index, apic_index;
if (!(bitmap & BIT(j))) continue;
cpu_index = find_cpu_index_by_apicid(apic_id); if (cpu_index < 0) {
dev_warn(amd_hfi_data->dev, "APIC ID %u not found\n", apic_id); continue;
}
info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu_index);
info->apic_id = apic_id;
/* Fill the ranking data for each logical processor */
info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu_index);
apic_index = apic_start * info->nr_class * 2; for (unsignedint k = 0; k < info->nr_class; k++) {
u32 *table = amd_hfi_data->shmem->table_data +
amd_hfi_data->shmem->n_bitmaps +
i * info->nr_class;
staticint amd_set_hfi_ipcc_score(struct amd_hfi_cpuinfo *hfi_cpuinfo, int cpu)
{ for (int i = 0; i < hfi_cpuinfo->nr_class; i++)
WRITE_ONCE(hfi_cpuinfo->ipcc_scores[i],
hfi_cpuinfo->amd_hfi_classes[i].perf);
/** * amd_hfi_online() - Enable workload classification on @cpu * @cpu: CPU in which the workload classification will be enabled * * Return: 0 on success, negative error code on failure.
*/ staticint amd_hfi_online(unsignedint cpu)
{ struct amd_hfi_cpuinfo *hfi_info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu); struct amd_hfi_classes *hfi_classes; int ret;
if (WARN_ON_ONCE(!hfi_info)) return -EINVAL;
/* * Check if @cpu as an associated, initialized and ranking data must * be filled.
*/
hfi_classes = hfi_info->amd_hfi_classes; if (!hfi_classes) return -EINVAL;
guard(mutex)(&hfi_cpuinfo_lock);
if (!zalloc_cpumask_var(&hfi_info->cpus, GFP_KERNEL)) return -ENOMEM;
cpumask_set_cpu(cpu, hfi_info->cpus);
ret = amd_hfi_set_state(cpu, true); if (ret)
pr_err("WCT enable failed for CPU %u\n", cpu);
return ret;
}
/** * amd_hfi_offline() - Disable workload classification on @cpu * @cpu: CPU in which the workload classification will be disabled * * Remove @cpu from those covered by its HFI instance. * * Return: 0 on success, negative error code on failure
*/ staticint amd_hfi_offline(unsignedint cpu)
{ struct amd_hfi_cpuinfo *hfi_info = &per_cpu(amd_hfi_cpuinfo, cpu); int ret;
if (WARN_ON_ONCE(!hfi_info)) return -EINVAL;
guard(mutex)(&hfi_cpuinfo_lock);
ret = amd_hfi_set_state(cpu, false); if (ret)
pr_err("WCT disable failed for CPU %u\n", cpu);
free_cpumask_var(hfi_info->cpus);
return ret;
}
staticint update_hfi_ipcc_scores(void)
{ int cpu; int ret;
pcc_mbox_channels = devm_kcalloc(&pdev->dev, AMD_HFI_MAILBOX_COUNT, sizeof(*pcc_mbox_channels), GFP_KERNEL); if (!pcc_mbox_channels) return -ENOMEM;
pcc_chan = devm_kcalloc(&pdev->dev, AMD_HFI_MAILBOX_COUNT, sizeof(*pcc_chan), GFP_KERNEL); if (!pcc_chan) return -ENOMEM;
status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl); if (ACPI_FAILURE(status) || !pcct_tbl) return -ENODEV;
/* get pointer to the first PCC subspace entry */
pcct_entry = (struct acpi_subtable_header *) (
(unsignedlong)pcct_tbl + sizeof(struct acpi_table_pcct));
ret = amd_hfi_alloc_class_data(pdev); if (ret) return ret;
ret = amd_hfi_metadata_parser(pdev, amd_hfi_data); if (ret) return ret;
ret = update_hfi_ipcc_scores(); if (ret) return ret;
/* * Tasks will already be running at the time this happens. This is * OK because rankings will be adjusted by the callbacks.
*/
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/amd_hfi:online",
amd_hfi_online, amd_hfi_offline); if (ret < 0) return ret;
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.