All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.