summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2015-02-13 22:12:06 (GMT)
committerScott Wood <scottwood@freescale.com>2015-02-13 22:19:22 (GMT)
commit6faa2909871d8937cb2f79a10e1b21ffe193fac1 (patch)
treef558a94f1553814cc122ab8d9e04c0ebad5262a5 /drivers/misc
parentfcb2fb84301c673ee15ca04e7a2fc965712d49a0 (diff)
downloadlinux-fsl-qoriq-6faa2909871d8937cb2f79a10e1b21ffe193fac1.tar.xz
Reset to 3.12.37
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig42
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/hwlat_detector.c1240
-rw-r--r--drivers/misc/mei/bus.c2
-rw-r--r--drivers/misc/mei/client.c77
-rw-r--r--drivers/misc/mei/client.h18
-rw-r--r--drivers/misc/mei/hw-me-regs.h5
-rw-r--r--drivers/misc/mei/hw-me.c32
-rw-r--r--drivers/misc/mei/interrupt.c3
-rw-r--r--drivers/misc/mei/main.c3
-rw-r--r--drivers/misc/mei/nfc.c11
-rw-r--r--drivers/misc/mei/pci-me.c30
12 files changed, 115 insertions, 1349 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e9b20e8..8dacd4c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -63,7 +63,6 @@ config ATMEL_PWM
config ATMEL_TCLIB
bool "Atmel AT32/AT91 Timer/Counter Library"
depends on (AVR32 || ARCH_AT91)
- default y if PREEMPT_RT_FULL
help
Select this if you want a library to allocate the Timer/Counter
blocks found on many Atmel processors. This facilitates using
@@ -79,7 +78,8 @@ config ATMEL_TCB_CLKSRC
are combined to make a single 32-bit timer.
When GENERIC_CLOCKEVENTS is defined, the third timer channel
- may be used as a clock event device supporting oneshot mode.
+ may be used as a clock event device supporting oneshot mode
+ (delays of up to two seconds) based on the 32 KiHz clock.
config ATMEL_TCB_CLKSRC_BLOCK
int
@@ -93,15 +93,6 @@ config ATMEL_TCB_CLKSRC_BLOCK
TC can be used for other purposes, such as PWM generation and
interval timing.
-config ATMEL_TCB_CLKSRC_USE_SLOW_CLOCK
- bool "TC Block use 32 KiHz clock"
- depends on ATMEL_TCB_CLKSRC
- default y if !PREEMPT_RT_FULL
- help
- Select this to use 32 KiHz base clock rate as TC block clock
- source for clock events.
-
-
config DUMMY_IRQ
tristate "Dummy IRQ handler"
default n
@@ -131,35 +122,6 @@ config IBM_ASM
for information on the specific driver level and support statement
for your IBM server.
-config HWLAT_DETECTOR
- tristate "Testing module to detect hardware-induced latencies"
- depends on DEBUG_FS
- depends on RING_BUFFER
- default m
- ---help---
- A simple hardware latency detector. Use this module to detect
- large latencies introduced by the behavior of the underlying
- system firmware external to Linux. We do this using periodic
- use of stop_machine to grab all available CPUs and measure
- for unexplainable gaps in the CPU timestamp counter(s). By
- default, the module is not enabled until the "enable" file
- within the "hwlat_detector" debugfs directory is toggled.
-
- This module is often used to detect SMI (System Management
- Interrupts) on x86 systems, though is not x86 specific. To
- this end, we default to using a sample window of 1 second,
- during which we will sample for 0.5 seconds. If an SMI or
- similar event occurs during that time, it is recorded
- into an 8K samples global ring buffer until retreived.
-
- WARNING: This software should never be enabled (it can be built
- but should not be turned on after it is loaded) in a production
- environment where high latencies are a concern since the
- sampling mechanism actually introduces latencies for
- regular tasks while the CPU(s) are being held.
-
- If unsure, say N
-
config PHANTOM
tristate "Sensable PHANToM (PCI)"
depends on PCI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 6bb08da40..c235d5b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,4 +53,3 @@ obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o
-obj-$(CONFIG_HWLAT_DETECTOR) += hwlat_detector.o
diff --git a/drivers/misc/hwlat_detector.c b/drivers/misc/hwlat_detector.c
deleted file mode 100644
index 2429c43..0000000
--- a/drivers/misc/hwlat_detector.c
+++ /dev/null
@@ -1,1240 +0,0 @@
-/*
- * hwlat_detector.c - A simple Hardware Latency detector.
- *
- * Use this module to detect large system latencies induced by the behavior of
- * certain underlying system hardware or firmware, independent of Linux itself.
- * The code was developed originally to detect the presence of SMIs on Intel
- * and AMD systems, although there is no dependency upon x86 herein.
- *
- * The classical example usage of this module is in detecting the presence of
- * SMIs or System Management Interrupts on Intel and AMD systems. An SMI is a
- * somewhat special form of hardware interrupt spawned from earlier CPU debug
- * modes in which the (BIOS/EFI/etc.) firmware arranges for the South Bridge
- * LPC (or other device) to generate a special interrupt under certain
- * circumstances, for example, upon expiration of a special SMI timer device,
- * due to certain external thermal readings, on certain I/O address accesses,
- * and other situations. An SMI hits a special CPU pin, triggers a special
- * SMI mode (complete with special memory map), and the OS is unaware.
- *
- * Although certain hardware-inducing latencies are necessary (for example,
- * a modern system often requires an SMI handler for correct thermal control
- * and remote management) they can wreak havoc upon any OS-level performance
- * guarantees toward low-latency, especially when the OS is not even made
- * aware of the presence of these interrupts. For this reason, we need a
- * somewhat brute force mechanism to detect these interrupts. In this case,
- * we do it by hogging all of the CPU(s) for configurable timer intervals,
- * sampling the built-in CPU timer, looking for discontiguous readings.
- *
- * WARNING: This implementation necessarily introduces latencies. Therefore,
- * you should NEVER use this module in a production environment
- * requiring any kind of low-latency performance guarantee(s).
- *
- * Copyright (C) 2008-2009 Jon Masters, Red Hat, Inc. <jcm@redhat.com>
- *
- * Includes useful feedback from Clark Williams <clark@redhat.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ring_buffer.h>
-#include <linux/time.h>
-#include <linux/hrtimer.h>
-#include <linux/kthread.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-#include <linux/version.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/trace_clock.h>
-
-#define BUF_SIZE_DEFAULT 262144UL /* 8K*(sizeof(entry)) */
-#define BUF_FLAGS (RB_FL_OVERWRITE) /* no block on full */
-#define U64STR_SIZE 22 /* 20 digits max */
-
-#define VERSION "1.0.0"
-#define BANNER "hwlat_detector: "
-#define DRVNAME "hwlat_detector"
-#define DEFAULT_SAMPLE_WINDOW 1000000 /* 1s */
-#define DEFAULT_SAMPLE_WIDTH 500000 /* 0.5s */
-#define DEFAULT_LAT_THRESHOLD 10 /* 10us */
-
-/* Module metadata */
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jon Masters <jcm@redhat.com>");
-MODULE_DESCRIPTION("A simple hardware latency detector");
-MODULE_VERSION(VERSION);
-
-/* Module parameters */
-
-static int debug;
-static int enabled;
-static int threshold;
-
-module_param(debug, int, 0); /* enable debug */
-module_param(enabled, int, 0); /* enable detector */
-module_param(threshold, int, 0); /* latency threshold */
-
-/* Buffering and sampling */
-
-static struct ring_buffer *ring_buffer; /* sample buffer */
-static DEFINE_MUTEX(ring_buffer_mutex); /* lock changes */
-static unsigned long buf_size = BUF_SIZE_DEFAULT;
-static struct task_struct *kthread; /* sampling thread */
-
-/* DebugFS filesystem entries */
-
-static struct dentry *debug_dir; /* debugfs directory */
-static struct dentry *debug_max; /* maximum TSC delta */
-static struct dentry *debug_count; /* total detect count */
-static struct dentry *debug_sample_width; /* sample width us */
-static struct dentry *debug_sample_window; /* sample window us */
-static struct dentry *debug_sample; /* raw samples us */
-static struct dentry *debug_threshold; /* threshold us */
-static struct dentry *debug_enable; /* enable/disable */
-
-/* Individual samples and global state */
-
-struct sample; /* latency sample */
-struct data; /* Global state */
-
-/* Sampling functions */
-static int __buffer_add_sample(struct sample *sample);
-static struct sample *buffer_get_sample(struct sample *sample);
-
-/* Threading and state */
-static int kthread_fn(void *unused);
-static int start_kthread(void);
-static int stop_kthread(void);
-static void __reset_stats(void);
-static int init_stats(void);
-
-/* Debugfs interface */
-static ssize_t simple_data_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos, const u64 *entry);
-static ssize_t simple_data_write(struct file *filp, const char __user *ubuf,
- size_t cnt, loff_t *ppos, u64 *entry);
-static int debug_sample_fopen(struct inode *inode, struct file *filp);
-static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos);
-static int debug_sample_release(struct inode *inode, struct file *filp);
-static int debug_enable_fopen(struct inode *inode, struct file *filp);
-static ssize_t debug_enable_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos);
-static ssize_t debug_enable_fwrite(struct file *file,
- const char __user *user_buffer,
- size_t user_size, loff_t *offset);
-
-/* Initialization functions */
-static int init_debugfs(void);
-static void free_debugfs(void);
-static int detector_init(void);
-static void detector_exit(void);
-
-/* Individual latency samples are stored here when detected and packed into
- * the ring_buffer circular buffer, where they are overwritten when
- * more than buf_size/sizeof(sample) samples are received. */
-struct sample {
- u64 seqnum; /* unique sequence */
- u64 duration; /* ktime delta */
- u64 outer_duration; /* ktime delta (outer loop) */
- struct timespec timestamp; /* wall time */
- unsigned long lost;
-};
-
-/* keep the global state somewhere. */
-static struct data {
-
- struct mutex lock; /* protect changes */
-
- u64 count; /* total since reset */
- u64 max_sample; /* max hardware latency */
- u64 threshold; /* sample threshold level */
-
- u64 sample_window; /* total sampling window (on+off) */
- u64 sample_width; /* active sampling portion of window */
-
- atomic_t sample_open; /* whether the sample file is open */
-
- wait_queue_head_t wq; /* waitqeue for new sample values */
-
-} data;
-
-/**
- * __buffer_add_sample - add a new latency sample recording to the ring buffer
- * @sample: The new latency sample value
- *
- * This receives a new latency sample and records it in a global ring buffer.
- * No additional locking is used in this case.
- */
-static int __buffer_add_sample(struct sample *sample)
-{
- return ring_buffer_write(ring_buffer,
- sizeof(struct sample), sample);
-}
-
-/**
- * buffer_get_sample - remove a hardware latency sample from the ring buffer
- * @sample: Pre-allocated storage for the sample
- *
- * This retrieves a hardware latency sample from the global circular buffer
- */
-static struct sample *buffer_get_sample(struct sample *sample)
-{
- struct ring_buffer_event *e = NULL;
- struct sample *s = NULL;
- unsigned int cpu = 0;
-
- if (!sample)
- return NULL;
-
- mutex_lock(&ring_buffer_mutex);
- for_each_online_cpu(cpu) {
- e = ring_buffer_consume(ring_buffer, cpu, NULL, &sample->lost);
- if (e)
- break;
- }
-
- if (e) {
- s = ring_buffer_event_data(e);
- memcpy(sample, s, sizeof(struct sample));
- } else
- sample = NULL;
- mutex_unlock(&ring_buffer_mutex);
-
- return sample;
-}
-
-#ifndef CONFIG_TRACING
-#define time_type ktime_t
-#define time_get() ktime_get()
-#define time_to_us(x) ktime_to_us(x)
-#define time_sub(a, b) ktime_sub(a, b)
-#define init_time(a, b) (a).tv64 = b
-#define time_u64(a) ((a).tv64)
-#else
-#define time_type u64
-#define time_get() trace_clock_local()
-#define time_to_us(x) div_u64(x, 1000)
-#define time_sub(a, b) ((a) - (b))
-#define init_time(a, b) (a = b)
-#define time_u64(a) a
-#endif
-/**
- * get_sample - sample the CPU TSC and look for likely hardware latencies
- *
- * Used to repeatedly capture the CPU TSC (or similar), looking for potential
- * hardware-induced latency. Called with interrupts disabled and with
- * data.lock held.
- */
-static int get_sample(void)
-{
- time_type start, t1, t2, last_t2;
- s64 diff, total = 0;
- u64 sample = 0;
- u64 outer_sample = 0;
- int ret = -1;
-
- init_time(last_t2, 0);
- start = time_get(); /* start timestamp */
-
- do {
-
- t1 = time_get(); /* we'll look for a discontinuity */
- t2 = time_get();
-
- if (time_u64(last_t2)) {
- /* Check the delta from outer loop (t2 to next t1) */
- diff = time_to_us(time_sub(t1, last_t2));
- /* This shouldn't happen */
- if (diff < 0) {
- pr_err(BANNER "time running backwards\n");
- goto out;
- }
- if (diff > outer_sample)
- outer_sample = diff;
- }
- last_t2 = t2;
-
- total = time_to_us(time_sub(t2, start)); /* sample width */
-
- /* This checks the inner loop (t1 to t2) */
- diff = time_to_us(time_sub(t2, t1)); /* current diff */
-
- /* This shouldn't happen */
- if (diff < 0) {
- pr_err(BANNER "time running backwards\n");
- goto out;
- }
-
- if (diff > sample)
- sample = diff; /* only want highest value */
-
- } while (total <= data.sample_width);
-
- ret = 0;
-
- /* If we exceed the threshold value, we have found a hardware latency */
- if (sample > data.threshold || outer_sample > data.threshold) {
- struct sample s;
-
- ret = 1;
-
- data.count++;
- s.seqnum = data.count;
- s.duration = sample;
- s.outer_duration = outer_sample;
- s.timestamp = CURRENT_TIME;
- __buffer_add_sample(&s);
-
- /* Keep a running maximum ever recorded hardware latency */
- if (sample > data.max_sample)
- data.max_sample = sample;
- }
-
-out:
- return ret;
-}
-
-/*
- * kthread_fn - The CPU time sampling/hardware latency detection kernel thread
- * @unused: A required part of the kthread API.
- *
- * Used to periodically sample the CPU TSC via a call to get_sample. We
- * disable interrupts, which does (intentionally) introduce latency since we
- * need to ensure nothing else might be running (and thus pre-empting).
- * Obviously this should never be used in production environments.
- *
- * Currently this runs on which ever CPU it was scheduled on, but most
- * real-worald hardware latency situations occur across several CPUs,
- * but we might later generalize this if we find there are any actualy
- * systems with alternate SMI delivery or other hardware latencies.
- */
-static int kthread_fn(void *unused)
-{
- int ret;
- u64 interval;
-
- while (!kthread_should_stop()) {
-
- mutex_lock(&data.lock);
-
- local_irq_disable();
- ret = get_sample();
- local_irq_enable();
-
- if (ret > 0)
- wake_up(&data.wq); /* wake up reader(s) */
-
- interval = data.sample_window - data.sample_width;
- do_div(interval, USEC_PER_MSEC); /* modifies interval value */
-
- mutex_unlock(&data.lock);
-
- if (msleep_interruptible(interval))
- break;
- }
-
- return 0;
-}
-
-/**
- * start_kthread - Kick off the hardware latency sampling/detector kthread
- *
- * This starts a kernel thread that will sit and sample the CPU timestamp
- * counter (TSC or similar) and look for potential hardware latencies.
- */
-static int start_kthread(void)
-{
- kthread = kthread_run(kthread_fn, NULL,
- DRVNAME);
- if (IS_ERR(kthread)) {
- pr_err(BANNER "could not start sampling thread\n");
- enabled = 0;
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/**
- * stop_kthread - Inform the hardware latency samping/detector kthread to stop
- *
- * This kicks the running hardware latency sampling/detector kernel thread and
- * tells it to stop sampling now. Use this on unload and at system shutdown.
- */
-static int stop_kthread(void)
-{
- int ret;
-
- ret = kthread_stop(kthread);
-
- return ret;
-}
-
-/**
- * __reset_stats - Reset statistics for the hardware latency detector
- *
- * We use data to store various statistics and global state. We call this
- * function in order to reset those when "enable" is toggled on or off, and
- * also at initialization. Should be called with data.lock held.
- */
-static void __reset_stats(void)
-{
- data.count = 0;
- data.max_sample = 0;
- ring_buffer_reset(ring_buffer); /* flush out old sample entries */
-}
-
-/**
- * init_stats - Setup global state statistics for the hardware latency detector
- *
- * We use data to store various statistics and global state. We also use
- * a global ring buffer (ring_buffer) to keep raw samples of detected hardware
- * induced system latencies. This function initializes these structures and
- * allocates the global ring buffer also.
- */
-static int init_stats(void)
-{
- int ret = -ENOMEM;
-
- mutex_init(&data.lock);
- init_waitqueue_head(&data.wq);
- atomic_set(&data.sample_open, 0);
-
- ring_buffer = ring_buffer_alloc(buf_size, BUF_FLAGS);
-
- if (WARN(!ring_buffer, KERN_ERR BANNER
- "failed to allocate ring buffer!\n"))
- goto out;
-
- __reset_stats();
- data.threshold = threshold ?: DEFAULT_LAT_THRESHOLD; /* threshold us */
- data.sample_window = DEFAULT_SAMPLE_WINDOW; /* window us */
- data.sample_width = DEFAULT_SAMPLE_WIDTH; /* width us */
-
- ret = 0;
-
-out:
- return ret;
-
-}
-
-/*
- * simple_data_read - Wrapper read function for global state debugfs entries
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to read value into
- * @cnt: The maximum number of bytes to read
- * @ppos: The current "file" position
- * @entry: The entry to read from
- *
- * This function provides a generic read implementation for the global state
- * "data" structure debugfs filesystem entries. It would be nice to use
- * simple_attr_read directly, but we need to make sure that the data.lock
- * is held during the actual read.
- */
-static ssize_t simple_data_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos, const u64 *entry)
-{
- char buf[U64STR_SIZE];
- u64 val = 0;
- int len = 0;
-
- memset(buf, 0, sizeof(buf));
-
- if (!entry)
- return -EFAULT;
-
- mutex_lock(&data.lock);
- val = *entry;
- mutex_unlock(&data.lock);
-
- len = snprintf(buf, sizeof(buf), "%llu\n", (unsigned long long)val);
-
- return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
-
-}
-
-/*
- * simple_data_write - Wrapper write function for global state debugfs entries
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to write value from
- * @cnt: The maximum number of bytes to write
- * @ppos: The current "file" position
- * @entry: The entry to write to
- *
- * This function provides a generic write implementation for the global state
- * "data" structure debugfs filesystem entries. It would be nice to use
- * simple_attr_write directly, but we need to make sure that the data.lock
- * is held during the actual write.
- */
-static ssize_t simple_data_write(struct file *filp, const char __user *ubuf,
- size_t cnt, loff_t *ppos, u64 *entry)
-{
- char buf[U64STR_SIZE];
- int csize = min(cnt, sizeof(buf));
- u64 val = 0;
- int err = 0;
-
- memset(buf, '\0', sizeof(buf));
- if (copy_from_user(buf, ubuf, csize))
- return -EFAULT;
-
- buf[U64STR_SIZE-1] = '\0'; /* just in case */
- err = kstrtoull(buf, 10, &val);
- if (err)
- return -EINVAL;
-
- mutex_lock(&data.lock);
- *entry = val;
- mutex_unlock(&data.lock);
-
- return csize;
-}
-
-/**
- * debug_count_fopen - Open function for "count" debugfs entry
- * @inode: The in-kernel inode representation of the debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function provides an open implementation for the "count" debugfs
- * interface to the hardware latency detector.
- */
-static int debug_count_fopen(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-/**
- * debug_count_fread - Read function for "count" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to read value into
- * @cnt: The maximum number of bytes to read
- * @ppos: The current "file" position
- *
- * This function provides a read implementation for the "count" debugfs
- * interface to the hardware latency detector. Can be used to read the
- * number of latency readings exceeding the configured threshold since
- * the detector was last reset (e.g. by writing a zero into "count").
- */
-static ssize_t debug_count_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- return simple_data_read(filp, ubuf, cnt, ppos, &data.count);
-}
-
-/**
- * debug_count_fwrite - Write function for "count" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The user buffer that contains the value to write
- * @cnt: The maximum number of bytes to write to "file"
- * @ppos: The current position in the debugfs "file"
- *
- * This function provides a write implementation for the "count" debugfs
- * interface to the hardware latency detector. Can be used to write a
- * desired value, especially to zero the total count.
- */
-static ssize_t debug_count_fwrite(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
-{
- return simple_data_write(filp, ubuf, cnt, ppos, &data.count);
-}
-
-/**
- * debug_enable_fopen - Dummy open function for "enable" debugfs interface
- * @inode: The in-kernel inode representation of the debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function provides an open implementation for the "enable" debugfs
- * interface to the hardware latency detector.
- */
-static int debug_enable_fopen(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-/**
- * debug_enable_fread - Read function for "enable" debugfs interface
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to read value into
- * @cnt: The maximum number of bytes to read
- * @ppos: The current "file" position
- *
- * This function provides a read implementation for the "enable" debugfs
- * interface to the hardware latency detector. Can be used to determine
- * whether the detector is currently enabled ("0\n" or "1\n" returned).
- */
-static ssize_t debug_enable_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- char buf[4];
-
- if ((cnt < sizeof(buf)) || (*ppos))
- return 0;
-
- buf[0] = enabled ? '1' : '0';
- buf[1] = '\n';
- buf[2] = '\0';
- if (copy_to_user(ubuf, buf, strlen(buf)))
- return -EFAULT;
- return *ppos = strlen(buf);
-}
-
-/**
- * debug_enable_fwrite - Write function for "enable" debugfs interface
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The user buffer that contains the value to write
- * @cnt: The maximum number of bytes to write to "file"
- * @ppos: The current position in the debugfs "file"
- *
- * This function provides a write implementation for the "enable" debugfs
- * interface to the hardware latency detector. Can be used to enable or
- * disable the detector, which will have the side-effect of possibly
- * also resetting the global stats and kicking off the measuring
- * kthread (on an enable) or the converse (upon a disable).
- */
-static ssize_t debug_enable_fwrite(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
-{
- char buf[4];
- int csize = min(cnt, sizeof(buf));
- long val = 0;
- int err = 0;
-
- memset(buf, '\0', sizeof(buf));
- if (copy_from_user(buf, ubuf, csize))
- return -EFAULT;
-
- buf[sizeof(buf)-1] = '\0'; /* just in case */
- err = kstrtoul(buf, 10, &val);
- if (0 != err)
- return -EINVAL;
-
- if (val) {
- if (enabled)
- goto unlock;
- enabled = 1;
- __reset_stats();
- if (start_kthread())
- return -EFAULT;
- } else {
- if (!enabled)
- goto unlock;
- enabled = 0;
- err = stop_kthread();
- if (err) {
- pr_err(BANNER "cannot stop kthread\n");
- return -EFAULT;
- }
- wake_up(&data.wq); /* reader(s) should return */
- }
-unlock:
- return csize;
-}
-
-/**
- * debug_max_fopen - Open function for "max" debugfs entry
- * @inode: The in-kernel inode representation of the debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function provides an open implementation for the "max" debugfs
- * interface to the hardware latency detector.
- */
-static int debug_max_fopen(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-/**
- * debug_max_fread - Read function for "max" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to read value into
- * @cnt: The maximum number of bytes to read
- * @ppos: The current "file" position
- *
- * This function provides a read implementation for the "max" debugfs
- * interface to the hardware latency detector. Can be used to determine
- * the maximum latency value observed since it was last reset.
- */
-static ssize_t debug_max_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- return simple_data_read(filp, ubuf, cnt, ppos, &data.max_sample);
-}
-
-/**
- * debug_max_fwrite - Write function for "max" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The user buffer that contains the value to write
- * @cnt: The maximum number of bytes to write to "file"
- * @ppos: The current position in the debugfs "file"
- *
- * This function provides a write implementation for the "max" debugfs
- * interface to the hardware latency detector. Can be used to reset the
- * maximum or set it to some other desired value - if, then, subsequent
- * measurements exceed this value, the maximum will be updated.
- */
-static ssize_t debug_max_fwrite(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
-{
- return simple_data_write(filp, ubuf, cnt, ppos, &data.max_sample);
-}
-
-
-/**
- * debug_sample_fopen - An open function for "sample" debugfs interface
- * @inode: The in-kernel inode representation of this debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function handles opening the "sample" file within the hardware
- * latency detector debugfs directory interface. This file is used to read
- * raw samples from the global ring_buffer and allows the user to see a
- * running latency history. Can be opened blocking or non-blocking,
- * affecting whether it behaves as a buffer read pipe, or does not.
- * Implements simple locking to prevent multiple simultaneous use.
- */
-static int debug_sample_fopen(struct inode *inode, struct file *filp)
-{
- if (!atomic_add_unless(&data.sample_open, 1, 1))
- return -EBUSY;
- else
- return 0;
-}
-
-/**
- * debug_sample_fread - A read function for "sample" debugfs interface
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The user buffer that will contain the samples read
- * @cnt: The maximum bytes to read from the debugfs "file"
- * @ppos: The current position in the debugfs "file"
- *
- * This function handles reading from the "sample" file within the hardware
- * latency detector debugfs directory interface. This file is used to read
- * raw samples from the global ring_buffer and allows the user to see a
- * running latency history. By default this will block pending a new
- * value written into the sample buffer, unless there are already a
- * number of value(s) waiting in the buffer, or the sample file was
- * previously opened in a non-blocking mode of operation.
- */
-static ssize_t debug_sample_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- int len = 0;
- char buf[64];
- struct sample *sample = NULL;
-
- if (!enabled)
- return 0;
-
- sample = kzalloc(sizeof(struct sample), GFP_KERNEL);
- if (!sample)
- return -ENOMEM;
-
- while (!buffer_get_sample(sample)) {
-
- DEFINE_WAIT(wait);
-
- if (filp->f_flags & O_NONBLOCK) {
- len = -EAGAIN;
- goto out;
- }
-
- prepare_to_wait(&data.wq, &wait, TASK_INTERRUPTIBLE);
- schedule();
- finish_wait(&data.wq, &wait);
-
- if (signal_pending(current)) {
- len = -EINTR;
- goto out;
- }
-
- if (!enabled) { /* enable was toggled */
- len = 0;
- goto out;
- }
- }
-
- len = snprintf(buf, sizeof(buf), "%010lu.%010lu\t%llu\t%llu\n",
- sample->timestamp.tv_sec,
- sample->timestamp.tv_nsec,
- sample->duration,
- sample->outer_duration);
-
-
- /* handling partial reads is more trouble than it's worth */
- if (len > cnt)
- goto out;
-
- if (copy_to_user(ubuf, buf, len))
- len = -EFAULT;
-
-out:
- kfree(sample);
- return len;
-}
-
-/**
- * debug_sample_release - Release function for "sample" debugfs interface
- * @inode: The in-kernel inode represenation of the debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function completes the close of the debugfs interface "sample" file.
- * Frees the sample_open "lock" so that other users may open the interface.
- */
-static int debug_sample_release(struct inode *inode, struct file *filp)
-{
- atomic_dec(&data.sample_open);
-
- return 0;
-}
-
-/**
- * debug_threshold_fopen - Open function for "threshold" debugfs entry
- * @inode: The in-kernel inode representation of the debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function provides an open implementation for the "threshold" debugfs
- * interface to the hardware latency detector.
- */
-static int debug_threshold_fopen(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-/**
- * debug_threshold_fread - Read function for "threshold" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to read value into
- * @cnt: The maximum number of bytes to read
- * @ppos: The current "file" position
- *
- * This function provides a read implementation for the "threshold" debugfs
- * interface to the hardware latency detector. It can be used to determine
- * the current threshold level at which a latency will be recorded in the
- * global ring buffer, typically on the order of 10us.
- */
-static ssize_t debug_threshold_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- return simple_data_read(filp, ubuf, cnt, ppos, &data.threshold);
-}
-
-/**
- * debug_threshold_fwrite - Write function for "threshold" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The user buffer that contains the value to write
- * @cnt: The maximum number of bytes to write to "file"
- * @ppos: The current position in the debugfs "file"
- *
- * This function provides a write implementation for the "threshold" debugfs
- * interface to the hardware latency detector. It can be used to configure
- * the threshold level at which any subsequently detected latencies will
- * be recorded into the global ring buffer.
- */
-static ssize_t debug_threshold_fwrite(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
-{
- int ret;
-
- ret = simple_data_write(filp, ubuf, cnt, ppos, &data.threshold);
-
- if (enabled)
- wake_up_process(kthread);
-
- return ret;
-}
-
-/**
- * debug_width_fopen - Open function for "width" debugfs entry
- * @inode: The in-kernel inode representation of the debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function provides an open implementation for the "width" debugfs
- * interface to the hardware latency detector.
- */
-static int debug_width_fopen(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-/**
- * debug_width_fread - Read function for "width" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to read value into
- * @cnt: The maximum number of bytes to read
- * @ppos: The current "file" position
- *
- * This function provides a read implementation for the "width" debugfs
- * interface to the hardware latency detector. It can be used to determine
- * for how many us of the total window us we will actively sample for any
- * hardware-induced latecy periods. Obviously, it is not possible to
- * sample constantly and have the system respond to a sample reader, or,
- * worse, without having the system appear to have gone out to lunch.
- */
-static ssize_t debug_width_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_width);
-}
-
-/**
- * debug_width_fwrite - Write function for "width" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The user buffer that contains the value to write
- * @cnt: The maximum number of bytes to write to "file"
- * @ppos: The current position in the debugfs "file"
- *
- * This function provides a write implementation for the "width" debugfs
- * interface to the hardware latency detector. It can be used to configure
- * for how many us of the total window us we will actively sample for any
- * hardware-induced latency periods. Obviously, it is not possible to
- * sample constantly and have the system respond to a sample reader, or,
- * worse, without having the system appear to have gone out to lunch. It
- * is enforced that width is less that the total window size.
- */
-static ssize_t debug_width_fwrite(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
-{
- char buf[U64STR_SIZE];
- int csize = min(cnt, sizeof(buf));
- u64 val = 0;
- int err = 0;
-
- memset(buf, '\0', sizeof(buf));
- if (copy_from_user(buf, ubuf, csize))
- return -EFAULT;
-
- buf[U64STR_SIZE-1] = '\0'; /* just in case */
- err = kstrtoull(buf, 10, &val);
- if (0 != err)
- return -EINVAL;
-
- mutex_lock(&data.lock);
- if (val < data.sample_window)
- data.sample_width = val;
- else {
- mutex_unlock(&data.lock);
- return -EINVAL;
- }
- mutex_unlock(&data.lock);
-
- if (enabled)
- wake_up_process(kthread);
-
- return csize;
-}
-
-/**
- * debug_window_fopen - Open function for "window" debugfs entry
- * @inode: The in-kernel inode representation of the debugfs "file"
- * @filp: The active open file structure for the debugfs "file"
- *
- * This function provides an open implementation for the "window" debugfs
- * interface to the hardware latency detector. The window is the total time
- * in us that will be considered one sample period. Conceptually, windows
- * occur back-to-back and contain a sample width period during which
- * actual sampling occurs.
- */
-static int debug_window_fopen(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
-/**
- * debug_window_fread - Read function for "window" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The userspace provided buffer to read value into
- * @cnt: The maximum number of bytes to read
- * @ppos: The current "file" position
- *
- * This function provides a read implementation for the "window" debugfs
- * interface to the hardware latency detector. The window is the total time
- * in us that will be considered one sample period. Conceptually, windows
- * occur back-to-back and contain a sample width period during which
- * actual sampling occurs. Can be used to read the total window size.
- */
-static ssize_t debug_window_fread(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- return simple_data_read(filp, ubuf, cnt, ppos, &data.sample_window);
-}
-
-/**
- * debug_window_fwrite - Write function for "window" debugfs entry
- * @filp: The active open file structure for the debugfs "file"
- * @ubuf: The user buffer that contains the value to write
- * @cnt: The maximum number of bytes to write to "file"
- * @ppos: The current position in the debugfs "file"
- *
- * This function provides a write implementation for the "window" debufds
- * interface to the hardware latency detetector. The window is the total time
- * in us that will be considered one sample period. Conceptually, windows
- * occur back-to-back and contain a sample width period during which
- * actual sampling occurs. Can be used to write a new total window size. It
- * is enfoced that any value written must be greater than the sample width
- * size, or an error results.
- */
-static ssize_t debug_window_fwrite(struct file *filp,
- const char __user *ubuf,
- size_t cnt,
- loff_t *ppos)
-{
- char buf[U64STR_SIZE];
- int csize = min(cnt, sizeof(buf));
- u64 val = 0;
- int err = 0;
-
- memset(buf, '\0', sizeof(buf));
- if (copy_from_user(buf, ubuf, csize))
- return -EFAULT;
-
- buf[U64STR_SIZE-1] = '\0'; /* just in case */
- err = kstrtoull(buf, 10, &val);
- if (0 != err)
- return -EINVAL;
-
- mutex_lock(&data.lock);
- if (data.sample_width < val)
- data.sample_window = val;
- else {
- mutex_unlock(&data.lock);
- return -EINVAL;
- }
- mutex_unlock(&data.lock);
-
- return csize;
-}
-
-/*
- * Function pointers for the "count" debugfs file operations
- */
-static const struct file_operations count_fops = {
- .open = debug_count_fopen,
- .read = debug_count_fread,
- .write = debug_count_fwrite,
- .owner = THIS_MODULE,
-};
-
-/*
- * Function pointers for the "enable" debugfs file operations
- */
-static const struct file_operations enable_fops = {
- .open = debug_enable_fopen,
- .read = debug_enable_fread,
- .write = debug_enable_fwrite,
- .owner = THIS_MODULE,
-};
-
-/*
- * Function pointers for the "max" debugfs file operations
- */
-static const struct file_operations max_fops = {
- .open = debug_max_fopen,
- .read = debug_max_fread,
- .write = debug_max_fwrite,
- .owner = THIS_MODULE,
-};
-
-/*
- * Function pointers for the "sample" debugfs file operations
- */
-static const struct file_operations sample_fops = {
- .open = debug_sample_fopen,
- .read = debug_sample_fread,
- .release = debug_sample_release,
- .owner = THIS_MODULE,
-};
-
-/*
- * Function pointers for the "threshold" debugfs file operations
- */
-static const struct file_operations threshold_fops = {
- .open = debug_threshold_fopen,
- .read = debug_threshold_fread,
- .write = debug_threshold_fwrite,
- .owner = THIS_MODULE,
-};
-
-/*
- * Function pointers for the "width" debugfs file operations
- */
-static const struct file_operations width_fops = {
- .open = debug_width_fopen,
- .read = debug_width_fread,
- .write = debug_width_fwrite,
- .owner = THIS_MODULE,
-};
-
-/*
- * Function pointers for the "window" debugfs file operations
- */
-static const struct file_operations window_fops = {
- .open = debug_window_fopen,
- .read = debug_window_fread,
- .write = debug_window_fwrite,
- .owner = THIS_MODULE,
-};
-
-/**
- * init_debugfs - A function to initialize the debugfs interface files
- *
- * This function creates entries in debugfs for "hwlat_detector", including
- * files to read values from the detector, current samples, and the
- * maximum sample that has been captured since the hardware latency
- * dectector was started.
- */
-static int init_debugfs(void)
-{
- int ret = -ENOMEM;
-
- debug_dir = debugfs_create_dir(DRVNAME, NULL);
- if (!debug_dir)
- goto err_debug_dir;
-
- debug_sample = debugfs_create_file("sample", 0444,
- debug_dir, NULL,
- &sample_fops);
- if (!debug_sample)
- goto err_sample;
-
- debug_count = debugfs_create_file("count", 0444,
- debug_dir, NULL,
- &count_fops);
- if (!debug_count)
- goto err_count;
-
- debug_max = debugfs_create_file("max", 0444,
- debug_dir, NULL,
- &max_fops);
- if (!debug_max)
- goto err_max;
-
- debug_sample_window = debugfs_create_file("window", 0644,
- debug_dir, NULL,
- &window_fops);
- if (!debug_sample_window)
- goto err_window;
-
- debug_sample_width = debugfs_create_file("width", 0644,
- debug_dir, NULL,
- &width_fops);
- if (!debug_sample_width)
- goto err_width;
-
- debug_threshold = debugfs_create_file("threshold", 0644,
- debug_dir, NULL,
- &threshold_fops);
- if (!debug_threshold)
- goto err_threshold;
-
- debug_enable = debugfs_create_file("enable", 0644,
- debug_dir, &enabled,
- &enable_fops);
- if (!debug_enable)
- goto err_enable;
-
- else {
- ret = 0;
- goto out;
- }
-
-err_enable:
- debugfs_remove(debug_threshold);
-err_threshold:
- debugfs_remove(debug_sample_width);
-err_width:
- debugfs_remove(debug_sample_window);
-err_window:
- debugfs_remove(debug_max);
-err_max:
- debugfs_remove(debug_count);
-err_count:
- debugfs_remove(debug_sample);
-err_sample:
- debugfs_remove(debug_dir);
-err_debug_dir:
-out:
- return ret;
-}
-
-/**
- * free_debugfs - A function to cleanup the debugfs file interface
- */
-static void free_debugfs(void)
-{
- /* could also use a debugfs_remove_recursive */
- debugfs_remove(debug_enable);
- debugfs_remove(debug_threshold);
- debugfs_remove(debug_sample_width);
- debugfs_remove(debug_sample_window);
- debugfs_remove(debug_max);
- debugfs_remove(debug_count);
- debugfs_remove(debug_sample);
- debugfs_remove(debug_dir);
-}
-
-/**
- * detector_init - Standard module initialization code
- */
-static int detector_init(void)
-{
- int ret = -ENOMEM;
-
- pr_info(BANNER "version %s\n", VERSION);
-
- ret = init_stats();
- if (0 != ret)
- goto out;
-
- ret = init_debugfs();
- if (0 != ret)
- goto err_stats;
-
- if (enabled)
- ret = start_kthread();
-
- goto out;
-
-err_stats:
- ring_buffer_free(ring_buffer);
-out:
- return ret;
-
-}
-
-/**
- * detector_exit - Standard module cleanup code
- */
-static void detector_exit(void)
-{
- int err;
-
- if (enabled) {
- enabled = 0;
- err = stop_kthread();
- if (err)
- pr_err(BANNER "cannot stop kthread\n");
- }
-
- free_debugfs();
- ring_buffer_free(ring_buffer); /* free up the ring buffer */
-
-}
-
-module_init(detector_init);
-module_exit(detector_exit);
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index cd2033c..72b6823 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -71,7 +71,7 @@ static int mei_cl_device_probe(struct device *dev)
dev_dbg(dev, "Device probe\n");
- strncpy(id.name, dev_name(dev), sizeof(id.name));
+ strlcpy(id.name, dev_name(dev), sizeof(id.name));
return driver->probe(device, &id);
}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index b66cec9..e9ea08d 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -74,23 +74,69 @@ int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
/**
- * mei_io_list_flush - removes list entry belonging to cl.
+ * mei_cl_cmp_id - tells if the clients are the same
*
- * @list: An instance of our list structure
- * @cl: host client
+ * @cl1: host client 1
+ * @cl2: host client 2
+ *
+ * returns true - if the clients has same host and me ids
+ * false - otherwise
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+ const struct mei_cl *cl2)
+{
+ return cl1 && cl2 &&
+ (cl1->host_client_id == cl2->host_client_id) &&
+ (cl1->me_client_id == cl2->me_client_id);
+}
+
+/**
+ * mei_io_list_flush - removes cbs belonging to cl.
+ *
+ * @list: an instance of our list structure
+ * @cl: host client, can be NULL for flushing the whole list
+ * @free: whether to free the cbs
*/
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+static void __mei_io_list_flush(struct mei_cl_cb *list,
+ struct mei_cl *cl, bool free)
{
struct mei_cl_cb *cb;
struct mei_cl_cb *next;
+ /* enable removing everything if no cl is specified */
list_for_each_entry_safe(cb, next, &list->list, list) {
- if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
+ if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
list_del(&cb->list);
+ if (free)
+ mei_io_cb_free(cb);
+ }
}
}
/**
+ * mei_io_list_flush - removes list entry belonging to cl.
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ __mei_io_list_flush(list, cl, false);
+}
+
+
+/**
+ * mei_io_list_free - removes cb belonging to cl and free them
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ __mei_io_list_flush(list, cl, true);
+}
+
+/**
* mei_io_cb_free - free mei_cb_private related memory
*
* @cb: mei callback struct
@@ -192,8 +238,8 @@ int mei_cl_flush_queues(struct mei_cl *cl)
dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
mei_io_list_flush(&cl->dev->read_list, cl);
- mei_io_list_flush(&cl->dev->write_list, cl);
- mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+ mei_io_list_free(&cl->dev->write_list, cl);
+ mei_io_list_free(&cl->dev->write_waiting_list, cl);
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
@@ -405,6 +451,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
dev_err(&dev->pdev->dev, "failed to disconnect.\n");
goto free;
}
+ cl->timer_count = MEI_CONNECT_TIMEOUT;
mdelay(10); /* Wait for hardware disconnection ready */
list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
} else {
@@ -916,20 +963,8 @@ void mei_cl_all_wakeup(struct mei_device *dev)
*/
void mei_cl_all_write_clear(struct mei_device *dev)
{
- struct mei_cl_cb *cb, *next;
- struct list_head *list;
-
- list = &dev->write_list.list;
- list_for_each_entry_safe(cb, next, list, list) {
- list_del(&cb->list);
- mei_io_cb_free(cb);
- }
-
- list = &dev->write_waiting_list.list;
- list_for_each_entry_safe(cb, next, list, list) {
- list_del(&cb->list);
- mei_io_cb_free(cb);
- }
+ mei_io_list_free(&dev->write_list, NULL);
+ mei_io_list_free(&dev->write_waiting_list, NULL);
}
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 892cc42..5d75ab5 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -45,8 +45,6 @@ static inline void mei_io_list_init(struct mei_cl_cb *list)
{
INIT_LIST_HEAD(&list->list);
}
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
-
/*
* MEI Host Client Functions
*/
@@ -61,22 +59,6 @@ int mei_cl_unlink(struct mei_cl *cl);
int mei_cl_flush_queues(struct mei_cl *cl);
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl);
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
- const struct mei_cl *cl2)
-{
- return cl1 && cl2 &&
- (cl1->host_client_id == cl2->host_client_id) &&
- (cl1->me_client_id == cl2->me_client_id);
-}
-
int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
index 66f411a..cabc043 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -115,6 +115,11 @@
#define MEI_DEV_ID_LPT_HR 0x8CBA /* Lynx Point H Refresh */
#define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */
+
+/* Host Firmware Status Registers in PCI Config Space */
+#define PCI_CFG_HFS_1 0x40
+#define PCI_CFG_HFS_2 0x48
+
/*
* MEI HW Section
*/
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 3412adc..e513354 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -164,6 +164,9 @@ static void mei_me_hw_reset_release(struct mei_device *dev)
hcsr |= H_IG;
hcsr &= ~H_RST;
mei_hcsr_set(hw, hcsr);
+
+ /* complete this write before we set host ready on another CPU */
+ mmiowb();
}
/**
* mei_me_hw_reset - resets fw via mei csr register.
@@ -183,9 +186,22 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
else
hcsr &= ~H_IE;
+ dev->recvd_hw_ready = false;
mei_me_reg_write(hw, H_CSR, hcsr);
- if (dev->dev_state == MEI_DEV_POWER_DOWN)
+ /*
+ * Host reads the H_CSR once to ensure that the
+ * posted write to H_CSR completes.
+ */
+ hcsr = mei_hcsr_read(hw);
+
+ if ((hcsr & H_RST) == 0)
+ dev_warn(&dev->pdev->dev, "H_RST is not set = 0x%08X", hcsr);
+
+ if ((hcsr & H_RDY) == H_RDY)
+ dev_warn(&dev->pdev->dev, "H_RDY is not cleared 0x%08X", hcsr);
+
+ if (intr_enable == false)
mei_me_hw_reset_release(dev);
return 0;
@@ -201,6 +217,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
static void mei_me_host_set_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
+ hw->host_hw_state = mei_hcsr_read(hw);
hw->host_hw_state |= H_IE | H_IG | H_RDY;
mei_hcsr_set(hw, hw->host_hw_state);
}
@@ -233,10 +250,7 @@ static bool mei_me_hw_is_ready(struct mei_device *dev)
static int mei_me_hw_ready_wait(struct mei_device *dev)
{
int err;
- if (mei_me_hw_is_ready(dev))
- return 0;
- dev->recvd_hw_ready = false;
mutex_unlock(&dev->device_lock);
err = wait_event_interruptible_timeout(dev->wait_hw_ready,
dev->recvd_hw_ready,
@@ -496,19 +510,15 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if we need to start the dev */
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
+ mei_me_hw_reset_release(dev);
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
dev->recvd_hw_ready = true;
wake_up_interruptible(&dev->wait_hw_ready);
-
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
} else {
- dev_dbg(&dev->pdev->dev, "Reset Completed.\n");
- mei_me_hw_reset_release(dev);
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
+ dev_dbg(&dev->pdev->dev, "Spurious Interrupt\n");
}
+ goto end;
}
/* check slots available for reading */
slots = mei_count_full_read_slots(dev);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 1b922e9..41b4b48 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -420,8 +420,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
cl->status = 0;
list_del(&cb->list);
- if (MEI_WRITING == cl->writing_state &&
- cb->fop_type == MEI_FOP_WRITE &&
+ if (cb->fop_type == MEI_FOP_WRITE &&
cl != &dev->iamthif_cl) {
dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n");
cl->writing_state = MEI_WRITE_COMPLETE;
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index cabeddd..9558bef 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -648,8 +648,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
goto out;
}
- if (MEI_WRITE_COMPLETE == cl->writing_state)
- mask |= (POLLIN | POLLRDNORM);
+ mask |= (POLLIN | POLLRDNORM);
out:
mutex_unlock(&dev->device_lock);
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 994ca4a..4b7ea3f 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -342,9 +342,10 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
ndev = (struct mei_nfc_dev *) cldev->priv_data;
dev = ndev->cl->dev;
+ err = -ENOMEM;
mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
if (!mei_buf)
- return -ENOMEM;
+ goto out;
hdr = (struct mei_nfc_hci_hdr *) mei_buf;
hdr->cmd = MEI_NFC_CMD_HCI_SEND;
@@ -354,12 +355,9 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
hdr->data_size = length;
memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
-
err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE);
if (err < 0)
- return err;
-
- kfree(mei_buf);
+ goto out;
if (!wait_event_interruptible_timeout(ndev->send_wq,
ndev->recv_req_id == ndev->req_id, HZ)) {
@@ -368,7 +366,8 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
} else {
ndev->req_id++;
}
-
+out:
+ kfree(mei_buf);
return err;
}
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index e637318..20fb058 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -100,15 +100,31 @@ static bool mei_me_quirk_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
u32 reg;
- if (ent->device == MEI_DEV_ID_PBG_1) {
- pci_read_config_dword(pdev, 0x48, &reg);
- /* make sure that bit 9 is up and bit 10 is down */
- if ((reg & 0x600) == 0x200) {
- dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
- return false;
- }
+ /* Cougar Point || Patsburg */
+ if (ent->device == MEI_DEV_ID_CPT_1 ||
+ ent->device == MEI_DEV_ID_PBG_1) {
+ pci_read_config_dword(pdev, PCI_CFG_HFS_2, &reg);
+ /* make sure that bit 9 (NM) is up and bit 10 (DM) is down */
+ if ((reg & 0x600) == 0x200)
+ goto no_mei;
}
+
+ /* Lynx Point */
+ if (ent->device == MEI_DEV_ID_LPT_H ||
+ ent->device == MEI_DEV_ID_LPT_W ||
+ ent->device == MEI_DEV_ID_LPT_HR) {
+ /* Read ME FW Status check for SPS Firmware */
+ pci_read_config_dword(pdev, PCI_CFG_HFS_1, &reg);
+ /* if bits [19:16] = 15, running SPS Firmware */
+ if ((reg & 0xf0000) == 0xf0000)
+ goto no_mei;
+ }
+
return true;
+
+no_mei:
+ dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
+ return false;
}
/**
* mei_probe - Device Initialization Routine