--- 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 #include +#include +#include + #include #include #include @@ -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 "); MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); MODULE_LICENSE ("GPL");