All of lore.kernel.org
 help / color / mirror / Atom feed
* Longhaul - patch proposal
@ 2006-05-12 20:37 Rafał Bilski
  0 siblings, 0 replies; 2+ messages in thread
From: Rafał Bilski @ 2006-05-12 20:37 UTC (permalink / raw)
  To: cpufreq

[-- Attachment #1: Type: text/plain, Size: 241 bytes --]

Sorry. Bad English inside.
Idea is simple - write ide suspend which waits for end of DMA transfer.



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

[-- Attachment #2: longhaul.patch --]
[-- Type: text/plain, Size: 5812 bytes --]

--- longhaul.orig.c	2006-03-20 06:53:29.000000000 +0100
+++ longhaul.c	2006-05-12 22:05:08.000000000 +0200
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
 
 #include <asm/msr.h>
 #include <asm/timex.h>
@@ -114,17 +115,114 @@
 	return eblcr_table[invalue];
 }
 
+/* This is copy from pci.c and pci-driver.c
+ * Better export this functions there 
+ */
 
-static void do_powersaver(union msr_longhaul *longhaul,
-			unsigned int clock_ratio_index)
+static void goto_sleep_pci(void)
 {
 	struct pci_dev *dev;
+	struct pci_driver *drv;
+	struct pm_message pm_freeze;
+	u16 pci_command;
+
+	/*
+	 * Get current pci bus master state for all devices
+	 * and clear bus master bit
+	 */
+
+	pm_freeze.event = PM_EVENT_FREEZE;
+	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, pm_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;
+
+	preempt_disable();
+	goto_sleep_pci();
+
+	local_irq_save(flags);
+
+	tmp_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFE, 0x21);	/* TMR0 only */
+
+	local_irq_disable();
+	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);
+
+	wakeup_pci();
+	preempt_enable();
+}
+
+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 +235,40 @@
 		return;
 	}
 
+	preempt_disable();
+	goto_sleep_pci();
+
+	local_irq_save(flags);
+
+	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);
+
+	wakeup_pci();
+	preempt_enable();
 }
 
 /**
@@ -206,7 +283,6 @@
 	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 +317,7 @@
 	 */
 	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;
 
 	/*

[-- Attachment #3: Type: text/plain, Size: 147 bytes --]

_______________________________________________
Cpufreq mailing list
Cpufreq@lists.linux.org.uk
http://lists.linux.org.uk/mailman/listinfo/cpufreq

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

* Longhaul - patch proposal
@ 2006-05-14  6:51 Rafał Bilski
  0 siblings, 0 replies; 2+ messages in thread
From: Rafał Bilski @ 2006-05-14  6:51 UTC (permalink / raw)
  To: Dave Jones, cpufreq

[-- Attachment #1: Type: text/plain, Size: 866 bytes --]

I think this is working. Patches are for linux-2.6.16. Preempt_disable
seems to be unnecesary before goto_sleep_pci so I do it later. I can do:

while [ 1 ]
do
echo >scaling_setspeed 532000
sleep 1s
echo >scaling_setspeed 997000
sleep 1s
done

on one console while on other is running:

while [ 1 ]
do
hdparm -t /dev/hda
done

Output (24MB/s is max for my drive):
dev/hda:
 Timing buffered disk reads:   60 MB in  3.02 seconds =  19.90 MB/sec
 Timing buffered disk reads:   62 MB in  3.02 seconds =  20.52 MB/sec
 Timing buffered disk reads:   68 MB in  3.01 seconds =  22.56 MB/sec
 Timing buffered disk reads:   50 MB in  3.44 seconds =  14.55 MB/sec
 Timing buffered disk reads:   70 MB in  3.07 seconds =  22.80 MB/sec




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

[-- Attachment #2: longhaul.patch --]
[-- Type: text/plain, Size: 5968 bytes --]

--- longhaul.orig.c	2006-03-20 06:53:29.000000000 +0100
+++ longhaul.c	2006-05-14 00:28:01.000000000 +0200
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
 
 #include <asm/msr.h>
 #include <asm/timex.h>
@@ -114,17 +115,114 @@
 	return eblcr_table[invalue];
 }
 
+/* This is copy from pci.c and pci-driver.c
+ * Better export this functions there 
+ */
 
-static void do_powersaver(union msr_longhaul *longhaul,
-			unsigned int clock_ratio_index)
+static void goto_sleep_pci(void)
 {
 	struct pci_dev *dev;
+	struct pci_driver *drv;
+	struct pm_message pm_freeze;
+	u16 pci_command;
+
+	/*
+	 * Get current pci bus master state for all devices
+	 * and clear bus master bit
+	 */
+
+	pm_freeze.event = PM_EVENT_FREEZE;
+	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, pm_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;
+
+	goto_sleep_pci();
+
+	preempt_disable();
+	local_irq_save(flags);
+
+	tmp_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFE, 0x21);	/* TMR0 only */
+
+	local_irq_disable();
+	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();
+}
+
+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 +235,40 @@
 		return;
 	}
 
-	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;
+	goto_sleep_pci();
 
 	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. */
+	pic2_mask=inb(0xA1);
+	pic1_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFF,0xA1);	/* Overkill */
 	outb(0xFE,0x21);	/* TMR0 only */
-	outb(0xFF,0x80);	/* delay */
 
-	safe_halt();
+	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();
 
-	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();
 }
 
 /**
@@ -206,7 +283,6 @@
 	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 +317,7 @@
 	 */
 	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;
 
 	/*

[-- Attachment #3: via82cxxx.patch --]
[-- Type: text/plain, Size: 3071 bytes --]

--- via82cxxx.orig.c	2006-05-01 09:18:15.000000000 +0200
+++ via82cxxx.c	2006-05-14 08:23:48.000000000 +0200
@@ -34,6 +34,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/pm.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
@@ -469,6 +470,99 @@
 	hwif->drives[1].autodma = hwif->autodma;
 }
 
+/* Copy of sc1200.c */
+
+static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		if (prev) {
+			if (hwif == prev)
+				prev = NULL;	// found previous, now look for next match
+		} else {
+			if (hwif && hwif->pci_dev == dev)
+				return hwif;	// found next match
+		}
+	}
+	return NULL;	// not found
+}
+
+static int via_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	ide_hwif_t *hwif = NULL;
+	ide_drive_t *drive = NULL;
+	struct request rq;
+	struct request_pm_state rqpm;
+	ide_task_t args;
+	unsigned int d;
+
+	printk("VIA IDE: suspend(%u)\n", state.event);
+
+	while ( ( hwif = lookup_pci_dev(hwif, dev) ) != NULL ) {
+		for (d = 0; d < MAX_DRIVES; ++d) {
+			drive = &(hwif->drives[d]);
+			if (drive->present) {
+				ide_init_drive_cmd(&rq);
+				memset(&rqpm, 0, sizeof(rqpm));
+			    	memset(&args, 0, sizeof(args));
+				rq.flags = REQ_PM_SUSPEND;
+		    		rq.pm = &rqpm;
+				rq.special = &args;
+				rqpm.pm_step = ide_pm_state_start_suspend;
+				rqpm.pm_state = state.event;
+				ide_do_drive_cmd(drive, &rq, ide_head_wait);
+			}
+		}
+	}
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+	dev->current_state = state.event;
+	return 0;
+}
+
+static int via_resume(struct pci_dev *dev)
+{
+	ide_hwif_t *hwif = NULL;
+	ide_drive_t *drive = NULL;
+	struct request rq;
+	struct request_pm_state rqpm;
+	ide_task_t args;
+	unsigned int d;
+
+	printk("VIA IDE: resume\n");
+
+	pci_restore_state(dev);
+	pci_set_power_state(dev, PCI_D0);	// bring chip back from sleep state
+	dev->current_state = PM_EVENT_ON;
+	/* 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 ( ( hwif = lookup_pci_dev(hwif, dev) ) != NULL ) {
+		for (d = 0; d < MAX_DRIVES; ++d) {
+			drive = &(hwif->drives[d]);
+			if (drive->present) {
+				ide_init_drive_cmd(&rq);
+				memset(&args, 0, sizeof(args));
+				memset(&rqpm, 0, sizeof(rqpm));
+				rq.flags = REQ_PM_RESUME;
+		    		rq.pm = &rqpm;
+				rq.special = &args;
+				rqpm.pm_step = ide_pm_state_start_resume;
+				rqpm.pm_state = PM_EVENT_ON;
+				ide_do_drive_cmd(drive, &rq, ide_head_wait);
+			}
+		}
+	}
+	return 0;
+}
+
 static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
 	{	/* 0 */
 		.name		= "VP_IDE",
@@ -506,6 +600,8 @@
 	.name 		= "VIA_IDE",
 	.id_table 	= via_pci_tbl,
 	.probe 		= via_init_one,
+	.suspend	= via_suspend,
+	.resume		= via_resume,
 };
 
 static int via_ide_init(void)

[-- Attachment #4: Type: text/plain, Size: 147 bytes --]

_______________________________________________
Cpufreq mailing list
Cpufreq@lists.linux.org.uk
http://lists.linux.org.uk/mailman/listinfo/cpufreq

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

end of thread, other threads:[~2006-05-14  6:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-12 20:37 Longhaul - patch proposal Rafał Bilski
  -- strict thread matches above, loose matches on Subject: below --
2006-05-14  6:51 Rafał Bilski

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.