Commit 12725675 authored by Steve French's avatar Steve French
parents af6f5e32 eff910a9
CPU frequency and voltage scaling statictics in the Linux(TM) kernel
L i n u x c p u f r e q - s t a t s d r i v e r
- information for users -
Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Contents
1. Introduction
2. Statistics Provided (with example)
3. Configuring cpufreq-stats
1. Introduction
cpufreq-stats is a driver that provices CPU frequency statistics for each CPU.
This statistics is provided in /sysfs as a bunch of read_only interfaces. This
interface (when configured) will appear in a seperate directory under cpufreq
in /sysfs (<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/) for each CPU.
Various statistics will form read_only files under this directory.
This driver is designed to be independent of any particular cpufreq_driver
that may be running on your CPU. So, it will work with any cpufreq_driver.
2. Statistics Provided (with example)
cpufreq stats provides following statistics (explained in detail below).
- time_in_state
- total_trans
- trans_table
All the statistics will be from the time the stats driver has been inserted
to the time when a read of a particular statistic is done. Obviously, stats
driver will not have any information about the the frequcny transitions before
the stats driver insertion.
--------------------------------------------------------------------------------
<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
total 0
drwxr-xr-x 2 root root 0 May 14 16:06 .
drwxr-xr-x 3 root root 0 May 14 15:58 ..
-r--r--r-- 1 root root 4096 May 14 16:06 time_in_state
-r--r--r-- 1 root root 4096 May 14 16:06 total_trans
-r--r--r-- 1 root root 4096 May 14 16:06 trans_table
--------------------------------------------------------------------------------
- time_in_state
This gives the amount of time spent in each of the frequencies supported by
this CPU. The cat output will have "<frequency> <time>" pair in each line, which
will mean this CPU spent <time> usertime units of time at <frequency>. Output
will have one line for each of the supported freuencies. usertime units here
is 10mS (similar to other time exported in /proc).
--------------------------------------------------------------------------------
<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state
3600000 2089
3400000 136
3200000 34
3000000 67
2800000 172488
--------------------------------------------------------------------------------
- total_trans
This gives the total number of frequency transitions on this CPU. The cat
output will have a single count which is the total number of frequency
transitions.
--------------------------------------------------------------------------------
<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans
20
--------------------------------------------------------------------------------
- trans_table
This will give a fine grained information about all the CPU frequency
transitions. The cat output here is a two dimensional matrix, where an entry
<i,j> (row i, column j) represents the count of number of transitions from
Freq_i to Freq_j. Freq_i is in descending order with increasing rows and
Freq_j is in descending order with increasing columns. The output here also
contains the actual freq values for each row and column for better readability.
--------------------------------------------------------------------------------
<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
From : To
: 3600000 3400000 3200000 3000000 2800000
3600000: 0 5 0 0 0
3400000: 4 0 2 0 0
3200000: 0 1 0 2 0
3000000: 0 0 1 0 3
2800000: 0 0 0 2 0
--------------------------------------------------------------------------------
3. Configuring cpufreq-stats
To configure cpufreq-stats in your kernel
Config Main Menu
Power management options (ACPI, APM) --->
CPU Frequency scaling --->
[*] CPU Frequency scaling
<*> CPU frequency translation statistics
[*] CPU frequency translation statistics details
"CPU Frequency scaling" (CONFIG_CPU_FREQ) should be enabled to configure
cpufreq-stats.
"CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT) provides the
basic statistics which includes time_in_state and total_trans.
"CPU frequency translation statistics details" (CONFIG_CPU_FREQ_STAT_DETAILS)
provides fine grained cpufreq stats by trans_table. The reason for having a
seperate config option for trans_table is:
- trans_table goes against the traditional /sysfs rule of one value per
interface. It provides a whole bunch of value in a 2 dimensional matrix
form.
Once these two options are enabled and your CPU supports cpufrequency, you
will be able to see the CPU frequency statistics in /sysfs.
...@@ -239,6 +239,12 @@ L: linux-usb-devel@lists.sourceforge.net ...@@ -239,6 +239,12 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.linux-usb.org/SpeedTouch/ W: http://www.linux-usb.org/SpeedTouch/
S: Maintained S: Maintained
ALI1563 I2C DRIVER
P: Rudolf Marek
M: r.marek@sh.cvut.cz
L: sensors@stimpy.netroedge.com
S: Maintained
ALPHA PORT ALPHA PORT
P: Richard Henderson P: Richard Henderson
M: rth@twiddle.net M: rth@twiddle.net
......
...@@ -54,7 +54,7 @@ asmlinkage void ret_from_fork(void); ...@@ -54,7 +54,7 @@ asmlinkage void ret_from_fork(void);
void default_idle(void) void default_idle(void)
{ {
while(1) { while(1) {
if (need_resched()) { if (!need_resched()) {
local_irq_enable(); local_irq_enable();
__asm__("sleep"); __asm__("sleep");
local_irq_disable(); local_irq_disable();
......
...@@ -23,7 +23,7 @@ config X86_ACPI_CPUFREQ ...@@ -23,7 +23,7 @@ config X86_ACPI_CPUFREQ
If in doubt, say N. If in doubt, say N.
config ELAN_CPUFREQ config ELAN_CPUFREQ
tristate "AMD Elan" tristate "AMD Elan SC400 and SC410"
select CPU_FREQ_TABLE select CPU_FREQ_TABLE
depends on X86_ELAN depends on X86_ELAN
---help--- ---help---
...@@ -38,6 +38,18 @@ config ELAN_CPUFREQ ...@@ -38,6 +38,18 @@ config ELAN_CPUFREQ
If in doubt, say N. If in doubt, say N.
config SC520_CPUFREQ
tristate "AMD Elan SC520"
select CPU_FREQ_TABLE
depends on X86_ELAN
---help---
This adds the CPUFreq driver for AMD Elan SC520 processor.
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
config X86_POWERNOW_K6 config X86_POWERNOW_K6
tristate "AMD Mobile K6-2/K6-3 PowerNow!" tristate "AMD Mobile K6-2/K6-3 PowerNow!"
select CPU_FREQ_TABLE select CPU_FREQ_TABLE
......
...@@ -3,6 +3,7 @@ obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o ...@@ -3,6 +3,7 @@ obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
obj-$(CONFIG_X86_LONGHAUL) += longhaul.o obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o
obj-$(CONFIG_X86_LONGRUN) += longrun.o obj-$(CONFIG_X86_LONGRUN) += longrun.o
obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o
obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/pci.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/timex.h> #include <asm/timex.h>
...@@ -119,7 +120,13 @@ static int longhaul_get_cpu_mult(void) ...@@ -119,7 +120,13 @@ static int longhaul_get_cpu_mult(void)
static void do_powersaver(union msr_longhaul *longhaul, static void do_powersaver(union msr_longhaul *longhaul,
unsigned int clock_ratio_index) unsigned int clock_ratio_index)
{ {
struct pci_dev *dev;
unsigned long flags;
unsigned int tmp_mask;
int version; int version;
int i;
u16 pci_cmd;
u16 cmd_state[64];
switch (cpu_model) { switch (cpu_model) {
case CPU_EZRA_T: case CPU_EZRA_T:
...@@ -137,17 +144,58 @@ static void do_powersaver(union msr_longhaul *longhaul, ...@@ -137,17 +144,58 @@ static void do_powersaver(union msr_longhaul *longhaul,
longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
longhaul->bits.EnableSoftBusRatio = 1; longhaul->bits.EnableSoftBusRatio = 1;
longhaul->bits.RevisionKey = 0; longhaul->bits.RevisionKey = 0;
local_irq_disable();
wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); preempt_disable();
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);
tmp_mask=inb(0x21); /* works on C3. save mask. */
outb(0xFE,0x21); /* TMR0 only */
outb(0xFF,0x80); /* delay */
local_irq_enable(); local_irq_enable();
__hlt();
wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
__hlt(); __hlt();
local_irq_disable();
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); rdmsrl(MSR_VIA_LONGHAUL, longhaul->val);
longhaul->bits.EnableSoftBusRatio = 0; longhaul->bits.EnableSoftBusRatio = 0;
longhaul->bits.RevisionKey = version; longhaul->bits.RevisionKey = version;
local_irq_disable();
wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); wrmsrl(MSR_VIA_LONGHAUL, longhaul->val);
local_irq_enable();
} }
/** /**
...@@ -578,7 +626,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) ...@@ -578,7 +626,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
longhaul_setup_voltagescaling(); longhaul_setup_voltagescaling();
policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 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()); policy->cur = calc_speed(longhaul_get_cpu_mult());
ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/timer.h>
#include <asm/timex.h> #include <asm/timex.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -586,13 +587,17 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) ...@@ -586,13 +587,17 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val);
/* A K7 with powernow technology is set to max frequency by BIOS */ /* recalibrate cpu_khz */
fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID]; result = recalibrate_cpu_khz();
if (result)
return result;
fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID];
if (!fsb) { if (!fsb) {
printk(KERN_WARNING PFX "can not determine bus frequency\n"); printk(KERN_WARNING PFX "can not determine bus frequency\n");
return -EINVAL; return -EINVAL;
} }
dprintk("FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000); dprintk("FSB: %3dMHz\n", fsb/1000);
if (dmi_check_system(powernow_dmi_table) || acpi_force) { if (dmi_check_system(powernow_dmi_table) || acpi_force) {
printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n");
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* GNU general public license version 2. See "COPYING" or * GNU general public license version 2. See "COPYING" or
* http://www.gnu.org/licenses/gpl.html * http://www.gnu.org/licenses/gpl.html
* *
* Support : paul.devriendt@amd.com * Support : mark.langsdorf@amd.com
* *
* Based on the powernow-k7.c module written by Dave Jones. * Based on the powernow-k7.c module written by Dave Jones.
* (C) 2003 Dave Jones <davej@codemonkey.org.uk> on behalf of SuSE Labs * (C) 2003 Dave Jones <davej@codemonkey.org.uk> on behalf of SuSE Labs
...@@ -15,12 +15,13 @@ ...@@ -15,12 +15,13 @@
* *
* Valuable input gratefully received from Dave Jones, Pavel Machek, * Valuable input gratefully received from Dave Jones, Pavel Machek,
* Dominik Brodowski, and others. * Dominik Brodowski, and others.
* Originally developed by Paul Devriendt.
* Processor information obtained from Chapter 9 (Power and Thermal Management) * Processor information obtained from Chapter 9 (Power and Thermal Management)
* of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD * of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
* Opteron Processors" available for download from www.amd.com * Opteron Processors" available for download from www.amd.com
* *
* Tables for specific CPUs can be infrerred from * Tables for specific CPUs can be infrerred from
* http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/cpumask.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -42,7 +44,7 @@ ...@@ -42,7 +44,7 @@
#define PFX "powernow-k8: " #define PFX "powernow-k8: "
#define BFX PFX "BIOS error: " #define BFX PFX "BIOS error: "
#define VERSION "version 1.00.09e" #define VERSION "version 1.40.2"
#include "powernow-k8.h" #include "powernow-k8.h"
/* serialize freq changes */ /* serialize freq changes */
...@@ -50,6 +52,10 @@ static DECLARE_MUTEX(fidvid_sem); ...@@ -50,6 +52,10 @@ static DECLARE_MUTEX(fidvid_sem);
static struct powernow_k8_data *powernow_data[NR_CPUS]; static struct powernow_k8_data *powernow_data[NR_CPUS];
#ifndef CONFIG_SMP
static cpumask_t cpu_core_map[1];
#endif
/* Return a frequency in MHz, given an input fid */ /* Return a frequency in MHz, given an input fid */
static u32 find_freq_from_fid(u32 fid) static u32 find_freq_from_fid(u32 fid)
{ {
...@@ -274,11 +280,18 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid ...@@ -274,11 +280,18 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
{ {
u32 rvosteps = data->rvo; u32 rvosteps = data->rvo;
u32 savefid = data->currfid; u32 savefid = data->currfid;
u32 maxvid, lo;
dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n", dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n",
smp_processor_id(), smp_processor_id(),
data->currfid, data->currvid, reqvid, data->rvo); data->currfid, data->currvid, reqvid, data->rvo);
rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
maxvid = 0x1f & (maxvid >> 16);
dprintk("ph1 maxvid=0x%x\n", maxvid);
if (reqvid < maxvid) /* lower numbers are higher voltages */
reqvid = maxvid;
while (data->currvid > reqvid) { while (data->currvid > reqvid) {
dprintk("ph1: curr 0x%x, req vid 0x%x\n", dprintk("ph1: curr 0x%x, req vid 0x%x\n",
data->currvid, reqvid); data->currvid, reqvid);
...@@ -286,8 +299,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid ...@@ -286,8 +299,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid
return 1; return 1;
} }
while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) { while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) {
if (data->currvid == 0) { if (data->currvid == maxvid) {
rvosteps = 0; rvosteps = 0;
} else { } else {
dprintk("ph1: changing vid for rvo, req 0x%x\n", dprintk("ph1: changing vid for rvo, req 0x%x\n",
...@@ -671,7 +684,7 @@ static int find_psb_table(struct powernow_k8_data *data) ...@@ -671,7 +684,7 @@ static int find_psb_table(struct powernow_k8_data *data)
* BIOS and Kernel Developer's Guide, which is available on * BIOS and Kernel Developer's Guide, which is available on
* www.amd.com * www.amd.com
*/ */
printk(KERN_ERR PFX "BIOS error - no PSB\n"); printk(KERN_INFO PFX "BIOS error - no PSB or ACPI _PSS objects\n");
return -ENODEV; return -ENODEV;
} }
...@@ -695,7 +708,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) ...@@ -695,7 +708,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
struct cpufreq_frequency_table *powernow_table; struct cpufreq_frequency_table *powernow_table;
if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
dprintk("register performance failed\n"); dprintk("register performance failed: bad ACPI data\n");
return -EIO; return -EIO;
} }
...@@ -746,22 +759,23 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) ...@@ -746,22 +759,23 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
continue; continue;
} }
if (fid < HI_FID_TABLE_BOTTOM) { /* verify only 1 entry from the lo frequency table */
if (cntlofreq) { if (fid < HI_FID_TABLE_BOTTOM) {
/* if both entries are the same, ignore this if (cntlofreq) {
* one... /* if both entries are the same, ignore this
*/ * one...
if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) || */
(powernow_table[i].index != powernow_table[cntlofreq].index)) { if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) ||
printk(KERN_ERR PFX "Too many lo freq table entries\n"); (powernow_table[i].index != powernow_table[cntlofreq].index)) {
goto err_out_mem; printk(KERN_ERR PFX "Too many lo freq table entries\n");
} goto err_out_mem;
}
dprintk("double low frequency table entry, ignoring it.\n");
powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; dprintk("double low frequency table entry, ignoring it.\n");
continue; powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
} else continue;
cntlofreq = i; } else
cntlofreq = i;
} }
if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) { if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) {
...@@ -816,7 +830,7 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde ...@@ -816,7 +830,7 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde
{ {
u32 fid; u32 fid;
u32 vid; u32 vid;
int res; int res, i;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
dprintk("cpu %d transition to index %u\n", smp_processor_id(), index); dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
...@@ -841,7 +855,8 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde ...@@ -841,7 +855,8 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde
} }
if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) {
printk("ignoring illegal change in lo freq table-%x to 0x%x\n", printk(KERN_ERR PFX
"ignoring illegal change in lo freq table-%x to 0x%x\n",
data->currfid, fid); data->currfid, fid);
return 1; return 1;
} }
...@@ -850,18 +865,20 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde ...@@ -850,18 +865,20 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde
smp_processor_id(), fid, vid); smp_processor_id(), fid, vid);
freqs.cpu = data->cpu; freqs.cpu = data->cpu;
freqs.old = find_khz_freq_from_fid(data->currfid); freqs.old = find_khz_freq_from_fid(data->currfid);
freqs.new = find_khz_freq_from_fid(fid); freqs.new = find_khz_freq_from_fid(fid);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); for_each_cpu_mask(i, cpu_core_map[data->cpu]) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
down(&fidvid_sem);
res = transition_fid_vid(data, fid, vid); res = transition_fid_vid(data, fid, vid);
up(&fidvid_sem);
freqs.new = find_khz_freq_from_fid(data->currfid); freqs.new = find_khz_freq_from_fid(data->currfid);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); for_each_cpu_mask(i, cpu_core_map[data->cpu]) {
freqs.cpu = i;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
return res; return res;
} }
...@@ -874,6 +891,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi ...@@ -874,6 +891,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
u32 checkvid = data->currvid; u32 checkvid = data->currvid;
unsigned int newstate; unsigned int newstate;
int ret = -EIO; int ret = -EIO;
int i;
/* only run on specific CPU from here on */ /* only run on specific CPU from here on */
oldmask = current->cpus_allowed; oldmask = current->cpus_allowed;
...@@ -902,22 +920,41 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi ...@@ -902,22 +920,41 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
data->currfid, data->currvid); data->currfid, data->currvid);
if ((checkvid != data->currvid) || (checkfid != data->currfid)) { if ((checkvid != data->currvid) || (checkfid != data->currfid)) {
printk(KERN_ERR PFX printk(KERN_INFO PFX
"error - out of sync, fid 0x%x 0x%x, vid 0x%x 0x%x\n", "error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
checkfid, data->currfid, checkvid, data->currvid); checkfid, data->currfid, checkvid, data->currvid);
} }
if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate)) if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate))
goto err_out; goto err_out;
down(&fidvid_sem);
for_each_cpu_mask(i, cpu_core_map[pol->cpu]) {
/* make sure the sibling is initialized */
if (!powernow_data[i]) {
ret = 0;
up(&fidvid_sem);
goto err_out;
}
}
powernow_k8_acpi_pst_values(data, newstate); powernow_k8_acpi_pst_values(data, newstate);
if (transition_frequency(data, newstate)) { if (transition_frequency(data, newstate)) {
printk(KERN_ERR PFX "transition frequency failed\n"); printk(KERN_ERR PFX "transition frequency failed\n");
ret = 1; ret = 1;
up(&fidvid_sem);
goto err_out; goto err_out;
} }
/* Update all the fid/vids of our siblings */
for_each_cpu_mask(i, cpu_core_map[pol->cpu]) {
powernow_data[i]->currvid = data->currvid;
powernow_data[i]->currfid = data->currfid;
}
up(&fidvid_sem);
pol->cur = find_khz_freq_from_fid(data->currfid); pol->cur = find_khz_freq_from_fid(data->currfid);
ret = 0; ret = 0;
...@@ -962,7 +999,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -962,7 +999,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol)
*/ */
if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) {
printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); printk(KERN_ERR PFX "MP systems not supported by PSB BIOS structure\n");
kfree(data); kfree(data);
return -ENODEV; return -ENODEV;
} }
...@@ -1003,6 +1040,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1003,6 +1040,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol)
schedule(); schedule();
pol->governor = CPUFREQ_DEFAULT_GOVERNOR; pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
pol->cpus = cpu_core_map[pol->cpu];
/* Take a crude guess here. /* Take a crude guess here.
* That guess was in microseconds, so multiply with 1000 */ * That guess was in microseconds, so multiply with 1000 */
...@@ -1069,7 +1107,7 @@ static unsigned int powernowk8_get (unsigned int cpu) ...@@ -1069,7 +1107,7 @@ static unsigned int powernowk8_get (unsigned int cpu)
return 0; return 0;
} }
preempt_disable(); preempt_disable();
if (query_current_values_with_pending_wait(data)) if (query_current_values_with_pending_wait(data))
goto out; goto out;
...@@ -1127,9 +1165,10 @@ static void __exit powernowk8_exit(void) ...@@ -1127,9 +1165,10 @@ static void __exit powernowk8_exit(void)
cpufreq_unregister_driver(&cpufreq_amd64_driver); cpufreq_unregister_driver(&cpufreq_amd64_driver);
} }
MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>"); MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and Mark Langsdorf <mark.langsdorf@amd.com.");
MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver."); MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
late_initcall(powernowk8_init); late_initcall(powernowk8_init);
module_exit(powernowk8_exit); module_exit(powernowk8_exit);
...@@ -174,3 +174,18 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi ...@@ -174,3 +174,18 @@ static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvi
static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid); static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid);
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index); static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
#ifndef for_each_cpu_mask
#define for_each_cpu_mask(i,mask) for (i=0;i<1;i++)
#endif
#ifdef CONFIG_SMP
static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
{
}
#else
static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
{
cpu_set(0, cpu_sharedcore_mask[0]);
}
#endif
/*
* sc520_freq.c: cpufreq driver for the AMD Elan sc520
*
* Copyright (C) 2005 Sean Young <sean@mess.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Based on elanfreq.c
*
* 2005-03-30: - initial revision
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/cpufreq.h>
#include <asm/msr.h>
#include <asm/timex.h>
#include <asm/io.h>
#define MMCR_BASE 0xfffef000 /* The default base address */
#define OFFS_CPUCTL 0x2 /* CPU Control Register */
static __u8 __iomem *cpuctl;
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "sc520_freq", msg)
static struct cpufreq_frequency_table sc520_freq_table[] = {
{0x01, 100000},
{0x02, 133000},
{0, CPUFREQ_TABLE_END},
};
static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
{
u8 clockspeed_reg = *cpuctl;
switch (clockspeed_reg & 0x03) {
default:
printk(KERN_ERR "sc520_freq: error: cpuctl register has unexpected value %02x\n", clockspeed_reg);
case 0x01:
return 100000;
case 0x02:
return 133000;
}
}
static void sc520_freq_set_cpu_state (unsigned int state)
{
struct cpufreq_freqs freqs;
u8 clockspeed_reg;
freqs.old = sc520_freq_get_cpu_frequency(0);
freqs.new = sc520_freq_table[state].frequency;
freqs.cpu = 0; /* AMD Elan is UP */
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
dprintk("attempting to set frequency to %i kHz\n",
sc520_freq_table[state].frequency);
local_irq_disable();
clockspeed_reg = *cpuctl & ~0x03;
*cpuctl = clockspeed_reg | sc520_freq_table[state].index;
local_irq_enable();
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
};
static int sc520_freq_verify (struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]);
}
static int sc520_freq_target (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
unsigned int newstate = 0;
if (cpufreq_frequency_table_target(policy, sc520_freq_table, target_freq, relation, &newstate))
return -EINVAL;
sc520_freq_set_cpu_state(newstate);
return 0;
}
/*
* Module init and exit code
*/
static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = cpu_data;
int result;
/* capability check */
if (c->x86_vendor != X86_VENDOR_AMD ||
c->x86 != 4 || c->x86_model != 9)
return -ENODEV;
/* cpuinfo and default policy values */
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = sc520_freq_get_cpu_frequency(0);
result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table);
if (result)
return (result);
cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu);
return 0;
}
static int sc520_freq_cpu_exit(struct cpufreq_policy *policy)
{
cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
static struct freq_attr* sc520_freq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static struct cpufreq_driver sc520_freq_driver = {
.get = sc520_freq_get_cpu_frequency,
.verify = sc520_freq_verify,
.target = sc520_freq_target,
.init = sc520_freq_cpu_init,
.exit = sc520_freq_cpu_exit,
.name = "sc520_freq",
.owner = THIS_MODULE,
.attr = sc520_freq_attr,
};
static int __init sc520_freq_init(void)
{
struct cpuinfo_x86 *c = cpu_data;
/* Test if we have the right hardware */
if(c->x86_vendor != X86_VENDOR_AMD ||
c->x86 != 4 || c->x86_model != 9) {
dprintk("no Elan SC520 processor found!\n");
return -ENODEV;
}
cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
if(!cpuctl) {
printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
return -ENOMEM;
}
return cpufreq_register_driver(&sc520_freq_driver);
}
static void __exit sc520_freq_exit(void)
{
cpufreq_unregister_driver(&sc520_freq_driver);
iounmap(cpuctl);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sean Young <sean@mess.org>");
MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
module_init(sc520_freq_init);
module_exit(sc520_freq_exit);
...@@ -54,6 +54,8 @@ enum { ...@@ -54,6 +54,8 @@ enum {
CPU_DOTHAN_A1, CPU_DOTHAN_A1,
CPU_DOTHAN_A2, CPU_DOTHAN_A2,
CPU_DOTHAN_B0, CPU_DOTHAN_B0,
CPU_MP4HT_D0,
CPU_MP4HT_E0,
}; };
static const struct cpu_id cpu_ids[] = { static const struct cpu_id cpu_ids[] = {
...@@ -61,6 +63,8 @@ static const struct cpu_id cpu_ids[] = { ...@@ -61,6 +63,8 @@ static const struct cpu_id cpu_ids[] = {
[CPU_DOTHAN_A1] = { 6, 13, 1 }, [CPU_DOTHAN_A1] = { 6, 13, 1 },
[CPU_DOTHAN_A2] = { 6, 13, 2 }, [CPU_DOTHAN_A2] = { 6, 13, 2 },
[CPU_DOTHAN_B0] = { 6, 13, 6 }, [CPU_DOTHAN_B0] = { 6, 13, 6 },
[CPU_MP4HT_D0] = {15, 3, 4 },
[CPU_MP4HT_E0] = {15, 4, 1 },
}; };
#define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0])) #define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0]))
...@@ -226,6 +230,8 @@ static struct cpu_model models[] = ...@@ -226,6 +230,8 @@ static struct cpu_model models[] =
{ &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL },
{ &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL },
{ &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL },
{ &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL },
{ &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL },
{ NULL, } { NULL, }
}; };
......
...@@ -336,7 +336,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -336,7 +336,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
if (!prev_speed) if (!prev_speed)
return -EIO; return -EIO;
dprintk("previous seped is %u\n", prev_speed); dprintk("previous speed is %u\n", prev_speed);
local_irq_save(flags); local_irq_save(flags);
...@@ -348,7 +348,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -348,7 +348,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
goto out; goto out;
} }
dprintk("low seped is %u\n", *low_speed); dprintk("low speed is %u\n", *low_speed);
/* switch to high state */ /* switch to high state */
set_state(SPEEDSTEP_HIGH); set_state(SPEEDSTEP_HIGH);
...@@ -358,7 +358,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, ...@@ -358,7 +358,7 @@ unsigned int speedstep_get_freqs(unsigned int processor,
goto out; goto out;
} }
dprintk("high seped is %u\n", *high_speed); dprintk("high speed is %u\n", *high_speed);
if (*low_speed == *high_speed) { if (*low_speed == *high_speed) {
ret = -ENODEV; ret = -ENODEV;
......
...@@ -357,6 +357,9 @@ static int __init speedstep_init(void) ...@@ -357,6 +357,9 @@ static int __init speedstep_init(void)
case SPEEDSTEP_PROCESSOR_PIII_C: case SPEEDSTEP_PROCESSOR_PIII_C:
case SPEEDSTEP_PROCESSOR_PIII_C_EARLY: case SPEEDSTEP_PROCESSOR_PIII_C_EARLY:
break; break;
case SPEEDSTEP_PROCESSOR_P4M:
printk(KERN_INFO "speedstep-smi: you're trying to use this cpufreq driver on a Pentium 4-based CPU. Most likely it will not work.\n");
break;
default: default:
speedstep_processor = 0; speedstep_processor = 0;
} }
......
...@@ -1502,11 +1502,13 @@ void __init setup_arch(char **cmdline_p) ...@@ -1502,11 +1502,13 @@ void __init setup_arch(char **cmdline_p)
if (efi_enabled) if (efi_enabled)
efi_map_memmap(); efi_map_memmap();
#ifdef CONFIG_ACPI_BOOT
/* /*
* Parse the ACPI tables for possible boot-time SMP configuration. * Parse the ACPI tables for possible boot-time SMP configuration.
*/ */
acpi_boot_table_init(); acpi_boot_table_init();
acpi_boot_init(); acpi_boot_init();
#endif
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
if (smp_found_config) if (smp_found_config)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/module.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/timer.h> #include <asm/timer.h>
...@@ -24,7 +25,7 @@ ...@@ -24,7 +25,7 @@
#define CALIBRATE_TIME (5 * 1000020/HZ) #define CALIBRATE_TIME (5 * 1000020/HZ)
unsigned long __init calibrate_tsc(void) unsigned long calibrate_tsc(void)
{ {
mach_prepare_counter(); mach_prepare_counter();
...@@ -139,7 +140,7 @@ unsigned long __init calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr) ...@@ -139,7 +140,7 @@ unsigned long __init calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr)
#endif #endif
/* calculate cpu_khz */ /* calculate cpu_khz */
void __init init_cpu_khz(void) void init_cpu_khz(void)
{ {
if (cpu_has_tsc) { if (cpu_has_tsc) {
unsigned long tsc_quotient = calibrate_tsc(); unsigned long tsc_quotient = calibrate_tsc();
...@@ -158,3 +159,4 @@ void __init init_cpu_khz(void) ...@@ -158,3 +159,4 @@ void __init init_cpu_khz(void)
} }
} }
} }
...@@ -320,6 +320,26 @@ core_initcall(cpufreq_tsc); ...@@ -320,6 +320,26 @@ core_initcall(cpufreq_tsc);
static inline void cpufreq_delayed_get(void) { return; } static inline void cpufreq_delayed_get(void) { return; }
#endif #endif
int recalibrate_cpu_khz(void)
{
#ifndef CONFIG_SMP
unsigned long cpu_khz_old = cpu_khz;
if (cpu_has_tsc) {
init_cpu_khz();
cpu_data[0].loops_per_jiffy =
cpufreq_scale(cpu_data[0].loops_per_jiffy,
cpu_khz_old,
cpu_khz);
return 0;
} else
return -ENODEV;
#else
return -ENODEV;
#endif
}
EXPORT_SYMBOL(recalibrate_cpu_khz);
static void mark_offset_tsc(void) static void mark_offset_tsc(void)
{ {
unsigned long lost,delay; unsigned long lost,delay;
......
...@@ -626,8 +626,18 @@ inspect_node(phandle node, struct device_node *dad, ...@@ -626,8 +626,18 @@ inspect_node(phandle node, struct device_node *dad,
l = call_prom("package-to-path", 3, 1, node, l = call_prom("package-to-path", 3, 1, node,
mem_start, mem_end - mem_start); mem_start, mem_end - mem_start);
if (l >= 0) { if (l >= 0) {
char *p, *ep;
np->full_name = PTRUNRELOC((char *) mem_start); np->full_name = PTRUNRELOC((char *) mem_start);
*(char *)(mem_start + l) = 0; *(char *)(mem_start + l) = 0;
/* Fixup an Apple bug where they have bogus \0 chars in the
* middle of the path in some properties
*/
for (p = (char *)mem_start, ep = p + l; p < ep; p++)
if ((*p) == '\0') {
memmove(p, p+1, ep - p);
ep--;
}
mem_start = ALIGNUL(mem_start + l + 1); mem_start = ALIGNUL(mem_start + l + 1);
} }
......
...@@ -47,14 +47,6 @@ static void remove_node_proc_entries(struct device_node *np) ...@@ -47,14 +47,6 @@ static void remove_node_proc_entries(struct device_node *np)
remove_proc_entry(pp->name, np->pde); remove_proc_entry(pp->name, np->pde);
pp = pp->next; pp = pp->next;
} }
/* Assuming that symlinks have the same parent directory as
* np->pde.
*/
if (np->name_link)
remove_proc_entry(np->name_link->name, parent->pde);
if (np->addr_link)
remove_proc_entry(np->addr_link->name, parent->pde);
if (np->pde) if (np->pde)
remove_proc_entry(np->pde->name, parent->pde); remove_proc_entry(np->pde->name, parent->pde);
} }
......
...@@ -1566,7 +1566,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1566,7 +1566,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
{ {
int l, align; int l, align;
phandle child; phandle child;
char *namep, *prev_name, *sstart; char *namep, *prev_name, *sstart, *p, *ep;
unsigned long soff; unsigned long soff;
unsigned char *valp; unsigned char *valp;
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
...@@ -1588,6 +1588,14 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1588,6 +1588,14 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
call_prom("package-to-path", 3, 1, node, namep, l); call_prom("package-to-path", 3, 1, node, namep, l);
} }
namep[l] = '\0'; namep[l] = '\0';
/* Fixup an Apple bug where they have bogus \0 chars in the
* middle of the path in some properties
*/
for (p = namep, ep = namep + l; p < ep; p++)
if (*p == '\0') {
memmove(p, p+1, ep - p);
ep--; l--;
}
*mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
} }
......
...@@ -325,9 +325,7 @@ int timer_interrupt(struct pt_regs * regs) ...@@ -325,9 +325,7 @@ int timer_interrupt(struct pt_regs * regs)
irq_enter(); irq_enter();
#ifndef CONFIG_PPC_ISERIES
profile_tick(CPU_PROFILING, regs); profile_tick(CPU_PROFILING, regs);
#endif
lpaca->lppaca.int_dword.fields.decr_int = 0; lpaca->lppaca.int_dword.fields.decr_int = 0;
......
...@@ -305,6 +305,7 @@ config HPET_TIMER ...@@ -305,6 +305,7 @@ config HPET_TIMER
config X86_PM_TIMER config X86_PM_TIMER
bool "PM timer" bool "PM timer"
depends on ACPI
default y default y
help help
Support the ACPI PM timer for time keeping. This is slow, Support the ACPI PM timer for time keeping. This is slow,
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <asm/desc.h> #include <asm/desc.h>
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/mach_apic.h> #include <asm/mach_apic.h>
#include <asm/acpi.h>
#define __apicdebuginit __init #define __apicdebuginit __init
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/io_apic.h> #include <asm/io_apic.h>
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/acpi.h>
/* Have we found an MP table */ /* Have we found an MP table */
int smp_found_config; int smp_found_config;
......
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#ifdef CONFIG_ACPI
#include <acpi/achware.h> /* for PM timer frequency */ #include <acpi/achware.h> /* for PM timer frequency */
#endif
#include <asm/8253pit.h> #include <asm/8253pit.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/vsyscall.h> #include <asm/vsyscall.h>
......
...@@ -46,6 +46,10 @@ config CPU_FREQ_STAT_DETAILS ...@@ -46,6 +46,10 @@ config CPU_FREQ_STAT_DETAILS
This will show detail CPU frequency translation table in sysfs file This will show detail CPU frequency translation table in sysfs file
system system
# Note that it is not currently possible to set the other governors (such as ondemand)
# as the default, since if they fail to initialise, cpufreq will be
# left in an undefined state.
choice choice
prompt "Default CPUFreq governor" prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
...@@ -115,4 +119,24 @@ config CPU_FREQ_GOV_ONDEMAND ...@@ -115,4 +119,24 @@ config CPU_FREQ_GOV_ONDEMAND
If in doubt, say N. If in doubt, say N.
config CPU_FREQ_GOV_CONSERVATIVE
tristate "'conservative' cpufreq governor"
depends on CPU_FREQ
help
'conservative' - this driver is rather similar to the 'ondemand'
governor both in its source code and its purpose, the difference is
its optimisation for better suitability in a battery powered
environment. The frequency is gracefully increased and decreased
rather than jumping to 100% when speed is required.
If you have a desktop machine then you should really be considering
the 'ondemand' governor instead, however if you are using a laptop,
PDA or even an AMD64 based computer (due to the unacceptable
step-by-step latency issues between the minimum and maximum frequency
transitions in the CPU) you will probably want to use this governor.
For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
endif # CPU_FREQ endif # CPU_FREQ
...@@ -8,6 +8,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o ...@@ -8,6 +8,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
# CPUfreq cross-arch helpers # CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
......
...@@ -258,7 +258,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) ...@@ -258,7 +258,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
(likely(cpufreq_cpu_data[freqs->cpu]->cur)) && (likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{ {
printk(KERN_WARNING "Warning: CPU frequency is %u, " dprintk(KERN_WARNING "Warning: CPU frequency is %u, "
"cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur); "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur);
freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
} }
...@@ -814,7 +814,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigne ...@@ -814,7 +814,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigne
{ {
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " dprintk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
"core thinks of %u, is %u kHz.\n", old_freq, new_freq); "core thinks of %u, is %u kHz.\n", old_freq, new_freq);
freqs.cpu = cpu; freqs.cpu = cpu;
...@@ -923,7 +923,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, u32 state) ...@@ -923,7 +923,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
printk(KERN_DEBUG "Warning: CPU frequency is %u, " dprintk(KERN_DEBUG "Warning: CPU frequency is %u, "
"cpufreq assumed %u kHz.\n", "cpufreq assumed %u kHz.\n",
cur_freq, cpu_policy->cur); cur_freq, cpu_policy->cur);
...@@ -1004,7 +1004,7 @@ static int cpufreq_resume(struct sys_device * sysdev) ...@@ -1004,7 +1004,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
printk(KERN_WARNING "Warning: CPU frequency" dprintk(KERN_WARNING "Warning: CPU frequency"
"is %u, cpufreq assumed %u kHz.\n", "is %u, cpufreq assumed %u kHz.\n",
cur_freq, cpu_policy->cur); cur_freq, cpu_policy->cur);
......
This diff is collapsed.
This diff is collapsed.
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/cputime.h>
static spinlock_t cpufreq_stats_lock; static spinlock_t cpufreq_stats_lock;
...@@ -29,20 +30,14 @@ static struct freq_attr _attr_##_name = {\ ...@@ -29,20 +30,14 @@ static struct freq_attr _attr_##_name = {\
.show = _show,\ .show = _show,\
}; };
static unsigned long
delta_time(unsigned long old, unsigned long new)
{
return (old > new) ? (old - new): (new + ~old + 1);
}
struct cpufreq_stats { struct cpufreq_stats {
unsigned int cpu; unsigned int cpu;
unsigned int total_trans; unsigned int total_trans;
unsigned long long last_time; unsigned long long last_time;
unsigned int max_state; unsigned int max_state;
unsigned int state_num; unsigned int state_num;
unsigned int last_index; unsigned int last_index;
unsigned long long *time_in_state; cputime64_t *time_in_state;
unsigned int *freq_table; unsigned int *freq_table;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
unsigned int *trans_table; unsigned int *trans_table;
...@@ -60,12 +55,16 @@ static int ...@@ -60,12 +55,16 @@ static int
cpufreq_stats_update (unsigned int cpu) cpufreq_stats_update (unsigned int cpu)
{ {
struct cpufreq_stats *stat; struct cpufreq_stats *stat;
unsigned long long cur_time;
cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock); spin_lock(&cpufreq_stats_lock);
stat = cpufreq_stats_table[cpu]; stat = cpufreq_stats_table[cpu];
if (stat->time_in_state) if (stat->time_in_state)
stat->time_in_state[stat->last_index] += stat->time_in_state[stat->last_index] =
delta_time(stat->last_time, jiffies); cputime64_add(stat->time_in_state[stat->last_index],
stat->last_time = jiffies; cputime_sub(cur_time, stat->last_time));
stat->last_time = cur_time;
spin_unlock(&cpufreq_stats_lock); spin_unlock(&cpufreq_stats_lock);
return 0; return 0;
} }
...@@ -90,8 +89,8 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf) ...@@ -90,8 +89,8 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf)
return 0; return 0;
cpufreq_stats_update(stat->cpu); cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) { for (i = 0; i < stat->state_num; i++) {
len += sprintf(buf + len, "%u %llu\n", len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
stat->freq_table[i], stat->time_in_state[i]); (unsigned long long)cputime64_to_clock_t(stat->time_in_state[i]));
} }
return len; return len;
} }
...@@ -107,16 +106,30 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) ...@@ -107,16 +106,30 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
if(!stat) if(!stat)
return 0; return 0;
cpufreq_stats_update(stat->cpu); cpufreq_stats_update(stat->cpu);
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
for (i = 0; i < stat->state_num; i++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
stat->freq_table[i]);
}
if (len >= PAGE_SIZE)
return len;
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
for (i = 0; i < stat->state_num; i++) { for (i = 0; i < stat->state_num; i++) {
if (len >= PAGE_SIZE) if (len >= PAGE_SIZE)
break; break;
len += snprintf(buf + len, PAGE_SIZE - len, "%9u:\t",
len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
stat->freq_table[i]); stat->freq_table[i]);
for (j = 0; j < stat->state_num; j++) { for (j = 0; j < stat->state_num; j++) {
if (len >= PAGE_SIZE) if (len >= PAGE_SIZE)
break; break;
len += snprintf(buf + len, PAGE_SIZE - len, "%u\t", len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
stat->trans_table[i*stat->max_state+j]); stat->trans_table[i*stat->max_state+j]);
} }
len += snprintf(buf + len, PAGE_SIZE - len, "\n"); len += snprintf(buf + len, PAGE_SIZE - len, "\n");
...@@ -197,7 +210,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, ...@@ -197,7 +210,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
count++; count++;
} }
alloc_size = count * sizeof(int) + count * sizeof(long long); alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
alloc_size += count * count * sizeof(int); alloc_size += count * count * sizeof(int);
...@@ -224,7 +237,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, ...@@ -224,7 +237,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
} }
stat->state_num = j; stat->state_num = j;
spin_lock(&cpufreq_stats_lock); spin_lock(&cpufreq_stats_lock);
stat->last_time = jiffies; stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur); stat->last_index = freq_table_get_index(stat, policy->cur);
spin_unlock(&cpufreq_stats_lock); spin_unlock(&cpufreq_stats_lock);
cpufreq_cpu_put(data); cpufreq_cpu_put(data);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/config.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/efi.h> #include <linux/efi.h>
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
* *
* Copyright (C) 2004 Patrick Mochel * Copyright (C) 2004 Patrick Mochel
* 2005 Rudolf Marek <r.marek@sh.cvut.cz>
* *
* The 1563 southbridge is deceptively similar to the 1533, with a * The 1563 southbridge is deceptively similar to the 1533, with a
* few notable exceptions. One of those happens to be the fact they * few notable exceptions. One of those happens to be the fact they
...@@ -57,10 +58,11 @@ ...@@ -57,10 +58,11 @@
#define HST_CNTL2_BLOCK 0x05 #define HST_CNTL2_BLOCK 0x05
#define HST_CNTL2_SIZEMASK 0x38
static unsigned short ali1563_smba; static unsigned short ali1563_smba;
static int ali1563_transaction(struct i2c_adapter * a) static int ali1563_transaction(struct i2c_adapter * a, int size)
{ {
u32 data; u32 data;
int timeout; int timeout;
...@@ -73,7 +75,7 @@ static int ali1563_transaction(struct i2c_adapter * a) ...@@ -73,7 +75,7 @@ static int ali1563_transaction(struct i2c_adapter * a)
data = inb_p(SMB_HST_STS); data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD) { if (data & HST_STS_BAD) {
dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); dev_err(&a->dev, "ali1563: Trying to reset busy device\n");
outb_p(data | HST_STS_BAD,SMB_HST_STS); outb_p(data | HST_STS_BAD,SMB_HST_STS);
data = inb_p(SMB_HST_STS); data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD) if (data & HST_STS_BAD)
...@@ -94,19 +96,31 @@ static int ali1563_transaction(struct i2c_adapter * a) ...@@ -94,19 +96,31 @@ static int ali1563_transaction(struct i2c_adapter * a)
if (timeout && !(data & HST_STS_BAD)) if (timeout && !(data & HST_STS_BAD))
return 0; return 0;
dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n",
timeout ? "Timeout " : "",
data & HST_STS_FAIL ? "Transaction Failed " : "",
data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
data & HST_STS_DEVERR ? "Device Error " : "",
!(data & HST_STS_DONE) ? "Transaction Never Finished " : "");
if (!(data & HST_STS_DONE)) if (!timeout) {
dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
/* Issue 'kill' to host controller */ /* Issue 'kill' to host controller */
outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
else data = inb_p(SMB_HST_STS);
/* Issue timeout to reset all devices on bus */ }
/* device error - no response, ignore the autodetection case */
if ((data & HST_STS_DEVERR) && (size != HST_CNTL2_QUICK)) {
dev_err(&a->dev, "Device error!\n");
}
/* bus collision */
if (data & HST_STS_BUSERR) {
dev_err(&a->dev, "Bus collision!\n");
/* Issue timeout, hoping it helps */
outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1);
}
if (data & HST_STS_FAIL) {
dev_err(&a->dev, "Cleaning fail after KILL!\n");
outb_p(0x0,SMB_HST_CNTL2);
}
return -1; return -1;
} }
...@@ -149,7 +163,7 @@ static int ali1563_block_start(struct i2c_adapter * a) ...@@ -149,7 +163,7 @@ static int ali1563_block_start(struct i2c_adapter * a)
if (timeout && !(data & HST_STS_BAD)) if (timeout && !(data & HST_STS_BAD))
return 0; return 0;
dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n",
timeout ? "Timeout " : "", timeout ? "Timeout " : "",
data & HST_STS_FAIL ? "Transaction Failed " : "", data & HST_STS_FAIL ? "Transaction Failed " : "",
data & HST_STS_BUSERR ? "No response or Bus Collision " : "", data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
...@@ -242,13 +256,15 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, ...@@ -242,13 +256,15 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
} }
outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
outb_p(inb_p(SMB_HST_CNTL2) | (size << 3), SMB_HST_CNTL2); outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2);
/* Write the command register */ /* Write the command register */
switch(size) { switch(size) {
case HST_CNTL2_BYTE: case HST_CNTL2_BYTE:
if (rw== I2C_SMBUS_WRITE) if (rw== I2C_SMBUS_WRITE)
outb_p(cmd, SMB_HST_CMD); /* Beware it uses DAT0 register and not CMD! */
outb_p(cmd, SMB_HST_DAT0);
break; break;
case HST_CNTL2_BYTE_DATA: case HST_CNTL2_BYTE_DATA:
outb_p(cmd, SMB_HST_CMD); outb_p(cmd, SMB_HST_CMD);
...@@ -268,7 +284,7 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, ...@@ -268,7 +284,7 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
goto Done; goto Done;
} }
if ((error = ali1563_transaction(a))) if ((error = ali1563_transaction(a, size)))
goto Done; goto Done;
if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
......
...@@ -72,6 +72,7 @@ static struct amd_ide_chip { ...@@ -72,6 +72,7 @@ static struct amd_ide_chip {
{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 },
{ 0 } { 0 }
}; };
...@@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { ...@@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"), /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"), /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
}; };
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
...@@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = { ...@@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
#endif #endif
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
{ 0, }, { 0, },
}; };
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
......
This diff is collapsed.
/* /*
* CompactPCI Hot Plug Driver PCI functions * CompactPCI Hot Plug Driver PCI functions
* *
* Copyright (C) 2002 by SOMA Networks, Inc. * Copyright (C) 2002,2005 by SOMA Networks, Inc.
* *
* All rights reserved. * All rights reserved.
* *
...@@ -38,10 +38,10 @@ extern int cpci_debug; ...@@ -38,10 +38,10 @@ extern int cpci_debug;
#define dbg(format, arg...) \ #define dbg(format, arg...) \
do { \ do { \
if(cpci_debug) \ if (cpci_debug) \
printk (KERN_DEBUG "%s: " format "\n", \ printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \ MY_NAME , ## arg); \
} while(0) } while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
...@@ -57,16 +57,15 @@ u8 cpci_get_attention_status(struct slot* slot) ...@@ -57,16 +57,15 @@ u8 cpci_get_attention_status(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
}
if(pci_bus_read_config_word(slot->bus, if (pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
}
return hs_csr & 0x0008 ? 1 : 0; return hs_csr & 0x0008 ? 1 : 0;
} }
...@@ -78,27 +77,22 @@ int cpci_set_attention_status(struct slot* slot, int status) ...@@ -78,27 +77,22 @@ int cpci_set_attention_status(struct slot* slot, int status)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
} if (status)
if(status) {
hs_csr |= HS_CSR_LOO; hs_csr |= HS_CSR_LOO;
} else { else
hs_csr &= ~HS_CSR_LOO; hs_csr &= ~HS_CSR_LOO;
} if (pci_bus_write_config_word(slot->bus,
if(pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr))
return 0; return 0;
}
return 1; return 1;
} }
...@@ -110,16 +104,13 @@ u16 cpci_get_hs_csr(struct slot* slot) ...@@ -110,16 +104,13 @@ u16 cpci_get_hs_csr(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0xFFFF; return 0xFFFF;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0xFFFF; return 0xFFFF;
}
return hs_csr; return hs_csr;
} }
...@@ -132,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot* slot) ...@@ -132,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
} if (hs_csr & HS_CSR_INS) {
if(hs_csr & HS_CSR_INS) {
/* Clear INS (by setting it) */ /* Clear INS (by setting it) */
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr))
ins = 0; ins = 0;
} else
ins = 1; ins = 1;
} }
return ins; return ins;
} }
...@@ -163,18 +152,15 @@ int cpci_check_ext(struct slot* slot) ...@@ -163,18 +152,15 @@ int cpci_check_ext(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
} if (hs_csr & HS_CSR_EXT)
if(hs_csr & HS_CSR_EXT) {
ext = 1; ext = 1;
}
return ext; return ext;
} }
...@@ -186,23 +172,20 @@ int cpci_clear_ext(struct slot* slot) ...@@ -186,23 +172,20 @@ int cpci_clear_ext(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return -ENODEV; return -ENODEV;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return -ENODEV; return -ENODEV;
} if (hs_csr & HS_CSR_EXT) {
if(hs_csr & HS_CSR_EXT) {
/* Clear EXT (by setting it) */ /* Clear EXT (by setting it) */
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr))
return -ENODEV; return -ENODEV;
}
} }
return 0; return 0;
} }
...@@ -215,18 +198,16 @@ int cpci_led_on(struct slot* slot) ...@@ -215,18 +198,16 @@ int cpci_led_on(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return -ENODEV; return -ENODEV;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return -ENODEV; return -ENODEV;
} if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
hs_csr |= HS_CSR_LOO; hs_csr |= HS_CSR_LOO;
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr)) {
...@@ -246,18 +227,16 @@ int cpci_led_off(struct slot* slot) ...@@ -246,18 +227,16 @@ int cpci_led_off(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return -ENODEV; return -ENODEV;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return -ENODEV; return -ENODEV;
} if (hs_csr & HS_CSR_LOO) {
if(hs_csr & HS_CSR_LOO) {
hs_csr &= ~HS_CSR_LOO; hs_csr &= ~HS_CSR_LOO;
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr)) {
...@@ -274,19 +253,6 @@ int cpci_led_off(struct slot* slot) ...@@ -274,19 +253,6 @@ int cpci_led_off(struct slot* slot)
* Device configuration functions * Device configuration functions
*/ */
static void cpci_enable_device(struct pci_dev *dev)
{
struct pci_bus *bus;
pci_enable_device(dev);
if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
bus = dev->subordinate;
list_for_each_entry(dev, &bus->devices, bus_list) {
cpci_enable_device(dev);
}
}
}
int cpci_configure_slot(struct slot* slot) int cpci_configure_slot(struct slot* slot)
{ {
unsigned char busnr; unsigned char busnr;
...@@ -294,14 +260,14 @@ int cpci_configure_slot(struct slot* slot) ...@@ -294,14 +260,14 @@ int cpci_configure_slot(struct slot* slot)
dbg("%s - enter", __FUNCTION__); dbg("%s - enter", __FUNCTION__);
if(slot->dev == NULL) { if (slot->dev == NULL) {
dbg("pci_dev null, finding %02x:%02x:%x", dbg("pci_dev null, finding %02x:%02x:%x",
slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
slot->dev = pci_find_slot(slot->bus->number, slot->devfn); slot->dev = pci_get_slot(slot->bus, slot->devfn);
} }
/* Still NULL? Well then scan for it! */ /* Still NULL? Well then scan for it! */
if(slot->dev == NULL) { if (slot->dev == NULL) {
int n; int n;
dbg("pci_dev still null"); dbg("pci_dev still null");
...@@ -311,10 +277,10 @@ int cpci_configure_slot(struct slot* slot) ...@@ -311,10 +277,10 @@ int cpci_configure_slot(struct slot* slot)
*/ */
n = pci_scan_slot(slot->bus, slot->devfn); n = pci_scan_slot(slot->bus, slot->devfn);
dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
if(n > 0) if (n > 0)
pci_bus_add_devices(slot->bus); pci_bus_add_devices(slot->bus);
slot->dev = pci_find_slot(slot->bus->number, slot->devfn); slot->dev = pci_get_slot(slot->bus, slot->devfn);
if(slot->dev == NULL) { if (slot->dev == NULL) {
err("Could not find PCI device for slot %02x", slot->number); err("Could not find PCI device for slot %02x", slot->number);
return 1; return 1;
} }
...@@ -329,8 +295,6 @@ int cpci_configure_slot(struct slot* slot) ...@@ -329,8 +295,6 @@ int cpci_configure_slot(struct slot* slot)
pci_bus_assign_resources(slot->dev->bus); pci_bus_assign_resources(slot->dev->bus);
cpci_enable_device(slot->dev);
dbg("%s - exit", __FUNCTION__); dbg("%s - exit", __FUNCTION__);
return 0; return 0;
} }
...@@ -341,15 +305,15 @@ int cpci_unconfigure_slot(struct slot* slot) ...@@ -341,15 +305,15 @@ int cpci_unconfigure_slot(struct slot* slot)
struct pci_dev *dev; struct pci_dev *dev;
dbg("%s - enter", __FUNCTION__); dbg("%s - enter", __FUNCTION__);
if(!slot->dev) { if (!slot->dev) {
err("No device for slot %02x\n", slot->number); err("No device for slot %02x\n", slot->number);
return -ENODEV; return -ENODEV;
} }
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
dev = pci_find_slot(slot->bus->number, dev = pci_get_slot(slot->bus,
PCI_DEVFN(PCI_SLOT(slot->devfn), i)); PCI_DEVFN(PCI_SLOT(slot->devfn), i));
if(dev) { if (dev) {
pci_remove_bus_device(dev); pci_remove_bus_device(dev);
slot->dev = NULL; slot->dev = NULL;
} }
......
...@@ -1626,7 +1626,7 @@ int shpchprm_set_hpp( ...@@ -1626,7 +1626,7 @@ int shpchprm_set_hpp(
pci_bus->number = func->bus; pci_bus->number = func->bus;
devfn = PCI_DEVFN(func->device, func->function); devfn = PCI_DEVFN(func->device, func->function);
ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
if (ab) { if (ab) {
if (ab->_hpp) { if (ab->_hpp) {
...@@ -1681,7 +1681,7 @@ void shpchprm_enable_card( ...@@ -1681,7 +1681,7 @@ void shpchprm_enable_card(
| PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA;
ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
if (ab) { if (ab) {
if (ab->_hpp) { if (ab->_hpp) {
if (ab->_hpp->enable_perr) { if (ab->_hpp->enable_perr) {
......
...@@ -124,3 +124,14 @@ config USB_SL811_HCD ...@@ -124,3 +124,14 @@ config USB_SL811_HCD
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called sl811-hcd. module will be called sl811-hcd.
config USB_SL811_CS
tristate "CF/PCMCIA support for SL811HS HCD"
depends on USB_SL811_HCD && PCMCIA
default N
help
Wraps a PCMCIA driver around the SL811HS HCD, supporting the RATOC
REX-CFU1U CF card (often used with PDAs). If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called "sl811_cs".
...@@ -7,4 +7,5 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o ...@@ -7,4 +7,5 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* SL811HS HCD (Host Controller Driver) for USB. * SL811HS HCD (Host Controller Driver) for USB.
* *
* Copyright (C) 2004 Psion Teklogix (for NetBook PRO) * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
* Copyright (C) 2004 David Brownell * Copyright (C) 2004-2005 David Brownell
* *
* Periodic scheduling is based on Roman's OHCI code * Periodic scheduling is based on Roman's OHCI code
* Copyright (C) 1999 Roman Weissgaerber * Copyright (C) 1999 Roman Weissgaerber
* *
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* For documentation, see the SL811HS spec and the "SL811HS Embedded Host" * For documentation, see the SL811HS spec and the "SL811HS Embedded Host"
* document (providing significant pieces missing from that spec); plus * document (providing significant pieces missing from that spec); plus
* the SL811S spec if you want peripheral side info. * the SL811S spec if you want peripheral side info.
*/ */
/* /*
* Status: Passed basic stress testing, works with hubs, mice, keyboards, * Status: Passed basic stress testing, works with hubs, mice, keyboards,
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
MODULE_DESCRIPTION("SL811HS USB Host Controller Driver"); MODULE_DESCRIPTION("SL811HS USB Host Controller Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define DRIVER_VERSION "15 Dec 2004" #define DRIVER_VERSION "19 May 2005"
#ifndef DEBUG #ifndef DEBUG
...@@ -121,6 +121,10 @@ static void port_power(struct sl811 *sl811, int is_on) ...@@ -121,6 +121,10 @@ static void port_power(struct sl811 *sl811, int is_on)
/* reset as thoroughly as we can */ /* reset as thoroughly as we can */
if (sl811->board && sl811->board->reset) if (sl811->board && sl811->board->reset)
sl811->board->reset(hcd->self.controller); sl811->board->reset(hcd->self.controller);
else {
sl811_write(sl811, SL11H_CTLREG1, SL11H_CTL1MASK_SE0);
mdelay(20);
}
sl811_write(sl811, SL11H_IRQ_ENABLE, 0); sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
...@@ -443,6 +447,7 @@ static void finish_request( ...@@ -443,6 +447,7 @@ static void finish_request(
spin_lock(&urb->lock); spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS) if (urb->status == -EINPROGRESS)
urb->status = status; urb->status = status;
urb->hcpriv = NULL;
spin_unlock(&urb->lock); spin_unlock(&urb->lock);
spin_unlock(&sl811->lock); spin_unlock(&sl811->lock);
...@@ -472,7 +477,7 @@ static void finish_request( ...@@ -472,7 +477,7 @@ static void finish_request(
if (*prev) if (*prev)
*prev = ep->next; *prev = ep->next;
sl811->load[i] -= ep->load; sl811->load[i] -= ep->load;
} }
ep->branch = PERIODIC_SIZE; ep->branch = PERIODIC_SIZE;
sl811->periodic_count--; sl811->periodic_count--;
sl811_to_hcd(sl811)->self.bandwidth_allocated sl811_to_hcd(sl811)->self.bandwidth_allocated
...@@ -661,9 +666,9 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -661,9 +666,9 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
#ifdef QUIRK2 #ifdef QUIRK2
/* this may no longer be necessary ... */ /* this may no longer be necessary ... */
if (irqstat == 0 && ret == IRQ_NONE) { if (irqstat == 0) {
irqstat = checkdone(sl811); irqstat = checkdone(sl811);
if (irqstat /* && irq != ~0 */ ) if (irqstat)
sl811->stat_lost++; sl811->stat_lost++;
} }
#endif #endif
...@@ -722,7 +727,8 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -722,7 +727,8 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
if (sl811->active_a) { if (sl811->active_a) {
sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
finish_request(sl811, sl811->active_a, finish_request(sl811, sl811->active_a,
container_of(sl811->active_a->hep->urb_list.next, container_of(sl811->active_a
->hep->urb_list.next,
struct urb, urb_list), struct urb, urb_list),
NULL, -ESHUTDOWN); NULL, -ESHUTDOWN);
sl811->active_a = NULL; sl811->active_a = NULL;
...@@ -731,7 +737,8 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -731,7 +737,8 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
if (sl811->active_b) { if (sl811->active_b) {
sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
finish_request(sl811, sl811->active_b, finish_request(sl811, sl811->active_b,
container_of(sl811->active_b->hep->urb_list.next, container_of(sl811->active_b
->hep->urb_list.next,
struct urb, urb_list), struct urb, urb_list),
NULL, -ESHUTDOWN); NULL, -ESHUTDOWN);
sl811->active_b = NULL; sl811->active_b = NULL;
...@@ -761,7 +768,7 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs) ...@@ -761,7 +768,7 @@ static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
goto retry; goto retry;
} }
if (sl811->periodic_count == 0 && list_empty(&sl811->async)) if (sl811->periodic_count == 0 && list_empty(&sl811->async))
sofirq_off(sl811); sofirq_off(sl811);
sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
...@@ -796,7 +803,7 @@ static int balance(struct sl811 *sl811, u16 period, u16 load) ...@@ -796,7 +803,7 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
} }
if (j < PERIODIC_SIZE) if (j < PERIODIC_SIZE)
continue; continue;
branch = i; branch = i;
} }
} }
return branch; return branch;
...@@ -890,6 +897,7 @@ static int sl811h_urb_enqueue( ...@@ -890,6 +897,7 @@ static int sl811h_urb_enqueue(
break; break;
} }
ep->hep = hep;
hep->hcpriv = ep; hep->hcpriv = ep;
} }
...@@ -961,15 +969,16 @@ static int sl811h_urb_enqueue( ...@@ -961,15 +969,16 @@ static int sl811h_urb_enqueue(
static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
{ {
struct sl811 *sl811 = hcd_to_sl811(hcd); struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_host_endpoint *hep = urb->hcpriv; struct usb_host_endpoint *hep;
unsigned long flags; unsigned long flags;
struct sl811h_ep *ep; struct sl811h_ep *ep;
int retval = 0; int retval = 0;
spin_lock_irqsave(&sl811->lock, flags);
hep = urb->hcpriv;
if (!hep) if (!hep)
return -EINVAL; goto fail;
spin_lock_irqsave(&sl811->lock, flags);
ep = hep->hcpriv; ep = hep->hcpriv;
if (ep) { if (ep) {
/* finish right away if this urb can't be active ... /* finish right away if this urb can't be active ...
...@@ -1017,6 +1026,7 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ...@@ -1017,6 +1026,7 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
VDBG("dequeue, urb %p active %s; wait4irq\n", urb, VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B"); (sl811->active_a == ep) ? "A" : "B");
} else } else
fail:
retval = -EINVAL; retval = -EINVAL;
spin_unlock_irqrestore(&sl811->lock, flags); spin_unlock_irqrestore(&sl811->lock, flags);
return retval; return retval;
...@@ -1576,6 +1586,9 @@ sl811h_start(struct usb_hcd *hcd) ...@@ -1576,6 +1586,9 @@ sl811h_start(struct usb_hcd *hcd)
if (sl811->board && sl811->board->power) if (sl811->board && sl811->board->power)
hub_set_power_budget(udev, sl811->board->power * 2); hub_set_power_budget(udev, sl811->board->power * 2);
/* enable power and interupts */
port_power(sl811, 1);
return 0; return 0;
} }
...@@ -1618,7 +1631,7 @@ static struct hc_driver sl811h_hc_driver = { ...@@ -1618,7 +1631,7 @@ static struct hc_driver sl811h_hc_driver = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int __init_or_module static int __devexit
sl811h_remove(struct device *dev) sl811h_remove(struct device *dev)
{ {
struct usb_hcd *hcd = dev_get_drvdata(dev); struct usb_hcd *hcd = dev_get_drvdata(dev);
...@@ -1631,21 +1644,20 @@ sl811h_remove(struct device *dev) ...@@ -1631,21 +1644,20 @@ sl811h_remove(struct device *dev)
remove_debug_file(sl811); remove_debug_file(sl811);
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
iounmap(sl811->data_reg); /* some platforms may use IORESOURCE_IO */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
release_mem_region(res->start, 1); if (res)
iounmap(sl811->data_reg);
iounmap(sl811->addr_reg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, 1); if (res)
iounmap(sl811->addr_reg);
usb_put_hcd(hcd); usb_put_hcd(hcd);
return 0; return 0;
} }
#define resource_len(r) (((r)->end - (r)->start) + 1) static int __devinit
static int __init
sl811h_probe(struct device *dev) sl811h_probe(struct device *dev)
{ {
struct usb_hcd *hcd; struct usb_hcd *hcd;
...@@ -1656,7 +1668,7 @@ sl811h_probe(struct device *dev) ...@@ -1656,7 +1668,7 @@ sl811h_probe(struct device *dev)
void __iomem *addr_reg; void __iomem *addr_reg;
void __iomem *data_reg; void __iomem *data_reg;
int retval; int retval;
u8 tmp; u8 tmp, ioaddr = 0;
/* basic sanity checks first. board-specific init logic should /* basic sanity checks first. board-specific init logic should
* have initialized these three resources and probably board * have initialized these three resources and probably board
...@@ -1664,13 +1676,8 @@ sl811h_probe(struct device *dev) ...@@ -1664,13 +1676,8 @@ sl811h_probe(struct device *dev)
* minimal sanity checking. * minimal sanity checking.
*/ */
pdev = container_of(dev, struct platform_device, dev); pdev = container_of(dev, struct platform_device, dev);
if (pdev->num_resources < 3)
return -ENODEV;
addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (!addr || !data || irq < 0) if (pdev->num_resources < 3 || irq < 0)
return -ENODEV; return -ENODEV;
/* refuse to confuse usbcore */ /* refuse to confuse usbcore */
...@@ -1679,24 +1686,31 @@ sl811h_probe(struct device *dev) ...@@ -1679,24 +1686,31 @@ sl811h_probe(struct device *dev)
return -EINVAL; return -EINVAL;
} }
if (!request_mem_region(addr->start, 1, hcd_name)) { /* the chip may be wired for either kind of addressing */
retval = -EBUSY; addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
goto err1; data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
} retval = -EBUSY;
addr_reg = ioremap(addr->start, resource_len(addr)); if (!addr || !data) {
if (addr_reg == NULL) { addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
retval = -ENOMEM; data = platform_get_resource(pdev, IORESOURCE_IO, 1);
goto err2; if (!addr || !data)
} return -ENODEV;
ioaddr = 1;
addr_reg = (void __iomem *) addr->start;
data_reg = (void __iomem *) data->start;
} else {
addr_reg = ioremap(addr->start, 1);
if (addr_reg == NULL) {
retval = -ENOMEM;
goto err2;
}
if (!request_mem_region(data->start, 1, hcd_name)) { data_reg = ioremap(data->start, 1);
retval = -EBUSY; if (data_reg == NULL) {
goto err3; retval = -ENOMEM;
} goto err4;
data_reg = ioremap(data->start, resource_len(addr)); }
if (data_reg == NULL) {
retval = -ENOMEM;
goto err4;
} }
/* allocate and initialize hcd */ /* allocate and initialize hcd */
...@@ -1737,12 +1751,14 @@ sl811h_probe(struct device *dev) ...@@ -1737,12 +1751,14 @@ sl811h_probe(struct device *dev)
goto err6; goto err6;
} }
/* sl811s would need a different handler for this irq */ /* The chip's IRQ is level triggered, active high. A requirement
#ifdef CONFIG_ARM * for platform device setup is to cope with things like signal
/* Cypress docs say the IRQ is IRQT_HIGH ... */ * inverters (e.g. CF is active low) or working only with edge
set_irq_type(irq, IRQT_RISING); * triggers (e.g. most ARM CPUs). Initial driver stress testing
#endif * was on a system with single edge triggering, so most sorts of
retval = usb_add_hcd(hcd, irq, SA_INTERRUPT); * triggering arrangement should work.
*/
retval = usb_add_hcd(hcd, irq, SA_INTERRUPT | SA_SHIRQ);
if (retval != 0) if (retval != 0)
goto err6; goto err6;
...@@ -1752,14 +1768,12 @@ sl811h_probe(struct device *dev) ...@@ -1752,14 +1768,12 @@ sl811h_probe(struct device *dev)
err6: err6:
usb_put_hcd(hcd); usb_put_hcd(hcd);
err5: err5:
iounmap(data_reg); if (!ioaddr)
iounmap(data_reg);
err4: err4:
release_mem_region(data->start, 1); if (!ioaddr)
err3: iounmap(addr_reg);
iounmap(addr_reg);
err2: err2:
release_mem_region(addr->start, 1);
err1:
DBG("init error, %d\n", retval); DBG("init error, %d\n", retval);
return retval; return retval;
} }
...@@ -1767,7 +1781,7 @@ sl811h_probe(struct device *dev) ...@@ -1767,7 +1781,7 @@ sl811h_probe(struct device *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* for this device there's no useful distinction between the controller /* for this device there's no useful distinction between the controller
* and its root hub, except that the root hub only gets direct PM calls * and its root hub, except that the root hub only gets direct PM calls
* when CONFIG_USB_SUSPEND is enabled. * when CONFIG_USB_SUSPEND is enabled.
*/ */
...@@ -1821,20 +1835,22 @@ sl811h_resume(struct device *dev, u32 phase) ...@@ -1821,20 +1835,22 @@ sl811h_resume(struct device *dev, u32 phase)
#endif #endif
static struct device_driver sl811h_driver = { /* this driver is exported so sl811_cs can depend on it */
struct device_driver sl811h_driver = {
.name = (char *) hcd_name, .name = (char *) hcd_name,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = sl811h_probe, .probe = sl811h_probe,
.remove = sl811h_remove, .remove = __devexit_p(sl811h_remove),
.suspend = sl811h_suspend, .suspend = sl811h_suspend,
.resume = sl811h_resume, .resume = sl811h_resume,
}; };
EXPORT_SYMBOL(sl811h_driver);
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int __init sl811h_init(void) static int __init sl811h_init(void)
{ {
if (usb_disabled()) if (usb_disabled())
return -ENODEV; return -ENODEV;
...@@ -1844,8 +1860,8 @@ static int __init sl811h_init(void) ...@@ -1844,8 +1860,8 @@ static int __init sl811h_init(void)
} }
module_init(sl811h_init); module_init(sl811h_init);
static void __exit sl811h_cleanup(void) static void __exit sl811h_cleanup(void)
{ {
driver_unregister(&sl811h_driver); driver_unregister(&sl811h_driver);
} }
module_exit(sl811h_cleanup); module_exit(sl811h_cleanup);
This diff is collapsed.
...@@ -364,6 +364,7 @@ static struct usb_device_id id_table_8U232AM [] = { ...@@ -364,6 +364,7 @@ static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) },
{ USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) }, { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) }, { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) },
...@@ -475,6 +476,7 @@ static struct usb_device_id id_table_FT232BM [] = { ...@@ -475,6 +476,7 @@ static struct usb_device_id id_table_FT232BM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
...@@ -618,6 +620,7 @@ static struct usb_device_id id_table_combined [] = { ...@@ -618,6 +620,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
{ USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
......
...@@ -144,6 +144,8 @@ ...@@ -144,6 +144,8 @@
/* ELV USB Module UO100 (PID sent by Stefan Frings) */ /* ELV USB Module UO100 (PID sent by Stefan Frings) */
#define FTDI_ELV_UO100_PID 0xFB58 /* Product Id */ #define FTDI_ELV_UO100_PID 0xFB58 /* Product Id */
/* ELV USB Module UM100 (PID sent by Arnim Laeuger) */
#define FTDI_ELV_UM100_PID 0xFB5A /* Product Id */
/* /*
* Definitions for ID TECH (www.idt-net.com) devices * Definitions for ID TECH (www.idt-net.com) devices
......
...@@ -1297,13 +1297,6 @@ static int __init usb_serial_init(void) ...@@ -1297,13 +1297,6 @@ static int __init usb_serial_init(void)
goto exit_bus; goto exit_bus;
} }
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0) {
err("%s - registering generic driver failed", __FUNCTION__);
goto exit_generic;
}
usb_serial_tty_driver->owner = THIS_MODULE; usb_serial_tty_driver->owner = THIS_MODULE;
usb_serial_tty_driver->driver_name = "usbserial"; usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->devfs_name = "usb/tts/"; usb_serial_tty_driver->devfs_name = "usb/tts/";
...@@ -1329,17 +1322,24 @@ static int __init usb_serial_init(void) ...@@ -1329,17 +1322,24 @@ static int __init usb_serial_init(void)
goto exit_tty; goto exit_tty;
} }
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0) {
err("%s - registering generic driver failed", __FUNCTION__);
goto exit_generic;
}
info(DRIVER_DESC " " DRIVER_VERSION); info(DRIVER_DESC " " DRIVER_VERSION);
return result; return result;
exit_generic:
usb_deregister(&usb_serial_driver);
exit_tty: exit_tty:
tty_unregister_driver(usb_serial_tty_driver); tty_unregister_driver(usb_serial_tty_driver);
exit_reg_driver: exit_reg_driver:
usb_serial_generic_deregister();
exit_generic:
bus_unregister(&usb_serial_bus_type); bus_unregister(&usb_serial_bus_type);
exit_bus: exit_bus:
......
...@@ -12,15 +12,8 @@ ...@@ -12,15 +12,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#ifndef HAVE_ARCH_DEVTREE_FIXUPS #ifndef HAVE_ARCH_DEVTREE_FIXUPS
static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de) static inline void set_node_proc_entry(struct device_node *np,
{ struct proc_dir_entry *de)
}
static void inline set_node_name_link(struct device_node *np, struct proc_dir_entry *de)
{
}
static void inline set_node_addr_link(struct device_node *np, struct proc_dir_entry *de)
{ {
} }
#endif #endif
...@@ -58,89 +51,67 @@ static int property_read_proc(char *page, char **start, off_t off, ...@@ -58,89 +51,67 @@ static int property_read_proc(char *page, char **start, off_t off,
/* /*
* Process a node, adding entries for its children and its properties. * Process a node, adding entries for its children and its properties.
*/ */
void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *de) void proc_device_tree_add_node(struct device_node *np,
struct proc_dir_entry *de)
{ {
struct property *pp; struct property *pp;
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
struct device_node *child, *sib; struct device_node *child;
const char *p, *at; struct proc_dir_entry *list = NULL, **lastp;
int l; const char *p;
struct proc_dir_entry *list, **lastp, *al;
set_node_proc_entry(np, de); set_node_proc_entry(np, de);
lastp = &list; lastp = &list;
for (pp = np->properties; pp != 0; pp = pp->next) { for (child = NULL; (child = of_get_next_child(np, child));) {
/*
* Unfortunately proc_register puts each new entry
* at the beginning of the list. So we rearrange them.
*/
ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ?
S_IRUGO : S_IRUSR, de, property_read_proc, pp);
if (ent == 0)
break;
if (!strncmp(pp->name, "security-", 9))
ent->size = 0; /* don't leak number of password chars */
else
ent->size = pp->length;
*lastp = ent;
lastp = &ent->next;
}
child = NULL;
while ((child = of_get_next_child(np, child))) {
p = strrchr(child->full_name, '/'); p = strrchr(child->full_name, '/');
if (!p) if (!p)
p = child->full_name; p = child->full_name;
else else
++p; ++p;
/* chop off '@0' if the name ends with that */
l = strlen(p);
if (l > 2 && p[l-2] == '@' && p[l-1] == '0')
l -= 2;
ent = proc_mkdir(p, de); ent = proc_mkdir(p, de);
if (ent == 0) if (ent == 0)
break; break;
*lastp = ent; *lastp = ent;
ent->next = NULL;
lastp = &ent->next; lastp = &ent->next;
proc_device_tree_add_node(child, ent); proc_device_tree_add_node(child, ent);
}
/* of_node_put(child);
* If we left the address part on the name, consider for (pp = np->properties; pp != 0; pp = pp->next) {
* adding symlinks from the name and address parts.
*/
if (p[l] != 0 || (at = strchr(p, '@')) == 0)
continue;
/* /*
* If this is the first node with a given name property, * Yet another Apple device-tree bogosity: on some machines,
* add a symlink with the name property as its name. * they have properties & nodes with the same name. Those
* properties are quite unimportant for us though, thus we
* simply "skip" them here, but we do have to check.
*/ */
sib = NULL; for (ent = list; ent != NULL; ent = ent->next)
while ((sib = of_get_next_child(np, sib)) && sib != child) if (!strcmp(ent->name, pp->name))
if (sib->name && strcmp(sib->name, child->name) == 0)
break;
if (sib == child && strncmp(p, child->name, l) != 0) {
al = proc_symlink(child->name, de, ent->name);
if (al == 0) {
of_node_put(sib);
break; break;
} if (ent != NULL) {
set_node_name_link(child, al); printk(KERN_WARNING "device-tree: property \"%s\" name"
*lastp = al; " conflicts with node in %s\n", pp->name,
lastp = &al->next; np->full_name);
continue;
} }
of_node_put(sib);
/* /*
* Add another directory with the @address part as its name. * Unfortunately proc_register puts each new entry
* at the beginning of the list. So we rearrange them.
*/ */
al = proc_symlink(at, de, ent->name); ent = create_proc_read_entry(pp->name,
if (al == 0) strncmp(pp->name, "security-", 9)
? S_IRUGO : S_IRUSR, de,
property_read_proc, pp);
if (ent == 0)
break; break;
set_node_addr_link(child, al); if (!strncmp(pp->name, "security-", 9))
*lastp = al; ent->size = 0; /* don't leak number of password chars */
lastp = &al->next; else
ent->size = pp->length;
ent->next = NULL;
*lastp = ent;
lastp = &ent->next;
} }
of_node_put(child);
*lastp = NULL;
de->subdir = list; de->subdir = list;
} }
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#endif #endif
/* How many days come before each month (0-12). */ /* How many days come before each month (0-12). */
const unsigned short int __mon_yday[2][13] = static const unsigned short int __mon_yday[2][13] =
{ {
/* Normal years. */ /* Normal years. */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
......
...@@ -53,6 +53,7 @@ extern struct init_timer_opts timer_cyclone_init; ...@@ -53,6 +53,7 @@ extern struct init_timer_opts timer_cyclone_init;
extern unsigned long calibrate_tsc(void); extern unsigned long calibrate_tsc(void);
extern void init_cpu_khz(void); extern void init_cpu_khz(void);
extern int recalibrate_cpu_khz(void);
#ifdef CONFIG_HPET_TIMER #ifdef CONFIG_HPET_TIMER
extern struct init_timer_opts timer_hpet_init; extern struct init_timer_opts timer_hpet_init;
extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr); extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
......
...@@ -147,9 +147,7 @@ struct device_node { ...@@ -147,9 +147,7 @@ struct device_node {
struct device_node *sibling; struct device_node *sibling;
struct device_node *next; /* next device of same type */ struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */ struct device_node *allnext; /* next in list of all nodes */
struct proc_dir_entry *pde; /* this node's proc directory */ struct proc_dir_entry *pde; /* this node's proc directory */
struct proc_dir_entry *name_link; /* name symlink */
struct proc_dir_entry *addr_link; /* addr symlink */
struct kref kref; struct kref kref;
unsigned long _flags; unsigned long _flags;
}; };
...@@ -174,15 +172,6 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e ...@@ -174,15 +172,6 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e
dn->pde = de; dn->pde = de;
} }
static void inline set_node_name_link(struct device_node *dn, struct proc_dir_entry *de)
{
dn->name_link = de;
}
static void inline set_node_addr_link(struct device_node *dn, struct proc_dir_entry *de)
{
dn->addr_link = de;
}
/* OBSOLETE: Old stlye node lookup */ /* OBSOLETE: Old stlye node lookup */
extern struct device_node *find_devices(const char *name); extern struct device_node *find_devices(const char *name);
......
...@@ -49,7 +49,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); ...@@ -49,7 +49,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
/* Frequency values here are CPU kHz so that hardware which doesn't run /* Frequency values here are CPU kHz so that hardware which doesn't run
* with some frequencies can complain without having to guess what per * with some frequencies can complain without having to guess what per
* cent / per mille means. * cent / per mille means.
* Maximum transition latency is in microseconds - if it's unknown, * Maximum transition latency is in nanoseconds - if it's unknown,
* CPUFREQ_ETERNAL shall be used. * CPUFREQ_ETERNAL shall be used.
*/ */
......
...@@ -1230,6 +1230,12 @@ ...@@ -1230,6 +1230,12 @@
#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258
#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259
#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B #define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267
#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268
#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269
#define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO 0x026B
#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280
#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281
#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282
......
...@@ -1758,6 +1758,7 @@ sys_init_module(void __user *umod, ...@@ -1758,6 +1758,7 @@ sys_init_module(void __user *umod,
const char __user *uargs) const char __user *uargs)
{ {
struct module *mod; struct module *mod;
mm_segment_t old_fs = get_fs();
int ret = 0; int ret = 0;
/* Must have permission */ /* Must have permission */
...@@ -1775,6 +1776,9 @@ sys_init_module(void __user *umod, ...@@ -1775,6 +1776,9 @@ sys_init_module(void __user *umod,
return PTR_ERR(mod); return PTR_ERR(mod);
} }
/* flush the icache in correct context */
set_fs(KERNEL_DS);
/* Flush the instruction cache, since we've played with text */ /* Flush the instruction cache, since we've played with text */
if (mod->module_init) if (mod->module_init)
flush_icache_range((unsigned long)mod->module_init, flush_icache_range((unsigned long)mod->module_init,
...@@ -1783,6 +1787,8 @@ sys_init_module(void __user *umod, ...@@ -1783,6 +1787,8 @@ sys_init_module(void __user *umod,
flush_icache_range((unsigned long)mod->module_core, flush_icache_range((unsigned long)mod->module_core,
(unsigned long)mod->module_core + mod->core_size); (unsigned long)mod->module_core + mod->core_size);
set_fs(old_fs);
/* Now sew it into the lists. They won't access us, since /* Now sew it into the lists. They won't access us, since
strong_try_module_get() will fail. */ strong_try_module_get() will fail. */
stop_machine_run(__link_module, mod, NR_CPUS); stop_machine_run(__link_module, mod, NR_CPUS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment