public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Longhaul - call suspend(PMSG_FREEZE) before and resume() after
@ 2006-05-27 22:30 Rafał Bilski
  2006-05-28  7:16 ` Pavel Machek
  0 siblings, 1 reply; 6+ messages in thread
From: Rafał Bilski @ 2006-05-27 22:30 UTC (permalink / raw)
  To: linux-kernel

I posted this to Dave Jones, but:
> This really should also get posted to linux-kernel, though I don't
> think people are going to be particularly enthusiastic about exposing
> these innards to modules.
So I'm posting this patch here too. I'm not subscribed to this list.
If You wish email me.
Minor change: preempt_disabled() goto_sleep_pci() and wakeup_pci() 
causes "sheduling while atomic". So in this patch below it isn't
preempt_disabled(). But I think that this should be protected
in some way. 

How it works:
1. Call suspend(PMSG_FREEZE) for each block device.
2. Call suspend(PMSG_FREEZE) for each PCI device.
3. Change CPU frequency.
4. Call resume() for each PCI device.
5. Call resume() for each block device.

Result: No more broken DMA transfers caused by frequency change.

diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/Kconfig linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/Kconfig
--- linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/Kconfig	2006-05-27 15:50:00.000000000 +0200
+++ linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/Kconfig	2006-05-27 15:53:13.000000000 +0200
@@ -203,7 +203,6 @@ config X86_LONGRUN
 config X86_LONGHAUL
 	tristate "VIA Cyrix III Longhaul"
 	select CPU_FREQ_TABLE
-	depends on BROKEN
 	help
 	  This adds the CPUFreq driver for VIA Samuel/CyrixIII, 
 	  VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T 
diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/longhaul.c linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/longhaul.c	2006-03-20 06:53:29.000000000 +0100
+++ linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/longhaul.c	2006-05-27 15:53:13.000000000 +0200
@@ -30,6 +30,11 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
 
 #include <asm/msr.h>
 #include <asm/timex.h>
@@ -115,16 +120,144 @@ static int longhaul_get_cpu_mult(void)
 }
 
 
-static void do_powersaver(union msr_longhaul *longhaul,
-			unsigned int clock_ratio_index)
+extern struct subsystem block_subsys;
+extern struct semaphore block_subsys_sem;
+
+static struct pm_message pmsg_freeze = { .event = PM_EVENT_FREEZE, };
+
+void block_freeze_resume(int freeze)
+{
+	struct gendisk *disk;
+	struct list_head *p;
+	struct bus_type *bus;
+
+	list_for_each(p, &block_subsys.kset.list) {
+		disk = list_entry(p, struct gendisk, kobj.entry);
+		if (disk->driverfs_dev && disk->driverfs_dev->bus) {
+			bus = disk->driverfs_dev->bus;
+			if (bus->suspend && freeze) {
+				printk("Longhaul: %.32s (%.32s) -> suspend(PMSG_FREEZE)\n", &disk->disk_name[0], &disk->driverfs_dev->bus_id[0]);
+				bus->suspend(disk->driverfs_dev, pmsg_freeze); 
+			} else if (bus->resume && !freeze) {
+				printk("Longhaul: %.32s (%.32s) -> resume()\n", &disk->disk_name[0], &disk->driverfs_dev->bus_id[0]);
+				bus->resume(disk->driverfs_dev); 
+			}
+		}
+	}
+}
+
+
+/* This is copy from pci.c and pci-driver.c
+ */
+
+static void goto_sleep_pci(void)
+{
+	struct pci_dev *dev;
+	struct pci_driver *drv;
+	u16 pci_command;
+
+	/*
+	 * Get current pci bus master state for all devices
+	 * and clear bus master bit
+	 */
+
+	dev = NULL;
+	do {
+		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+		if (dev != NULL) {
+			drv = dev->driver;
+			if (drv && drv->suspend)
+				drv->suspend(dev, pmsg_freeze);
+			else
+	    			pci_save_state(dev);
+			pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+			if (pci_command & PCI_COMMAND_MASTER) {
+				pci_command &= ~PCI_COMMAND_MASTER;
+				pci_write_config_word(dev, PCI_COMMAND, pci_command);
+			}
+			/* pcibios_disable_device omited because
+			   USB devices don't respond after resume
+			   on EPIA M10000 */
+		}
+	} while (dev != NULL);
+}
+
+
+static void wakeup_pci(void)
 {
 	struct pci_dev *dev;
+	struct pci_driver *drv;
+
+	/* Restore pci bus master state for all devices */
+
+	dev = NULL;
+	do {
+		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+		if (dev != NULL) {
+			drv = dev->driver;
+			if (drv && drv->resume)
+				drv->resume(dev);
+			else
+				/* restore the PCI config space */
+				pci_restore_state(dev);
+	    		/* if the device was busmaster before the suspend, make it busmaster again */
+			if (dev->is_busmaster)
+				pci_set_master(dev);
+			/* if the device was enabled before suspend, reenable */
+			if (dev->is_enabled)
+				pci_enable_device(dev);
+		}
+	} while (dev != NULL);
+}
+
+
+static void do_longhaul1(int reserved, unsigned int clock_ratio_index)
+{
 	unsigned long flags;
 	unsigned int tmp_mask;
+	union msr_bcr2 bcr2;
+
+        down(&block_subsys_sem);
+	block_freeze_resume(1);
+	goto_sleep_pci();
+	preempt_disable();
+	local_irq_save(flags);
+
+	local_irq_disable();
+
+	tmp_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFE, 0x21);	/* TMR0 only */
+
+	rdmsrl(MSR_VIA_BCR2, bcr2.val);
+	/* Enable software clock multiplier */
+	bcr2.bits.ESOFTBF = 1;
+	bcr2.bits.CLOCKMUL = clock_ratio_index;
+	safe_halt();		/* Sync */
+	wrmsrl(MSR_VIA_BCR2, bcr2.val);	/* Change */
+	halt();
+
+	/* Disable software clock multiplier */
+	local_irq_disable();
+	rdmsrl(MSR_VIA_BCR2, bcr2.val);
+	bcr2.bits.ESOFTBF = 0;
+	wrmsrl(MSR_VIA_BCR2, bcr2.val);
+	local_irq_enable();
+
+	outb(tmp_mask, 0x21);	/* restore mask */
+	local_irq_restore(flags);
+	preempt_enable();
+	wakeup_pci();
+	block_freeze_resume(0);
+        up(&block_subsys_sem);
+}
+
+
+static void do_powersaver(union msr_longhaul *longhaul,
+			unsigned int clock_ratio_index)
+{
+	unsigned long flags;
+	unsigned int pic1_mask, pic2_mask;
 	int version;
-	int i;
-	u16 pci_cmd;
-	u16 cmd_state[64];
 
 	switch (cpu_model) {
 	case CPU_EZRA_T:
@@ -137,61 +270,44 @@ static void do_powersaver(union msr_long
 		return;
 	}
 
+        down(&block_subsys_sem);
+	block_freeze_resume(1);
+	goto_sleep_pci();
+	preempt_disable();
+	local_irq_save(flags);
+
+	local_irq_disable();
+	pic2_mask=inb(0xA1);
+	pic1_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFF,0xA1);	/* Overkill */
+	outb(0xFE,0x21);	/* TMR0 only */
+
 	rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
 	longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf;
 	longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
 	longhaul->bits.EnableSoftBusRatio = 1;
 	longhaul->bits.RevisionKey = 0;
 
-	preempt_disable();
-	local_irq_save(flags);
-
-	/*
-	 * get current pci bus master state for all devices
-	 * and clear bus master bit
-	 */
-	dev = NULL;
-	i = 0;
-	do {
-		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-		if (dev != NULL) {
-			pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
-			cmd_state[i++] = pci_cmd;
-			pci_cmd &= ~PCI_COMMAND_MASTER;
-			pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
-		}
-	} while (dev != NULL);
-
-	tmp_mask=inb(0x21);	/* works on C3. save mask. */
-	outb(0xFE,0x21);	/* TMR0 only */
-	outb(0xFF,0x80);	/* delay */
-
-	safe_halt();
+	safe_halt();		/* Sync */
 	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
 	halt();
 
 	local_irq_disable();
 
-	outb(tmp_mask,0x21);	/* restore mask */
-
-	/* restore pci bus master state for all devices */
-	dev = NULL;
-	i = 0;
-	do {
-		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-		if (dev != NULL) {
-			pci_cmd = cmd_state[i++];
-			pci_write_config_byte(dev, PCI_COMMAND, pci_cmd);
-		}
-	} while (dev != NULL);
-	local_irq_restore(flags);
-	preempt_enable();
-
 	/* disable bus ratio bit */
 	rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
 	longhaul->bits.EnableSoftBusRatio = 0;
 	longhaul->bits.RevisionKey = version;
 	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+
+	outb(pic2_mask,0xA1);
+	outb(pic1_mask,0x21);	/* restore mask */
+
+	local_irq_restore(flags);
+	preempt_enable();
+	wakeup_pci();
+	block_freeze_resume(0);
+        up(&block_subsys_sem);
 }
 
 /**
@@ -206,7 +322,6 @@ static void longhaul_setstate(unsigned i
 	int speed, mult;
 	struct cpufreq_freqs freqs;
 	union msr_longhaul longhaul;
-	union msr_bcr2 bcr2;
 	static unsigned int old_ratio=-1;
 
 	if (old_ratio == clock_ratio_index)
@@ -241,20 +356,7 @@ static void longhaul_setstate(unsigned i
 	 */
 	case TYPE_LONGHAUL_V1:
 	case TYPE_LONGHAUL_V2:
-		rdmsrl (MSR_VIA_BCR2, bcr2.val);
-		/* Enable software clock multiplier */
-		bcr2.bits.ESOFTBF = 1;
-		bcr2.bits.CLOCKMUL = clock_ratio_index;
-		local_irq_disable();
-		wrmsrl (MSR_VIA_BCR2, bcr2.val);
-		safe_halt();
-
-		/* Disable software clock multiplier */
-		rdmsrl (MSR_VIA_BCR2, bcr2.val);
-		bcr2.bits.ESOFTBF = 0;
-		local_irq_disable();
-		wrmsrl (MSR_VIA_BCR2, bcr2.val);
-		local_irq_enable();
+		do_longhaul1(0, clock_ratio_index);
 		break;
 
 	/*
diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/block/genhd.c linux-2.6.16.18/block/genhd.c
--- linux-2.6.16.18-vanilla/block/genhd.c	2006-05-27 15:50:01.000000000 +0200
+++ linux-2.6.16.18/block/genhd.c	2006-05-27 15:53:13.000000000 +0200
@@ -16,9 +16,9 @@
 #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
 
-static struct subsystem block_subsys;
+struct subsystem block_subsys;
 
-static DECLARE_MUTEX(block_subsys_sem);
+DECLARE_MUTEX(block_subsys_sem);
 
 /*
  * Can be deleted altogether. Later.
@@ -511,8 +511,10 @@ static struct kset_uevent_ops block_ueve
 };
 
 /* declare block_subsys. */
-static decl_subsys(block, &ktype_block, &block_uevent_ops);
+decl_subsys(block, &ktype_block, &block_uevent_ops);
 
+EXPORT_SYMBOL(block_subsys);
+EXPORT_SYMBOL(block_subsys_sem);
 
 /*
  * aggregate disk stat collector.  Uses the same stats that the sysfs




----------------------------------------------------------------------
Tysiace zdjec swietnych samochodow! >>> http://link.interia.pl/f1944


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Longhaul - call suspend(PMSG_FREEZE) before and resume() after
  2006-05-27 22:30 [PATCH] " Rafał Bilski
@ 2006-05-28  7:16 ` Pavel Machek
  0 siblings, 0 replies; 6+ messages in thread
From: Pavel Machek @ 2006-05-28  7:16 UTC (permalink / raw)
  To: Rafa Bilski, kernel list, Linux-pm mailing list

Hi!

> I posted this to Dave Jones, but:
> > This really should also get posted to linux-kernel, though I don't
> > think people are going to be particularly enthusiastic about exposing
> > these innards to modules.
> So I'm posting this patch here too. I'm not subscribed to this list.
> If You wish email me.
> Minor change: preempt_disabled() goto_sleep_pci() and wakeup_pci() 
> causes "sheduling while atomic". So in this patch below it isn't
> preempt_disabled(). But I think that this should be protected
> in some way. 

Well, suspend/resume is normally called during system suspend/resume,
so it has 'interesting' locking requirements.

> How it works:
> 1. Call suspend(PMSG_FREEZE) for each block device.
> 2. Call suspend(PMSG_FREEZE) for each PCI device.
> 3. Change CPU frequency.
> 4. Call resume() for each PCI device.
> 5. Call resume() for each block device.
> 
> Result: No more broken DMA transfers caused by frequency change.

Result: system hang if userspace tries to do request at the same time
-- PCI drivers probably were not designed for _that_... but we
probably want to fix them, anyway, so this is probably ok (but expect
to do some driver debugging).

But you should really add that preempt_disable and not try this on smp
system...
						Pavel

-- 
Thanks for all the (sleeping) penguins.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [ PATCH ] Longhaul - call suspend(PMSG_FREEZE) before and resume() after
@ 2006-05-28 11:38 Rafa? Bilski
  2006-05-28 14:56 ` Dave Jones
  0 siblings, 1 reply; 6+ messages in thread
From: Rafa? Bilski @ 2006-05-28 11:38 UTC (permalink / raw)
  To: linux-kernel; +Cc: Dave Jones

> This is an horrible hack that breaks so many defined semantics that it's
> not even funny.

> If you want something like that, then you need to freeze/resume _all_
> devices with the proper ordering defined by the bus linkage. It has a
> number of side effects though, can't be done that easily. Maybe cpufreq
> should have the necessary infrastructure for that ?

> That's the wrong approach. If you need to stop
> DMA's during the frequency change, you either need to fix all drivers to
> register cpufreq notifiers that do so (ick !) or if you want to reuse
> the PM callbacks, you need to respect their semantics, notably vs. call
> ordering, or very bad things will happen.

> If we want to go that way, we probably need to add a bit of
> infrastructure to cpufreq to cooperate with the PM code to trigger a
> "light" machine suspend/resume, though expect delays and artifacts, it's
> not something that code be done lightly.

> Ben.

I'm toys salesman. I don't think that I'm capable.
There is already necessary infrastructure (PM). I can do freeze for all 
devices with just one function call. Problem is that only block devices 
implement freeze. Most devices do suspend insteed of freeze. Some 
devices (Speedtouch) don't implement suspend/resume. After USB power 
down You have to unplug modem.
Block devices are at top level? If I remove PCI suspend/resume 
(network card compatible) will this be OK? Other subsystems 
are visible. Can block subsystem be visible too?


> But you should really add that preempt_disable and not try this on smp
> system...
	
> Pavel

Datasheet for my C3 Nehemiah says that this processor don't have local 
APIC and is not SMP capable. I have assumed (based on original longhaul.c) 
that all VIA C3 are not SMP capable.

Would You consider appling part of this patch if I add all my assumptions
to Kconfig?

depends on EXPERIMENTAL && (HZ_100 || HZ_250) && (PREEMPT_NONE || PREEMPT_VOLUNTARY)

Rafal


----------------------------------------------------------------------
Potrzebujesz gotowki? Halogotowka to nawet 50 000 bez wizyty w banku.
Rata od 35 zl, bez poreczycieli. Wypelnij formularz. Oddzwonimy.
>>> http://link.interia.pl/f1942


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Longhaul - call suspend(PMSG_FREEZE) before and resume() after
@ 2006-05-28 14:42 Rafał Bilski
  0 siblings, 0 replies; 6+ messages in thread
From: Rafał Bilski @ 2006-05-28 14:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: Dave Jones

Here is simplier patch using PCI bus master disabling code by Dave Jones.
Still using block subsystem, but this time it isn't exported to modules.

1. Call suspend(PMSG_FREEZE) for each block device.
2. Change frequency - notice that in this patch at least we give a chance to BCR2 MSR CPU's.
3. Call resume() for each block device.

Tested on Epia M10000. 22MB/s while changing from 997MHz to 532MHz at 1s interval.

EXPERIMENTAL - Please!
(HZ_100 || HZ_250) - because VIA CPU's with BCR2 MSR need >=1ms to sync PLL.
!SMP - original code and patch aren't SMP compatible.
!X86_UP_APIC - original code and patch aren't APIC compatible.


diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/Kconfig linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/Kconfig
--- linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/Kconfig	2006-05-28 15:04:34.000000000 +0200
+++ linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/Kconfig	2006-05-28 15:36:54.000000000 +0200
@@ -201,14 +201,17 @@ config X86_LONGRUN
 	  If in doubt, say N.
 
 config X86_LONGHAUL
-	tristate "VIA Cyrix III Longhaul"
+	bool "VIA Cyrix III Longhaul (EXPERIMENTAL)"
+	default n
 	select CPU_FREQ_TABLE
-	depends on BROKEN
+	depends on EXPERIMENTAL && !SMP && !X86_UP_APIC
+	depends on (HZ_100 || HZ_250) && (PREEMPT_NONE || PREEMPT_VOLUNTARY)
 	help
 	  This adds the CPUFreq driver for VIA Samuel/CyrixIII, 
 	  VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T 
 	  processors.
 
+	  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
 	  For details, take a look at <file:Documentation/cpu-freq/>.
 
 	  If in doubt, say N.
diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/longhaul.c linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/longhaul.c	2006-03-20 06:53:29.000000000 +0100
+++ linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/longhaul.c	2006-05-28 15:57:58.000000000 +0200
@@ -30,6 +30,11 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
 
 #include <asm/msr.h>
 #include <asm/timex.h>
@@ -115,36 +120,40 @@ static int longhaul_get_cpu_mult(void)
 }
 
 
-static void do_powersaver(union msr_longhaul *longhaul,
-			unsigned int clock_ratio_index)
-{
-	struct pci_dev *dev;
-	unsigned long flags;
-	unsigned int tmp_mask;
-	int version;
-	int i;
-	u16 pci_cmd;
-	u16 cmd_state[64];
+extern struct subsystem block_subsys;
+extern struct semaphore block_subsys_sem;
 
-	switch (cpu_model) {
-	case CPU_EZRA_T:
-		version = 3;
-		break;
-	case CPU_NEHEMIAH:
-		version = 0xf;
-		break;
-	default:
-		return;
+static struct pm_message pmsg_freeze = { .event = PM_EVENT_FREEZE, };
+
+void block_freeze_resume(int freeze)
+{
+	struct gendisk *disk;
+	struct list_head *p;
+	struct bus_type *bus;
+
+	list_for_each(p, &block_subsys.kset.list) {
+		disk = list_entry(p, struct gendisk, kobj.entry);
+		if (disk->driverfs_dev && disk->driverfs_dev->bus) {
+			bus = disk->driverfs_dev->bus;
+			if (bus->suspend && freeze) {
+				printk(KERN_INFO PFX "%.32s (%.32s) -> suspend(PMSG_FREEZE)\n", &disk->disk_name[0], &disk->driverfs_dev->bus_id[0]);
+				bus->suspend(disk->driverfs_dev, pmsg_freeze); 
+			} else if (bus->resume && !freeze) {
+				printk(KERN_INFO PFX "%.32s (%.32s) -> resume()\n", &disk->disk_name[0], &disk->driverfs_dev->bus_id[0]);
+				bus->resume(disk->driverfs_dev); 
+			}
+		}
 	}
+}
 
-	rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
-	longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf;
-	longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
-	longhaul->bits.EnableSoftBusRatio = 1;
-	longhaul->bits.RevisionKey = 0;
 
-	preempt_disable();
-	local_irq_save(flags);
+static u16 cmd_state[64];
+
+static void clear_bus_master(void)
+{
+	struct pci_dev *dev;
+	u16 pci_cmd;
+	int i;
 
 	/*
 	 * get current pci bus master state for all devices
@@ -161,18 +170,14 @@ static void do_powersaver(union msr_long
 			pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
 		}
 	} while (dev != NULL);
+}
 
-	tmp_mask=inb(0x21);	/* works on C3. save mask. */
-	outb(0xFE,0x21);	/* TMR0 only */
-	outb(0xFF,0x80);	/* delay */
-
-	safe_halt();
-	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
-	halt();
-
-	local_irq_disable();
 
-	outb(tmp_mask,0x21);	/* restore mask */
+static void restore_bus_master(void)
+{
+	struct pci_dev *dev;
+	u16 pci_cmd;
+	int i;
 
 	/* restore pci bus master state for all devices */
 	dev = NULL;
@@ -184,14 +189,106 @@ static void do_powersaver(union msr_long
 			pci_write_config_byte(dev, PCI_COMMAND, pci_cmd);
 		}
 	} while (dev != NULL);
+}
+
+
+static void do_longhaul1(int reserved, unsigned int clock_ratio_index)
+{
+	unsigned long flags;
+	unsigned int tmp_mask;
+	union msr_bcr2 bcr2;
+
+        down(&block_subsys_sem);
+	block_freeze_resume(1);
+	preempt_disable();
+	clear_bus_master();
+	local_irq_save(flags);
+
+	local_irq_disable();
+
+	tmp_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFE, 0x21);	/* TMR0 only */
+
+	rdmsrl(MSR_VIA_BCR2, bcr2.val);
+	/* Enable software clock multiplier */
+	bcr2.bits.ESOFTBF = 1;
+	bcr2.bits.CLOCKMUL = clock_ratio_index;
+	safe_halt();		/* Sync */
+	wrmsrl(MSR_VIA_BCR2, bcr2.val);	/* Change */
+	halt();
+
+	/* Disable software clock multiplier */
+	local_irq_disable();
+	rdmsrl(MSR_VIA_BCR2, bcr2.val);
+	bcr2.bits.ESOFTBF = 0;
+	wrmsrl(MSR_VIA_BCR2, bcr2.val);
+	local_irq_enable();
+
+	outb(tmp_mask, 0x21);	/* restore mask */
 	local_irq_restore(flags);
+	restore_bus_master();
 	preempt_enable();
+	block_freeze_resume(0);
+        up(&block_subsys_sem);
+}
+
+
+static void do_powersaver(union msr_longhaul *longhaul,
+			unsigned int clock_ratio_index)
+{
+	unsigned long flags;
+	unsigned int pic1_mask, pic2_mask;
+	int version;
+
+	switch (cpu_model) {
+	case CPU_EZRA_T:
+		version = 3;
+		break;
+	case CPU_NEHEMIAH:
+		version = 0xf;
+		break;
+	default:
+		return;
+	}
+
+        down(&block_subsys_sem);
+	block_freeze_resume(1);
+	preempt_disable();
+	clear_bus_master();
+	local_irq_save(flags);
+
+	local_irq_disable();
+	pic2_mask=inb(0xA1);
+	pic1_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFF,0xA1);	/* Overkill */
+	outb(0xFE,0x21);	/* TMR0 only */
+
+	rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+	longhaul->bits.SoftBusRatio = clock_ratio_index & 0xf;
+	longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
+	longhaul->bits.EnableSoftBusRatio = 1;
+	longhaul->bits.RevisionKey = 0;
+
+	safe_halt();		/* Sync */
+	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+	halt();
+
+	local_irq_disable();
 
 	/* disable bus ratio bit */
 	rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
 	longhaul->bits.EnableSoftBusRatio = 0;
 	longhaul->bits.RevisionKey = version;
 	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+
+	outb(pic2_mask,0xA1);
+	outb(pic1_mask,0x21);	/* restore mask */
+
+	local_irq_restore(flags);
+	restore_bus_master();
+	preempt_enable();
+	block_freeze_resume(0);
+        up(&block_subsys_sem);
 }
 
 /**
@@ -206,7 +303,6 @@ static void longhaul_setstate(unsigned i
 	int speed, mult;
 	struct cpufreq_freqs freqs;
 	union msr_longhaul longhaul;
-	union msr_bcr2 bcr2;
 	static unsigned int old_ratio=-1;
 
 	if (old_ratio == clock_ratio_index)
@@ -241,20 +337,7 @@ static void longhaul_setstate(unsigned i
 	 */
 	case TYPE_LONGHAUL_V1:
 	case TYPE_LONGHAUL_V2:
-		rdmsrl (MSR_VIA_BCR2, bcr2.val);
-		/* Enable software clock multiplier */
-		bcr2.bits.ESOFTBF = 1;
-		bcr2.bits.CLOCKMUL = clock_ratio_index;
-		local_irq_disable();
-		wrmsrl (MSR_VIA_BCR2, bcr2.val);
-		safe_halt();
-
-		/* Disable software clock multiplier */
-		rdmsrl (MSR_VIA_BCR2, bcr2.val);
-		bcr2.bits.ESOFTBF = 0;
-		local_irq_disable();
-		wrmsrl (MSR_VIA_BCR2, bcr2.val);
-		local_irq_enable();
+		do_longhaul1(0, clock_ratio_index);
 		break;
 
 	/*
diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/block/genhd.c linux-2.6.16.18/block/genhd.c
--- linux-2.6.16.18-vanilla/block/genhd.c	2006-05-28 15:04:34.000000000 +0200
+++ linux-2.6.16.18/block/genhd.c	2006-05-28 15:34:31.000000000 +0200
@@ -16,9 +16,9 @@
 #include <linux/kobj_map.h>
 #include <linux/buffer_head.h>
 
-static struct subsystem block_subsys;
+struct subsystem block_subsys;
 
-static DECLARE_MUTEX(block_subsys_sem);
+DECLARE_MUTEX(block_subsys_sem);
 
 /*
  * Can be deleted altogether. Later.
@@ -511,8 +511,7 @@ static struct kset_uevent_ops block_ueve
 };
 
 /* declare block_subsys. */
-static decl_subsys(block, &ktype_block, &block_uevent_ops);
-
+decl_subsys(block, &ktype_block, &block_uevent_ops);
 
 /*
  * aggregate disk stat collector.  Uses the same stats that the sysfs


----------------------------------------------------------------------
Poznaj Stefana! Zmien komunikator! >>> http://link.interia.pl/f1924


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [ PATCH ] Longhaul - call suspend(PMSG_FREEZE) before and resume() after
  2006-05-28 11:38 [ PATCH ] " Rafa? Bilski
@ 2006-05-28 14:56 ` Dave Jones
  2006-05-28 16:23   ` Rafał Bilski
  0 siblings, 1 reply; 6+ messages in thread
From: Dave Jones @ 2006-05-28 14:56 UTC (permalink / raw)
  To: Rafa? Bilski; +Cc: linux-kernel, Dave Jones

On Sun, May 28, 2006 at 01:38:01PM +0200, Rafa? Bilski wrote:

 > Datasheet for my C3 Nehemiah says that this processor don't have local 
 > APIC and is not SMP capable. I have assumed (based on original longhaul.c) 
 > that all VIA C3 are not SMP capable.

Nehemiah has a local APIC, and is SMP capable.
(Though boards are hard to come by, and longhaul.ko has never
 been tested on such a system)

		Dave

-- 
http://www.codemonkey.org.uk

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [ PATCH ] Longhaul - call suspend(PMSG_FREEZE) before and resume() after
  2006-05-28 14:56 ` Dave Jones
@ 2006-05-28 16:23   ` Rafał Bilski
  0 siblings, 0 replies; 6+ messages in thread
From: Rafał Bilski @ 2006-05-28 16:23 UTC (permalink / raw)
  To: Dave Jones; +Cc: linux-kernel


> Nehemiah has a local APIC, and is SMP capable.
> (Though boards are hard to come by, and longhaul.ko has never
>  been tested on such a system)
> 
> 		Dave

We both have right. My C3 is in EBGA and datasheet (v1.90) for 
EBGA C3 says:
> OMITTED FUNCTIONS
> 
> Symmetric Multiprocessing Support: APIC
> This bus function is omitted since the target market for the VIA C3 
> in EBGA is portables and typical desktop systems (which do not 
> support APIC multiprocessing). A bit in the feature identification 
> returned from the CPUID instruction indicates whether this feature 
> is present or not. This enhancement is not provided on the VIA C3 in EBGA.

But C3 in FCPGA(?) have APIC support.

Rafal


----------------------------------------------------------------------
INTERIA.PL dla kobiet... >>> http://link.interia.pl/f193b


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2006-05-28 16:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-28 14:42 [PATCH] Longhaul - call suspend(PMSG_FREEZE) before and resume() after Rafał Bilski
  -- strict thread matches above, loose matches on Subject: below --
2006-05-28 11:38 [ PATCH ] " Rafa? Bilski
2006-05-28 14:56 ` Dave Jones
2006-05-28 16:23   ` Rafał Bilski
2006-05-27 22:30 [PATCH] " Rafał Bilski
2006-05-28  7:16 ` Pavel Machek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox