aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
author <jgarzik@pretzel.yyz.us>2005-06-02 18:43:09 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-06-02 18:43:09 -0400
commitd7aaf48128ec7fcefcee92ea22833afc1a80e268 (patch)
tree16ff78f6be6a5519944bb7bfc6034dfbd71ae97f /drivers
parentdecc6d0b68f27bbb8a0357fccf41936a3c196b03 (diff)
parent1e86d1c648508fd50e6c9960576b87906a7906ad (diff)
Automatic merge of /spare/repo/linux-2.6/.git branch HEAD
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cdrom/viocd.c14
-rw-r--r--drivers/cpufreq/Kconfig24
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/cpufreq.c8
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c586
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c180
-rw-r--r--drivers/cpufreq/cpufreq_stats.c47
-rw-r--r--drivers/firmware/pcdp.c1
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c46
-rw-r--r--drivers/ide/ide-cd.c2
-rw-r--r--drivers/ide/pci/amd74xx.c3
-rw-r--r--drivers/input/gameport/Kconfig20
-rw-r--r--drivers/input/joydev.c2
-rw-r--r--drivers/input/keyboard/atkbd.c6
-rw-r--r--drivers/input/mouse/psmouse-base.c7
-rw-r--r--drivers/input/mouse/synaptics.c39
-rw-r--r--drivers/input/mousedev.c15
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h32
-rw-r--r--drivers/input/serio/i8042.c50
-rw-r--r--drivers/input/touchscreen/gunze.c3
-rw-r--r--drivers/macintosh/via-pmu.c8
-rw-r--r--drivers/media/dvb/bt8xx/dst.c122
-rw-r--r--drivers/net/tg3.c571
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c302
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c144
-rw-r--r--drivers/pci/hotplug/shpchprm_acpi.c4
-rw-r--r--drivers/scsi/ahci.c3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c2
-rw-r--r--drivers/scsi/ata_piix.c2
-rw-r--r--drivers/scsi/libata-core.c15
-rw-r--r--drivers/scsi/libata.h2
-rw-r--r--drivers/scsi/sata_nv.c2
-rw-r--r--drivers/scsi/sata_promise.c1
-rw-r--r--drivers/scsi/sata_qstor.c2
-rw-r--r--drivers/scsi/sata_sil.c1
-rw-r--r--drivers/scsi/sata_sis.c1
-rw-r--r--drivers/scsi/sata_svw.c1
-rw-r--r--drivers/scsi/sata_sx4.c2
-rw-r--r--drivers/scsi/sata_uli.c1
-rw-r--r--drivers/scsi/sata_via.c1
-rw-r--r--drivers/scsi/sata_vsc.c2
-rw-r--r--drivers/usb/host/Kconfig11
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/sl811-hcd.c146
-rw-r--r--drivers/usb/host/sl811_cs.c442
-rw-r--r--drivers/usb/media/pwc/pwc-ctrl.c2
-rw-r--r--drivers/usb/media/pwc/pwc-uncompress.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.h2
-rw-r--r--drivers/usb/serial/usb-serial.c20
-rw-r--r--drivers/video/intelfb/intelfbdrv.c22
51 files changed, 2274 insertions, 652 deletions
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index fcca26c89bb..38dd9ffbe8b 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -488,6 +488,20 @@ static int viocd_packet(struct cdrom_device_info *cdi,
& (CDC_DVD_RAM | CDC_RAM)) != 0;
}
break;
+ case GPCMD_GET_CONFIGURATION:
+ if (cgc->cmd[3] == CDF_RWRT) {
+ struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header));
+
+ if ((buflen >=
+ (sizeof(struct feature_header) + sizeof(*rfd))) &&
+ (cdi->ops->capability & ~cdi->mask
+ & (CDC_DVD_RAM | CDC_RAM))) {
+ rfd->feature_code = cpu_to_be16(CDF_RWRT);
+ rfd->curr = 1;
+ ret = 0;
+ }
+ }
+ break;
default:
if (cgc->sense) {
/* indicate Unknown code */
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 95882bb1950..60c9be99c6d 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -46,6 +46,10 @@ config CPU_FREQ_STAT_DETAILS
This will show detail CPU frequency translation table in sysfs file
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
prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -115,4 +119,24 @@ config CPU_FREQ_GOV_ONDEMAND
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
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 67b16e5a41a..71fc3b4173f 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -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_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
+obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8e561313d09..03b5fb2ddcf 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -258,7 +258,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
(likely(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);
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
{
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);
freqs.cpu = cpu;
@@ -923,7 +923,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
struct cpufreq_freqs freqs;
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",
cur_freq, cpu_policy->cur);
@@ -1004,7 +1004,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
struct cpufreq_freqs freqs;
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",
cur_freq, cpu_policy->cur);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
new file mode 100644
index 00000000000..e1df376e709
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -0,0 +1,586 @@
+/*
+ * drivers/cpufreq/cpufreq_conservative.c
+ *
+ * Copyright (C) 2001 Russell King
+ * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
+ * Jun Nakajima <jun.nakajima@intel.com>
+ * (C) 2004 Alexander Clouter <alex-kernel@digriz.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+#include <linux/cpufreq.h>
+#include <linux/sysctl.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sysfs.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/kernel_stat.h>
+#include <linux/percpu.h>
+
+/*
+ * dbs is used in this file as a shortform for demandbased switching
+ * It helps to keep variable names smaller, simpler
+ */
+
+#define DEF_FREQUENCY_UP_THRESHOLD (80)
+#define MIN_FREQUENCY_UP_THRESHOLD (0)
+#define MAX_FREQUENCY_UP_THRESHOLD (100)
+
+#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
+#define MIN_FREQUENCY_DOWN_THRESHOLD (0)
+#define MAX_FREQUENCY_DOWN_THRESHOLD (100)
+
+/*
+ * The polling frequency of this governor depends on the capability of
+ * the processor. Default polling frequency is 1000 times the transition
+ * latency of the processor. The governor will work on any processor with
+ * transition latency <= 10mS, using appropriate sampling
+ * rate.
+ * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
+ * this governor will not work.
+ * All times here are in uS.
+ */
+static unsigned int def_sampling_rate;
+#define MIN_SAMPLING_RATE (def_sampling_rate / 2)
+#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
+#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (100000)
+#define DEF_SAMPLING_DOWN_FACTOR (5)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+
+static void do_dbs_timer(void *data);
+
+struct cpu_dbs_info_s {
+ struct cpufreq_policy *cur_policy;
+ unsigned int prev_cpu_idle_up;
+ unsigned int prev_cpu_idle_down;
+ unsigned int enable;
+};
+static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
+
+static unsigned int dbs_enable; /* number of CPUs using this policy */
+
+static DECLARE_MUTEX (dbs_sem);
+static DECLARE_WORK (dbs_work, do_dbs_timer, NULL);
+
+struct dbs_tuners {
+ unsigned int sampling_rate;
+ unsigned int sampling_down_factor;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+ unsigned int ignore_nice;
+ unsigned int freq_step;
+};
+
+static struct dbs_tuners dbs_tuners_ins = {
+ .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+ .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
+ .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
+};
+
+static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+{
+ return kstat_cpu(cpu).cpustat.idle +
+ kstat_cpu(cpu).cpustat.iowait +
+ ( !dbs_tuners_ins.ignore_nice ?
+ kstat_cpu(cpu).cpustat.nice :
+ 0);
+}
+
+/************************** sysfs interface ************************/
+static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf (buf, "%u\n", MAX_SAMPLING_RATE);
+}
+
+static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
+{
+ return sprintf (buf, "%u\n", MIN_SAMPLING_RATE);
+}
+
+#define define_one_ro(_name) \
+static struct freq_attr _name = \
+__ATTR(_name, 0444, show_##_name, NULL)
+
+define_one_ro(sampling_rate_max);
+define_one_ro(sampling_rate_min);
+
+/* cpufreq_conservative Governor Tunables */
+#define show_one(file_name, object) \
+static ssize_t show_##file_name \
+(struct cpufreq_policy *unused, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", dbs_tuners_ins.object); \
+}
+show_one(sampling_rate, sampling_rate);
+show_one(sampling_down_factor, sampling_down_factor);
+show_one(up_threshold, up_threshold);
+show_one(down_threshold, down_threshold);
+show_one(ignore_nice, ignore_nice);
+show_one(freq_step, freq_step);
+
+static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+ if (ret != 1 )
+ return -EINVAL;
+
+ down(&dbs_sem);
+ dbs_tuners_ins.sampling_down_factor = input;
+ up(&dbs_sem);
+
+ return count;
+}
+
+static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+
+ down(&dbs_sem);
+ if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
+ up(&dbs_sem);
+ return -EINVAL;
+ }
+
+ dbs_tuners_ins.sampling_rate = input;
+ up(&dbs_sem);
+
+ return count;
+}
+
+static ssize_t store_up_threshold(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+
+ down(&dbs_sem);
+ if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
+ input < MIN_FREQUENCY_UP_THRESHOLD ||
+ input <= dbs_tuners_ins.down_threshold) {
+ up(&dbs_sem);
+ return -EINVAL;
+ }
+
+ dbs_tuners_ins.up_threshold = input;
+ up(&dbs_sem);
+
+ return count;
+}
+
+static ssize_t store_down_threshold(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf (buf, "%u", &input);
+
+ down(&dbs_sem);
+ if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD ||
+ input < MIN_FREQUENCY_DOWN_THRESHOLD ||
+ input >= dbs_tuners_ins.up_threshold) {
+ up(&dbs_sem);
+ return -EINVAL;
+ }
+
+ dbs_tuners_ins.down_threshold = input;
+ up(&dbs_sem);
+
+ return count;
+}
+
+static ssize_t store_ignore_nice(struct cpufreq_policy *policy,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ unsigned int j;
+
+ ret = sscanf (buf, "%u", &input);
+ if ( ret != 1 )
+ return -EINVAL;
+
+ if ( input > 1 )
+ input = 1;
+
+ down(&dbs_sem);
+ if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
+ up(&dbs_sem);
+ return count;
+ }
+ dbs_tuners_ins.ignore_nice = input;
+
+ /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+ for_each_online_cpu(j) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+ }
+ up(&dbs_sem);
+
+ return count;
+}
+
+static ssize_t store_freq_step(struct cpufreq_policy *policy,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ ret = sscanf (buf, "%u", &input);
+
+ if ( ret != 1 )
+ return -EINVAL;
+
+ if ( input > 100 )
+ input = 100;
+
+ /* no need to test here if freq_step is zero as the user might actually
+ * want this, they would be crazy though :) */
+ down(&dbs_sem);
+ dbs_tuners_ins.freq_step = input;
+ up(&dbs_sem);
+
+ return count;
+}
+
+#define define_one_rw(_name) \
+static struct freq_attr _name = \
+__ATTR(_name, 0644, show_##_name, store_##_name)
+
+define_one_rw(sampling_rate);
+define_one_rw(sampling_down_factor);
+define_one_rw(up_threshold);
+define_one_rw(down_threshold);
+define_one_rw(ignore_nice);
+define_one_rw(freq_step);
+
+static struct attribute * dbs_attributes[] = {
+ &sampling_rate_max.attr,
+ &sampling_rate_min.attr,
+ &sampling_rate.attr,
+ &sampling_down_factor.attr,
+ &up_threshold.attr,
+ &down_threshold.attr,
+ &ignore_nice.attr,
+ &freq_step.attr,
+ NULL
+};
+
+static struct attribute_group dbs_attr_group = {
+ .attrs = dbs_attributes,
+ .name = "conservative",
+};
+
+/************************** sysfs end ************************/
+
+static void dbs_check_cpu(int cpu)
+{
+ unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
+ unsigned int freq_step;
+ unsigned int freq_down_sampling_rate;
+ static int down_skip[NR_CPUS];
+ static int requested_freq[NR_CPUS];
+ static unsigned short init_flag = 0;
+ struct cpu_dbs_info_s *this_dbs_info;
+ struct cpu_dbs_info_s *dbs_info;
+
+ struct cpufreq_policy *policy;
+ unsigned int j;
+
+ this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ if (!this_dbs_info->enable)
+ return;
+
+ policy = this_dbs_info->cur_policy;
+
+ if ( init_flag == 0 ) {
+ for ( /* NULL */; init_flag < NR_CPUS; init_flag++ ) {
+ dbs_info = &per_cpu(cpu_dbs_info, init_flag);
+ requested_freq[cpu] = dbs_info->cur_policy->cur;
+ }
+ init_flag = 1;
+ }
+
+ /*
+ * The default safe range is 20% to 80%
+ * Every sampling_rate, we check
+ * - If current idle time is less than 20%, then we try to
+ * increase frequency
+ * Every sampling_rate*sampling_down_factor, we check
+ * - If current idle time is more than 80%, then we try to
+ * decrease frequency
+ *
+ * Any frequency increase takes it to the maximum frequency.
+ * Frequency reduction happens at minimum steps of
+ * 5% (default) of max_frequency
+ */
+
+ /* Check for frequency increase */
+
+ idle_ticks = UINT_MAX;
+ for_each_cpu_mask(j, policy->cpus) {
+ unsigned int tmp_idle_ticks, total_idle_ticks;
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ /* Check for frequency increase */
+ total_idle_ticks = get_cpu_idle_time(j);
+ tmp_idle_ticks = total_idle_ticks -
+ j_dbs_info->prev_cpu_idle_up;
+ j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+
+ if (tmp_idle_ticks < idle_ticks)
+ idle_ticks = tmp_idle_ticks;
+ }
+
+ /* Scale idle ticks by 100 and compare with up and down ticks */
+ idle_ticks *= 100;
+ up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+
+ if (idle_ticks < up_idle_ticks) {
+ down_skip[cpu] = 0;
+ for_each_cpu_mask(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_down =
+ j_dbs_info->prev_cpu_idle_up;
+ }
+ /* if we are already at full speed then break out early */
+ if (requested_freq[cpu] == policy->max)
+ return;
+
+ freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100;
+
+ /* max freq cannot be less than 100. But who knows.... */
+ if (unlikely(freq_step == 0))
+ freq_step = 5;
+
+ requested_freq[cpu] += freq_step;
+ if (requested_freq[cpu] > policy->max)
+ requested_freq[cpu] = policy->max;
+
+ __cpufreq_driver_target(policy, requested_freq[cpu],
+ CPUFREQ_RELATION_H);
+ return;
+ }
+
+ /* Check for frequency decrease */
+ down_skip[cpu]++;
+ if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
+ return;
+
+ idle_ticks = UINT_MAX;
+ for_each_cpu_mask(j, policy->cpus) {
+ unsigned int tmp_idle_ticks, total_idle_ticks;
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
+ tmp_idle_ticks = total_idle_ticks -
+ j_dbs_info->prev_cpu_idle_down;
+ j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+
+ if (tmp_idle_ticks < idle_ticks)
+ idle_ticks = tmp_idle_ticks;
+ }
+
+ /* Scale idle ticks by 100 and compare with up and down ticks */
+ idle_ticks *= 100;
+ down_skip[cpu] = 0;
+
+ freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
+ dbs_tuners_ins.sampling_down_factor;
+ down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
+ usecs_to_jiffies(freq_down_sampling_rate);
+
+ if (idle_ticks > down_idle_ticks) {
+ /* if we are already at the lowest speed then break out early
+ * or if we 'cannot' reduce the speed as the user might want
+ * freq_step to be zero */
+ if (requested_freq[cpu] == policy->min
+ || dbs_tuners_ins.freq_step == 0)
+ return;
+
+ freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100;
+
+ /* max freq cannot be less than 100. But who knows.... */
+ if (unlikely(freq_step == 0))
+ freq_step = 5;
+
+ requested_freq[cpu] -= freq_step;
+ if (requested_freq[cpu] < policy->min)
+ requested_freq[cpu] = policy->min;
+
+ __cpufreq_driver_target(policy,
+ requested_freq[cpu],
+ CPUFREQ_RELATION_H);
+ return;
+ }
+}
+
+static void do_dbs_timer(void *data)
+{
+ int i;
+ down(&dbs_sem);
+ for_each_online_cpu(i)
+ dbs_check_cpu(i);
+ schedule_delayed_work(&dbs_work,
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+ up(&dbs_sem);
+}
+
+static inline void dbs_timer_init(void)
+{
+ INIT_WORK(&dbs_work, do_dbs_timer, NULL);
+ schedule_delayed_work(&dbs_work,
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
+ return;
+}
+
+static inline void dbs_timer_exit(void)
+{
+ cancel_delayed_work(&dbs_work);
+ return;
+}
+
+static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ unsigned int event)
+{
+ unsigned int cpu = policy->cpu;
+ struct cpu_dbs_info_s *this_dbs_info;
+ unsigned int j;
+
+ this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
+
+ switch (event) {
+ case CPUFREQ_GOV_START:
+ if ((!cpu_online(cpu)) ||
+ (!policy->cur))
+ return -EINVAL;
+
+ if (policy->cpuinfo.transition_latency >
+ (TRANSITION_LATENCY_LIMIT * 1000))
+ return -EINVAL;
+ if (this_dbs_info->enable) /* Already enabled */
+ break;
+
+ down(&dbs_sem);
+ for_each_cpu_mask(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->cur_policy = policy;
+
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down
+ = j_dbs_info->prev_cpu_idle_up;
+ }
+ this_dbs_info->enable = 1;
+ sysfs_create_group(&policy->kobj, &dbs_attr_group);
+ dbs_enable++;
+ /*
+ * Start the timerschedule work, when this governor
+ * is used for first time
+ */
+ if (dbs_enable == 1) {
+ unsigned int latency;
+ /* policy latency is in nS. Convert it to uS first */
+
+ latency = policy->cpuinfo.transition_latency;
+ if (latency < 1000)
+ latency = 1000;
+
+ def_sampling_rate = (latency / 1000) *
+ DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
+ dbs_tuners_ins.sampling_rate = def_sampling_rate;
+ dbs_tuners_ins.ignore_nice = 0;
+ dbs_tuners_ins.freq_step = 5;
+
+ dbs_timer_init();
+ }
+
+ up(&dbs_sem);
+ break;
+
+ case CPUFREQ_GOV_STOP:
+ down(&dbs_sem);
+ this_dbs_info->enable = 0;
+ sysfs_remove_group(&policy->kobj, &dbs_attr_group);
+ dbs_enable--;
+ /*
+ * Stop the timerschedule work, when this governor
+ * is used for first time
+ */
+ if (dbs_enable == 0)
+ dbs_timer_exit();
+
+ up(&dbs_sem);
+
+ break;
+
+ case CPUFREQ_GOV_LIMITS:
+ down(&dbs_sem);
+ if (policy->max < this_dbs_info->cur_policy->cur)
+ __cpufreq_driver_target(
+ this_dbs_info->cur_policy,
+ policy->max, CPUFREQ_RELATION_H);
+ else if (policy->min > this_dbs_info->cur_policy->cur)
+ __cpufreq_driver_target(
+ this_dbs_info->cur_policy,
+ policy->min, CPUFREQ_RELATION_L);
+ up(&dbs_sem);
+ break;
+ }
+ return 0;
+}
+
+static struct cpufreq_governor cpufreq_gov_dbs = {
+ .name = "conservative",
+ .governor = cpufreq_governor_dbs,
+ .owner = THIS_MODULE,
+};
+
+static int __init cpufreq_gov_dbs_init(void)
+{
+ return cpufreq_register_governor(&cpufreq_gov_dbs);
+}
+
+static void __exit cpufreq_gov_dbs_exit(void)
+{
+ /* Make sure that the scheduled work is indeed not running */
+ flush_scheduled_work();
+
+ cpufreq_unregister_governor(&cpufreq_gov_dbs);
+}
+
+
+MODULE_AUTHOR ("Alexander Clouter <alex-kernel@digriz.org.uk>");
+MODULE_DESCRIPTION ("'cpufreq_conservative' - A dynamic cpufreq governor for "
+ "Low Latency Frequency Transition capable processors "
+ "optimised for use in a battery environment");
+MODULE_LICENSE ("GPL");
+
+module_init(cpufreq_gov_dbs_init);
+module_exit(cpufreq_gov_dbs_exit);
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 8d83a21c647..c1fc9c62bb5 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -34,13 +34,9 @@
*/
#define DEF_FREQUENCY_UP_THRESHOLD (80)
-#define MIN_FREQUENCY_UP_THRESHOLD (0)
+#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
-#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
-#define MIN_FREQUENCY_DOWN_THRESHOLD (0)
-#define MAX_FREQUENCY_DOWN_THRESHOLD (100)
-
/*
* The polling frequency of this governor depends on the capability of
* the processor. Default polling frequency is 1000 times the transition
@@ -55,9 +51,9 @@ static unsigned int def_sampling_rate;
#define MIN_SAMPLING_RATE (def_sampling_rate / 2)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define DEF_SAMPLING_DOWN_FACTOR (10)
+#define DEF_SAMPLING_DOWN_FACTOR (1)
+#define MAX_SAMPLING_DOWN_FACTOR (10)
#define TRANSITION_LATENCY_LIMIT (10 * 1000)
-#define sampling_rate_in_HZ(x) (((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000)))
static void do_dbs_timer(void *data);
@@ -78,15 +74,23 @@ struct dbs_tuners {
unsigned int sampling_rate;
unsigned int sampling_down_factor;
unsigned int up_threshold;
- unsigned int down_threshold;
+ unsigned int ignore_nice;
};
static struct dbs_tuners dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
};
+static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+{
+ return kstat_cpu(cpu).cpustat.idle +
+ kstat_cpu(cpu).cpustat.iowait +
+ ( !dbs_tuners_ins.ignore_nice ?
+ kstat_cpu(cpu).cpustat.nice :
+ 0);
+}
+
/************************** sysfs interface ************************/
static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
{
@@ -115,7 +119,7 @@ static ssize_t show_##file_name \
show_one(sampling_rate, sampling_rate);
show_one(sampling_down_factor, sampling_down_factor);
show_one(up_threshold, up_threshold);
-show_one(down_threshold, down_threshold);
+show_one(ignore_nice, ignore_nice);
static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
const char *buf, size_t count)
@@ -126,6 +130,9 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
if (ret != 1 )
return -EINVAL;
+ if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
+ return -EINVAL;
+
down(&dbs_sem);
dbs_tuners_ins.sampling_down_factor = input;
up(&dbs_sem);
@@ -161,8 +168,7 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
down(&dbs_sem);
if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
- input < MIN_FREQUENCY_UP_THRESHOLD ||
- input <= dbs_tuners_ins.down_threshold) {
+ input < MIN_FREQUENCY_UP_THRESHOLD) {
up(&dbs_sem);
return -EINVAL;
}
@@ -173,22 +179,35 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_down_threshold(struct cpufreq_policy *unused,
+static ssize_t store_ignore_nice(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
unsigned int input;
int ret;
+
+ unsigned int j;
+
ret = sscanf (buf, "%u", &input);
+ if ( ret != 1 )
+ return -EINVAL;
+ if ( input > 1 )
+ input = 1;
+
down(&dbs_sem);
- if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD ||
- input < MIN_FREQUENCY_DOWN_THRESHOLD ||
- input >= dbs_tuners_ins.up_threshold) {
+ if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
up(&dbs_sem);
- return -EINVAL;
+ return count;
}
+ dbs_tuners_ins.ignore_nice = input;
- dbs_tuners_ins.down_threshold = input;
+ /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+ for_each_online_cpu(j) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+ }
up(&dbs_sem);
return count;
@@ -201,7 +220,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
define_one_rw(sampling_rate);
define_one_rw(sampling_down_factor);
define_one_rw(up_threshold);
-define_one_rw(down_threshold);
+define_one_rw(ignore_nice);
static struct attribute * dbs_attributes[] = {
&sampling_rate_max.attr,
@@ -209,7 +228,7 @@ static struct attribute * dbs_attributes[] = {
&sampling_rate.attr,
&sampling_down_factor.attr,
&up_threshold.attr,
- &down_threshold.attr,
+ &ignore_nice.attr,
NULL
};
@@ -222,9 +241,8 @@ static struct attribute_group dbs_attr_group = {
static void dbs_check_cpu(int cpu)
{
- unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
- unsigned int total_idle_ticks;
- unsigned int freq_down_step;
+ unsigned int idle_ticks, up_idle_ticks, total_ticks;
+ unsigned int freq_next;
unsigned int freq_down_sampling_rate;
static int down_skip[NR_CPUS];
struct cpu_dbs_info_s *this_dbs_info;
@@ -238,38 +256,25 @@ static void dbs_check_cpu(int cpu)
policy = this_dbs_info->cur_policy;
/*
- * The default safe range is 20% to 80%
- * Every sampling_rate, we check
- * - If current idle time is less than 20%, then we try to
- * increase frequency
- * Every sampling_rate*sampling_down_factor, we check
- * - If current idle time is more than 80%, then we try to
- * decrease frequency
+ * Every sampling_rate, we check, if current idle time is less
+ * than 20% (default), then we try to increase frequency
+ * Every sampling_rate*sampling_down_factor, we look for a the lowest
+ * frequency which can sustain the load while keeping idle time over
+ * 30%. If such a frequency exist, we try to decrease to this frequency.
*
* Any frequency increase takes it to the maximum frequency.
* Frequency reduction happens at minimum steps of
- * 5% of max_frequency
+ * 5% (default) of current frequency
*/
/* Check for frequency increase */
- total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
- idle_ticks = total_idle_ticks -
- this_dbs_info->prev_cpu_idle_up;
- this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
-
-
+ idle_ticks = UINT_MAX;
for_each_cpu_mask(j, policy->cpus) {
- unsigned int tmp_idle_ticks;
+ unsigned int tmp_idle_ticks, total_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
- if (j == cpu)
- continue;
-
j_dbs_info = &per_cpu(cpu_dbs_info, j);
- /* Check for frequency increase */
- total_idle_ticks = kstat_cpu(j).cpustat.idle +
- kstat_cpu(j).cpustat.iowait;
+ total_idle_ticks = get_cpu_idle_time(j);
tmp_idle_ticks = total_idle_ticks -
j_dbs_info->prev_cpu_idle_up;
j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
@@ -281,13 +286,23 @@ static void dbs_check_cpu(int cpu)
/* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100;
up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
- sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate);
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
if (idle_ticks < up_idle_ticks) {
+ down_skip[cpu] = 0;
+ for_each_cpu_mask(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_down =
+ j_dbs_info->prev_cpu_idle_up;
+ }
+ /* if we are already at full speed then break out early */
+ if (policy->cur == policy->max)
+ return;
+
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
- down_skip[cpu] = 0;
- this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
return;
}
@@ -296,23 +311,14 @@ static void dbs_check_cpu(int cpu)
if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
return;
- total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
- idle_ticks = total_idle_ticks -
- this_dbs_info->prev_cpu_idle_down;
- this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
-
+ idle_ticks = UINT_MAX;
for_each_cpu_mask(j, policy->cpus) {
- unsigned int tmp_idle_ticks;
+ unsigned int tmp_idle_ticks, total_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
- if (j == cpu)
- continue;
-
j_dbs_info = &per_cpu(cpu_dbs_info, j);
- /* Check for frequency increase */
- total_idle_ticks = kstat_cpu(j).cpustat.idle +
- kstat_cpu(j).cpustat.iowait;
+ /* Check for frequency decrease */
+ total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
tmp_idle_ticks = total_idle_ticks -
j_dbs_info->prev_cpu_idle_down;
j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
@@ -321,38 +327,37 @@ static void dbs_check_cpu(int cpu)
idle_ticks = tmp_idle_ticks;
}
- /* Scale idle ticks by 100 and compare with up and down ticks */
- idle_ticks *= 100;
down_skip[cpu] = 0;
+ /* if we cannot reduce the frequency anymore, break out early */
+ if (policy->cur == policy->min)
+ return;
+ /* Compute how many ticks there are between two measurements */
freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
dbs_tuners_ins.sampling_down_factor;
- down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
- sampling_rate_in_HZ(freq_down_sampling_rate);
+ total_ticks = usecs_to_jiffies(freq_down_sampling_rate);
- if (idle_ticks > down_idle_ticks ) {
- freq_down_step = (5 * policy->max) / 100;
-
- /* max freq cannot be less than 100. But who knows.... */
- if (unlikely(freq_down_step == 0))
- freq_down_step = 5;
+ /*
+ * The optimal frequency is the frequency that is the lowest that
+ * can support the current CPU usage without triggering the up
+ * policy. To be safe, we focus 10 points under the threshold.
+ */
+ freq_next = ((total_ticks - idle_ticks) * 100) / total_ticks;
+ freq_next = (freq_next * policy->cur) /
+ (dbs_tuners_ins.up_threshold - 10);
- __cpufreq_driver_target(policy,
- policy->cur - freq_down_step,
- CPUFREQ_RELATION_H);
- return;
- }
+ if (freq_next <= ((policy->cur * 95) / 100))
+ __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
}
static void do_dbs_timer(void *data)
{
int i;
down(&dbs_sem);
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_online(i))
- dbs_check_cpu(i);
+ for_each_online_cpu(i)
+ dbs_check_cpu(i);
schedule_delayed_work(&dbs_work,
- sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
up(&dbs_sem);
}
@@ -360,7 +365,7 @@ static inline void dbs_timer_init(void)
{
INIT_WORK(&dbs_work, do_dbs_timer, NULL);
schedule_delayed_work(&dbs_work,
- sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
return;
}
@@ -397,12 +402,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
- j_dbs_info->prev_cpu_idle_up =
- kstat_cpu(j).cpustat.idle +
- kstat_cpu(j).cpustat.iowait;
- j_dbs_info->prev_cpu_idle_down =
- kstat_cpu(j).cpustat.idle +
- kstat_cpu(j).cpustat.iowait;
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down
+ = j_dbs_info->prev_cpu_idle_up;
}
this_dbs_info->enable = 1;
sysfs_create_group(&policy->kobj, &dbs_attr_group);
@@ -422,6 +424,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
def_sampling_rate = (latency / 1000) *
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
dbs_tuners_ins.sampling_rate = def_sampling_rate;
+ dbs_tuners_ins.ignore_nice = 0;
dbs_timer_init();
}
@@ -461,12 +464,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-struct cpufreq_governor cpufreq_gov_dbs = {
+static struct cpufreq_governor cpufreq_gov_dbs = {
.name = "ondemand",
.governor = cpufreq_governor_dbs,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_dbs);
static int __init cpufreq_gov_dbs_init(void)
{
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 2084593937c..741b6b191e6 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -19,6 +19,7 @@
#include <linux/percpu.h>
#include <linux/kobject.h>
#include <linux/spinlock.h>
+#include <asm/cputime.h>
static spinlock_t cpufreq_stats_lock;
@@ -29,20 +30,14 @@ static struct freq_attr _attr_##_name = {\
.show = _show,\
};
-static unsigned long
-delta_time(unsigned long old, unsigned long new)
-{
- return (old > new) ? (old - new): (new + ~old + 1);
-}
-
struct cpufreq_stats {
unsigned int cpu;
unsigned int total_trans;
- unsigned long long last_time;
+ unsigned long long last_time;
unsigned int max_state;
unsigned int state_num;
unsigned int last_index;
- unsigned long long *time_in_state;
+ cputime64_t *time_in_state;
unsigned int *freq_table;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
unsigned int *trans_table;
@@ -60,12 +55,16 @@ static int
cpufreq_stats_update (unsigned int cpu)
{
struct cpufreq_stats *stat;
+ unsigned long long cur_time;
+
+ cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock);
stat = cpufreq_stats_table[cpu];
if (stat->time_in_state)
- stat->time_in_state[stat->last_index] +=
- delta_time(stat->last_time, jiffies);
- stat->last_time = jiffies;
+ stat->time_in_state[stat->last_index] =
+ cputime64_add(stat->time_in_state[stat->last_index],
+ cputime_sub(cur_time, stat->last_time));
+ stat->last_time = cur_time;
spin_unlock(&cpufreq_stats_lock);
return 0;
}
@@ -90,8 +89,8 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf)
return 0;
cpufreq_stats_update(stat->cpu);
for (i = 0; i < stat->state_num; i++) {
- len += sprintf(buf + len, "%u %llu\n",
- stat->freq_table[i], stat->time_in_state[i]);
+ len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
+ (unsigned long long)cputime64_to_clock_t(stat->time_in_state[i]));
}
return len;
}
@@ -107,16 +106,30 @@ show_trans_table(struct cpufreq_policy *policy, char *buf)
if(!stat)
return 0;
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++) {
if (len >= PAGE_SIZE)
break;
- len += snprintf(buf + len, PAGE_SIZE - len, "%9u:\t",
+
+ len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
stat->freq_table[i]);
for (j = 0; j < stat->state_num; j++) {
if (len >= PAGE_SIZE)
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]);
}
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
@@ -197,7 +210,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
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
alloc_size += count * count * sizeof(int);
@@ -224,7 +237,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy,
}
stat->state_num = j;
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);
spin_unlock(&cpufreq_stats_lock);
cpufreq_cpu_put(data);
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index 6d5df6c2efa..df1b721154d 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -11,6 +11,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/config.h>
#include <linux/acpi.h>
#include <linux/console.h>
#include <linux/efi.h>
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index 35710818fe4..fdd881aee61 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -2,6 +2,7 @@
* i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
*
* Copyright (C) 2004 Patrick Mochel
+ * 2005 Rudolf Marek <r.marek@sh.cvut.cz>
*
* The 1563 southbridge is deceptively similar to the 1533, with a
* few notable exceptions. One of those happens to be the fact they
@@ -57,10 +58,11 @@
#define HST_CNTL2_BLOCK 0x05
+#define HST_CNTL2_SIZEMASK 0x38
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;
int timeout;
@@ -73,7 +75,7 @@ static int ali1563_transaction(struct i2c_adapter * a)
data = inb_p(SMB_HST_STS);
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);
data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD)
@@ -94,19 +96,31 @@ static int ali1563_transaction(struct i2c_adapter * a)
if (timeout && !(data & HST_STS_BAD))
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 */
outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
- else
- /* Issue timeout to reset all devices on bus */
+ data = inb_p(SMB_HST_STS);
+ }
+
+ /* 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);
+ }
+
+ if (data & HST_STS_FAIL) {
+ dev_err(&a->dev, "Cleaning fail after KILL!\n");
+ outb_p(0x0,SMB_HST_CNTL2);
+ }
+
return -1;
}
@@ -149,7 +163,7 @@ static int ali1563_block_start(struct i2c_adapter * a)
if (timeout && !(data & HST_STS_BAD))
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 " : "",
data & HST_STS_FAIL ? "Transaction Failed " : "",
data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
@@ -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(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 */
+
switch(size) {
case HST_CNTL2_BYTE:
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;
case HST_CNTL2_BYTE_DATA:
outb_p(cmd, SMB_HST_CMD);
@@ -268,7 +284,7 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
goto Done;
}
- if ((error = ali1563_transaction(a)))
+ if ((error = ali1563_transaction(a, size)))
goto Done;
if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 78e3e7b24d7..39f3e9101ed 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1936,7 +1936,7 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
* NOTE! The "len" and "addr" checks should possibly have
* separate masks.
*/
- if ((rq->data_len & mask) || (addr & mask))
+ if ((rq->data_len & 15) || (addr & mask))
info->dma = 0;
}
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 47225e32435..4e0f13d1d06 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -72,6 +72,7 @@ static struct amd_ide_chip {
{ 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_MCP04_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 },
{ 0 }
};
@@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
/* 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)
@@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
#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_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, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index 6282f460aba..1d93f509290 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -68,23 +68,3 @@ config GAMEPORT_CS461X
depends on PCI
endif
-
-# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on
-# in every .config. Please don't touch it. It is here to handle an
-# unusual dependency between GAMEPORT and sound drivers.
-#
-# Some sound drivers call gameport functions. If GAMEPORT is
-# not selected, empty stubs are provided for the functions and all is
-# well.
-# If GAMEPORT is built in, everything is fine.
-# If GAMEPORT is a module, however, it would need to be loaded for the
-# sound driver to be able to link properly. Therefore, the sound
-# driver must be a module as well in that case. Since there's no way
-# to express that directly in Kconfig, we use SOUND_GAMEPORT to
-# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm',
-# anything that depends on SOUND_GAMEPORT must be 'm' as well. if
-# GAMEPORT is 'y' or 'n', it can be anything".
-config SOUND_GAMEPORT
- tristate
- default m if GAMEPORT=m
- default y
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 7d7527f8b02..627d343dfba 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -422,7 +422,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev->nkey++;
}
- for (i = 0; i < BTN_JOYSTICK - BTN_MISC + 1; i++)
+ for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
if (test_bit(i + BTN_MISC, dev->keybit)) {
joydev->keymap[i] = joydev->nkey;
joydev->keypam[joydev->nkey] = i + BTN_MISC;
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 79c332f16fc..af0446c6de8 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -171,9 +171,9 @@ static struct {
unsigned char set2;
} atkbd_scroll_keys[] = {
{ ATKBD_SCR_1, 0xc5 },
- { ATKBD_SCR_2, 0xa9 },
- { ATKBD_SCR_4, 0xb6 },
- { ATKBD_SCR_8, 0xa7 },
+ { ATKBD_SCR_2, 0x9d },
+ { ATKBD_SCR_4, 0xa4 },
+ { ATKBD_SCR_8, 0x9b },
{ ATKBD_SCR_CLICK, 0xe0 },
{ ATKBD_SCR_LEFT, 0xcb },
{ ATKBD_SCR_RIGHT, 0xd2 },
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index cd8509549ea..019034b21a0 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -518,13 +518,16 @@ static int psmouse_probe(struct psmouse *psmouse)
/*
* First, we check if it's a mouse. It should send 0x00 or 0x03
* in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
+ * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent
+ * ID queries, probably due to a firmware bug.
*/
param[0] = 0xa5;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
return -1;
- if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
+ if (param[0] != 0x00 && param[0] != 0x03 &&
+ param[0] != 0x04 && param[0] != 0xff)
return -1;
/*
@@ -972,7 +975,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
return -EINVAL;
if (!strncmp(val, "any", 3)) {
- *((unsigned int *)kp->arg) = -1UL;
+ *((unsigned int *)kp->arg) = -1U;
return 0;
}
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 69832f8fb72..36c721227b6 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -143,39 +143,6 @@ static int synaptics_identify(struct psmouse *psmouse)
return -1;
}
-static void print_ident(struct synaptics_data *priv)
-{
- printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
- printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
- SYN_ID_MINOR(priv->identity));
- if (SYN_MODEL_ROT180(priv->model_id))
- printk(KERN_INFO " 180 degree mounted touchpad\n");
- if (SYN_MODEL_PORTRAIT(priv->model_id))
- printk(KERN_INFO " portrait touchpad\n");
- printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
- if (SYN_MODEL_NEWABS(priv->model_id))
- printk(KERN_INFO " new absolute packet format\n");
- if (SYN_MODEL_PEN(priv->model_id))
- printk(KERN_INFO " pen detection\n");
-
- if (SYN_CAP_EXTENDED(priv->capabilities)) {
- printk(KERN_INFO " Touchpad has extended capability bits\n");
- if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
- printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
- (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
- if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
- printk(KERN_INFO " -> middle button\n");
- if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
- printk(KERN_INFO " -> four buttons\n");
- if (SYN_CAP_MULTIFINGER(priv->capabilities))
- printk(KERN_INFO " -> multifinger detection\n");
- if (SYN_CAP_PALMDETECT(priv->capabilities))
- printk(KERN_INFO " -> palm detection\n");
- if (SYN_CAP_PASS_THROUGH(priv->capabilities))
- printk(KERN_INFO " -> pass-through port\n");
- }
-}
-
static int synaptics_query_hardware(struct psmouse *psmouse)
{
int retries = 0;
@@ -666,7 +633,11 @@ int synaptics_init(struct psmouse *psmouse)
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
- print_ident(priv);
+ printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n",
+ SYN_ID_MODEL(priv->identity),
+ SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
+ priv->model_id, priv->capabilities, priv->ext_cap);
+
set_input_params(&psmouse->dev, priv);
psmouse->protocol_handler = synaptics_process_byte;
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 564974ce579..96fb9870834 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -101,6 +101,7 @@ struct mousedev_list {
unsigned char ready, buffer, bufsiz;
unsigned char imexseq, impsseq;
enum mousedev_emul mode;
+ unsigned long last_buttons;
};
#define MOUSEDEV_SEQ_LEN 6
@@ -224,7 +225,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
spin_lock_irqsave(&list->packet_lock, flags);
p = &list->packets[list->head];
- if (list->ready && p->buttons != packet->buttons) {
+ if (list->ready && p->buttons != mousedev->packet.buttons) {
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
if (new_head != list->tail) {
p = &list->packets[list->head = new_head];
@@ -249,10 +250,13 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
- list->ready = 1;
+ if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
+ list->ready = 1;
spin_unlock_irqrestore(&list->packet_lock, flags);
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+
+ if (list->ready)
+ kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&mousedev->wait);
@@ -477,9 +481,10 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
}
if (!p->dx && !p->dy && !p->dz) {
- if (list->tail == list->head)
+ if (list->tail == list->head) {
list->ready = 0;
- else
+ list->last_buttons = p->buttons;
+ } else
list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
}
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index f64867808fe..0487ecbb8a4 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -88,9 +88,11 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
};
/*
- * Some Fujitsu notebooks are ahving trouble with touhcpads if
+ * Some Fujitsu notebooks are having trouble with touchpads if
* active multiplexing mode is activated. Luckily they don't have
* external PS/2 ports so we can safely disable it.
+ * ... apparently some Toshibas don't like MUX mode either and
+ * die horrible death on reboot.
*/
static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
{
@@ -115,12 +117,26 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
},
},
{
+ .ident = "Fujitsu Lifebook S6230",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
+ },
+ },
+ {
.ident = "Fujitsu T70H",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
},
},
+ {
+ .ident = "Toshiba P10",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
+ },
+ },
{ }
};
@@ -215,11 +231,15 @@ static struct pnp_driver i8042_pnp_aux_driver = {
static void i8042_pnp_exit(void)
{
- if (i8042_pnp_kbd_registered)
+ if (i8042_pnp_kbd_registered) {
+ i8042_pnp_kbd_registered = 0;
pnp_unregister_driver(&i8042_pnp_kbd_driver);
+ }
- if (i8042_pnp_aux_registered)
+ if (i8042_pnp_aux_registered) {
+ i8042_pnp_aux_registered = 0;
pnp_unregister_driver(&i8042_pnp_aux_driver);
+ }
}
static int i8042_pnp_init(void)
@@ -227,7 +247,7 @@ static int i8042_pnp_init(void)
int result_kbd, result_aux;
if (i8042_nopnp) {
- printk("i8042: PNP detection disabled\n");
+ printk(KERN_INFO "i8042: PNP detection disabled\n");
return 0;
}
@@ -241,7 +261,7 @@ static int i8042_pnp_init(void)
#if defined(__ia64__)
return -ENODEV;
#else
- printk(KERN_WARNING "PNP: No PS/2 controller found. Probing ports directly.\n");
+ printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n");
return 0;
#endif
}
@@ -265,7 +285,7 @@ static int i8042_pnp_init(void)
i8042_pnp_kbd_irq = i8042_kbd_irq;
}
- if (result_aux > 0 && !i8042_pnp_aux_irq) {
+ if (!i8042_pnp_aux_irq) {
printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq);
i8042_pnp_aux_irq = i8042_aux_irq;
}
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 8e63e464d36..5900de3c3f4 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -698,6 +698,26 @@ static void i8042_timer_func(unsigned long data)
i8042_interrupt(0, NULL, NULL);
}
+static int i8042_ctl_test(void)
+{
+ unsigned char param;
+
+ if (!i8042_reset)
+ return 0;
+
+ if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
+ printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+ return -1;
+ }
+
+ if (param != I8042_RET_CTL_TEST) {
+ printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
+ param, I8042_RET_CTL_TEST);
+ return -1;
+ }
+
+ return 0;
+}
/*
* i8042_controller init initializes the i8042 controller, and,
@@ -719,21 +739,8 @@ static int i8042_controller_init(void)
return -1;
}
- if (i8042_reset) {
-
- unsigned char param;
-
- if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
- printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
- return -1;
- }
-
- if (param != I8042_RET_CTL_TEST) {
- printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
- param, I8042_RET_CTL_TEST);
- return -1;
- }
- }
+ if (i8042_ctl_test())
+ return -1;
/*
* Save the CTR for restoral on unload / reboot.
@@ -802,15 +809,11 @@ static int i8042_controller_init(void)
*/
static void i8042_controller_reset(void)
{
- unsigned char param;
-
/*
* Reset the controller if requested.
*/
- if (i8042_reset)
- if (i8042_command(&param, I8042_CMD_CTL_TEST))
- printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
+ i8042_ctl_test();
/*
* Disable MUX mode if present.
@@ -922,8 +925,11 @@ static int i8042_resume(struct device *dev, u32 level)
if (level != RESUME_ENABLE)
return 0;
- if (i8042_controller_init()) {
- printk(KERN_ERR "i8042: resume failed\n");
+ if (i8042_ctl_test())
+ return -1;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042: Can't write CTR\n");
return -1;
}
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index c9d0a153671..53a27e43dd2 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -68,8 +68,7 @@ static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs)
if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
(gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
- gunze->data[10] = 0;
- printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data);
+ printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data);
return;
}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index e654aa5eecd..bb9f4044c74 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -2421,7 +2421,7 @@ pmac_wakeup_devices(void)
/* Re-enable local CPU interrupts */
local_irq_enable();
- mdelay(100);
+ mdelay(10);
preempt_enable();
/* Re-enable clock spreading on some machines */
@@ -2549,7 +2549,9 @@ powerbook_sleep_Core99(void)
return ret;
}
- printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
+ /* Stop environment and ADB interrupts */
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
+ pmu_wait_complete(&req);
/* Tell PMU what events will wake us up */
pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
@@ -2611,8 +2613,6 @@ powerbook_sleep_Core99(void)
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
pmu_wait_complete(&req);
- printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
-
pmac_wakeup_devices();
return 0;
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index d047e349d70..1339912c308 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -906,22 +906,12 @@ static int dst_tone_power_cmd(struct dst_state* state)
if (state->dst_type == DST_TYPE_IS_TERR)
return 0;
- if (state->voltage == SEC_VOLTAGE_OFF)
- paket[4] = 0;
- else
- paket[4] = 1;
-
- if (state->tone == SEC_TONE_ON)
- paket[2] = 0x02;
- else
- paket[2] = 0;
- if (state->minicmd == SEC_MINI_A)
- paket[3] = 0x02;
- else
- paket[3] = 0;
-
+ paket[4] = state->tx_tuna[4];
+ paket[2] = state->tx_tuna[2];
+ paket[3] = state->tx_tuna[3];
paket[7] = dst_check_sum (paket, 7);
dst_command(state, paket, 8);
+
return 0;
}
@@ -980,7 +970,7 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
static int dst_write_tuna(struct dvb_frontend* fe)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
int retval;
u8 reply;
@@ -1048,10 +1038,10 @@ static int dst_write_tuna(struct dvb_frontend* fe)
static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
- if (state->dst_type == DST_TYPE_IS_TERR)
+ if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
if (cmd->msg_len == 0 || cmd->msg_len > 4)
@@ -1064,39 +1054,32 @@ static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd*
static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
- u8 *val;
int need_cmd;
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
state->voltage = voltage;
- if (state->dst_type == DST_TYPE_IS_TERR)
+ if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
need_cmd = 0;
- val = &state->tx_tuna[0];
- val[8] &= ~0x40;
switch (voltage) {
- case SEC_VOLTAGE_13:
- if ((state->diseq_flags & HAS_POWER) == 0)
- need_cmd = 1;
- state->diseq_flags |= HAS_POWER;
- break;
+ case SEC_VOLTAGE_13:
+ case SEC_VOLTAGE_18:
+ if ((state->diseq_flags & HAS_POWER) == 0)
+ need_cmd = 1;
+ state->diseq_flags |= HAS_POWER;
+ state->tx_tuna[4] = 0x01;
+ break;
- case SEC_VOLTAGE_18:
- if ((state->diseq_flags & HAS_POWER) == 0)
+ case SEC_VOLTAGE_OFF:
need_cmd = 1;
- state->diseq_flags |= HAS_POWER;
- val[8] |= 0x40;
- break;
-
- case SEC_VOLTAGE_OFF:
- need_cmd = 1;
- state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
- break;
+ state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
+ state->tx_tuna[4] = 0x00;
+ break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
if (need_cmd)
dst_tone_power_cmd(state);
@@ -1106,37 +1089,56 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
- u8 *val;
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
state->tone = tone;
- if (state->dst_type == DST_TYPE_IS_TERR)
+ if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
- val = &state->tx_tuna[0];
+ switch (tone) {
+ case SEC_TONE_OFF:
+ state->tx_tuna[2] = 0xff;
+ break;
- val[8] &= ~0x1;
+ case SEC_TONE_ON:
+ state->tx_tuna[2] = 0x02;
+ break;
- switch (tone) {
- case SEC_TONE_OFF:
- break;
+ default:
+ return -EINVAL;
+ }
+ dst_tone_power_cmd(state);
- case SEC_TONE_ON:
- val[8] |= 1;
- break;
+ return 0;
+}
- default:
- return -EINVAL;
+static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct dst_state *state = fe->demodulator_priv;
+
+ if (state->dst_type != DST_TYPE_IS_SAT)
+ return 0;
+
+ state->minicmd = minicmd;
+
+ switch (minicmd) {
+ case SEC_MINI_A:
+ state->tx_tuna[3] = 0x02;
+ break;
+ case SEC_MINI_B:
+ state->tx_tuna[3] = 0xff;
+ break;
}
dst_tone_power_cmd(state);
return 0;
}
+
static int dst_init(struct dvb_frontend* fe)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
@@ -1168,7 +1170,7 @@ static int dst_init(struct dvb_frontend* fe)
static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
*status = 0;
if (state->diseq_flags & HAS_LOCK) {
@@ -1182,7 +1184,7 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
dst_get_signal(state);
*strength = state->decode_strength;
@@ -1192,7 +1194,7 @@ static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength)
static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
dst_get_signal(state);
*snr = state->decode_snr;
@@ -1202,7 +1204,7 @@ static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
dst_set_freq(state, p->frequency);
if (verbose > 4)
@@ -1228,7 +1230,7 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
p->frequency = state->decode_freq;
p->inversion = state->inversion;
@@ -1248,7 +1250,7 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
static void dst_release(struct dvb_frontend* fe)
{
- struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
+ struct dst_state* state = fe->demodulator_priv;
kfree(state);
}
@@ -1346,7 +1348,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
- .diseqc_send_burst = dst_set_tone,
+ .diseqc_send_burst = dst_send_burst,
.diseqc_send_master_cmd = dst_set_diseqc,
.set_voltage = dst_set_voltage,
.set_tone = dst_set_tone,
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f10dd74988c..fc9b5cd957a 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -133,6 +133,8 @@
/* number of ETHTOOL_GSTATS u64's */
#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64))
+#define TG3_NUM_TEST 6
+
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -316,6 +318,17 @@ static struct {
{ "nic_tx_threshold_hit" }
};
+static struct {
+ const char string[ETH_GSTRING_LEN];
+} ethtool_test_keys[TG3_NUM_TEST] = {
+ { "nvram test (online) " },
+ { "link test (online) " },
+ { "register test (offline)" },
+ { "memory test (offline)" },
+ { "loopback test (offline)" },
+ { "interrupt test (offline)" },
+};
+
static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{
if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
@@ -3070,7 +3083,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
}
static int tg3_init_hw(struct tg3 *);
-static int tg3_halt(struct tg3 *, int);
+static int tg3_halt(struct tg3 *, int, int);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void tg3_poll_controller(struct net_device *dev)
@@ -3094,7 +3107,7 @@ static void tg3_reset_task(void *_data)
restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
- tg3_halt(tp, 0);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
tg3_init_hw(tp);
tg3_netif_start(tp);
@@ -3440,7 +3453,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_set_mtu(dev, tp, new_mtu);
@@ -4131,19 +4144,19 @@ static void tg3_stop_fw(struct tg3 *tp)
}
/* tp->lock is held. */
-static int tg3_halt(struct tg3 *tp, int silent)
+static int tg3_halt(struct tg3 *tp, int kind, int silent)
{
int err;
tg3_stop_fw(tp);
- tg3_write_sig_pre_reset(tp, RESET_KIND_SHUTDOWN);
+ tg3_write_sig_pre_reset(tp, kind);
tg3_abort_hw(tp, silent);
err = tg3_chip_reset(tp);
- tg3_write_sig_legacy(tp, RESET_KIND_SHUTDOWN);
- tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
+ tg3_write_sig_legacy(tp, kind);
+ tg3_write_sig_post_reset(tp, kind);
if (err)
return err;
@@ -4357,7 +4370,12 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
*/
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
+ /* It is possible that bootcode is still loading at this point.
+ * Get the nvram lock first before halting the cpu.
+ */
+ tg3_nvram_lock(tp);
err = tg3_halt_cpu(tp, cpu_base);
+ tg3_nvram_unlock(tp);
if (err)
goto out;
@@ -5881,6 +5899,9 @@ static int tg3_test_interrupt(struct tg3 *tp)
int err, i;
u32 int_mbox = 0;
+ if (!netif_running(dev))
+ return -ENODEV;
+
tg3_disable_ints(tp);
free_irq(tp->pdev->irq, dev);
@@ -5984,7 +6005,7 @@ static int tg3_test_msi(struct tg3 *tp)
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
err = tg3_init_hw(tp);
spin_unlock(&tp->tx_lock);
@@ -6060,7 +6081,7 @@ static int tg3_open(struct net_device *dev)
err = tg3_init_hw(tp);
if (err) {
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
} else {
if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
@@ -6104,7 +6125,7 @@ static int tg3_open(struct net_device *dev)
pci_disable_msi(tp->pdev);
tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
}
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
tg3_free_consistent(tp);
@@ -6377,7 +6398,7 @@ static int tg3_close(struct net_device *dev)
tg3_disable_ints(tp);
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
tp->tg3_flags &=
~(TG3_FLAG_INIT_COMPLETE |
@@ -7097,7 +7118,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
tp->tx_pending = ering->tx_pending;
if (netif_running(dev)) {
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_init_hw(tp);
tg3_netif_start(tp);
}
@@ -7140,7 +7161,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
if (netif_running(dev)) {
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_init_hw(tp);
tg3_netif_start(tp);
}
@@ -7199,12 +7220,20 @@ static int tg3_get_stats_count (struct net_device *dev)
return TG3_NUM_STATS;
}
+static int tg3_get_test_count (struct net_device *dev)
+{
+ return TG3_NUM_TEST;
+}
+
static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
{
switch (stringset) {
case ETH_SS_STATS:
memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
break;
+ case ETH_SS_TEST:
+ memcpy(buf, &ethtool_test_keys, sizeof(ethtool_test_keys));
+ break;
default:
WARN_ON(1); /* we need a WARN() */
break;
@@ -7218,6 +7247,516 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
}
+#define NVRAM_TEST_SIZE 0x100
+
+static int tg3_test_nvram(struct tg3 *tp)
+{
+ u32 *buf, csum;
+ int i, j, err = 0;
+
+ buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) {
+ u32 val;
+
+ if ((err = tg3_nvram_read(tp, i, &val)) != 0)
+ break;
+ buf[j] = cpu_to_le32(val);
+ }
+ if (i < NVRAM_TEST_SIZE)
+ goto out;
+
+ err = -EIO;
+ if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC)
+ goto out;
+
+ /* Bootstrap checksum at offset 0x10 */
+ csum = calc_crc((unsigned char *) buf, 0x10);
+ if(csum != cpu_to_le32(buf[0x10/4]))
+ goto out;
+
+ /* Manufacturing block starts at offset 0x74, checksum at 0xfc */
+ csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88);
+ if (csum != cpu_to_le32(buf[0xfc/4]))
+ goto out;
+
+ err = 0;
+
+out:
+ kfree(buf);
+ return err;
+}
+
+#define TG3_SERDES_TIMEOUT_SEC 2
+#define TG3_COPPER_TIMEOUT_SEC 6
+
+static int tg3_test_link(struct tg3 *tp)
+{
+ int i, max;
+
+ if (!netif_running(tp->dev))
+ return -ENODEV;
+
+ if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ max = TG3_SERDES_TIMEOUT_SEC;
+ else
+ max = TG3_COPPER_TIMEOUT_SEC;
+
+ for (i = 0; i < max; i++) {
+ if (netif_carrier_ok(tp->dev))
+ return 0;
+
+ if (msleep_interruptible(1000))
+ break;
+ }
+
+ return -EIO;
+}
+
+/* Only test the commonly used registers */
+static int tg3_test_registers(struct tg3 *tp)
+{
+ int i, is_5705;
+ u32 offset, read_mask, write_mask, val, save_val, read_val;
+ static struct {
+ u16 offset;
+ u16 flags;
+#define TG3_FL_5705 0x1
+#define TG3_FL_NOT_5705 0x2
+#define TG3_FL_NOT_5788 0x4
+ u32 read_mask;
+ u32 write_mask;
+ } reg_tbl[] = {
+ /* MAC Control Registers */
+ { MAC_MODE, TG3_FL_NOT_5705,
+ 0x00000000, 0x00ef6f8c },
+ { MAC_MODE, TG3_FL_5705,
+ 0x00000000, 0x01ef6b8c },
+ { MAC_STATUS, TG3_FL_NOT_5705,
+ 0x03800107, 0x00000000 },
+ { MAC_STATUS, TG3_FL_5705,
+ 0x03800100, 0x00000000 },
+ { MAC_ADDR_0_HIGH, 0x0000,
+ 0x00000000, 0x0000ffff },
+ { MAC_ADDR_0_LOW, 0x0000,
+ 0x00000000, 0xffffffff },
+ { MAC_RX_MTU_SIZE, 0x0000,
+ 0x00000000, 0x0000ffff },
+ { MAC_TX_MODE, 0x0000,
+ 0x00000000, 0x00000070 },
+ { MAC_TX_LENGTHS, 0x0000,
+ 0x00000000, 0x00003fff },
+ { MAC_RX_MODE, TG3_FL_NOT_5705,
+ 0x00000000, 0x000007fc },
+ { MAC_RX_MODE, TG3_FL_5705,
+ 0x00000000, 0x000007dc },
+ { MAC_HASH_REG_0, 0x0000,
+ 0x00000000, 0xffffffff },
+ { MAC_HASH_REG_1, 0x0000,
+ 0x00000000, 0xffffffff },
+ { MAC_HASH_REG_2, 0x0000,
+ 0x00000000, 0xffffffff },
+ { MAC_HASH_REG_3, 0x0000,
+ 0x00000000, 0xffffffff },
+
+ /* Receive Data and Receive BD Initiator Control Registers. */
+ { RCVDBDI_JUMBO_BD+0, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { RCVDBDI_JUMBO_BD+4, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { RCVDBDI_JUMBO_BD+8, TG3_FL_NOT_5705,
+ 0x00000000, 0x00000003 },
+ { RCVDBDI_JUMBO_BD+0xc, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { RCVDBDI_STD_BD+0, 0x0000,
+ 0x00000000, 0xffffffff },
+ { RCVDBDI_STD_BD+4, 0x0000,
+ 0x00000000, 0xffffffff },
+ { RCVDBDI_STD_BD+8, 0x0000,
+ 0x00000000, 0xffff0002 },
+ { RCVDBDI_STD_BD+0xc, 0x0000,
+ 0x00000000, 0xffffffff },
+
+ /* Receive BD Initiator Control Registers. */
+ { RCVBDI_STD_THRESH, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { RCVBDI_STD_THRESH, TG3_FL_5705,
+ 0x00000000, 0x000003ff },
+ { RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+
+ /* Host Coalescing Control Registers. */
+ { HOSTCC_MODE, TG3_FL_NOT_5705,
+ 0x00000000, 0x00000004 },
+ { HOSTCC_MODE, TG3_FL_5705,
+ 0x00000000, 0x000000f6 },
+ { HOSTCC_RXCOL_TICKS, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_RXCOL_TICKS, TG3_FL_5705,
+ 0x00000000, 0x000003ff },
+ { HOSTCC_TXCOL_TICKS, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_TXCOL_TICKS, TG3_FL_5705,
+ 0x00000000, 0x000003ff },
+ { HOSTCC_RXMAX_FRAMES, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_RXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788,
+ 0x00000000, 0x000000ff },
+ { HOSTCC_TXMAX_FRAMES, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_TXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788,
+ 0x00000000, 0x000000ff },
+ { HOSTCC_RXCOAL_TICK_INT, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_TXCOAL_TICK_INT, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788,
+ 0x00000000, 0x000000ff },
+ { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788,
+ 0x00000000, 0x000000ff },
+ { HOSTCC_STAT_COAL_TICKS, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_STATS_BLK_HOST_ADDR, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_STATS_BLK_HOST_ADDR+4, TG3_FL_NOT_5705,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_STATUS_BLK_HOST_ADDR, 0x0000,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_STATUS_BLK_HOST_ADDR+4, 0x0000,
+ 0x00000000, 0xffffffff },
+ { HOSTCC_STATS_BLK_NIC_ADDR, 0x0000,
+ 0xffffffff, 0x00000000 },
+ { HOSTCC_STATUS_BLK_NIC_ADDR, 0x0000,
+ 0xffffffff, 0x00000000 },
+
+ /* Buffer Manager Control Registers. */
+ { BUFMGR_MB_POOL_ADDR, 0x0000,
+ 0x00000000, 0x007fff80 },
+ { BUFMGR_MB_POOL_SIZE, 0x0000,
+ 0x00000000, 0x007fffff },
+ { BUFMGR_MB_RDMA_LOW_WATER, 0x0000,
+ 0x00000000, 0x0000003f },
+ { BUFMGR_MB_MACRX_LOW_WATER, 0x0000,
+ 0x00000000, 0x000001ff },
+ { BUFMGR_MB_HIGH_WATER, 0x0000,
+ 0x00000000, 0x000001ff },
+ { BUFMGR_DMA_DESC_POOL_ADDR, TG3_FL_NOT_5705,
+ 0xffffffff, 0x00000000 },
+ { BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705,
+ 0xffffffff, 0x00000000 },
+
+ /* Mailbox Registers */
+ { GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000,
+ 0x00000000, 0x000001ff },
+ { GRCMBOX_RCVJUMBO_PROD_IDX+4, TG3_FL_NOT_5705,
+ 0x00000000, 0x000001ff },
+ { GRCMBOX_RCVRET_CON_IDX_0+4, 0x0000,
+ 0x00000000, 0x000007ff },
+ { GRCMBOX_SNDHOST_PROD_IDX_0+4, 0x0000,
+ 0x00000000, 0x000001ff },
+
+ { 0xffff, 0x0000, 0x00000000, 0x00000000 },
+ };
+
+ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ is_5705 = 1;
+ else
+ is_5705 = 0;
+
+ for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
+ if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705))
+ continue;
+
+ if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705))
+ continue;
+
+ if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) &&
+ (reg_tbl[i].flags & TG3_FL_NOT_5788))
+ continue;
+
+ offset = (u32) reg_tbl[i].offset;
+ read_mask = reg_tbl[i].read_mask;
+ write_mask = reg_tbl[i].write_mask;
+
+ /* Save the original register content */
+ save_val = tr32(offset);
+
+ /* Determine the read-only value. */
+ read_val = save_val & read_mask;
+
+ /* Write zero to the register, then make sure the read-only bits
+ * are not changed and the read/write bits are all zeros.
+ */
+ tw32(offset, 0);
+
+ val = tr32(offset);
+
+ /* Test the read-only and read/write bits. */
+ if (((val & read_mask) != read_val) || (val & write_mask))
+ goto out;
+
+ /* Write ones to all the bits defined by RdMask and WrMask, then
+ * make sure the read-only bits are not changed and the
+ * read/write bits are all ones.
+ */
+ tw32(offset, read_mask | write_mask);
+
+ val = tr32(offset);
+
+ /* Test the read-only bits. */
+ if ((val & read_mask) != read_val)
+ goto out;
+
+ /* Test the read/write bits. */
+ if ((val & write_mask) != write_mask)
+ goto out;
+
+ tw32(offset, save_val);
+ }
+
+ return 0;
+
+out:
+ printk(KERN_ERR PFX "Register test failed at offset %x\n", offset);
+ tw32(offset, save_val);
+ return -EIO;
+}
+
+static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len)
+{
+ static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a };
+ int i;
+ u32 j;
+
+ for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) {
+ for (j = 0; j < len; j += 4) {
+ u32 val;
+
+ tg3_write_mem(tp, offset + j, test_pattern[i]);
+ tg3_read_mem(tp, offset + j, &val);
+ if (val != test_pattern[i])
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int tg3_test_memory(struct tg3 *tp)
+{
+ static struct mem_entry {
+ u32 offset;
+ u32 len;
+ } mem_tbl_570x[] = {
+ { 0x00000000, 0x01000},
+ { 0x00002000, 0x1c000},
+ { 0xffffffff, 0x00000}
+ }, mem_tbl_5705[] = {
+ { 0x00000100, 0x0000c},
+ { 0x00000200, 0x00008},
+ { 0x00000b50, 0x00400},
+ { 0x00004000, 0x00800},
+ { 0x00006000, 0x01000},
+ { 0x00008000, 0x02000},
+ { 0x00010000, 0x0e000},
+ { 0xffffffff, 0x00000}
+ };
+ struct mem_entry *mem_tbl;
+ int err = 0;
+ int i;
+
+ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ mem_tbl = mem_tbl_5705;
+ else
+ mem_tbl = mem_tbl_570x;
+
+ for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
+ if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset,
+ mem_tbl[i].len)) != 0)
+ break;
+ }
+
+ return err;
+}
+
+static int tg3_test_loopback(struct tg3 *tp)
+{
+ u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key;
+ u32 desc_idx;
+ struct sk_buff *skb, *rx_skb;
+ u8 *tx_data;
+ dma_addr_t map;
+ int num_pkts, tx_len, rx_len, i, err;
+ struct tg3_rx_buffer_desc *desc;
+
+ if (!netif_running(tp->dev))
+ return -ENODEV;
+
+ err = -EIO;
+
+ tg3_abort_hw(tp, 1);
+
+ /* Clearing this flag to keep interrupts disabled */
+ tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
+ tg3_reset_hw(tp);
+
+ mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
+ MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
+ MAC_MODE_PORT_MODE_GMII;
+ tw32(MAC_MODE, mac_mode);
+
+ tx_len = 1514;
+ skb = dev_alloc_skb(tx_len);
+ tx_data = skb_put(skb, tx_len);
+ memcpy(tx_data, tp->dev->dev_addr, 6);
+ memset(tx_data + 6, 0x0, 8);
+
+ tw32(MAC_RX_MTU_SIZE, tx_len + 4);
+
+ for (i = 14; i < tx_len; i++)
+ tx_data[i] = (u8) (i & 0xff);
+
+ map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE);
+
+ tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
+ HOSTCC_MODE_NOW);
+
+ udelay(10);
+
+ rx_start_idx = tp->hw_status->idx[0].rx_producer;
+
+ send_idx = 0;
+ num_pkts = 0;
+
+ tg3_set_txd(tp, send_idx, map, tx_len, 0, 1);
+
+ send_idx++;
+ num_pkts++;
+
+ tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx);
+ tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW);
+
+ udelay(10);
+
+ for (i = 0; i < 10; i++) {
+ tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
+ HOSTCC_MODE_NOW);
+
+ udelay(10);
+
+ tx_idx = tp->hw_status->idx[0].tx_consumer;
+ rx_idx = tp->hw_status->idx[0].rx_producer;
+ if ((tx_idx == send_idx) &&
+ (rx_idx == (rx_start_idx + num_pkts)))
+ break;
+ }
+
+ pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+
+ if (tx_idx != send_idx)
+ goto out;
+
+ if (rx_idx != rx_start_idx + num_pkts)
+ goto out;
+
+ desc = &tp->rx_rcb[rx_start_idx];
+ desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
+ opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
+ if (opaque_key != RXD_OPAQUE_RING_STD)
+ goto out;
+
+ if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
+ (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII))
+ goto out;
+
+ rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4;
+ if (rx_len != tx_len)
+ goto out;
+
+ rx_skb = tp->rx_std_buffers[desc_idx].skb;
+
+ map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping);
+ pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE);
+
+ for (i = 14; i < tx_len; i++) {
+ if (*(rx_skb->data + i) != (u8) (i & 0xff))
+ goto out;
+ }
+ err = 0;
+
+ /* tg3_free_rings will unmap and free the rx_skb */
+out:
+ return err;
+}
+
+static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
+ u64 *data)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
+
+ if (tg3_test_nvram(tp) != 0) {
+ etest->flags |= ETH_TEST_FL_FAILED;
+ data[0] = 1;
+ }
+ if (tg3_test_link(tp) != 0) {
+ etest->flags |= ETH_TEST_FL_FAILED;
+ data[1] = 1;
+ }
+ if (etest->flags & ETH_TEST_FL_OFFLINE) {
+ if (netif_running(dev))
+ tg3_netif_stop(tp);
+
+ spin_lock_irq(&tp->lock);
+ spin_lock(&tp->tx_lock);
+
+ tg3_halt(tp, RESET_KIND_SUSPEND, 1);
+ tg3_nvram_lock(tp);
+ tg3_halt_cpu(tp, RX_CPU_BASE);
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ tg3_halt_cpu(tp, TX_CPU_BASE);
+ tg3_nvram_unlock(tp);
+
+ if (tg3_test_registers(tp) != 0) {
+ etest->flags |= ETH_TEST_FL_FAILED;
+ data[2] = 1;
+ }
+ if (tg3_test_memory(tp) != 0) {
+ etest->flags |= ETH_TEST_FL_FAILED;
+ data[3] = 1;
+ }
+ if (tg3_test_loopback(tp) != 0) {
+ etest->flags |= ETH_TEST_FL_FAILED;
+ data[4] = 1;
+ }
+
+ spin_unlock(&tp->tx_lock);
+ spin_unlock_irq(&tp->lock);
+ if (tg3_test_interrupt(tp) != 0) {
+ etest->flags |= ETH_TEST_FL_FAILED;
+ data[5] = 1;
+ }
+ spin_lock_irq(&tp->lock);
+ spin_lock(&tp->tx_lock);
+
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+ if (netif_running(dev)) {
+ tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+ tg3_init_hw(tp);
+ tg3_netif_start(tp);
+ }
+ spin_unlock(&tp->tx_lock);
+ spin_unlock_irq(&tp->lock);
+ }
+}
+
static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = if_mii(ifr);
@@ -7331,6 +7870,8 @@ static struct ethtool_ops tg3_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso,
#endif
+ .self_test_count = tg3_get_test_count,
+ .self_test = tg3_self_test,
.get_strings = tg3_get_strings,
.get_stats_count = tg3_get_stats_count,
.get_ethtool_stats = tg3_get_ethtool_stats,
@@ -9478,7 +10019,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
pci_save_state(tp->pdev);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
}
err = tg3_test_dma(tp);
@@ -9605,7 +10146,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
- tg3_halt(tp, 1);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index 9e9dab7fe86..8132d946c38 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -1,7 +1,7 @@
/*
* CompactPCI Hot Plug Driver
*
- * Copyright (C) 2002 SOMA Networks, Inc.
+ * Copyright (C) 2002,2005 SOMA Networks, Inc.
* Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2001 IBM Corp.
*
@@ -45,10 +45,10 @@
#define dbg(format, arg...) \
do { \
- if(cpci_debug) \
+ if (cpci_debug) \
printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \
- } while(0)
+ } while (0)
#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 warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
@@ -111,10 +111,8 @@ enable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
- if(controller->ops->set_power) {
+ if (controller->ops->set_power)
retval = controller->ops->set_power(slot, 1);
- }
-
return retval;
}
@@ -126,37 +124,41 @@ disable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+ down_write(&list_rwsem);
+
/* Unconfigure device */
dbg("%s - unconfiguring slot %s",
__FUNCTION__, slot->hotplug_slot->name);
- if((retval = cpci_unconfigure_slot(slot))) {
+ if ((retval = cpci_unconfigure_slot(slot))) {
err("%s - could not unconfigure slot %s",
__FUNCTION__, slot->hotplug_slot->name);
- return retval;
+ goto disable_error;
}
dbg("%s - finished unconfiguring slot %s",
__FUNCTION__, slot->hotplug_slot->name);
/* Clear EXT (by setting it) */
- if(cpci_clear_ext(slot)) {
+ if (cpci_clear_ext(slot)) {
err("%s - could not clear EXT for slot %s",
__FUNCTION__, slot->hotplug_slot->name);
retval = -ENODEV;
+ goto disable_error;
}
cpci_led_on(slot);
- if(controller->ops->set_power) {
- retval = controller->ops->set_power(slot, 0);
- }
+ if (controller->ops->set_power)
+ if ((retval = controller->ops->set_power(slot, 0)))
+ goto disable_error;
- if(update_adapter_status(slot->hotplug_slot, 0)) {
+ if (update_adapter_status(slot->hotplug_slot, 0))
warn("failure to update adapter file");
- }
- if(slot->extracting) {
+ if (slot->extracting) {
slot->extracting = 0;
atomic_dec(&extracting);
}
+disable_error:
+ up_write(&list_rwsem);
return retval;
}
@@ -165,9 +167,8 @@ cpci_get_power_status(struct slot *slot)
{
u8 power = 1;
- if(controller->ops->get_power) {
+ if (controller->ops->get_power)
power = controller->ops->get_power(slot);
- }
return power;
}
@@ -237,9 +238,8 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
int status = -ENOMEM;
int i;
- if(!(controller && bus)) {
+ if (!(controller && bus))
return -ENODEV;
- }
/*
* Create a structure for each slot, and register that slot
@@ -316,32 +316,30 @@ int
cpci_hp_unregister_bus(struct pci_bus *bus)
{
struct slot *slot;
- struct list_head *tmp;
- struct list_head *next;
- int status;
+ struct slot *tmp;
+ int status = 0;
down_write(&list_rwsem);
- if(!slots) {
+ if (!slots) {
up_write(&list_rwsem);
return -1;
}
- list_for_each_safe(tmp, next, &slot_list) {
- slot = list_entry(tmp, struct slot, slot_list);
- if(slot->bus == bus) {
+ list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
+ if (slot->bus == bus) {
+ list_del(&slot->slot_list);
+ slots--;
+
dbg("deregistering slot %s", slot->hotplug_slot->name);
status = pci_hp_deregister(slot->hotplug_slot);
- if(status) {
+ if (status) {
err("pci_hp_deregister failed with error %d",
status);
- return status;
+ break;
}
-
- list_del(&slot->slot_list);
- slots--;
}
}
up_write(&list_rwsem);
- return 0;
+ return status;
}
/* This is the interrupt mode interrupt handler */
@@ -351,7 +349,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
dbg("entered cpci_hp_intr");
/* Check to see if it was our interrupt */
- if((controller->irq_flags & SA_SHIRQ) &&
+ if ((controller->irq_flags & SA_SHIRQ) &&
!controller->ops->check_irq(controller->dev_id)) {
dbg("exited cpci_hp_intr, not our interrupt");
return IRQ_NONE;
@@ -373,38 +371,30 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
* INS bits of the cold-inserted devices.
*/
static int
-init_slots(void)
+init_slots(int clear_ins)
{
struct slot *slot;
- struct list_head *tmp;
struct pci_dev* dev;
dbg("%s - enter", __FUNCTION__);
down_read(&list_rwsem);
- if(!slots) {
+ if (!slots) {
up_read(&list_rwsem);
return -1;
}
- list_for_each(tmp, &slot_list) {
- slot = list_entry(tmp, struct slot, slot_list);
+ list_for_each_entry(slot, &slot_list, slot_list) {
dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name);
- if(cpci_check_and_clear_ins(slot)) {
+ if (clear_ins && cpci_check_and_clear_ins(slot))
dbg("%s - cleared INS for slot %s",
__FUNCTION__, slot->hotplug_slot->name);
- dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0));
- if(dev) {
- if(update_adapter_status(slot->hotplug_slot, 1)) {
- warn("failure to update adapter file");
- }
- if(update_latch_status(slot->hotplug_slot, 1)) {
- warn("failure to update latch file");
- }
- slot->dev = dev;
- } else {
- err("%s - no driver attached to device in slot %s",
- __FUNCTION__, slot->hotplug_slot->name);
- }
+ dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
+ if (dev) {
+ if (update_adapter_status(slot->hotplug_slot, 1))
+ warn("failure to update adapter file");
+ if (update_latch_status(slot->hotplug_slot, 1))
+ warn("failure to update latch file");
+ slot->dev = dev;
}
}
up_read(&list_rwsem);
@@ -416,26 +406,28 @@ static int
check_slots(void)
{
struct slot *slot;
- struct list_head *tmp;
int extracted;
int inserted;
u16 hs_csr;
down_read(&list_rwsem);
- if(!slots) {
+ if (!slots) {
up_read(&list_rwsem);
err("no slots registered, shutting down");
return -1;
}
extracted = inserted = 0;
- list_for_each(tmp, &slot_list) {
- slot = list_entry(tmp, struct slot, slot_list);
+ list_for_each_entry(slot, &slot_list, slot_list) {
dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name);
- if(cpci_check_and_clear_ins(slot)) {
- /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
- if(slot->dev) {
- warn("slot %s already inserted", slot->hotplug_slot->name);
+ if (cpci_check_and_clear_ins(slot)) {
+ /*
+ * Some broken hardware (e.g. PLX 9054AB) asserts
+ * ENUM# twice...
+ */
+ if (slot->dev) {
+ warn("slot %s already inserted",
+ slot->hotplug_slot->name);
inserted++;
continue;
}
@@ -452,7 +444,7 @@ check_slots(void)
/* Configure device */
dbg("%s - configuring slot %s",
__FUNCTION__, slot->hotplug_slot->name);
- if(cpci_configure_slot(slot)) {
+ if (cpci_configure_slot(slot)) {
err("%s - could not configure slot %s",
__FUNCTION__, slot->hotplug_slot->name);
continue;
@@ -465,13 +457,11 @@ check_slots(void)
dbg("%s - slot %s HS_CSR (2) = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr);
- if(update_latch_status(slot->hotplug_slot, 1)) {
+ if (update_latch_status(slot->hotplug_slot, 1))
warn("failure to update latch file");
- }
- if(update_adapter_status(slot->hotplug_slot, 1)) {
+ if (update_adapter_status(slot->hotplug_slot, 1))
warn("failure to update adapter file");
- }
cpci_led_off(slot);
@@ -481,7 +471,7 @@ check_slots(void)
__FUNCTION__, slot->hotplug_slot->name, hs_csr);
inserted++;
- } else if(cpci_check_ext(slot)) {
+ } else if (cpci_check_ext(slot)) {
/* Process extraction request */
dbg("%s - slot %s extracted",
__FUNCTION__, slot->hotplug_slot->name);
@@ -491,27 +481,25 @@ check_slots(void)
dbg("%s - slot %s HS_CSR = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr);
- if(!slot->extracting) {
- if(update_latch_status(slot->hotplug_slot, 0)) {
+ if (!slot->extracting) {
+ if (update_latch_status(slot->hotplug_slot, 0)) {
warn("failure to update latch file");
-
}
- atomic_inc(&extracting);
slot->extracting = 1;
+ atomic_inc(&extracting);
}
extracted++;
- } else if(slot->extracting) {
+ } else if (slot->extracting) {
hs_csr = cpci_get_hs_csr(slot);
- if(hs_csr == 0xffff) {
+ if (hs_csr == 0xffff) {
/*
* Hmmm, we're likely hosed at this point, should we
* bother trying to tell the driver or not?
*/
err("card in slot %s was improperly removed",
slot->hotplug_slot->name);
- if(update_adapter_status(slot->hotplug_slot, 0)) {
+ if (update_adapter_status(slot->hotplug_slot, 0))
warn("failure to update adapter file");
- }
slot->extracting = 0;
atomic_dec(&extracting);
}
@@ -520,10 +508,9 @@ check_slots(void)
up_read(&list_rwsem);
dbg("inserted=%d, extracted=%d, extracting=%d",
inserted, extracted, atomic_read(&extracting));
- if(inserted || extracted) {
+ if (inserted || extracted)
return extracted;
- }
- else if(!atomic_read(&extracting)) {
+ else if (!atomic_read(&extracting)) {
err("cannot find ENUM# source, shutting down");
return -1;
}
@@ -541,12 +528,12 @@ event_thread(void *data)
unlock_kernel();
dbg("%s - event thread started", __FUNCTION__);
- while(1) {
+ while (1) {
dbg("event thread sleeping");
down_interruptible(&event_semaphore);
dbg("event thread woken, thread_finished = %d",
thread_finished);
- if(thread_finished || signal_pending(current))
+ if (thread_finished || signal_pending(current))
break;
do {
rc = check_slots();
@@ -558,7 +545,9 @@ event_thread(void *data)
thread_finished = 1;
break;
}
- } while(atomic_read(&extracting) != 0);
+ } while (atomic_read(&extracting) && !thread_finished);
+ if (thread_finished)
+ break;
/* Re-enable ENUM# interrupt */
dbg("%s - re-enabling irq", __FUNCTION__);
@@ -579,21 +568,21 @@ poll_thread(void *data)
daemonize("cpci_hp_polld");
unlock_kernel();
- while(1) {
- if(thread_finished || signal_pending(current))
+ while (1) {
+ if (thread_finished || signal_pending(current))
break;
- if(controller->ops->query_enum()) {
+ if (controller->ops->query_enum()) {
do {
rc = check_slots();
- if(rc > 0) {
+ if (rc > 0) {
/* Give userspace a chance to handle extraction */
msleep(500);
- } else if(rc < 0) {
+ } else if (rc < 0) {
dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1;
break;
}
- } while(atomic_read(&extracting) != 0);
+ } while (atomic_read(&extracting) && !thread_finished);
}
msleep(100);
}
@@ -612,12 +601,11 @@ cpci_start_thread(void)
init_MUTEX_LOCKED(&thread_exit);
thread_finished = 0;
- if(controller->irq) {
+ if (controller->irq)
pid = kernel_thread(event_thread, NULL, 0);
- } else {
+ else
pid = kernel_thread(poll_thread, NULL, 0);
- }
- if(pid < 0) {
+ if (pid < 0) {
err("Can't start up our thread");
return -1;
}
@@ -630,9 +618,8 @@ cpci_stop_thread(void)
{
thread_finished = 1;
dbg("thread finish command given");
- if(controller->irq) {
+ if (controller->irq)
up(&event_semaphore);
- }
dbg("wait for thread to exit");
down(&thread_exit);
}
@@ -642,45 +629,67 @@ cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
{
int status = 0;
- if(!controller) {
- controller = new_controller;
- if(controller->irq) {
- if(request_irq(controller->irq,
- cpci_hp_intr,
- controller->irq_flags,
- MY_NAME, controller->dev_id)) {
- err("Can't get irq %d for the hotplug cPCI controller", controller->irq);
- status = -ENODEV;
- }
- dbg("%s - acquired controller irq %d", __FUNCTION__,
- controller->irq);
+ if (controller)
+ return -1;
+ if (!(new_controller && new_controller->ops))
+ return -EINVAL;
+ if (new_controller->irq) {
+ if (!(new_controller->ops->enable_irq &&
+ new_controller->ops->disable_irq))
+ status = -EINVAL;
+ if (request_irq(new_controller->irq,
+ cpci_hp_intr,
+ new_controller->irq_flags,
+ MY_NAME,
+ new_controller->dev_id)) {
+ err("Can't get irq %d for the hotplug cPCI controller",
+ new_controller->irq);
+ status = -ENODEV;
}
- } else {
- err("cPCI hotplug controller already registered");
- status = -1;
+ dbg("%s - acquired controller irq %d",
+ __FUNCTION__, new_controller->irq);
}
+ if (!status)
+ controller = new_controller;
return status;
}
+static void
+cleanup_slots(void)
+{
+ struct slot *slot;
+ struct slot *tmp;
+
+ /*
+ * Unregister all of our slots with the pci_hotplug subsystem,
+ * and free up all memory that we had allocated.
+ */
+ down_write(&list_rwsem);
+ if (!slots)
+ goto cleanup_null;
+ list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
+ list_del(&slot->slot_list);
+ pci_hp_deregister(slot->hotplug_slot);
+ }
+cleanup_null:
+ up_write(&list_rwsem);
+ return;
+}
+
int
cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
{
int status = 0;
- if(controller) {
- if(atomic_read(&extracting) != 0) {
- return -EBUSY;
- }
- if(!thread_finished) {
+ if (controller) {
+ if (!thread_finished)
cpci_stop_thread();
- }
- if(controller->irq) {
+ if (controller->irq)
free_irq(controller->irq, controller->dev_id);
- }
controller = NULL;
- } else {
+ cleanup_slots();
+ } else
status = -ENODEV;
- }
return status;
}
@@ -691,32 +700,28 @@ cpci_hp_start(void)
int status;
dbg("%s - enter", __FUNCTION__);
- if(!controller) {
+ if (!controller)
return -ENODEV;
- }
down_read(&list_rwsem);
- if(list_empty(&slot_list)) {
+ if (list_empty(&slot_list)) {
up_read(&list_rwsem);
return -ENODEV;
}
up_read(&list_rwsem);
- if(first) {
- status = init_slots();
- if(status) {
- return status;
- }
+ status = init_slots(first);
+ if (first)
first = 0;
- }
+ if (status)
+ return status;
status = cpci_start_thread();
- if(status) {
+ if (status)
return status;
- }
dbg("%s - thread started", __FUNCTION__);
- if(controller->irq) {
+ if (controller->irq) {
/* Start enum interrupt processing */
dbg("%s - enabling irq", __FUNCTION__);
controller->ops->enable_irq();
@@ -728,13 +733,9 @@ cpci_hp_start(void)
int
cpci_hp_stop(void)
{
- if(!controller) {
+ if (!controller)
return -ENODEV;
- }
- if(atomic_read(&extracting) != 0) {
- return -EBUSY;
- }
- if(controller->irq) {
+ if (controller->irq) {
/* Stop enum interrupt processing */
dbg("%s - disabling irq", __FUNCTION__);
controller->ops->disable_irq();
@@ -743,34 +744,6 @@ cpci_hp_stop(void)
return 0;
}
-static void __exit
-cleanup_slots(void)
-{
- struct list_head *tmp;
- struct slot *slot;
-
- /*
- * Unregister all of our slots with the pci_hotplug subsystem,
- * and free up all memory that we had allocated.
- */
- down_write(&list_rwsem);
- if(!slots) {
- goto null_cleanup;
- }
- list_for_each(tmp, &slot_list) {
- slot = list_entry(tmp, struct slot, slot_list);
- list_del(&slot->slot_list);
- pci_hp_deregister(slot->hotplug_slot);
- kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
- kfree(slot->hotplug_slot);
- kfree(slot);
- }
- null_cleanup:
- up_write(&list_rwsem);
- return;
-}
-
int __init
cpci_hotplug_init(int debug)
{
@@ -784,7 +757,8 @@ cpci_hotplug_exit(void)
/*
* Clean everything up.
*/
- cleanup_slots();
+ cpci_hp_stop();
+ cpci_hp_unregister_controller(controller);
}
EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 69eb4fc54f2..c878028ad21 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -1,7 +1,7 @@
/*
* CompactPCI Hot Plug Driver PCI functions
*
- * Copyright (C) 2002 by SOMA Networks, Inc.
+ * Copyright (C) 2002,2005 by SOMA Networks, Inc.
*
* All rights reserved.
*
@@ -38,10 +38,10 @@ extern int cpci_debug;
#define dbg(format, arg...) \
do { \
- if(cpci_debug) \
+ if (cpci_debug) \
printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \
- } while(0)
+ } while (0)
#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 warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
@@ -57,16 +57,15 @@ u8 cpci_get_attention_status(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return 0;
- }
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
return 0;
- }
+
return hs_csr & 0x0008 ? 1 : 0;
}
@@ -78,27 +77,22 @@ int cpci_set_attention_status(struct slot* slot, int status)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return 0;
- }
-
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
return 0;
- }
- if(status) {
+ if (status)
hs_csr |= HS_CSR_LOO;
- } else {
+ else
hs_csr &= ~HS_CSR_LOO;
- }
- if(pci_bus_write_config_word(slot->bus,
+ if (pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- hs_csr)) {
+ hs_csr))
return 0;
- }
return 1;
}
@@ -110,16 +104,13 @@ u16 cpci_get_hs_csr(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return 0xFFFF;
- }
-
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
return 0xFFFF;
- }
return hs_csr;
}
@@ -132,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return 0;
- }
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
return 0;
- }
- if(hs_csr & HS_CSR_INS) {
+ if (hs_csr & HS_CSR_INS) {
/* Clear INS (by setting it) */
- if(pci_bus_write_config_word(slot->bus,
+ if (pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- hs_csr)) {
+ hs_csr))
ins = 0;
- }
- ins = 1;
+ else
+ ins = 1;
}
return ins;
}
@@ -163,18 +152,15 @@ int cpci_check_ext(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return 0;
- }
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
return 0;
- }
- if(hs_csr & HS_CSR_EXT) {
+ if (hs_csr & HS_CSR_EXT)
ext = 1;
- }
return ext;
}
@@ -186,23 +172,20 @@ int cpci_clear_ext(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return -ENODEV;
- }
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
return -ENODEV;
- }
- if(hs_csr & HS_CSR_EXT) {
+ if (hs_csr & HS_CSR_EXT) {
/* Clear EXT (by setting it) */
- if(pci_bus_write_config_word(slot->bus,
+ if (pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- hs_csr)) {
+ hs_csr))
return -ENODEV;
- }
}
return 0;
}
@@ -215,18 +198,16 @@ int cpci_led_on(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return -ENODEV;
- }
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
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;
- if(pci_bus_write_config_word(slot->bus,
+ if (pci_bus_write_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
hs_csr)) {
@@ -246,18 +227,16 @@ int cpci_led_off(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn,
PCI_CAP_ID_CHSWP);
- if(!hs_cap) {
+ if (!hs_cap)
return -ENODEV;
- }
- if(pci_bus_read_config_word(slot->bus,
+ if (pci_bus_read_config_word(slot->bus,
slot->devfn,
hs_cap + 2,
- &hs_csr)) {
+ &hs_csr))
return -ENODEV;
- }
- if(hs_csr & HS_CSR_LOO) {
+ if (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,
hs_cap + 2,
hs_csr)) {
@@ -274,19 +253,6 @@ int cpci_led_off(struct slot* slot)
* 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)
{
unsigned char busnr;
@@ -294,14 +260,14 @@ int cpci_configure_slot(struct slot* slot)
dbg("%s - enter", __FUNCTION__);
- if(slot->dev == NULL) {
+ if (slot->dev == NULL) {
dbg("pci_dev null, finding %02x:%02x:%x",
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! */
- if(slot->dev == NULL) {
+ if (slot->dev == NULL) {
int n;
dbg("pci_dev still null");
@@ -311,10 +277,10 @@ int cpci_configure_slot(struct slot* slot)
*/
n = pci_scan_slot(slot->bus, slot->devfn);
dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
- if(n > 0)
+ if (n > 0)
pci_bus_add_devices(slot->bus);
- slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
- if(slot->dev == NULL) {
+ slot->dev = pci_get_slot(slot->bus, slot->devfn);
+ if (slot->dev == NULL) {
err("Could not find PCI device for slot %02x", slot->number);
return 1;
}
@@ -329,8 +295,6 @@ int cpci_configure_slot(struct slot* slot)
pci_bus_assign_resources(slot->dev->bus);
- cpci_enable_device(slot->dev);
-
dbg("%s - exit", __FUNCTION__);
return 0;
}
@@ -341,15 +305,15 @@ int cpci_unconfigure_slot(struct slot* slot)
struct pci_dev *dev;
dbg("%s - enter", __FUNCTION__);
- if(!slot->dev) {
+ if (!slot->dev) {
err("No device for slot %02x\n", slot->number);
return -ENODEV;
}
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));
- if(dev) {
+ if (dev) {
pci_remove_bus_device(dev);
slot->dev = NULL;
}
diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c
index 243a51d88b8..7957cdc72cd 100644
--- a/drivers/pci/hotplug/shpchprm_acpi.c
+++ b/drivers/pci/hotplug/shpchprm_acpi.c
@@ -1626,7 +1626,7 @@ int shpchprm_set_hpp(
pci_bus->number = func->bus;
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->_hpp) {
@@ -1681,7 +1681,7 @@ void shpchprm_enable_card(
| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
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->_hpp) {
if (ab->_hpp->enable_perr) {
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index da5bd33d982..fc5263c6b10 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
+#include <linux/dma-mapping.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
@@ -289,6 +290,8 @@ static void ahci_host_stop(struct ata_host_set *host_set)
{
struct ahci_host_priv *hpriv = host_set->private_data;
kfree(hpriv);
+
+ ata_host_stop(host_set);
}
static int ahci_port_start(struct ata_port *ap)
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 550c9921691..7c02b7dc709 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -2488,7 +2488,7 @@ ahd_linux_dv_thread(void *data)
sprintf(current->comm, "ahd_dv_%d", ahd->unit);
#else
daemonize("ahd_dv_%d", ahd->unit);
- current->flags |= PF_FREEZE;
+ current->flags |= PF_NOFREEZE;
#endif
unlock_kernel();
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index c2b00c9d40a..3be54643925 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -153,6 +153,7 @@ static struct ata_port_operations piix_pata_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static struct ata_port_operations piix_sata_ops = {
@@ -180,6 +181,7 @@ static struct ata_port_operations piix_sata_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static struct ata_port_info piix_port_info[] = {
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index a5d7c33a434..21d194c6ace 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -3666,6 +3666,13 @@ void ata_port_stop (struct ata_port *ap)
dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
}
+void ata_host_stop (struct ata_host_set *host_set)
+{
+ if (host_set->mmio_base)
+ iounmap(host_set->mmio_base);
+}
+
+
/**
* ata_host_remove - Unregister SCSI host structure with upper layers
* @ap: Port to unregister
@@ -4271,10 +4278,6 @@ void ata_pci_remove_one (struct pci_dev *pdev)
}
free_irq(host_set->irq, host_set);
- if (host_set->ops->host_stop)
- host_set->ops->host_stop(host_set);
- if (host_set->mmio_base)
- iounmap(host_set->mmio_base);
for (i = 0; i < host_set->n_ports; i++) {
ap = host_set->ports[i];
@@ -4293,6 +4296,9 @@ void ata_pci_remove_one (struct pci_dev *pdev)
scsi_host_put(ap->host);
}
+ if (host_set->ops->host_stop)
+ host_set->ops->host_stop(host_set);
+
kfree(host_set);
pci_release_regions(pdev);
@@ -4381,6 +4387,7 @@ EXPORT_SYMBOL_GPL(ata_chk_err);
EXPORT_SYMBOL_GPL(ata_exec_command);
EXPORT_SYMBOL_GPL(ata_port_start);
EXPORT_SYMBOL_GPL(ata_port_stop);
+EXPORT_SYMBOL_GPL(ata_host_stop);
EXPORT_SYMBOL_GPL(ata_interrupt);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 6518226b8f8..d90430bbb0d 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -26,7 +26,7 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
-#define DRV_VERSION "1.10" /* must be exactly four chars */
+#define DRV_VERSION "1.11" /* must be exactly four chars */
struct ata_scsi_args {
u16 *id;
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 69009f853a4..b0403ccd8a2 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -329,6 +329,8 @@ static void nv_host_stop (struct ata_host_set *host_set)
host->host_desc->disable_hotplug(host_set);
kfree(host);
+
+ ata_host_stop(host_set);
}
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index c4e9e029812..b18c90582e6 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -122,6 +122,7 @@ static struct ata_port_operations pdc_ata_ops = {
.scr_write = pdc_sata_scr_write,
.port_start = pdc_port_start,
.port_stop = pdc_port_stop,
+ .host_stop = ata_host_stop,
};
static struct ata_port_info pdc_port_info[] = {
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index dfd36210471..1383e8a28d7 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -536,6 +536,8 @@ static void qs_host_stop(struct ata_host_set *host_set)
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+
+ ata_host_stop(host_set);
}
static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 2b2ff48be39..238580d244e 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -161,6 +161,7 @@ static struct ata_port_operations sil_ops = {
.scr_write = sil_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static struct ata_port_info sil_port_info[] = {
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index 5105ddd0844..e418b89c6b9 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -114,6 +114,7 @@ static struct ata_port_operations sis_ops = {
.scr_write = sis_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static struct ata_port_info sis_port_info = {
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index 05075bd3a89..edef1fa969f 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -313,6 +313,7 @@ static struct ata_port_operations k2_sata_ops = {
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index 70118650c46..140cea05de3 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -245,6 +245,8 @@ static void pdc20621_host_stop(struct ata_host_set *host_set)
iounmap(dimm_mmio);
kfree(hpriv);
+
+ ata_host_stop(host_set);
}
static int pdc_port_start(struct ata_port *ap)
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 0bff4f475f2..a71fb54eebd 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -113,6 +113,7 @@ static struct ata_port_operations uli_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static struct ata_port_info uli_port_info = {
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 3a783066727..f43183c19a1 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -134,6 +134,7 @@ static struct ata_port_operations svia_sata_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static struct ata_port_info svia_port_info = {
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 2c28f0ad73c..c5e09dc6f3d 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -21,6 +21,7 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
@@ -230,6 +231,7 @@ static struct ata_port_operations vsc_sata_ops = {
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
};
static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 3196c3265ff..19e598c9641 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -124,3 +124,14 @@ config USB_SL811_HCD
To compile this driver as a module, choose M here: the
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".
+
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index a574ca06cf6..5dbd3e7a27c 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -7,4 +7,5 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-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
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index a374b769207..99d43f758ad 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -2,8 +2,8 @@
* SL811HS HCD (Host Controller Driver) for USB.
*
* 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
* Copyright (C) 1999 Roman Weissgaerber
*
@@ -15,7 +15,7 @@
* For documentation, see the SL811HS spec and the "SL811HS Embedded Host"
* document (providing significant pieces missing from that spec); plus
* the SL811S spec if you want peripheral side info.
- */
+ */
/*
* Status: Passed basic stress testing, works with hubs, mice, keyboards,
@@ -67,7 +67,7 @@
MODULE_DESCRIPTION("SL811HS USB Host Controller Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION "15 Dec 2004"
+#define DRIVER_VERSION "19 May 2005"
#ifndef DEBUG
@@ -121,6 +121,10 @@ static void port_power(struct sl811 *sl811, int is_on)
/* reset as thoroughly as we can */
if (sl811->board && sl811->board->reset)
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_CTLREG1, sl811->ctrl1);
@@ -443,6 +447,7 @@ static void finish_request(
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = status;
+ urb->hcpriv = NULL;
spin_unlock(&urb->lock);
spin_unlock(&sl811->lock);
@@ -472,7 +477,7 @@ static void finish_request(
if (*prev)
*prev = ep->next;
sl811->load[i] -= ep->load;
- }
+ }
ep->branch = PERIODIC_SIZE;
sl811->periodic_count--;
sl811_to_hcd(sl811)->self.bandwidth_allocated
@@ -661,9 +666,9 @@ retry:
#ifdef QUIRK2
/* this may no longer be necessary ... */
- if (irqstat == 0 && ret == IRQ_NONE) {
+ if (irqstat == 0) {
irqstat = checkdone(sl811);
- if (irqstat /* && irq != ~0 */ )
+ if (irqstat)
sl811->stat_lost++;
}
#endif
@@ -722,7 +727,8 @@ retry:
if (sl811->active_a) {
sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
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),
NULL, -ESHUTDOWN);
sl811->active_a = NULL;
@@ -731,7 +737,8 @@ retry:
if (sl811->active_b) {
sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
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),
NULL, -ESHUTDOWN);
sl811->active_b = NULL;
@@ -761,7 +768,7 @@ retry:
goto retry;
}
- if (sl811->periodic_count == 0 && list_empty(&sl811->async))
+ if (sl811->periodic_count == 0 && list_empty(&sl811->async))
sofirq_off(sl811);
sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
@@ -796,7 +803,7 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
}
if (j < PERIODIC_SIZE)
continue;
- branch = i;
+ branch = i;
}
}
return branch;
@@ -890,6 +897,7 @@ static int sl811h_urb_enqueue(
break;
}
+ ep->hep = hep;
hep->hcpriv = ep;
}
@@ -961,15 +969,16 @@ fail:
static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
- struct usb_host_endpoint *hep = urb->hcpriv;
+ struct usb_host_endpoint *hep;
unsigned long flags;
struct sl811h_ep *ep;
int retval = 0;
+ spin_lock_irqsave(&sl811->lock, flags);
+ hep = urb->hcpriv;
if (!hep)
- return -EINVAL;
+ goto fail;
- spin_lock_irqsave(&sl811->lock, flags);
ep = hep->hcpriv;
if (ep) {
/* 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)
VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
} else
+fail:
retval = -EINVAL;
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
@@ -1576,6 +1586,9 @@ sl811h_start(struct usb_hcd *hcd)
if (sl811->board && sl811->board->power)
hub_set_power_budget(udev, sl811->board->power * 2);
+ /* enable power and interupts */
+ port_power(sl811, 1);
+
return 0;
}
@@ -1618,7 +1631,7 @@ static struct hc_driver sl811h_hc_driver = {
/*-------------------------------------------------------------------------*/
-static int __init_or_module
+static int __devexit
sl811h_remove(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -1631,21 +1644,20 @@ sl811h_remove(struct device *dev)
remove_debug_file(sl811);
usb_remove_hcd(hcd);
- iounmap(sl811->data_reg);
+ /* some platforms may use IORESOURCE_IO */
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);
- release_mem_region(res->start, 1);
+ if (res)
+ iounmap(sl811->addr_reg);
usb_put_hcd(hcd);
return 0;
}
-#define resource_len(r) (((r)->end - (r)->start) + 1)
-
-static int __init
+static int __devinit
sl811h_probe(struct device *dev)
{
struct usb_hcd *hcd;
@@ -1656,7 +1668,7 @@ sl811h_probe(struct device *dev)
void __iomem *addr_reg;
void __iomem *data_reg;
int retval;
- u8 tmp;
+ u8 tmp, ioaddr = 0;
/* basic sanity checks first. board-specific init logic should
* have initialized these three resources and probably board
@@ -1664,13 +1676,8 @@ sl811h_probe(struct device *dev)
* minimal sanity checking.
*/
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);
- if (!addr || !data || irq < 0)
+ if (pdev->num_resources < 3 || irq < 0)
return -ENODEV;
/* refuse to confuse usbcore */
@@ -1679,24 +1686,31 @@ sl811h_probe(struct device *dev)
return -EINVAL;
}
- if (!request_mem_region(addr->start, 1, hcd_name)) {
- retval = -EBUSY;
- goto err1;
- }
- addr_reg = ioremap(addr->start, resource_len(addr));
- if (addr_reg == NULL) {
- retval = -ENOMEM;
- goto err2;
- }
+ /* the chip may be wired for either kind of addressing */
+ addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ retval = -EBUSY;
+ if (!addr || !data) {
+ addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ data = platform_get_resource(pdev, IORESOURCE_IO, 1);
+ 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)) {
- retval = -EBUSY;
- goto err3;
- }
- data_reg = ioremap(data->start, resource_len(addr));
- if (data_reg == NULL) {
- retval = -ENOMEM;
- goto err4;
+ data_reg = ioremap(data->start, 1);
+ if (data_reg == NULL) {
+ retval = -ENOMEM;
+ goto err4;
+ }
}
/* allocate and initialize hcd */
@@ -1737,12 +1751,14 @@ sl811h_probe(struct device *dev)
goto err6;
}
- /* sl811s would need a different handler for this irq */
-#ifdef CONFIG_ARM
- /* Cypress docs say the IRQ is IRQT_HIGH ... */
- set_irq_type(irq, IRQT_RISING);
-#endif
- retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ /* The chip's IRQ is level triggered, active high. A requirement
+ * for platform device setup is to cope with things like signal
+ * inverters (e.g. CF is active low) or working only with edge
+ * triggers (e.g. most ARM CPUs). Initial driver stress testing
+ * was on a system with single edge triggering, so most sorts of
+ * triggering arrangement should work.
+ */
+ retval = usb_add_hcd(hcd, irq, SA_INTERRUPT | SA_SHIRQ);
if (retval != 0)
goto err6;
@@ -1752,14 +1768,12 @@ sl811h_probe(struct device *dev)
err6:
usb_put_hcd(hcd);
err5:
- iounmap(data_reg);
+ if (!ioaddr)
+ iounmap(data_reg);
err4:
- release_mem_region(data->start, 1);
- err3:
- iounmap(addr_reg);
+ if (!ioaddr)
+ iounmap(addr_reg);
err2:
- release_mem_region(addr->start, 1);
- err1:
DBG("init error, %d\n", retval);
return retval;
}
@@ -1767,7 +1781,7 @@ sl811h_probe(struct device *dev)
#ifdef CONFIG_PM
/* 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.
*/
@@ -1821,20 +1835,22 @@ sl811h_resume(struct device *dev, u32 phase)
#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,
.bus = &platform_bus_type,
.probe = sl811h_probe,
- .remove = sl811h_remove,
+ .remove = __devexit_p(sl811h_remove),
.suspend = sl811h_suspend,
.resume = sl811h_resume,
};
+EXPORT_SYMBOL(sl811h_driver);
/*-------------------------------------------------------------------------*/
-
-static int __init sl811h_init(void)
+
+static int __init sl811h_init(void)
{
if (usb_disabled())
return -ENODEV;
@@ -1844,8 +1860,8 @@ static int __init sl811h_init(void)
}
module_init(sl811h_init);
-static void __exit sl811h_cleanup(void)
-{
+static void __exit sl811h_cleanup(void)
+{
driver_unregister(&sl811h_driver);
}
module_exit(sl811h_cleanup);
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
new file mode 100644
index 00000000000..6e173265095
--- /dev/null
+++ b/drivers/usb/host/sl811_cs.c
@@ -0,0 +1,442 @@
+/*
+ * PCMCIA driver for SL811HS (as found in REX-CFU1U)
+ * Filename: sl811_cs.c
+ * Author: Yukio Yamamoto
+ *
+ * Port to sl811-hcd and 2.6.x by
+ * Botond Botyanszki <boti@rocketmail.com>
+ * Simon Pickering
+ *
+ * Last update: 2005-05-12
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include <linux/usb_sl811.h>
+
+MODULE_AUTHOR("Botond Botyanszki");
+MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6");
+MODULE_LICENSE("GPL");
+
+
+/*====================================================================*/
+/* MACROS */
+/*====================================================================*/
+
+#if defined(DEBUG) || defined(CONFIG_USB_DEBUG) || defined(PCMCIA_DEBUG)
+
+static int pc_debug = 0;
+module_param(pc_debug, int, 0644);
+
+#define DBG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG "sl811_cs: " args)
+
+#else
+#define DBG(n, args...) do{}while(0)
+#endif /* no debugging */
+
+#define INFO(args...) printk(KERN_INFO "sl811_cs: " args)
+
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
+
+#define CS_CHECK(fn, ret) \
+ do { \
+ last_fn = (fn); \
+ if ((last_ret = (ret)) != 0) \
+ goto cs_failed; \
+ } while (0)
+
+/*====================================================================*/
+/* VARIABLES */
+/*====================================================================*/
+
+static const char driver_name[DEV_NAME_LEN] = "sl811_cs";
+
+static dev_link_t *dev_list = NULL;
+
+static int irq_list[4] = { -1 };
+static int irq_list_count;
+
+module_param_array(irq_list, int, &irq_list_count, 0444);
+
+INT_MODULE_PARM(irq_mask, 0xdeb8);
+
+typedef struct local_info_t {
+ dev_link_t link;
+ dev_node_t node;
+} local_info_t;
+
+/*====================================================================*/
+
+static void release_platform_dev(struct device * dev)
+{
+ DBG(0, "sl811_cs platform_dev release\n");
+ dev->parent = NULL;
+}
+
+static struct sl811_platform_data platform_data = {
+ .potpg = 100,
+ .power = 50, /* == 100mA */
+ // .reset = ... FIXME: invoke CF reset on the card
+};
+
+static struct resource resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ },
+ [1] = {
+ // .name = "address",
+ .flags = IORESOURCE_IO,
+ },
+ [2] = {
+ // .name = "data",
+ .flags = IORESOURCE_IO,
+ },
+};
+
+extern struct device_driver sl811h_driver;
+
+static struct platform_device platform_dev = {
+ .id = -1,
+ .dev = {
+ .platform_data = &platform_data,
+ .release = release_platform_dev,
+ },
+ .resource = resources,
+ .num_resources = ARRAY_SIZE(resources),
+};
+
+static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq)
+{
+ if (platform_dev.dev.parent)
+ return -EBUSY;
+ platform_dev.dev.parent = parent;
+
+ /* finish seting up the platform device */
+ resources[0].start = irq;
+
+ resources[1].start = base_addr;
+ resources[1].end = base_addr;
+
+ resources[2].start = base_addr + 1;
+ resources[2].end = base_addr + 1;
+
+ /* The driver core will probe for us. We know sl811-hcd has been
+ * initialized already because of the link order dependency.
+ */
+ platform_dev.name = sl811h_driver.name;
+ return platform_device_register(&platform_dev);
+}
+
+/*====================================================================*/
+
+static void sl811_cs_detach(dev_link_t *link)
+{
+ dev_link_t **linkp;
+
+ DBG(0, "sl811_cs_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) {
+ if (*linkp == link)
+ break;
+ }
+ if (*linkp == NULL)
+ return;
+
+ /* Break the link with Card Services */
+ if (link->handle)
+ pcmcia_deregister_client(link->handle);
+
+ /* Unlink device structure, and free it */
+ *linkp = link->next;
+ /* This points to the parent local_info_t struct */
+ kfree(link->priv);
+}
+
+static void sl811_cs_release(dev_link_t * link)
+{
+
+ DBG(0, "sl811_cs_release(0x%p)\n", link);
+
+ if (link->open) {
+ DBG(1, "sl811_cs: release postponed, '%s' still open\n",
+ link->dev->dev_name);
+ link->state |= DEV_STALE_CONFIG;
+ return;
+ }
+
+ /* Unlink the device chain */
+ link->dev = NULL;
+
+ platform_device_unregister(&platform_dev);
+ pcmcia_release_configuration(link->handle);
+ if (link->io.NumPorts1)
+ pcmcia_release_io(link->handle, &link->io);
+ if (link->irq.AssignedIRQ)
+ pcmcia_release_irq(link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
+
+ if (link->state & DEV_STALE_LINK)
+ sl811_cs_detach(link);
+}
+
+static void sl811_cs_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ struct device *parent = &handle_to_dev(handle);
+ local_info_t *dev = link->priv;
+ tuple_t tuple;
+ cisparse_t parse;
+ int last_fn, last_ret;
+ u_char buf[64];
+ config_info_t conf;
+ cistpl_cftable_entry_t dflt = { 0 };
+
+ DBG(0, "sl811_cs_config(0x%p)\n", link);
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ /* Look up the current Vcc */
+ CS_CHECK(GetConfigurationInfo,
+ pcmcia_get_configuration_info(handle, &conf));
+ link->conf.Vcc = conf.Vcc;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ while (1) {
+ cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+
+ if (pcmcia_get_tuple_data(handle, &tuple) != 0
+ || pcmcia_parse_tuple(handle, &tuple, &parse)
+ != 0)
+ goto next_entry;
+
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT) {
+ dflt = *cfg;
+ }
+
+ if (cfg->index == 0)
+ goto next_entry;
+
+ link->conf.ConfigIndex = cfg->index;
+
+ /* Use power settings for Vcc and Vpp if present */
+ /* Note that the CIS values need to be rescaled */
+ if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+ if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000
+ != conf.Vcc)
+ goto next_entry;
+ } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+ if (dflt.vcc.param[CISTPL_POWER_VNOM]/10000
+ != conf.Vcc)
+ goto next_entry;
+ }
+
+ if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+ else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+ /* we need an interrupt */
+ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+ link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+ /* IO window settings */
+ link->io.NumPorts1 = link->io.NumPorts2 = 0;
+ if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+ link->io.BasePort1 = io->win[0].base;
+ link->io.NumPorts1 = io->win[0].len;
+
+ if (pcmcia_request_io(link->handle, &link->io) != 0)
+ goto next_entry;
+ }
+ break;
+
+next_entry:
+ if (link->io.NumPorts1)
+ pcmcia_release_io(link->handle, &link->io);
+ last_ret = pcmcia_get_next_tuple(handle, &tuple);
+ }
+
+ /* require an IRQ and two registers */
+ if (!link->io.NumPorts1 || link->io.NumPorts1 < 2)
+ goto cs_failed;
+ if (link->conf.Attributes & CONF_ENABLE_IRQ)
+ CS_CHECK(RequestIRQ,
+ pcmcia_request_irq(link->handle, &link->irq));
+ else
+ goto cs_failed;
+
+ CS_CHECK(RequestConfiguration,
+ pcmcia_request_configuration(link->handle, &link->conf));
+
+ sprintf(dev->node.dev_name, driver_name);
+ dev->node.major = dev->node.minor = 0;
+ link->dev = &dev->node;
+
+ printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+ dev->node.dev_name, link->conf.ConfigIndex,
+ link->conf.Vcc/10, link->conf.Vcc%10);
+ if (link->conf.Vpp1)
+ printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+ printk(", irq %d", link->irq.AssignedIRQ);
+ printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+ link->io.BasePort1+link->io.NumPorts1-1);
+ printk("\n");
+
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ)
+ < 0) {
+cs_failed:
+ printk("sl811_cs_config failed\n");
+ cs_error(link->handle, last_fn, last_ret);
+ sl811_cs_release(link);
+ link->state &= ~DEV_CONFIG_PENDING;
+ }
+}
+
+static int
+sl811_cs_event(event_t event, int priority, event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DBG(1, "sl811_cs_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG)
+ sl811_cs_release(link);
+ break;
+
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ sl811_cs_config(link);
+ break;
+
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ pcmcia_release_configuration(link->handle);
+ break;
+
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (link->state & DEV_CONFIG)
+ pcmcia_request_configuration(link->handle, &link->conf);
+ DBG(0, "reset sl811-hcd here?\n");
+ break;
+ }
+ return 0;
+}
+
+static dev_link_t *sl811_cs_attach(void)
+{
+ local_info_t *local;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int ret, i;
+
+ local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ if (!local)
+ return NULL;
+ memset(local, 0, sizeof(local_info_t));
+ link = &local->link;
+ link->priv = local;
+
+ /* Initialize */
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+ if (irq_list[0] == -1)
+ link->irq.IRQInfo2 = irq_mask;
+ else
+ for (i = 0; i < irq_list_count; i++)
+ link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->irq.Handler = NULL;
+
+ link->conf.Attributes = 0;
+ link->conf.Vcc = 33;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = (dev_info_t *) &driver_name;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &sl811_cs_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = pcmcia_register_client(&link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(link->handle, RegisterClient, ret);
+ sl811_cs_detach(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+static struct pcmcia_driver sl811_cs_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = (char *)driver_name,
+ },
+ .attach = sl811_cs_attach,
+ .detach = sl811_cs_detach,
+};
+
+/*====================================================================*/
+
+static int __init init_sl811_cs(void)
+{
+ return pcmcia_register_driver(&sl811_cs_driver);
+}
+module_init(init_sl811_cs);
+
+static void __exit exit_sl811_cs(void)
+{
+ pcmcia_unregister_driver(&sl811_cs_driver);
+}
+module_exit(exit_sl811_cs);
diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c
index 3e1e4fe20d8..53099190952 100644
--- a/drivers/usb/media/pwc/pwc-ctrl.c
+++ b/drivers/usb/media/pwc/pwc-ctrl.c
@@ -48,8 +48,6 @@
#include "pwc-uncompress.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
-#include "pwc-dec1.h"
-#include "pwc-dec23.h"
/* Request types: video */
#define SET_LUM_CTL 0x01
diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c
index c596083f06b..bc3b1635eab 100644
--- a/drivers/usb/media/pwc/pwc-uncompress.c
+++ b/drivers/usb/media/pwc/pwc-uncompress.c
@@ -29,8 +29,6 @@
#include "pwc.h"
#include "pwc-uncompress.h"
-#include "pwc-dec1.h"
-#include "pwc-dec23.h"
int pwc_decompress(struct pwc_device *pdev)
{
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 52394f08a94..051c3a77b41 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -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_4, 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(INTREPID_VID, INTREPID_VALUECAN_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 [] = {
{ 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_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_MASTERDEVEL2_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 [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_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_UM100_PID) },
{ 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_FUTURE_0_PID, 0x400, 0xffff) },
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index a52bb13a9ce..8866376823a 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -144,6 +144,8 @@
/* ELV USB Module UO100 (PID sent by Stefan Frings) */
#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
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 4536f63faae..5da76dd8fb2 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1297,13 +1297,6 @@ static int __init usb_serial_init(void)
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->driver_name = "usbserial";
usb_serial_tty_driver->devfs_name = "usb/tts/";
@@ -1329,17 +1322,24 @@ static int __init usb_serial_init(void)
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);
return result;
+exit_generic:
+ usb_deregister(&usb_serial_driver);
+
exit_tty:
tty_unregister_driver(usb_serial_tty_driver);
exit_reg_driver:
- usb_serial_generic_deregister();
-
-exit_generic:
bus_unregister(&usb_serial_bus_type);
exit_bus:
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 549e2293926..25f9a9a65c2 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -228,17 +228,17 @@ MODULE_DESCRIPTION(
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
-static int accel __initdata = 1;
-static int vram __initdata = 4;
-static int hwcursor __initdata = 1;
-static int mtrr __initdata = 1;
-static int fixed __initdata = 0;
-static int noinit __initdata = 0;
-static int noregister __initdata = 0;
-static int probeonly __initdata = 0;
-static int idonly __initdata = 0;
-static int bailearly __initdata = 0;
-static char *mode __initdata = NULL;
+static int accel = 1;
+static int vram = 4;
+static int hwcursor = 1;
+static int mtrr = 1;
+static int fixed = 0;
+static int noinit = 0;
+static int noregister = 0;
+static int probeonly = 0;
+static int idonly = 0;
+static int bailearly = 0;
+static char *mode = NULL;
module_param(accel, bool, S_IRUGO);
MODULE_PARM_DESC(accel, "Enable console acceleration");