Skip to content

Commit

Permalink
[CPUFREQ] Longhaul - Disable arbiter
Browse files Browse the repository at this point in the history
ACPI C3 works for "Powersaver" processors, so use it only for them.

Older CPU will change frequency on "halt" only. But we can protect transition
in two ways:
- by ACPI PM2 register, there is "bus master arbiter disable" bit.
  This isn't tested because VIA mainboards don't have PM2 register,
- by PLE133 PCI/AGP arbiter disable register.
  There are two bits in this register. First is "PCI arbiter disable",
  second "AGP arbiter disable". This is working on VIA Epia 800 mainboards.

Test on bm_control is more proper because this is true
when PM2 register exist.

Signed-off-by: Rafa³ Bilski <rafalbilski@interia.pl>
Signed-off-by: Dave Jones <davej@redhat.com>
  • Loading branch information
Rafa³ Bilski authored and Dave Jones committed Aug 11, 2006
1 parent 05ca035 commit 179da8e
Showing 1 changed file with 64 additions and 22 deletions.
86 changes: 64 additions & 22 deletions arch/i386/kernel/cpu/cpufreq/longhaul.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/string.h>

Expand Down Expand Up @@ -60,6 +61,7 @@ static int can_scale_voltage;
static int vrmrev;
static struct acpi_processor *pr = NULL;
static struct acpi_processor_cx *cx = NULL;
static int port22_en = 0;

/* Module parameters */
static int dont_scale_voltage;
Expand Down Expand Up @@ -124,10 +126,9 @@ static int longhaul_get_cpu_mult(void)

/* For processor with BCR2 MSR */

static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)
static void do_longhaul1(unsigned int clock_ratio_index)
{
union msr_bcr2 bcr2;
u32 t;

rdmsrl(MSR_VIA_BCR2, bcr2.val);
/* Enable software clock multiplier */
Expand All @@ -136,13 +137,11 @@ static void do_longhaul1(int cx_address, unsigned int clock_ratio_index)

/* 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);
/* Invoke transition */
ACPI_FLUSH_CPU_CACHE();
halt();

/* Disable software clock multiplier */
local_irq_disable();
Expand All @@ -166,9 +165,9 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)

/* Sync to timer tick */
safe_halt();
ACPI_FLUSH_CPU_CACHE();
/* Change frequency on next halt or sleep */
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
ACPI_FLUSH_CPU_CACHE();
/* Invoke C3 */
inb(cx_address);
/* Dummy op - must do something useless after P_LVL3 read */
Expand Down Expand Up @@ -227,10 +226,13 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
outb(0xFF,0xA1); /* Overkill */
outb(0xFE,0x21); /* TMR0 only */

/* Disable bus master arbitration */
if (pr->flags.bm_check) {
if (pr->flags.bm_control) {
/* Disable bus master arbitration */
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
ACPI_MTX_DO_NOT_LOCK);
} else if (port22_en) {
/* Disable AGP and PCI arbiters */
outb(3, 0x22);
}

switch (longhaul_version) {
Expand All @@ -244,7 +246,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
*/
case TYPE_LONGHAUL_V1:
case TYPE_LONGHAUL_V2:
do_longhaul1(cx->address, clock_ratio_index);
do_longhaul1(clock_ratio_index);
break;

/*
Expand All @@ -259,14 +261,20 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
* to work in practice.
*/
case TYPE_POWERSAVER:
/* Don't allow wakeup */
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
ACPI_MTX_DO_NOT_LOCK);
do_powersaver(cx->address, clock_ratio_index);
break;
}

/* Enable bus master arbitration */
if (pr->flags.bm_check) {
if (pr->flags.bm_control) {
/* Enable bus master arbitration */
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
ACPI_MTX_DO_NOT_LOCK);
} else if (port22_en) {
/* Enable arbiters */
outb(0, 0x22);
}

outb(pic2_mask,0xA1); /* restore mask */
Expand Down Expand Up @@ -540,21 +548,33 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
return 1;
}

/* VIA don't support PM2 reg, but have something similar */
static int enable_arbiter_disable(void)
{
struct pci_dev *dev;
u8 pci_cmd;

/* Find PLE133 host bridge */
dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL);
if (dev != NULL) {
/* Enable access to port 0x22 */
pci_read_config_byte(dev, 0x78, &pci_cmd);
if ( !(pci_cmd & 1<<7) ) {
pci_cmd |= 1<<7;
pci_write_config_byte(dev, 0x78, pci_cmd);
}
return 1;
}
return 0;
}

static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
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 */
/* Check what we have on this motherboard */
switch (c->x86_model) {
case 6:
cpu_model = CPU_SAMUEL;
Expand Down Expand Up @@ -636,6 +656,28 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
break;
};

/* Find ACPI data for processor */
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
&longhaul_walk_callback, NULL, (void *)&pr);
if (pr == NULL)
goto err_acpi;

if (longhaul_version == TYPE_POWERSAVER) {
/* Check ACPI support for C3 state */
cx = &pr->power.states[ACPI_STATE_C3];
if (cx->address == 0 || cx->latency > 1000)
goto err_acpi;
} else {
/* Check ACPI support for bus master arbiter disable */
if (!pr->flags.bm_control) {
if (!enable_arbiter_disable()) {
printk(KERN_ERR PFX "No ACPI support. No VT8601 host bridge. Aborting.\n");
return -ENODEV;
} else
port22_en = 1;
}
}

ret = longhaul_get_ranges();
if (ret != 0)
return ret;
Expand Down

0 comments on commit 179da8e

Please sign in to comment.