public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
From: Dominik Brodowski <linux-X3ehHDuj6sIIGcDfoQAp7BvVK+yQ3ZXh@public.gmane.org>
To: Len Brown <len.brown-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Cc: Jos Delbar <jos.delbar-Cru1EgDzd7c@public.gmane.org>,
	ACPI Developers
	<acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>,
	Robert Moore
	<robert.moore-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>,
	James P Ketrenos
	<james.p.ketrenos-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Subject: Re: Re: Linux ACPI processor driver patch: user-definable power state limit
Date: Sat, 6 Nov 2004 00:54:03 +0100	[thread overview]
Message-ID: <20041105235403.GA21880@dominikbrodowski.de> (raw)
In-Reply-To: <1099696293.13834.1639.camel@d845pe>

[ACPI-PROCESSOR] Dynamic limitation of available C-State types

Some drivers and/or some operations need to disable certain types of ACPI
CPU power states (a.k.a. C-States). Drivers which have requirements >= 99%
of the time should do:

1.) during module_init, get a struct acpi_cstate_limit *acpi_set_cstate_limit
    and pass the appropriate limit to acpi_set_cstate_limit().
2.) pass the aquired struct acpi_cstate_limit * to acpi_remove_cstate_limit() in
    module_exit.

A driver with dynamic requirements can do the following

1.) get a struct acpi_cstate_limit *acpi_set_cstate_limit(0);
    [zero means no limit!]
2.) a critical section should be marked like:
	acpi_modify_cstate_limit(cstate_limit, NEW_LIMIT);
	/* no C3 may be going on here... */
	...
	/* the CPU can sleep safely again */
	acpi_modify_cstate_limit(cstate_limit, 0);
3.) pass the aquired struct acpi_cstate_limit * to acpi_remove_cstate_limit() in
    module_exit.

Signed-off-by: Dominik Brodowski <linux-JhLEnvuH02M@public.gmane.org>

diff -ruN linux-original/drivers/acpi/processor.c linux/drivers/acpi/processor.c
--- linux-original/drivers/acpi/processor.c	2004-11-05 23:59:49.586947488 +0100
+++ linux/drivers/acpi/processor.c	2004-11-06 00:46:45.852810000 +0100
@@ -44,6 +44,7 @@
 #include <linux/seq_file.h>
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
+#include <linux/list.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -304,6 +305,80 @@
                                 Power Management
    -------------------------------------------------------------------------- */
 
+/* others shall not modify anything in here directly, so the layout isn't
+ * exported anywhere else 
+ */
+struct acpi_cstate_limit {
+	struct list_head	list;
+	unsigned int		limit;
+};
+
+static unsigned int cstate_limit;
+static LIST_HEAD(cstate_limit_list);
+static spinlock_t cstate_limit_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void acpi_update_cstate_limit(void)
+{
+	struct acpi_cstate_limit *cur;
+	unsigned int new_limit = 0;
+
+	list_for_each_entry(cur, &cstate_limit_list, list) {
+		if (cur->limit > new_limit)
+			new_limit = cur->limit;
+	}
+	cstate_limit = new_limit;
+}
+
+struct acpi_cstate_limit *acpi_set_cstate_limit(unsigned int limit)
+{
+	struct acpi_cstate_limit *data;
+	unsigned long flags;
+
+	might_sleep();
+
+	data = kmalloc(sizeof(struct acpi_cstate_limit), GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	data->limit = limit;
+	
+	spin_lock_irqsave(&cstate_limit_lock, flags);
+	list_add(&data->list, &cstate_limit_list);
+	acpi_update_cstate_limit();
+	spin_unlock_irqrestore(&cstate_limit_lock, flags);
+
+	return data;
+}
+
+int acpi_modify_cstate_limit(struct acpi_cstate_limit *data, unsigned int limit)
+{
+	unsigned long flags;
+	if (!data)
+		return -ENODEV;
+
+	spin_lock_irqsave(&cstate_limit_lock, flags);
+	data->limit = limit;
+	acpi_update_cstate_limit();
+	spin_unlock_irqrestore(&cstate_limit_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(acpi_modify_cstate_limit);
+
+void acpi_remove_cstate_limit(struct acpi_cstate_limit *data)
+{
+	unsigned long flags;
+	if (!data)
+		return;
+
+	spin_lock_irqsave(&cstate_limit_lock, flags);
+	list_del(&data->list);
+	acpi_update_cstate_limit();
+	spin_unlock_irqrestore(&cstate_limit_lock, flags);
+}
+EXPORT_SYMBOL(acpi_remove_cstate_limit);
+
+
 static inline u32
 ticks_elapsed (
 	u32			t1,
@@ -359,6 +434,8 @@
 	int			next_state = 0;
 	int			sleep_ticks = 0;
 	u32			t1, t2 = 0;
+	unsigned long flags;
+
 
 	pr = processors[smp_processor_id()];
 	if (!pr)
@@ -419,6 +496,21 @@
 		}
 	}
 
+	/* Dynamic limitation? */
+	spin_lock_irqsave(&cstate_limit_lock, flags);
+	if ((cstate_limit) && (cstate_limit <= pr->power.state)) {
+		next_state = cstate_limit;
+		while (next_state > 1) {
+			if (!pr->power.states[next_state].valid)
+				next_state--;
+		}
+		spin_unlock_irqrestore(&cstate_limit_lock, flags);
+		local_irq_enable();
+		goto end;
+	}
+	spin_unlock_irqrestore(&cstate_limit_lock, flags);
+
+
 	cx->usage++;
 
 	/*
@@ -487,6 +579,7 @@
 
 	next_state = pr->power.state;
 
+
 	/*
 	 * Promotion?
 	 * ----------
@@ -494,7 +587,7 @@
 	 * and promote when the count threshold is reached.  Note that bus
 	 * mastering activity may prevent promotions.
 	 */
-	if (cx->promotion.state) {
+	if (cx->promotion.state && !t2) {
 		if (sleep_ticks > cx->promotion.threshold.ticks) {
 			cx->promotion.count++;
  			cx->demotion.count = 0;
@@ -537,8 +630,16 @@
 	 * If we're going to start using a new Cx state we must clean up
 	 * from the previous and prepare to use the new.
 	 */
-	if (next_state != pr->power.state)
-		acpi_processor_power_activate(pr, next_state);
+	if (next_state != pr->power.state) {
+		/* Dynamic limitation? */
+		spin_lock_irqsave(&cstate_limit_lock, flags);
+		if (cstate_limit && (cstate_limit >= next_state)) {
+			spin_unlock_irqrestore(&cstate_limit_lock, flags);
+		} else {
+			spin_unlock_irqrestore(&cstate_limit_lock, flags);
+			acpi_processor_power_activate(pr, next_state);
+		}
+	}
 
 	return;
 }
diff -ruN linux-original/include/acpi/processor.h linux/include/acpi/processor.h
--- linux-original/include/acpi/processor.h	2004-11-05 23:59:51.923592264 +0100
+++ linux/include/acpi/processor.h	2004-11-06 00:46:39.284808488 +0100
@@ -44,6 +44,13 @@
 	struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
 };
 
+struct acpi_cstate_limit;
+
+struct acpi_cstate_limit* acpi_set_cstate_limit(unsigned int limit);
+int acpi_modify_cstate_limit(struct acpi_cstate_limit *data, unsigned int limit);
+void acpi_remove_cstate_limit(struct acpi_cstate_limit *data);
+
+
 /* Performance Management */
 
 struct acpi_pct_register {


-------------------------------------------------------
This SF.Net email is sponsored by:
Sybase ASE Linux Express Edition - download now for FREE
LinuxWorld Reader's Choice Award Winner for best database on Linux.
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click

  parent reply	other threads:[~2004-11-05 23:54 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-10-10 16:56 Linux ACPI processor driver patch: user-definable power state limit Brown, Len
     [not found] ` <F7DC2337C7631D4386A2DF6E8FB22B3001A193B6-N2PTB0HCzHKkrb+BlOpmy7fspsVTdybXVpNB7YpNyf8@public.gmane.org>
2004-10-11 21:35   ` Jos Delbar
     [not found]     ` <200410112335.19159.jos.delbar-Cru1EgDzd7c@public.gmane.org>
2004-10-19 17:19       ` Len Brown
2004-11-05 19:45       ` Len Brown
2004-11-05 22:54         ` Dominik Brodowski
     [not found]           ` <20041105225438.GA8262-X3ehHDuj6sIIGcDfoQAp7BvVK+yQ3ZXh@public.gmane.org>
2004-11-05 23:11             ` Len Brown
2004-11-05 23:41               ` Dominik Brodowski
     [not found]                 ` <20041105234120.GA20761-X3ehHDuj6sIIGcDfoQAp7BvVK+yQ3ZXh@public.gmane.org>
2004-11-06  0:25                   ` Len Brown
2004-11-06  0:29                     ` Dominik Brodowski
     [not found]                       ` <20041106002935.GA30467-X3ehHDuj6sIIGcDfoQAp7BvVK+yQ3ZXh@public.gmane.org>
2004-11-06  0:44                         ` Len Brown
2004-11-06 13:15                         ` Jos Delbar
2004-11-05 23:54               ` Dominik Brodowski [this message]
     [not found]                 ` <20041105235403.GA21880-X3ehHDuj6sIIGcDfoQAp7BvVK+yQ3ZXh@public.gmane.org>
2004-11-06  0:33                   ` Len Brown
2004-11-05 23:39             ` Jos Delbar
     [not found]               ` <200411060039.28067.jos.delbar-Cru1EgDzd7c@public.gmane.org>
2004-11-05 23:55                 ` Dominik Brodowski
2004-11-05 22:58         ` Len Brown
2004-11-05 23:21         ` Jos Delbar
     [not found]           ` <200411060021.49794.jos.delbar-Cru1EgDzd7c@public.gmane.org>
2004-11-06  1:01             ` Len Brown
2004-11-06  2:59               ` Len Brown
  -- strict thread matches above, loose matches on Subject: below --
2004-10-10  7:14 Brown, Len
     [not found] <200408071959.10529.jos.delbar@ugent.be>
2004-10-09  5:52 ` Len Brown
2004-10-09 18:56   ` Dominik Brodowski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20041105235403.GA21880@dominikbrodowski.de \
    --to=linux-x3ehhduj6siigcdfoqap7bvvk+yq3zxh@public.gmane.org \
    --cc=acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    --cc=james.p.ketrenos-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    --cc=jos.delbar-Cru1EgDzd7c@public.gmane.org \
    --cc=len.brown-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    --cc=robert.moore-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox