Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b2d9942 authored by Venkatesh Pallipadi's avatar Venkatesh Pallipadi Committed by Len Brown
Browse files

P-state software coordination for ACPI core

parent 0bdd340c
Loading
Loading
Loading
Loading
+228 −0
Original line number Diff line number Diff line
@@ -553,6 +553,234 @@ static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
}
#endif				/* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */

static int acpi_processor_get_psd(struct acpi_processor	*pr)
{
	int result = 0;
	acpi_status status = AE_OK;
	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
	struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
	struct acpi_buffer state = {0, NULL};
	union acpi_object  *psd = NULL;
	struct acpi_psd_package *pdomain;

	ACPI_FUNCTION_TRACE("acpi_processor_get_psd");

	status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer);
	if (ACPI_FAILURE(status)) {
		return_VALUE(-ENODEV);
	}

	psd = (union acpi_object *) buffer.pointer;
	if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
		result = -EFAULT;
		goto end;
	}

	if (psd->package.count != 1) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
		result = -EFAULT;
		goto end;
	}

	pdomain = &(pr->performance->domain_info);

	state.length = sizeof(struct acpi_psd_package);
	state.pointer = pdomain;

	status = acpi_extract_package(&(psd->package.elements[0]),
		&format, &state);
	if (ACPI_FAILURE(status)) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
		result = -EFAULT;
		goto end;
	}

	if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n"));
		result = -EFAULT;
		goto end;
	}

	if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n"));
		result = -EFAULT;
		goto end;
	}

end:
	acpi_os_free(buffer.pointer);
	return_VALUE(result);
}

int acpi_processor_preregister_performance(
		struct acpi_processor_performance **performance)
{
	int count, count_target;
	int retval = 0;
	unsigned int i, j;
	cpumask_t covered_cpus;
	struct acpi_processor *pr;
	struct acpi_psd_package *pdomain;
	struct acpi_processor *match_pr;
	struct acpi_psd_package *match_pdomain;

	ACPI_FUNCTION_TRACE("acpi_processor_preregister_performance");

	down(&performance_sem);

	retval = 0;

	/* Call _PSD for all CPUs */
	for_each_cpu(i) {
		pr = processors[i];
		if (!pr) {
			/* Look only at processors in ACPI namespace */
			continue;
		}

		if (pr->performance) {
			retval = -EBUSY;
			continue;
		}

		if (!performance || !performance[i]) {
			retval = -EINVAL;
			continue;
		}

		pr->performance = performance[i];
		cpu_set(i, pr->performance->shared_cpu_map);
		if (acpi_processor_get_psd(pr)) {
			retval = -EINVAL;
			continue;
		}
	}
	if (retval)
		goto err_ret;

	/*
	 * Now that we have _PSD data from all CPUs, lets setup P-state 
	 * domain info.
	 */
	for_each_cpu(i) {
		pr = processors[i];
		if (!pr)
			continue;

		/* Basic validity check for domain info */
		pdomain = &(pr->performance->domain_info);
		if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
		    (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) {
			retval = -EINVAL;
			goto err_ret;
		}
		if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
		    pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
		    pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
			retval = -EINVAL;
			goto err_ret;
		}
	}

	cpus_clear(covered_cpus);
	for_each_cpu(i) {
		pr = processors[i];
		if (!pr)
			continue;

		if (cpu_isset(i, covered_cpus))
			continue;

		pdomain = &(pr->performance->domain_info);
		cpu_set(i, pr->performance->shared_cpu_map);
		cpu_set(i, covered_cpus);
		if (pdomain->num_processors <= 1)
			continue;

		/* Validate the Domain info */
		count_target = pdomain->num_processors;
		count = 1;
		if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL ||
		    pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) {
			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
		} else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) {
			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
		}

		for_each_cpu(j) {
			if (i == j)
				continue;

			match_pr = processors[j];
			if (!match_pr)
				continue;

			match_pdomain = &(match_pr->performance->domain_info);
			if (match_pdomain->domain != pdomain->domain)
				continue;

			/* Here i and j are in the same domain */

			if (match_pdomain->num_processors != count_target) {
				retval = -EINVAL;
				goto err_ret;
			}

			if (pdomain->coord_type != match_pdomain->coord_type) {
				retval = -EINVAL;
				goto err_ret;
			}

			cpu_set(j, covered_cpus);
			cpu_set(j, pr->performance->shared_cpu_map);
			count++;
		}

		for_each_cpu(j) {
			if (i == j)
				continue;

			match_pr = processors[j];
			if (!match_pr)
				continue;

			match_pdomain = &(match_pr->performance->domain_info);
			if (match_pdomain->domain != pdomain->domain)
				continue;

			match_pr->performance->shared_type = 
					pr->performance->shared_type;
			match_pr->performance->shared_cpu_map =
				pr->performance->shared_cpu_map;
		}
	}

err_ret:
	if (retval) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n"));
	}

	for_each_cpu(i) {
		pr = processors[i];
		if (!pr || !pr->performance)
			continue;

		/* Assume no coordination on any error parsing domain info */
		if (retval) {
			cpus_clear(pr->performance->shared_cpu_map);
			cpu_set(i, pr->performance->shared_cpu_map);
			pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
		}
		pr->performance = NULL; /* Will be set for real in register */
	}

	up(&performance_sem);
	return_VALUE(retval);
}
EXPORT_SYMBOL(acpi_processor_preregister_performance);


int
acpi_processor_register_performance(struct acpi_processor_performance
				    *performance, unsigned int cpu)
+26 −1
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include <linux/kernel.h>
#include <linux/config.h>
#include <linux/cpu.h>

#include <asm/acpi.h>

@@ -18,6 +19,17 @@

#define ACPI_PDC_REVISION_ID		0x1

#define ACPI_PSD_REV0_REVISION		0 /* Support for _PSD as in ACPI 3.0 */
#define ACPI_PSD_REV0_ENTRIES		5

/*
 * Types of coordination defined in ACPI 3.0. Same macros can be used across
 * P, C and T states
 */
#define DOMAIN_COORD_TYPE_SW_ALL	0xfc
#define DOMAIN_COORD_TYPE_SW_ANY	0xfd
#define DOMAIN_COORD_TYPE_HW_ALL	0xfe

/* Power Management */

struct acpi_processor_cx;
@@ -66,6 +78,14 @@ struct acpi_processor_power {

/* Performance Management */

struct acpi_psd_package {
	acpi_integer num_entries;
	acpi_integer revision;
	acpi_integer domain;
	acpi_integer coord_type;
	acpi_integer num_processors;
} __attribute__ ((packed));

struct acpi_pct_register {
	u8 descriptor;
	u16 length;
@@ -92,7 +112,9 @@ struct acpi_processor_performance {
	struct acpi_pct_register status_register;
	unsigned int state_count;
	struct acpi_processor_px *states;

	struct acpi_psd_package domain_info;
	cpumask_t shared_cpu_map;
	unsigned int shared_type;
};

/* Throttling Control */
@@ -161,6 +183,9 @@ struct acpi_processor_errata {
	} piix4;
};

extern int acpi_processor_preregister_performance(
		struct acpi_processor_performance **performance);

extern int acpi_processor_register_performance(struct acpi_processor_performance
					       *performance, unsigned int cpu);
extern void acpi_processor_unregister_performance(struct
+4 −0
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ struct cpufreq_real_policy {

struct cpufreq_policy {
	cpumask_t		cpus;	/* affected CPUs */
	unsigned int		shared_type; /* ANY or ALL affected CPUs
						should set cpufreq */
	unsigned int		cpu;    /* cpu nr of registered CPU */
	struct cpufreq_cpuinfo	cpuinfo;/* see above */

@@ -99,6 +101,8 @@ struct cpufreq_policy {
#define CPUFREQ_INCOMPATIBLE	(1)
#define CPUFREQ_NOTIFY		(2)

#define CPUFREQ_SHARED_TYPE_ALL	(0) /* All dependent CPUs should set freq */
#define CPUFREQ_SHARED_TYPE_ANY	(1) /* Freq can be set from any dependent CPU */

/******************** cpufreq transition notifiers *******************/