--- longhaul.c	2005-04-20 09:15:55.000000000 -0700
+++ longhaul-rc2.c	2005-04-20 09:15:13.000000000 -0700
@@ -30,6 +30,9 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
+#include <linux/ide.h>
+#include <linux/delay.h>
+
 #include <asm/msr.h>
 #include <asm/timex.h>
 #include <asm/io.h>
@@ -58,13 +61,26 @@
 
 /* Module parameters */
 static int dont_scale_voltage;
+static int debug;
 
+static void dprintk(const char *fmt, ...)
+{
+        char s[256];
+        va_list args;
 
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
+        if (debug == 0)
+                return;
+
+        va_start(args, fmt);
+        vsprintf(s, fmt, args);
+        printk(s);
+        va_end(args);
+}
 
 
 #define __hlt()     __asm__ __volatile__("hlt": : :"memory")
 
+
 /* Clock ratios multiplied by 10 */
 static int clock_ratio[32];
 static int eblcr_table[32];
@@ -73,9 +89,25 @@
 static int longhaul_version;
 static struct cpufreq_frequency_table *longhaul_table;
 
-#ifdef CONFIG_CPU_FREQ_DEBUG
 static char speedbuffer[8];
 
+void ide_idle(void) {
+	int i;
+	ide_hwif_t *hwif = ide_hwifs;
+	ide_drive_t *drive;
+
+	i = 0;
+	do {
+		drive = &hwif->drives[i];
+		i++;
+		if (strncmp(drive->name,"hd",2) == 0) {
+			while (drive->waiting_for_dma) udelay(10) ;
+		} else {
+			i = 0;
+		}
+	} while (i != 0);
+}
+
 static char *print_speed(int speed)
 {
 	if (speed > 1000) {
@@ -88,7 +120,6 @@
 
 	return speedbuffer;
 }
-#endif
 
 
 static unsigned int calc_speed(int mult)
@@ -120,6 +151,12 @@
 			unsigned int clock_ratio_index)
 {
 	int version;
+	unsigned long flags;
+	unsigned int tmp_mask;
+	struct pci_dev *dev;
+	int i;
+	u16 pci_cmd;
+	u16 cmd_state[64];
 
 	switch (cpu_model) {
 	case CPU_EZRA_T:
@@ -133,21 +170,77 @@
 	}
 
 	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;
-	local_irq_disable();
+
+	/* Begin critical section */
+	preempt_disable();
+	ide_idle();	/* avoid ide timeouts when bus master off */
+	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);
+
+	/* disabling INT2 takes care of ints 8-15 (cascaded) */
+
+	tmp_mask=inb(0x21);	/* works on C3. save mask. */
+	outb(0xFE,0x21);        /* TMR0 only */
+	outb(0xFF,0x80);        /* delay */
+
+	local_irq_enable();     /* sti */
+
+	__hlt();		/* make sure we've got a full tick */
+
 	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
-	local_irq_enable();
+
 	__hlt();
 
+	local_irq_disable();	/* cli */
+
+	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();
+
+	/* END CRITICAL SECTION */
+
+	/* disable bus ratio bit */
+
 	rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+
 	longhaul->bits.EnableSoftBusRatio = 0;
 	longhaul->bits.RevisionKey = version;
-	local_irq_disable();
+
 	wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
-	local_irq_enable();
+
 }
 
 /**
@@ -578,7 +671,7 @@
 		longhaul_setup_voltagescaling();
 
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	policy->cpuinfo.transition_latency = 200000;	/* nsec */
 	policy->cur = calc_speed(longhaul_get_cpu_mult());
 
 	ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
@@ -649,6 +742,9 @@
 module_param (dont_scale_voltage, int, 0644);
 MODULE_PARM_DESC(dont_scale_voltage, "Don't scale voltage of processor");
 
+module_param (debug, int, 0644);
+MODULE_PARM_DESC(debug, "Dump debugging information.");
+
 MODULE_AUTHOR ("Dave Jones <davej@codemonkey.org.uk>");
 MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
 MODULE_LICENSE ("GPL");
