lkml.org 
[lkml]   [2006]   [May]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [PATCH] Longhaul - call suspend(PMSG_FREEZE) before and resume() after
Here is simplier patch using PCI bus master disabling code by Dave Jones.
Still using block subsystem, but this time it isn't exported to modules.

1. Call suspend(PMSG_FREEZE) for each block device.
2. Change frequency - notice that in this patch at least we give a chance to BCR2 MSR CPU's.
3. Call resume() for each block device.

Tested on Epia M10000. 22MB/s while changing from 997MHz to 532MHz at 1s interval.

EXPERIMENTAL - Please!
(HZ_100 || HZ_250) - because VIA CPU's with BCR2 MSR need >=1ms to sync PLL.
!SMP - original code and patch aren't SMP compatible.
!X86_UP_APIC - original code and patch aren't APIC compatible.


diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/Kconfig linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/Kconfig
--- linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/Kconfig 2006-05-28 15:04:34.000000000 +0200
+++ linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/Kconfig 2006-05-28 15:36:54.000000000 +0200
@@ -201,14 +201,17 @@ config X86_LONGRUN
If in doubt, say N.

config X86_LONGHAUL
- tristate "VIA Cyrix III Longhaul"
+ bool "VIA Cyrix III Longhaul (EXPERIMENTAL)"
+ default n
select CPU_FREQ_TABLE
- depends on BROKEN
+ depends on EXPERIMENTAL && !SMP && !X86_UP_APIC
+ depends on (HZ_100 || HZ_250) && (PREEMPT_NONE || PREEMPT_VOLUNTARY)
help
This adds the CPUFreq driver for VIA Samuel/CyrixIII,
VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T
processors.

+ BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
For details, take a look at <file:Documentation/cpu-freq/>.

If in doubt, say N.
diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/longhaul.c linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- linux-2.6.16.18-vanilla/arch/i386/kernel/cpu/cpufreq/longhaul.c 2006-03-20 06:53:29.000000000 +0100
+++ linux-2.6.16.18/arch/i386/kernel/cpu/cpufreq/longhaul.c 2006-05-28 15:57:58.000000000 +0200
@@ -30,6 +30,11 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>

#include <asm/msr.h>
#include <asm/timex.h>
@@ -115,36 +120,40 @@ static int longhaul_get_cpu_mult(void)
}


-static void do_powersaver(union msr_longhaul *longhaul,
- unsigned int clock_ratio_index)
-{
- struct pci_dev *dev;
- unsigned long flags;
- unsigned int tmp_mask;
- int version;
- int i;
- u16 pci_cmd;
- u16 cmd_state[64];
+extern struct subsystem block_subsys;
+extern struct semaphore block_subsys_sem;

- switch (cpu_model) {
- case CPU_EZRA_T:
- version = 3;
- break;
- case CPU_NEHEMIAH:
- version = 0xf;
- break;
- default:
- return;
+static struct pm_message pmsg_freeze = { .event = PM_EVENT_FREEZE, };
+
+void block_freeze_resume(int freeze)
+{
+ struct gendisk *disk;
+ struct list_head *p;
+ struct bus_type *bus;
+
+ list_for_each(p, &block_subsys.kset.list) {
+ disk = list_entry(p, struct gendisk, kobj.entry);
+ if (disk->driverfs_dev && disk->driverfs_dev->bus) {
+ bus = disk->driverfs_dev->bus;
+ if (bus->suspend && freeze) {
+ printk(KERN_INFO PFX "%.32s (%.32s) -> suspend(PMSG_FREEZE)\n", &disk->disk_name[0], &disk->driverfs_dev->bus_id[0]);
+ bus->suspend(disk->driverfs_dev, pmsg_freeze);
+ } else if (bus->resume && !freeze) {
+ printk(KERN_INFO PFX "%.32s (%.32s) -> resume()\n", &disk->disk_name[0], &disk->driverfs_dev->bus_id[0]);
+ bus->resume(disk->driverfs_dev);
+ }
+ }
}
+}

- 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;

- preempt_disable();
- local_irq_save(flags);
+static u16 cmd_state[64];
+
+static void clear_bus_master(void)
+{
+ struct pci_dev *dev;
+ u16 pci_cmd;
+ int i;

/*
* get current pci bus master state for all devices
@@ -161,18 +170,14 @@ static void do_powersaver(union msr_long
pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
}
} while (dev != NULL);
+}

- tmp_mask=inb(0x21); /* works on C3. save mask. */
- outb(0xFE,0x21); /* TMR0 only */
- outb(0xFF,0x80); /* delay */
-
- safe_halt();
- wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
- halt();
-
- local_irq_disable();

- outb(tmp_mask,0x21); /* restore mask */
+static void restore_bus_master(void)
+{
+ struct pci_dev *dev;
+ u16 pci_cmd;
+ int i;

/* restore pci bus master state for all devices */
dev = NULL;
@@ -184,14 +189,106 @@ static void do_powersaver(union msr_long
pci_write_config_byte(dev, PCI_COMMAND, pci_cmd);
}
} while (dev != NULL);
+}
+
+
+static void do_longhaul1(int reserved, unsigned int clock_ratio_index)
+{
+ unsigned long flags;
+ unsigned int tmp_mask;
+ union msr_bcr2 bcr2;
+
+ down(&block_subsys_sem);
+ block_freeze_resume(1);
+ preempt_disable();
+ clear_bus_master();
+ local_irq_save(flags);
+
+ local_irq_disable();
+
+ tmp_mask=inb(0x21); /* works on C3. save mask. */
+ outb(0xFE, 0x21); /* TMR0 only */
+
+ rdmsrl(MSR_VIA_BCR2, bcr2.val);
+ /* Enable software clock multiplier */
+ bcr2.bits.ESOFTBF = 1;
+ bcr2.bits.CLOCKMUL = clock_ratio_index;
+ safe_halt(); /* Sync */
+ wrmsrl(MSR_VIA_BCR2, bcr2.val); /* Change */
+ halt();
+
+ /* Disable software clock multiplier */
+ local_irq_disable();
+ rdmsrl(MSR_VIA_BCR2, bcr2.val);
+ bcr2.bits.ESOFTBF = 0;
+ wrmsrl(MSR_VIA_BCR2, bcr2.val);
+ local_irq_enable();
+
+ outb(tmp_mask, 0x21); /* restore mask */
local_irq_restore(flags);
+ restore_bus_master();
preempt_enable();
+ block_freeze_resume(0);
+ up(&block_subsys_sem);
+}
+
+
+static void do_powersaver(union msr_longhaul *longhaul,
+ unsigned int clock_ratio_index)
+{
+ unsigned long flags;
+ unsigned int pic1_mask, pic2_mask;
+ int version;
+
+ switch (cpu_model) {
+ case CPU_EZRA_T:
+ version = 3;
+ break;
+ case CPU_NEHEMIAH:
+ version = 0xf;
+ break;
+ default:
+ return;
+ }
+
+ down(&block_subsys_sem);
+ block_freeze_resume(1);
+ preempt_disable();
+ clear_bus_master();
+ local_irq_save(flags);
+
+ local_irq_disable();
+ pic2_mask=inb(0xA1);
+ pic1_mask=inb(0x21); /* works on C3. save mask. */
+ outb(0xFF,0xA1); /* Overkill */
+ outb(0xFE,0x21); /* TMR0 only */
+
+ 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;
+
+ safe_halt(); /* Sync */
+ wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+ halt();
+
+ local_irq_disable();

/* disable bus ratio bit */
rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
longhaul->bits.EnableSoftBusRatio = 0;
longhaul->bits.RevisionKey = version;
wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
+
+ outb(pic2_mask,0xA1);
+ outb(pic1_mask,0x21); /* restore mask */
+
+ local_irq_restore(flags);
+ restore_bus_master();
+ preempt_enable();
+ block_freeze_resume(0);
+ up(&block_subsys_sem);
}

/**
@@ -206,7 +303,6 @@ static void longhaul_setstate(unsigned i
int speed, mult;
struct cpufreq_freqs freqs;
union msr_longhaul longhaul;
- union msr_bcr2 bcr2;
static unsigned int old_ratio=-1;

if (old_ratio == clock_ratio_index)
@@ -241,20 +337,7 @@ static void longhaul_setstate(unsigned i
*/
case TYPE_LONGHAUL_V1:
case TYPE_LONGHAUL_V2:
- 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();
+ do_longhaul1(0, clock_ratio_index);
break;

/*
diff -uprN -X linux-2.6.16.18-vanilla/Documentation/dontdiff linux-2.6.16.18-vanilla/block/genhd.c linux-2.6.16.18/block/genhd.c
--- linux-2.6.16.18-vanilla/block/genhd.c 2006-05-28 15:04:34.000000000 +0200
+++ linux-2.6.16.18/block/genhd.c 2006-05-28 15:34:31.000000000 +0200
@@ -16,9 +16,9 @@
#include <linux/kobj_map.h>
#include <linux/buffer_head.h>

-static struct subsystem block_subsys;
+struct subsystem block_subsys;

-static DECLARE_MUTEX(block_subsys_sem);
+DECLARE_MUTEX(block_subsys_sem);

/*
* Can be deleted altogether. Later.
@@ -511,8 +511,7 @@ static struct kset_uevent_ops block_ueve
};

/* declare block_subsys. */
-static decl_subsys(block, &ktype_block, &block_uevent_ops);
-
+decl_subsys(block, &ktype_block, &block_uevent_ops);

/*
* aggregate disk stat collector. Uses the same stats that the sysfs

----------------------------------------------------------------------
Poznaj Stefana! Zmien komunikator! >>> http://link.interia.pl/f1924
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2006-05-28 16:46    [W:0.051 / U:0.276 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site