Skip to contentSkip to conversation

Longhaul - Disable arbiter

PATCH In review Rafał Bilski 2 participants 4 messages Aug 8, 2006

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Longhaul - Disable arbiter

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.

---

arch/i386/kernel/cpu/cpufreq/longhaul.c +62 -22
@@ -27,6 +27,7 @@ #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/cpufreq.h>
+#include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 
@@ -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;
@@ -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 */
@@ -136,13 +137,11 @@ static void do_longhaul1(int cx_address,
 
 	/* 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();
@@ -166,9 +165,9 @@ static void do_powersaver(int cx_address
 
 	/* 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 */
@@ -227,10 +226,13 @@ static void longhaul_setstate(unsigned i
 	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) {
@@ -244,7 +246,7 @@ static void longhaul_setstate(unsigned i
 	 */
 	case TYPE_LONGHAUL_V1:
 	case TYPE_LONGHAUL_V2:
-		do_longhaul1(cx->address, clock_ratio_index);
+		do_longhaul1(clock_ratio_index);
 		break;
 
 	/*
@@ -259,14 +261,20 @@ static void longhaul_setstate(unsigned i
 	 * 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 */
@@ -540,21 +548,33 @@ static acpi_status longhaul_walk_callbac
 	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;
@@ -636,6 +656,26 @@ static int __init longhaul_cpu_init(stru
 		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;

----------------------------------------------------------------------
PS. Fajny portal... >>> http://link.interia.pl/f196a

#1 lore raw
Quoted 12 lines · RafaÅ‚ Bilski

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.

The only part about this I don't like is that we now need to add code to do similar things on every possible VIA chipset that could take a C3, and there's quite a few of them, and until we have good coverage...

Quoted 10 lines
arch/i386/kernel/cpu/cpufreq/longhaul.c +9 -0
+	/* 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;

arch/i386/kernel/cpu/cpufreq/longhaul.c static int __init longhaul_cpu_init(stru · line 677

Quoted 10 lines
arch/i386/kernel/cpu/cpufreq/longhaul.c +10 -0
+	} 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;
+		}
+	}

We're going to -ENODEV, possibly breaking some setups that it might actually already work on (even if only by chance).

Dave

Signature · 1 line
http://www.codemonkey.org.uk
#2 lore raw
Quoted 5 lines

The only part about this I don't like is that we now need to add code to do similar things on every possible VIA chipset that could take a C3, and there's quite a few of them, and until we have good coverage...

Would be nice, but I have datasheet only for PLE133. Older non VIA chipsets have this port enabled and its address is returned by BIOS as PM2 address, or maybe BIOS is enabling.

Coverage is big enough because mainboards with newer chipsets seems to have new, C3 capable, CPU's on board.

Quoted 6 lines

We're going to -ENODEV, possibly breaking some setups that it might actually already work on (even if only by chance).

Dave

It isn't working for BCR2. Cpufreq is saying that it is, but cpuinfo_cur_freq returns max f all the time.

Rafa³

----------------------------------------------------------------------
PS. Fajny portal... >>> http://link.interia.pl/f196a

#3 lore raw
Quoted 14 lines · RafaÅ‚ Bilski
Quoted 5 lines

The only part about this I don't like is that we now need to add code to do similar things on every possible VIA chipset that could take a C3, and there's quite a few of them, and until we have good coverage...

Would be nice, but I have datasheet only for PLE133. Older non VIA chipsets have this port enabled and its address is returned by BIOS as PM2 address, or maybe BIOS is enabling.

Coverage is big enough because mainboards with newer chipsets seems to have new, C3 capable, CPU's on board.

Quoted 1 line
Quoted 5 lines
Quoted 2 lines

We're going to -ENODEV, possibly breaking some setups that it might actually already work on (even if only by chance).

It isn't working for BCR2. Cpufreq is saying that it is, but cpuinfo_cur_freq returns max f all the time.

Ok, I'll apply this, and see if I can dig up some of the datasheets on the older chipsets for completeness.

Dave

Signature · 1 line
http://www.codemonkey.org.uk