[linux-pm] Alternative Concept [Was: Re: [RFC] CPUFreq PowerOP integration, Intro 0/3]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

Some very basic incomplete sketch of how some of my ideas might look in
code:

 /*
 * OMAP PM Core implementation by Eugeny S. Mints <eugeny.mints at gmail.com>,
 * modified by Dominik Brodowski.
 *
 * Copyright (C) 2006, Nomad Global Solutions, Inc.
 * Copyright (C) 2006  Dominik Brodowski
 *
 * Based on code by Todd Poynor, Matthew Locke, Dmitry Chigirev, and
 * Bishop Brock.
 *
 * Copyright (C) 2002, 2004 MontaVista Software <source at mvista.com>.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

/* Number of colums in operating points table */
#define OP_VALUES  4


/* GENERIC PART BEGINS HERE */

struct op_entry {
	unsigned int value[OP_VALUES];
	struct op_entry *next;
};

int pm_core_verify_value(unsigned int what, unsigned int value,
			 struct op_entry *table,
			 int set_other(unsigned int, unsigned int))
{
	int i, colum = -1;
	struct op_entry *table_entry = table->next;

	for (i=0; i<OP_VALUES; i++) {
		if (table->value[i] == what)
			colum = i;
	}
	if (colum == -1)
		return -EINVAL;

	while (table_entry) {
		/* very easy algorithm at first: use the first
		   operating point which matches what we are looking
		   for
		*/
		if (table_entry->value[colum] == value)
			goto found_it;

		table_entry = table_entry->next;
	};
	return -EINVAL;

 found_it:
	for (i=0; i<OP_VALUES; i++) {
		if (i==colum)
			continue;
		/* FIXME: error handling */
		set_other(table->value[i], table_entry->value[i]);
	}
	return 0;
}

/* GENERIC PART ENDS HERE */



/* dummy */
static int set_cpu_vltg(unsigned int value)
{
	return 0;
}

static int set_dpll(unsigned int value)
{
	return 0;
}

static int set_cpu_freq(unsigned int value)
{
	return 0;
}

enum {
	CPU_VLTG = 0,
	DPLL = 1,
	CPU_FREQ = 2,
	OPPOINT_NR = 3,
};

static int set_pm(unsigned int what, unsigned int value)
{
	int ret = -ENODEV;

	/* FIXME
	pm_core_notify_prechange(what, value);
	*/

	switch (what) {
	case CPU_VLTG:
		/* FIXME: only set it if it is really different
		 * from current level */
		ret = set_cpu_vltg(value);
		break;
	case DPLL:
		ret = set_dpll(value);
		break;
	case CPU_FREQ:
		ret = set_cpu_freq(value);
		break;
	case OPPOINT_NR:
		/* ignore */
		break;
	}

	/* FIXME
	if (!ret)
		pm_core_notify_postchange(what, value);
	else
		pm_core_notify_failed_change(what, value);
	*/

	return ret;
}

/* THE TABLE CONTAING PRE-DEFINED OPERATING POINTS */


/* FIXME: think of a better way to set up a static table */
struct op_entry omap_op_static_entry4 = {
	.value = {2, 3, 2, 4},
};

struct op_entry omap_op_static_entry3 = {
	.value = {1, 2, 2, 3},
	.next = &omap_op_static_entry4,
};

struct op_entry omap_op_static_entry2 = {
	.value = {2, 1, 1, 2},
	.next = &omap_op_static_entry3,
};

struct op_entry omap_op_static_entry1 = {
	.value = {1, 1, 1, 1},
	.next = &omap_op_static_entry2,
};

struct op_entry omap_op_table = {
	.value = {CPU_VLTG, DPLL, CPU_FREQ, OPPOINT_NR},
	.next = &omap_op_static_entry1,
};


/* function being called by external interface. You can add
   whatever userspace API on top of it you like -- configfs,
   sysfs, module parameter, syscall, ... */

int omap_set(unsigned int what, unsigned int value)
{
	int ret;

	ret = pm_core_verify_value(what, value, &omap_op_table, set_pm);
	if (ret)
		return ret;

	return set_pm(what, value);
}


/*
To set a specific operating point, let's say, oppoint 3, the
yet-to-be-defined interface needs to call:

omap_set(OPPOINT_NR, 3);


Setting up a cpufreq interaction is quite easy, as it basically only
needs to call

omap_set(CPU_FREQ, validated_target_freq);

You only need to make sure that you're not using in-kernel CPU
frequency scaling parallel to setting oppoints. But such a validation
should be trivial to add.
*/



IT COMPILES!!! SHIP IT! ;)

Thanks,
	Dominik


[Index of Archives]     [Linux ACPI]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [CPU Freq]     [Kernel Newbies]     [Fedora Kernel]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux