#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/pci.h>
#include <asm/msr.h>
#include <asm/timex.h>
#include <asm/io.h>
-#include <asm/acpi.h>
-#include <linux/acpi.h>
-#include <acpi/processor.h>
#include "longhaul.h"
static unsigned int minmult, maxmult;
static int can_scale_voltage;
static int vrmrev;
-static struct acpi_processor *pr = NULL;
-static struct acpi_processor_cx *cx = NULL;
/* Module parameters */
static int dont_scale_voltage;
static char *print_speed(int speed)
{
- if (speed < 1000) {
- snprintf(speedbuffer, sizeof(speedbuffer),"%dMHz", speed);
- return speedbuffer;
- }
-
- if (speed%1000 == 0)
- snprintf(speedbuffer, sizeof(speedbuffer),
- "%dGHz", speed/1000);
- else
- snprintf(speedbuffer, sizeof(speedbuffer),
- "%d.%dGHz", speed/1000, (speed%1000)/100);
+ if (speed > 1000) {
+ if (speed%1000 == 0)
+ sprintf (speedbuffer, "%dGHz", speed/1000);
+ else
+ sprintf (speedbuffer, "%d.%dGHz", speed/1000, (speed%1000)/100);
+ } else
+ sprintf (speedbuffer, "%dMHz", speed);
return speedbuffer;
}
return eblcr_table[invalue];
}
-/* For processor with BCR2 MSR */
-static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)
+static void do_powersaver(union msr_longhaul *longhaul,
+ unsigned int clock_ratio_index)
{
- union msr_bcr2 bcr2;
- u32 t;
+ struct pci_dev *dev;
+ unsigned long flags;
+ unsigned int tmp_mask;
+ int version;
+ int i;
+ u16 pci_cmd;
+ u16 cmd_state[64];
- rdmsrl(MSR_VIA_BCR2, bcr2.val);
- /* Enable software clock multiplier */
- bcr2.bits.ESOFTBF = 1;
- bcr2.bits.CLOCKMUL = clock_ratio_index;
+ switch (cpu_model) {
+ case CPU_EZRA_T:
+ version = 3;
+ break;
+ case CPU_NEHEMIAH:
+ version = 0xf;
+ break;
+ default:
+ return;
+ }
- /* Sync to timer tick */
- safe_halt();
- ACPI_FLUSH_CPU_CACHE();
- /* Change frequency on next halt or sleep */
- wrmsrl(MSR_VIA_BCR2, bcr2.val);
- /* Invoke C3 */
- inb(cx_address);
- /* Dummy op - must do something useless after P_LVL3 read */
- t = inl(acpi_fadt.xpm_tmr_blk.address);
-
- /* Disable software clock multiplier */
- local_irq_disable();
- rdmsrl(MSR_VIA_BCR2, bcr2.val);
- bcr2.bits.ESOFTBF = 0;
- wrmsrl(MSR_VIA_BCR2, bcr2.val);
-}
+ 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;
-/* For processor with Longhaul MSR */
+ preempt_disable();
+ local_irq_save(flags);
-static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
-{
- union msr_longhaul longhaul;
- u32 t;
+ /*
+ * 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);
- rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
- longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
- longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf;
- longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
- longhaul.bits.EnableSoftBusRatio = 1;
+ tmp_mask=inb(0x21); /* works on C3. save mask. */
+ outb(0xFE,0x21); /* TMR0 only */
+ outb(0xFF,0x80); /* delay */
- /* Sync to timer tick */
safe_halt();
- ACPI_FLUSH_CPU_CACHE();
- /* Change frequency on next halt or sleep */
- wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
- /* Invoke C3 */
- inb(cx_address);
- /* Dummy op - must do something useless after P_LVL3 read */
- t = inl(acpi_fadt.xpm_tmr_blk.address);
-
- /* Disable bus ratio bit */
+ wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+ halt();
+
local_irq_disable();
- longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
- longhaul.bits.EnableSoftBusRatio = 0;
- longhaul.bits.EnableSoftBSEL = 0;
- longhaul.bits.EnableSoftVID = 0;
- wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
+
+ 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);
}
/**
{
int speed, mult;
struct cpufreq_freqs freqs;
+ union msr_longhaul longhaul;
+ union msr_bcr2 bcr2;
static unsigned int old_ratio=-1;
- unsigned long flags;
- unsigned int pic1_mask, pic2_mask;
if (old_ratio == clock_ratio_index)
return;
dprintk ("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
fsb, mult/10, mult%10, print_speed(speed/1000));
- preempt_disable();
- 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 */
-
- /* Disable bus master arbitration */
- if (pr->flags.bm_check) {
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
- ACPI_MTX_DO_NOT_LOCK);
- }
-
switch (longhaul_version) {
/*
*/
case TYPE_LONGHAUL_V1:
case TYPE_LONGHAUL_V2:
- do_longhaul1(cx->address, clock_ratio_index);
+ 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();
break;
/*
* to work in practice.
*/
case TYPE_POWERSAVER:
- do_powersaver(cx->address, clock_ratio_index);
+ do_powersaver(&longhaul, clock_ratio_index);
break;
}
- /* Enable bus master arbitration */
- if (pr->flags.bm_check) {
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
- ACPI_MTX_DO_NOT_LOCK);
- }
-
- outb(pic2_mask,0xA1); /* restore mask */
- outb(pic1_mask,0x21);
-
- local_irq_restore(flags);
- preempt_enable();
-
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static int __init longhaul_get_ranges(void)
{
unsigned long invalue;
- unsigned int ezra_t_multipliers[32]= {
- 90, 30, 40, 100, 55, 35, 45, 95,
- 50, 70, 80, 60, 120, 75, 85, 65,
- -1, 110, 120, -1, 135, 115, 125, 105,
- 130, 150, 160, 140, -1, 155, -1, 145 };
+ unsigned int multipliers[32]= {
+ 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
+ -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };
unsigned int j, k = 0;
union msr_longhaul longhaul;
unsigned long lo, hi;
invalue = longhaul.bits.MaxMHzBR;
if (longhaul.bits.MaxMHzBR4)
invalue += 16;
- maxmult=ezra_t_multipliers[invalue];
+ maxmult=multipliers[invalue];
invalue = longhaul.bits.MinMHzBR;
if (longhaul.bits.MinMHzBR4 == 1)
minmult = 30;
else
- minmult = ezra_t_multipliers[invalue];
+ minmult = multipliers[invalue];
fsb = eblcr_fsb_table_v2[longhaul.bits.MaxMHzFSB];
break;
}
return calc_speed(longhaul_get_cpu_mult());
}
-static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
- u32 nesting_level,
- void *context, void **return_value)
-{
- struct acpi_device *d;
-
- if ( acpi_bus_get_device(obj_handle, &d) ) {
- return 0;
- }
- *return_value = (void *)acpi_driver_data(d);
- return 1;
-}
static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
{
char *cpuname=NULL;
int ret;
- /* Check ACPI support for C3 state */
- acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
- &longhaul_walk_callback, NULL, (void *)&pr);
- if (pr == NULL) goto err_acpi;
-
- cx = &pr->power.states[ACPI_STATE_C3];
- if (cx->address == 0 || cx->latency > 1000) goto err_acpi;
-
- /* Now check what we have on this motherboard */
switch (c->x86_model) {
case 6:
cpu_model = CPU_SAMUEL;
cpufreq_frequency_table_get_attr(longhaul_table, policy->cpu);
return 0;
-
-err_acpi:
- printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n");
- return -ENODEV;
}
static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy)
if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
return -ENODEV;
-#ifdef CONFIG_SMP
- if (num_online_cpus() > 1) {
- return -ENODEV;
- printk(KERN_ERR PFX "More than 1 CPU detected, longhaul disabled.\n");
- }
-#endif
-#ifdef CONFIG_X86_IO_APIC
- if (cpu_has_apic) {
- printk(KERN_ERR PFX "APIC detected. Longhaul is currently broken in this configuration.\n");
- return -ENODEV;
- }
-#endif
switch (c->x86_model) {
case 6 ... 9:
return cpufreq_register_driver(&longhaul_driver);
static void __exit longhaul_exit(void)
{
- int i;
+ int i=0;
for (i=0; i < numscales; i++) {
if (clock_ratio[i] == maxmult) {
MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
MODULE_LICENSE ("GPL");
-late_initcall(longhaul_init);
+module_init(longhaul_init);
module_exit(longhaul_exit);