From 840fe6359c1db978d01fceb8a023f5f6efdf7f1c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 5 Aug 2010 22:20:09 +0200 Subject: ieee1394: Adjust confusing if indentation Indent the branch of an if. Signed-off-by: Julia Lawall Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index d0dc1db80b29..50815022cff1 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -1106,7 +1106,7 @@ static int ohci_iso_recv_init(struct hpsb_iso *iso) if (recv->block_irq_interval * 4 > iso->buf_packets) recv->block_irq_interval = iso->buf_packets / 4; if (recv->block_irq_interval < 1) - recv->block_irq_interval = 1; + recv->block_irq_interval = 1; /* choose a buffer stride */ /* must be a power of 2, and <= PAGE_SIZE */ -- cgit v1.2.3-59-g8ed1b From 23a75eee070f1370bee803a34f285cf81eb5f331 Mon Sep 17 00:00:00 2001 From: Szilveszter Ördög Date: Fri, 6 Aug 2010 09:26:38 +0800 Subject: crypto: hash - Fix handling of small unaligned buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a scatterwalk chain contains an entry with an unaligned offset then hash_walk_next() will cut off the next step at the next alignment point. However, if the entry ends before the next alignment point then we a loop, which leads to a kernel oops. Fix this by checking whether the next aligment point is before the end of the current entry. Signed-off-by: Szilveszter Ördög Acked-by: David S. Miller Signed-off-by: Herbert Xu --- crypto/ahash.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index b8c59b889c6e..f669822a7a44 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -47,8 +47,11 @@ static int hash_walk_next(struct crypto_hash_walk *walk) walk->data = crypto_kmap(walk->pg, 0); walk->data += offset; - if (offset & alignmask) - nbytes = alignmask + 1 - (offset & alignmask); + if (offset & alignmask) { + unsigned int unaligned = alignmask + 1 - (offset & alignmask); + if (nbytes > unaligned) + nbytes = unaligned; + } walk->entrylen -= nbytes; return nbytes; -- cgit v1.2.3-59-g8ed1b From 326a6346ffb5b19eb593530d9d3096d409e46f62 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 6 Aug 2010 09:40:28 +0800 Subject: crypto: testmgr - Fix test disabling option This patch fixes a serious bug in the test disabling patch where it can cause an spurious load of the cryptomgr module even when it's compiled in. It also negates the test disabling option so that its absence causes tests to be enabled. The Kconfig option is also now behind EMBEDDED. Signed-off-by: Herbert Xu --- crypto/Kconfig | 11 +++++------ crypto/algboss.c | 8 ++++---- crypto/testmgr.c | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 1cd497d7a15a..6f5c50fdbbdd 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -101,13 +101,12 @@ config CRYPTO_MANAGER2 select CRYPTO_BLKCIPHER2 select CRYPTO_PCOMP2 -config CRYPTO_MANAGER_TESTS - bool "Run algolithms' self-tests" - default y - depends on CRYPTO_MANAGER2 +config CRYPTO_MANAGER_DISABLE_TESTS + bool "Disable run-time self tests" + depends on CRYPTO_MANAGER2 && EMBEDDED help - Run cryptomanager's tests for the new crypto algorithms being - registered. + Disable run-time self tests that normally take place at + algorithm registration. config CRYPTO_GF128MUL tristate "GF(2^128) multiplication functions (EXPERIMENTAL)" diff --git a/crypto/algboss.c b/crypto/algboss.c index 40bd391f34d9..791d194958fa 100644 --- a/crypto/algboss.c +++ b/crypto/algboss.c @@ -206,13 +206,16 @@ err: return NOTIFY_OK; } -#ifdef CONFIG_CRYPTO_MANAGER_TESTS static int cryptomgr_test(void *data) { struct crypto_test_param *param = data; u32 type = param->type; int err = 0; +#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS + goto skiptest; +#endif + if (type & CRYPTO_ALG_TESTED) goto skiptest; @@ -267,7 +270,6 @@ err_put_module: err: return NOTIFY_OK; } -#endif /* CONFIG_CRYPTO_MANAGER_TESTS */ static int cryptomgr_notify(struct notifier_block *this, unsigned long msg, void *data) @@ -275,10 +277,8 @@ static int cryptomgr_notify(struct notifier_block *this, unsigned long msg, switch (msg) { case CRYPTO_MSG_ALG_REQUEST: return cryptomgr_schedule_probe(data); -#ifdef CONFIG_CRYPTO_MANAGER_TESTS case CRYPTO_MSG_ALG_REGISTER: return cryptomgr_schedule_test(data); -#endif } return NOTIFY_DONE; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index abd980c729eb..fa8c8f78c8d4 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -23,7 +23,7 @@ #include "internal.h" -#ifndef CONFIG_CRYPTO_MANAGER_TESTS +#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS /* a perfect nop */ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) @@ -2542,6 +2542,6 @@ non_fips_alg: return -EINVAL; } -#endif /* CONFIG_CRYPTO_MANAGER_TESTS */ +#endif /* CONFIG_CRYPTO_MANAGER_DISABLE_TESTS */ EXPORT_SYMBOL_GPL(alg_test); -- cgit v1.2.3-59-g8ed1b From 00ca28a507b215dcd121735f16764ea4173c4ff9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 6 Aug 2010 10:34:00 +0800 Subject: crypto: testmgr - Default to no tests On Thu, Aug 05, 2010 at 07:01:21PM -0700, Linus Torvalds wrote: > On Thu, Aug 5, 2010 at 6:40 PM, Herbert Xu wrote: > > > > -config CRYPTO_MANAGER_TESTS > > - bool "Run algolithms' self-tests" > > - default y > > - depends on CRYPTO_MANAGER2 > > +config CRYPTO_MANAGER_DISABLE_TESTS > > + bool "Disable run-time self tests" > > + depends on CRYPTO_MANAGER2 && EMBEDDED > > Why do you still want to force-enable those tests? I was going to > complain about the "default y" anyway, now I'm _really_ complaining, > because you've now made it impossible to disable those tests. Why? As requested, this patch sets the default to y and removes the EMBEDDED dependency. Signed-off-by: Herbert Xu --- crypto/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 6f5c50fdbbdd..e573077f1672 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -103,7 +103,8 @@ config CRYPTO_MANAGER2 config CRYPTO_MANAGER_DISABLE_TESTS bool "Disable run-time self tests" - depends on CRYPTO_MANAGER2 && EMBEDDED + default y + depends on CRYPTO_MANAGER2 help Disable run-time self tests that normally take place at algorithm registration. -- cgit v1.2.3-59-g8ed1b From a106025015c8d24af6518aba3ac19c4dc9098b7c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 6 Aug 2010 14:51:10 +0200 Subject: HID: picolcd: testing the wrong variable "ref_cnt" is a point to the reference count and it's non-null. We really want to test the reference count itself. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 346f0e34987e..c0bdebac5672 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -547,7 +547,7 @@ static void picolcd_fb_destroy(struct fb_info *info) ref_cnt--; mutex_lock(&info->lock); (*ref_cnt)--; - may_release = !ref_cnt; + may_release = !*ref_cnt; mutex_unlock(&info->lock); if (may_release) { framebuffer_release(info); -- cgit v1.2.3-59-g8ed1b From 1778ca298b06ec86af5fc9603447c379cbfb477b Mon Sep 17 00:00:00 2001 From: Bruno Prémont Date: Fri, 6 Aug 2010 10:08:04 +0200 Subject: HID: picolcd: correct ordering of framebuffer freeing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the free() ordering (which was never reached due to wrong check). Signed-off-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index c0bdebac5672..bc2e07740628 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -550,8 +550,8 @@ static void picolcd_fb_destroy(struct fb_info *info) may_release = !*ref_cnt; mutex_unlock(&info->lock); if (may_release) { - framebuffer_release(info); vfree((u8 *)info->fix.smem_start); + framebuffer_release(info); } } -- cgit v1.2.3-59-g8ed1b From 575570f02761bd680ba5731c1dfd4701062e7fb2 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Tue, 27 Jul 2010 16:06:34 +0800 Subject: tracing: Fix an unallocated memory access in function_graph With CONFIG_DEBUG_PAGEALLOC, I observed an unallocated memory access in function_graph trace. It appears we find a small size entry in ring buffer, but we access it as a big size entry. The access overflows the page size and touches an unallocated page. Cc: Signed-off-by: Shaohua Li LKML-Reference: <1280217994.32400.76.camel@sli10-desk.sh.intel.com> [ Added a comment to explain the problem - SDR ] Signed-off-by: Steven Rostedt --- kernel/trace/trace_functions_graph.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 79f4bac99a94..b4c179ae4e45 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -507,7 +507,15 @@ get_return_for_leaf(struct trace_iterator *iter, * if the output fails. */ data->ent = *curr; - data->ret = *next; + /* + * If the next event is not a return type, then + * we only care about what type it is. Otherwise we can + * safely copy the entire event. + */ + if (next->ent.type == TRACE_GRAPH_RET) + data->ret = *next; + else + data->ret.ent.type = next->ent.type; } } -- cgit v1.2.3-59-g8ed1b From 18fab912d4fa70133df164d2dcf3310be0c38c34 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Wed, 28 Jul 2010 14:14:01 +0800 Subject: tracing: Fix ring_buffer_read_page reading out of page boundary With the configuration: CONFIG_DEBUG_PAGEALLOC=y and Shaohua's patch: [PATCH]x86: make spurious_fault check correct pte bit Function call graph trace with the following will trigger a page fault. # cd /sys/kernel/debug/tracing/ # echo function_graph > current_tracer # cat per_cpu/cpu1/trace_pipe_raw > /dev/null BUG: unable to handle kernel paging request at ffff880006e99000 IP: [] rb_event_length+0x1/0x3f PGD 1b19063 PUD 1b1d063 PMD 3f067 PTE 6e99160 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC last sysfs file: /sys/devices/virtual/net/lo/operstate CPU 1 Modules linked in: Pid: 1982, comm: cat Not tainted 2.6.35-rc6-aes+ #300 /Bochs RIP: 0010:[] [] rb_event_length+0x1/0x3f RSP: 0018:ffff880006475e38 EFLAGS: 00010006 RAX: 0000000000000ff0 RBX: ffff88000786c630 RCX: 000000000000001d RDX: ffff880006e98000 RSI: 0000000000000ff0 RDI: ffff880006e99000 RBP: ffff880006475eb8 R08: 000000145d7008bd R09: 0000000000000000 R10: 0000000000008000 R11: ffffffff815d9336 R12: ffff880006d08000 R13: ffff880006e605d8 R14: 0000000000000000 R15: 0000000000000018 FS: 00007f2b83e456f0(0000) GS:ffff880002100000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: ffff880006e99000 CR3: 00000000064a8000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process cat (pid: 1982, threadinfo ffff880006474000, task ffff880006e40770) Stack: ffff880006475eb8 ffffffff8108730f 0000000000000ff0 000000145d7008bd <0> ffff880006e98010 ffff880006d08010 0000000000000296 ffff88000786c640 <0> ffffffff81002956 0000000000000000 ffff8800071f4680 ffff8800071f4680 Call Trace: [] ? ring_buffer_read_page+0x15a/0x24a [] ? return_to_handler+0x15/0x2f [] tracing_buffers_read+0xb9/0x164 [] vfs_read+0xaf/0x150 [] return_to_handler+0x0/0x2f [] __bad_area_nosemaphore+0x17e/0x1a1 [] return_to_handler+0x0/0x2f [] bad_area_nosemaphore+0x13/0x15 Code: 80 25 b2 16 b3 00 fe c9 c3 55 48 89 e5 f0 80 0d a4 16 b3 00 02 c9 c3 55 31 c0 48 89 e5 48 83 3d 94 16 b3 00 01 c9 0f 94 c0 c3 55 <8a> 0f 48 89 e5 83 e1 1f b8 08 00 00 00 0f b6 d1 83 fa 1e 74 27 RIP [] rb_event_length+0x1/0x3f RSP CR2: ffff880006e99000 ---[ end trace a6877bb92ccb36bb ]--- The root cause is that ring_buffer_read_page() may read out of page boundary, because the boundary checking is done after reading. This is fixed via doing boundary checking before reading. Reported-by: Shaohua Li Cc: Signed-off-by: Huang Ying LKML-Reference: <1280297641.2771.307.camel@yhuang-dev> Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 1da7b6ea8b85..5ec8f1d1480e 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -3868,6 +3868,9 @@ int ring_buffer_read_page(struct ring_buffer *buffer, rpos = reader->read; pos += size; + if (rpos >= commit) + break; + event = rb_reader_event(cpu_buffer); size = rb_event_length(event); } while (len > size); -- cgit v1.2.3-59-g8ed1b From 18cb2aef91b37dbce2bec2f39bb1dddd0e9dd838 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sat, 7 Aug 2010 03:26:23 +0900 Subject: percpu: handle __percpu notations in UP accessors UP accessors didn't take care of __percpu notations leading to a lot of spurious sparse warnings on UP configurations. Fix it. Signed-off-by: Namhyung Kim Signed-off-by: Tejun Heo --- include/asm-generic/percpu.h | 15 ++++++++++----- include/linux/percpu.h | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index b5043a9890d8..08923b684768 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h @@ -70,11 +70,16 @@ extern void setup_per_cpu_areas(void); #else /* ! SMP */ -#define per_cpu(var, cpu) (*((void)(cpu), &(var))) -#define __get_cpu_var(var) (var) -#define __raw_get_cpu_var(var) (var) -#define this_cpu_ptr(ptr) per_cpu_ptr(ptr, 0) -#define __this_cpu_ptr(ptr) this_cpu_ptr(ptr) +#define VERIFY_PERCPU_PTR(__p) ({ \ + __verify_pcpu_ptr((__p)); \ + (typeof(*(__p)) __kernel __force *)(__p); \ +}) + +#define per_cpu(var, cpu) (*((void)(cpu), VERIFY_PERCPU_PTR(&(var)))) +#define __get_cpu_var(var) (*VERIFY_PERCPU_PTR(&(var))) +#define __raw_get_cpu_var(var) (*VERIFY_PERCPU_PTR(&(var))) +#define this_cpu_ptr(ptr) per_cpu_ptr(ptr, 0) +#define __this_cpu_ptr(ptr) this_cpu_ptr(ptr) #endif /* SMP */ diff --git a/include/linux/percpu.h b/include/linux/percpu.h index b8b9084527b1..49466b13c5c6 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -149,7 +149,7 @@ extern void __init percpu_init_late(void); #else /* CONFIG_SMP */ -#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); }) +#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); VERIFY_PERCPU_PTR((ptr)); }) /* can't distinguish from other static vars, always false */ static inline bool is_kernel_percpu_address(unsigned long addr) -- cgit v1.2.3-59-g8ed1b From 94cb121c9483f1ec9b1ef0c249fbfc49c628fa6b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sat, 7 Aug 2010 03:26:24 +0900 Subject: percpu: add __percpu notations to UP allocator Add __percpu notations to UP percpu allocator. Signed-off-by: Namhyung Kim Signed-off-by: Tejun Heo --- mm/percpu_up.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/percpu_up.c b/mm/percpu_up.c index c4351c7f57d2..db884fae5721 100644 --- a/mm/percpu_up.c +++ b/mm/percpu_up.c @@ -14,13 +14,13 @@ void __percpu *__alloc_percpu(size_t size, size_t align) * percpu sections on SMP for which this path isn't used. */ WARN_ON_ONCE(align > SMP_CACHE_BYTES); - return kzalloc(size, GFP_KERNEL); + return (void __percpu __force *)kzalloc(size, GFP_KERNEL); } EXPORT_SYMBOL_GPL(__alloc_percpu); void free_percpu(void __percpu *p) { - kfree(p); + kfree(this_cpu_ptr(p)); } EXPORT_SYMBOL_GPL(free_percpu); -- cgit v1.2.3-59-g8ed1b From 597603d615d2b19a9e451d8cfac24372856a522d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 9 Aug 2010 14:21:11 +0200 Subject: ALSA: introduce the snd-aloop module for the PCM loopback The snd-aloop module allows redirecting of the PCM playback in the kernel back to the user space using the standard ALSA PCM capture API. The module also allows time synchronization with another timing source and notifications of playback stream parameter changes. Signed-off-by: Jaroslav Kysela --- sound/drivers/Kconfig | 19 + sound/drivers/Makefile | 2 + sound/drivers/aloop.c | 1055 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1076 insertions(+) create mode 100644 sound/drivers/aloop.c diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 84714a65e5c8..b6ae76285255 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -74,6 +74,25 @@ config SND_DUMMY To compile this driver as a module, choose M here: the module will be called snd-dummy. +config SND_ALOOP + tristate "Generic loopback driver (PCM)" + select SND_PCM + help + Say 'Y' or 'M' to include support for the PCM loopback device. + This module returns played samples back to the user space using + the standard ALSA PCM device. The devices are routed 0->1 and + 1->0, where first number is the playback PCM device and second + number is the capture device. Module creates two PCM devices and + configured number of substreams (see the pcm_substreams module + parameter). + + The looback device allow time sychronization with an external + timing source using the time shift universal control (+-20% + of system time). + + To compile this driver as a module, choose M here: the module + will be called snd-aloop. + config SND_VIRMIDI tristate "Virtual MIDI soundcard" depends on SND_SEQUENCER diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index d4a07f9ff2c7..1a8440c8b138 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/Makefile @@ -4,6 +4,7 @@ # snd-dummy-objs := dummy.o +snd-aloop-objs := aloop.o snd-mtpav-objs := mtpav.o snd-mts64-objs := mts64.o snd-portman2x4-objs := portman2x4.o @@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o # Toplevel Module Dependency obj-$(CONFIG_SND_DUMMY) += snd-dummy.o +obj-$(CONFIG_SND_ALOOP) += snd-aloop.o obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c new file mode 100644 index 000000000000..3123a15d23f6 --- /dev/null +++ b/sound/drivers/aloop.c @@ -0,0 +1,1055 @@ +/* + * Loopback soundcard + * + * Original code: + * Copyright (c) by Jaroslav Kysela + * + * More accurate positioning and full-duplex support: + * Copyright (c) Ahmet İnan + * + * Major (almost complete) rewrite: + * Copyright (c) by Takashi Iwai + * + * A next major update in 2010 (separate timers for playback and capture): + * Copyright (c) Jaroslav Kysela + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_DESCRIPTION("A loopback soundcard"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}"); + +#define MAX_PCM_SUBSTREAMS 8 + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; +static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; +static int pcm_notify[SNDRV_CARDS]; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for loopback soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for loopback soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable this loopback soundcard."); +module_param_array(pcm_substreams, int, NULL, 0444); +MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); +module_param_array(pcm_notify, int, NULL, 0444); +MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); + +#define NO_PITCH 100000 + +struct loopback_pcm; + +struct loopback_cable { + spinlock_t lock; + struct loopback_pcm *streams[2]; + struct snd_pcm_hardware hw; + /* flags */ + unsigned int valid; + unsigned int running; +}; + +struct loopback_setup { + unsigned int notify: 1; + unsigned int rate_shift; + unsigned int format; + unsigned int rate; + unsigned int channels; + struct snd_ctl_elem_id active_id; + struct snd_ctl_elem_id format_id; + struct snd_ctl_elem_id rate_id; + struct snd_ctl_elem_id channels_id; +}; + +struct loopback { + struct snd_card *card; + struct mutex cable_lock; + struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; + struct snd_pcm *pcm[2]; + struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; +}; + +struct loopback_pcm { + struct loopback *loopback; + struct snd_pcm_substream *substream; + struct loopback_cable *cable; + unsigned int pcm_buffer_size; + unsigned int buf_pos; /* position in buffer */ + unsigned int silent_size; + /* PCM parameters */ + unsigned int pcm_period_size; + unsigned int pcm_bps; /* bytes per second */ + unsigned int pcm_salign; /* bytes per sample * channels */ + unsigned int pcm_rate_shift; /* rate shift value */ + /* flags */ + unsigned int period_update_pending :1; + /* timer stuff */ + unsigned int irq_pos; /* fractional IRQ position */ + unsigned int period_size_frac; + unsigned long last_jiffies; + struct timer_list timer; +}; + +static struct platform_device *devices[SNDRV_CARDS]; + +static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x) +{ + if (dpcm->pcm_rate_shift == NO_PITCH) { + x /= HZ; + } else { + x = div_u64(NO_PITCH * (unsigned long long)x, + HZ * (unsigned long long)dpcm->pcm_rate_shift); + } + return x - (x % dpcm->pcm_salign); +} + +static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x) +{ + if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */ + return x * HZ; + } else { + x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ, + NO_PITCH); + } + return x; +} + +static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm) +{ + int device = dpcm->substream->pstr->pcm->device; + + if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + device ^= 1; + return &dpcm->loopback->setup[dpcm->substream->number][device]; +} + +static inline unsigned int get_notify(struct loopback_pcm *dpcm) +{ + return get_setup(dpcm)->notify; +} + +static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) +{ + return get_setup(dpcm)->rate_shift; +} + +static void loopback_timer_start(struct loopback_pcm *dpcm) +{ + unsigned long tick; + unsigned int rate_shift = get_rate_shift(dpcm); + + if (rate_shift != dpcm->pcm_rate_shift) { + dpcm->pcm_rate_shift = rate_shift; + dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); + } + tick = dpcm->period_size_frac - dpcm->irq_pos; + tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; + dpcm->timer.expires = jiffies + tick; + add_timer(&dpcm->timer); +} + +static inline void loopback_timer_stop(struct loopback_pcm *dpcm) +{ + del_timer(&dpcm->timer); +} + +#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) +#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) +#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) + +static int loopback_check_format(struct loopback_cable *cable, int stream) +{ + struct snd_pcm_runtime *runtime; + struct loopback_setup *setup; + struct snd_card *card; + int check; + + if (cable->valid != CABLE_VALID_BOTH) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + goto __notify; + return 0; + } + runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> + substream->runtime; + check = cable->hw.formats != (1ULL << runtime->format) || + cable->hw.rate_min != runtime->rate || + cable->hw.rate_max != runtime->rate || + cable->hw.channels_min != runtime->channels || + cable->hw.channels_max != runtime->channels; + if (!check) + return 0; + if (stream == SNDRV_PCM_STREAM_CAPTURE) { + return -EIO; + } else { + snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> + substream, SNDRV_PCM_STATE_DRAINING); + __notify: + runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> + substream->runtime; + setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); + card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; + if (setup->format != runtime->format) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->format_id); + setup->format = runtime->format; + } + if (setup->rate != runtime->rate) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->rate_id); + setup->rate = runtime->rate; + } + if (setup->channels != runtime->channels) { + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &setup->channels_id); + setup->channels = runtime->channels; + } + } + return 0; +} + +static void loopback_active_notify(struct loopback_pcm *dpcm) +{ + snd_ctl_notify(dpcm->loopback->card, + SNDRV_CTL_EVENT_MASK_VALUE, + &get_setup(dpcm)->active_id); +} + +static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + int err; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + err = loopback_check_format(cable, substream->stream); + if (err < 0) + return err; + dpcm->last_jiffies = jiffies; + dpcm->pcm_rate_shift = 0; + loopback_timer_start(dpcm); + cable->running |= (1 << substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + loopback_active_notify(dpcm); + break; + case SNDRV_PCM_TRIGGER_STOP: + cable->running &= ~(1 << substream->stream); + loopback_timer_stop(dpcm); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + loopback_active_notify(dpcm); + break; + default: + return -EINVAL; + } + return 0; +} + +static int loopback_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + unsigned int bps, salign; + + salign = (snd_pcm_format_width(runtime->format) * + runtime->channels) / 8; + bps = salign * runtime->rate; + if (bps <= 0 || salign <= 0) + return -EINVAL; + + dpcm->buf_pos = 0; + dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + /* clear capture buffer */ + dpcm->silent_size = dpcm->pcm_buffer_size; + snd_pcm_format_set_silence(runtime->format, runtime->dma_area, + runtime->buffer_size * runtime->channels); + } + + dpcm->irq_pos = 0; + dpcm->period_update_pending = 0; + dpcm->pcm_bps = bps; + dpcm->pcm_salign = salign; + dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); + + mutex_lock(&dpcm->loopback->cable_lock); + if (!(cable->valid & ~(1 << substream->stream))) { + cable->hw.formats = (1ULL << runtime->format); + cable->hw.rate_min = runtime->rate; + cable->hw.rate_max = runtime->rate; + cable->hw.channels_min = runtime->channels; + cable->hw.channels_max = runtime->channels; + } + cable->valid |= 1 << substream->stream; + mutex_unlock(&dpcm->loopback->cable_lock); + + return 0; +} + +static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) +{ + struct snd_pcm_runtime *runtime = dpcm->substream->runtime; + char *dst = runtime->dma_area; + unsigned int dst_off = dpcm->buf_pos; + + if (dpcm->silent_size >= dpcm->pcm_buffer_size) + return; + if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size) + bytes = dpcm->pcm_buffer_size - dpcm->silent_size; + + for (;;) { + unsigned int size = bytes; + if (dst_off + size > dpcm->pcm_buffer_size) + size = dpcm->pcm_buffer_size - dst_off; + snd_pcm_format_set_silence(runtime->format, dst + dst_off, + bytes_to_frames(runtime, size) * + runtime->channels); + dpcm->silent_size += size; + bytes -= size; + if (!bytes) + break; + dst_off = 0; + } +} + +static void copy_play_buf(struct loopback_pcm *play, + struct loopback_pcm *capt, + unsigned int bytes) +{ + struct snd_pcm_runtime *runtime = play->substream->runtime; + char *src = play->substream->runtime->dma_area; + char *dst = capt->substream->runtime->dma_area; + unsigned int src_off = play->buf_pos; + unsigned int dst_off = capt->buf_pos; + unsigned int clear_bytes = 0; + + /* check if playback is draining, trim the capture copy size + * when our pointer is at the end of playback ring buffer */ + if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && + snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { + snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; + appl_ptr = appl_ptr1 = runtime->control->appl_ptr; + appl_ptr1 -= appl_ptr1 % runtime->buffer_size; + appl_ptr1 += play->buf_pos / play->pcm_salign; + if (appl_ptr < appl_ptr1) + appl_ptr1 -= runtime->buffer_size; + diff = (appl_ptr - appl_ptr1) * play->pcm_salign; + if (diff < bytes) { + clear_bytes = bytes - diff; + bytes = diff; + } + } + + for (;;) { + unsigned int size = bytes; + if (src_off + size > play->pcm_buffer_size) + size = play->pcm_buffer_size - src_off; + if (dst_off + size > capt->pcm_buffer_size) + size = capt->pcm_buffer_size - dst_off; + memcpy(dst + dst_off, src + src_off, size); + capt->silent_size = 0; + bytes -= size; + if (!bytes) + break; + src_off = (src_off + size) % play->pcm_buffer_size; + dst_off = (dst_off + size) % capt->pcm_buffer_size; + } + + if (clear_bytes > 0) + clear_capture_buf(capt, clear_bytes); +} + +#define BYTEPOS_UPDATE_POSONLY 0 +#define BYTEPOS_UPDATE_CLEAR 1 +#define BYTEPOS_UPDATE_COPY 2 + +static void loopback_bytepos_update(struct loopback_pcm *dpcm, + unsigned int delta, + unsigned int cmd) +{ + unsigned int count; + unsigned long last_pos; + + last_pos = byte_pos(dpcm, dpcm->irq_pos); + dpcm->irq_pos += delta * dpcm->pcm_bps; + count = byte_pos(dpcm, dpcm->irq_pos) - last_pos; + if (!count) + return; + if (cmd == BYTEPOS_UPDATE_CLEAR) + clear_capture_buf(dpcm, count); + else if (cmd == BYTEPOS_UPDATE_COPY) + copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK], + dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE], + count); + dpcm->buf_pos += count; + dpcm->buf_pos %= dpcm->pcm_buffer_size; + if (dpcm->irq_pos >= dpcm->period_size_frac) { + dpcm->irq_pos %= dpcm->period_size_frac; + dpcm->period_update_pending = 1; + } +} + +static void loopback_pos_update(struct loopback_cable *cable) +{ + struct loopback_pcm *dpcm_play = + cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; + struct loopback_pcm *dpcm_capt = + cable->streams[SNDRV_PCM_STREAM_CAPTURE]; + unsigned long delta_play = 0, delta_capt = 0; + + spin_lock(&cable->lock); + if (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { + delta_play = jiffies - dpcm_play->last_jiffies; + dpcm_play->last_jiffies += delta_play; + } + + if (cable->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { + delta_capt = jiffies - dpcm_capt->last_jiffies; + dpcm_capt->last_jiffies += delta_capt; + } + + if (delta_play == 0 && delta_capt == 0) { + spin_unlock(&cable->lock); + return; + } + + if (delta_play > delta_capt) { + loopback_bytepos_update(dpcm_play, delta_play - delta_capt, + BYTEPOS_UPDATE_POSONLY); + delta_play = delta_capt; + } else if (delta_play < delta_capt) { + loopback_bytepos_update(dpcm_capt, delta_capt - delta_play, + BYTEPOS_UPDATE_CLEAR); + delta_capt = delta_play; + } + + if (delta_play == 0 && delta_capt == 0) { + spin_unlock(&cable->lock); + return; + } + /* note delta_capt == delta_play at this moment */ + loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); + loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); + spin_unlock(&cable->lock); +} + +static void loopback_timer_function(unsigned long data) +{ + struct loopback_pcm *dpcm = (struct loopback_pcm *)data; + int stream; + + loopback_pos_update(dpcm->cable); + stream = dpcm->substream->stream; + if (dpcm->cable->running & (1 << stream)) + loopback_timer_start(dpcm); + if (dpcm->period_update_pending) { + dpcm->period_update_pending = 0; + if (dpcm->cable->running & (1 << stream)) + snd_pcm_period_elapsed(dpcm->substream); + } +} + +static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + + loopback_pos_update(dpcm->cable); + return bytes_to_frames(runtime, dpcm->buf_pos); +} + +static struct snd_pcm_hardware loopback_pcm_hardware = +{ + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | + SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 32, + .buffer_bytes_max = 2 * 1024 * 1024, + .period_bytes_min = 64, + .period_bytes_max = 2 * 1024 * 1024, + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static void loopback_runtime_free(struct snd_pcm_runtime *runtime) +{ + struct loopback_pcm *dpcm = runtime->private_data; + kfree(dpcm); +} + +static int loopback_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); +} + +static int loopback_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback_pcm *dpcm = runtime->private_data; + struct loopback_cable *cable = dpcm->cable; + + mutex_lock(&dpcm->loopback->cable_lock); + cable->valid &= ~(1 << substream->stream); + mutex_unlock(&dpcm->loopback->cable_lock); + return snd_pcm_lib_free_pages(substream); +} + +static unsigned int get_cable_index(struct snd_pcm_substream *substream) +{ + if (!substream->pcm->device) + return substream->stream; + else + return !substream->stream; +} + +static int loopback_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct loopback *loopback = substream->private_data; + struct loopback_pcm *dpcm; + struct loopback_cable *cable; + int err = 0; + int dev = get_cable_index(substream); + + mutex_lock(&loopback->cable_lock); + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); + if (!dpcm) { + err = -ENOMEM; + goto unlock; + } + dpcm->loopback = loopback; + dpcm->substream = substream; + setup_timer(&dpcm->timer, loopback_timer_function, + (unsigned long)dpcm); + + cable = loopback->cables[substream->number][dev]; + if (!cable) { + cable = kzalloc(sizeof(*cable), GFP_KERNEL); + if (!cable) { + kfree(dpcm); + err = -ENOMEM; + goto unlock; + } + spin_lock_init(&cable->lock); + cable->hw = loopback_pcm_hardware; + loopback->cables[substream->number][dev] = cable; + } + dpcm->cable = cable; + cable->streams[substream->stream] = dpcm; + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + + runtime->private_data = dpcm; + runtime->private_free = loopback_runtime_free; + if (get_notify(dpcm) && + substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + runtime->hw = loopback_pcm_hardware; + } else { + runtime->hw = cable->hw; + } + unlock: + mutex_unlock(&loopback->cable_lock); + return err; +} + +static int loopback_close(struct snd_pcm_substream *substream) +{ + struct loopback *loopback = substream->private_data; + struct loopback_pcm *dpcm = substream->runtime->private_data; + struct loopback_cable *cable; + int dev = get_cable_index(substream); + + loopback_timer_stop(dpcm); + mutex_lock(&loopback->cable_lock); + cable = loopback->cables[substream->number][dev]; + if (cable->streams[!substream->stream]) { + /* other stream is still alive */ + cable->streams[substream->stream] = NULL; + } else { + /* free the cable */ + loopback->cables[substream->number][dev] = NULL; + kfree(cable); + } + mutex_unlock(&loopback->cable_lock); + return 0; +} + +static struct snd_pcm_ops loopback_playback_ops = { + .open = loopback_open, + .close = loopback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = loopback_hw_params, + .hw_free = loopback_hw_free, + .prepare = loopback_prepare, + .trigger = loopback_trigger, + .pointer = loopback_pointer, +}; + +static struct snd_pcm_ops loopback_capture_ops = { + .open = loopback_open, + .close = loopback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = loopback_hw_params, + .hw_free = loopback_hw_free, + .prepare = loopback_prepare, + .trigger = loopback_trigger, + .pointer = loopback_pointer, +}; + +static int __devinit loopback_pcm_new(struct loopback *loopback, + int device, int substreams) +{ + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(loopback->card, "Loopback PCM", device, + substreams, substreams, &pcm); + if (err < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops); + + pcm->private_data = loopback; + pcm->info_flags = 0; + strcpy(pcm->name, "Loopback PCM"); + + loopback->pcm[device] = pcm; + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 0, 2 * 1024 * 1024); + return 0; +} + +static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 80000; + uinfo->value.integer.max = 120000; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate_shift; + return 0; +} + +static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + + val = ucontrol->value.integer.value[0]; + if (val < 80000) + val = 80000; + if (val > 120000) + val = 120000; + mutex_lock(&loopback->cable_lock); + if (val != loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate_shift) { + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate_shift = val; + change = 1; + } + mutex_unlock(&loopback->cable_lock); + return change; +} + +static int loopback_notify_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].notify; + return 0; +} + +static int loopback_notify_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + unsigned int val; + int change = 0; + + val = ucontrol->value.integer.value[0] ? 1 : 0; + if (val != loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].notify) { + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].notify = val; + change = 1; + } + return change; +} + +static int loopback_active_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + struct loopback_cable *cable = loopback->cables + [kcontrol->id.subdevice][kcontrol->id.device]; + unsigned int val = 0; + + if (cable != NULL) + val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? + 1 : 0; + ucontrol->value.integer.value[0] = val; + return 0; +} + +static int loopback_format_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].format; + return 0; +} + +static int loopback_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 192000; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate; + return 0; +} + +static int loopback_channels_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 1; + uinfo->value.integer.max = 1024; + uinfo->value.integer.step = 1; + return 0; +} + +static int loopback_channels_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct loopback *loopback = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + loopback->setup[kcontrol->id.subdevice] + [kcontrol->id.device].rate; + return 0; +} + +static struct snd_kcontrol_new loopback_controls[] __devinitdata = { +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Rate Shift 100000", + .info = loopback_rate_shift_info, + .get = loopback_rate_shift_get, + .put = loopback_rate_shift_put, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Notify", + .info = snd_ctl_boolean_mono_info, + .get = loopback_notify_get, + .put = loopback_notify_put, +}, +#define ACTIVE_IDX 2 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Active", + .info = snd_ctl_boolean_mono_info, + .get = loopback_active_get, +}, +#define FORMAT_IDX 3 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Format", + .info = loopback_format_info, + .get = loopback_format_get +}, +#define RATE_IDX 4 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Rate", + .info = loopback_rate_info, + .get = loopback_rate_get +}, +#define CHANNELS_IDX 5 +{ + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Slave Channels", + .info = loopback_channels_info, + .get = loopback_channels_get +} +}; + +static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) +{ + struct snd_card *card = loopback->card; + struct snd_pcm *pcm; + struct snd_kcontrol *kctl; + struct loopback_setup *setup; + int err, dev, substr, substr_count, idx; + + strcpy(card->mixername, "Loopback Mixer"); + for (dev = 0; dev < 2; dev++) { + pcm = loopback->pcm[dev]; + substr_count = + pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count; + for (substr = 0; substr < substr_count; substr++) { + setup = &loopback->setup[substr][dev]; + setup->notify = notify; + setup->rate_shift = NO_PITCH; + setup->format = SNDRV_PCM_FORMAT_S16_LE; + setup->rate = 48000; + setup->channels = 2; + for (idx = 0; idx < ARRAY_SIZE(loopback_controls); + idx++) { + kctl = snd_ctl_new1(&loopback_controls[idx], + loopback); + if (!kctl) + return -ENOMEM; + kctl->id.device = dev; + kctl->id.subdevice = substr; + switch (idx) { + case ACTIVE_IDX: + setup->active_id = kctl->id; + break; + case FORMAT_IDX: + setup->format_id = kctl->id; + break; + case RATE_IDX: + setup->rate_id = kctl->id; + break; + case CHANNELS_IDX: + setup->channels_id = kctl->id; + break; + default: + break; + } + err = snd_ctl_add(card, kctl); + if (err < 0) + return err; + } + } + } + return 0; +} + +static int __devinit loopback_probe(struct platform_device *devptr) +{ + struct snd_card *card; + struct loopback *loopback; + int dev = devptr->id; + int err; + + err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct loopback), &card); + if (err < 0) + return err; + loopback = card->private_data; + + if (pcm_substreams[dev] < 1) + pcm_substreams[dev] = 1; + if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) + pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; + + loopback->card = card; + mutex_init(&loopback->cable_lock); + + err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); + if (err < 0) + goto __nodev; + err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]); + if (err < 0) + goto __nodev; + err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); + if (err < 0) + goto __nodev; + strcpy(card->driver, "Loopback"); + strcpy(card->shortname, "Loopback"); + sprintf(card->longname, "Loopback %i", dev + 1); + err = snd_card_register(card); + if (!err) { + platform_set_drvdata(devptr, card); + return 0; + } + __nodev: + snd_card_free(card); + return err; +} + +static int __devexit loopback_remove(struct platform_device *devptr) +{ + snd_card_free(platform_get_drvdata(devptr)); + platform_set_drvdata(devptr, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int loopback_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_card *card = platform_get_drvdata(pdev); + struct loopback *loopback = card->private_data; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + snd_pcm_suspend_all(loopback->pcm[0]); + snd_pcm_suspend_all(loopback->pcm[1]); + return 0; +} + +static int loopback_resume(struct platform_device *pdev) +{ + struct snd_card *card = platform_get_drvdata(pdev); + + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + +#define SND_LOOPBACK_DRIVER "snd_aloop" + +static struct platform_driver loopback_driver = { + .probe = loopback_probe, + .remove = __devexit_p(loopback_remove), +#ifdef CONFIG_PM + .suspend = loopback_suspend, + .resume = loopback_resume, +#endif + .driver = { + .name = SND_LOOPBACK_DRIVER + }, +}; + +static void loopback_unregister_all(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(devices); ++i) + platform_device_unregister(devices[i]); + platform_driver_unregister(&loopback_driver); +} + +static int __init alsa_card_loopback_init(void) +{ + int i, err, cards; + + err = platform_driver_register(&loopback_driver); + if (err < 0) + return err; + + + cards = 0; + for (i = 0; i < SNDRV_CARDS; i++) { + struct platform_device *device; + if (!enable[i]) + continue; + device = platform_device_register_simple(SND_LOOPBACK_DRIVER, + i, NULL, 0); + if (IS_ERR(device)) + continue; + if (!platform_get_drvdata(device)) { + platform_device_unregister(device); + continue; + } + devices[i] = device; + cards++; + } + if (!cards) { +#ifdef MODULE + printk(KERN_ERR "aloop: No loopback enabled\n"); +#endif + loopback_unregister_all(); + return -ENODEV; + } + return 0; +} + +static void __exit alsa_card_loopback_exit(void) +{ + loopback_unregister_all(); +} + +module_init(alsa_card_loopback_init) +module_exit(alsa_card_loopback_exit) -- cgit v1.2.3-59-g8ed1b From 50b6e71ae83714be509b80727dbf90fa8b1c0717 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 9 Aug 2010 10:29:28 -0400 Subject: Revert "hwrng: n2-drv - remove casts from void*" This reverts commit 8b9cfdca9c52f7d39c3ccfac1668e31c20c9f42e. This patch needs to wait for the HWRNG API to start using void * for priv first. Signed-off-by: Herbert Xu --- drivers/char/hw_random/n2-drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 7a4f080f8356..d8a4ca87987d 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -387,7 +387,7 @@ static int n2rng_init_control(struct n2rng *np) static int n2rng_data_read(struct hwrng *rng, u32 *data) { - struct n2rng *np = rng->priv; + struct n2rng *np = (struct n2rng *) rng->priv; unsigned long ra = __pa(&np->test_data); int len; -- cgit v1.2.3-59-g8ed1b From 1b5ad24878b7e5a543b98c5d2f8c0d8c0dd3088f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sat, 7 Aug 2010 14:29:22 +0200 Subject: slub: add missing __percpu markup in mm/slub_def.h kmem_cache->cpu_slab is a percpu pointer but was missing __percpu markup. Add it. Signed-off-by: Namhyung Kim Acked-by: Tejun Heo Signed-off-by: Pekka Enberg --- include/linux/slub_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 6447a723ecb1..5ec4bc0e45aa 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -68,7 +68,7 @@ struct kmem_cache_order_objects { * Slab cache management. */ struct kmem_cache { - struct kmem_cache_cpu *cpu_slab; + struct kmem_cache_cpu __percpu *cpu_slab; /* Used for retriving partial slabs etc */ unsigned long flags; int size; /* The size of an object including meta data */ -- cgit v1.2.3-59-g8ed1b From 1ab335d8f85792e3b107ff8237d53cf64db714df Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Fri, 6 Aug 2010 18:19:22 +0200 Subject: slab: fix object alignment This patch fixes alignment of slab objects in case CONFIG_DEBUG_PAGEALLOC is active. Before this spot in kmem_cache_create, we have this situation: - align contains the required alignment of the object - cachep->obj_offset is 0 or equals align in case of CONFIG_DEBUG_SLAB - size equals the size of the object, or object plus trailing redzone in case of CONFIG_DEBUG_SLAB This spot tries to fill one page per object if the object is in certain size limits, however setting obj_offset to PAGE_SIZE - size does break the object alignment since size may not be aligned with the required alignment. This patch simply adds an ALIGN(size, align) to the equation and fixes the object size detection accordingly. This code in drivers/s390/cio/qdio_setup_init has lead to incorrectly aligned slab objects (sizeof(struct qdio_q) equals 1792): qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), 256, 0, NULL); Acked-by: Christoph Lameter Signed-off-by: Carsten Otte Signed-off-by: Pekka Enberg --- mm/slab.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index 736e497733d6..dd41b74c8322 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2330,8 +2330,8 @@ kmem_cache_create (const char *name, size_t size, size_t align, } #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC) if (size >= malloc_sizes[INDEX_L3 + 1].cs_size - && cachep->obj_size > cache_line_size() && size < PAGE_SIZE) { - cachep->obj_offset += PAGE_SIZE - size; + && cachep->obj_size > cache_line_size() && ALIGN(size, align) < PAGE_SIZE) { + cachep->obj_offset += PAGE_SIZE - ALIGN(size, align); size = PAGE_SIZE; } #endif -- cgit v1.2.3-59-g8ed1b From 3e33d94df7f5c94adb09139b5d816a248d703a36 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 11:17:25 +0100 Subject: drm/i915: Remove useless message when disabling "Big FIFO" on PineView As we already have appropriate debug and warnings when we activate and deactivate the self-refresh FIFO, having a further INFO is just annoying. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1e5e0d379fa9..1490a8c14d26 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2930,13 +2930,9 @@ static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, static void pineview_disable_cxsr(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg; /* deactivate cxsr */ - reg = I915_READ(DSPFW3); - reg &= ~(PINEVIEW_SELF_REFRESH_EN); - I915_WRITE(DSPFW3, reg); - DRM_INFO("Big FIFO is disabled\n"); + I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN); } /* @@ -3075,9 +3071,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg); /* activate cxsr */ - reg = I915_READ(DSPFW3); - reg |= PINEVIEW_SELF_REFRESH_EN; - I915_WRITE(DSPFW3, reg); + I915_WRITE(DSPFW3, + I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN); DRM_DEBUG_KMS("Self-refresh is enabled\n"); } else { pineview_disable_cxsr(dev); -- cgit v1.2.3-59-g8ed1b From 94113cecaea5067a0f7e1135abbd92cf2c297d42 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 11:25:21 +0100 Subject: drm/i915: Do not clobber the contents of TRANS_DP_CTL when enabling. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 281db6e5403a..97a35a42da28 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2928,6 +2928,7 @@ #define TRANS_DP_VSYNC_ACTIVE_LOW 0 #define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3) #define TRANS_DP_HSYNC_ACTIVE_LOW 0 +#define TRANS_DP_SYNC_MASK (3<<3) /* SNB eDP training params */ /* SNB A-stepping */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1490a8c14d26..c7f19ec88f98 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2097,9 +2097,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) int reg; reg = I915_READ(trans_dp_ctl); - reg &= ~TRANS_DP_PORT_SEL_MASK; - reg = TRANS_DP_OUTPUT_ENABLE | - TRANS_DP_ENH_FRAMING; + reg &= ~(TRANS_DP_PORT_SEL_MASK | + TRANS_DP_SYNC_MASK); + reg |= (TRANS_DP_OUTPUT_ENABLE | + TRANS_DP_ENH_FRAMING); if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; -- cgit v1.2.3-59-g8ed1b From ea5b213ad4b161463e76b63dbb115ea20e2200f0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:23 +0100 Subject: drm/i915: Subclass intel_encoder. Subclass intel_encoder to reduce the pointer dance through intel_encoder->dev_priv. 10 files changed, 896 insertions(+), 997 deletions(-) Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/dvo.h | 7 +- drivers/gpu/drm/i915/intel_crt.c | 11 +- drivers/gpu/drm/i915/intel_display.c | 14 + drivers/gpu/drm/i915/intel_dp.c | 462 ++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 136 +++-- drivers/gpu/drm/i915/intel_hdmi.c | 77 ++- drivers/gpu/drm/i915/intel_lvds.c | 62 +-- drivers/gpu/drm/i915/intel_sdvo.c | 972 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_tv.c | 150 +++--- 10 files changed, 896 insertions(+), 997 deletions(-) diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index 0d6ff640e1c6..8c2ad014c47f 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -30,20 +30,17 @@ #include "intel_drv.h" struct intel_dvo_device { - char *name; + const char *name; int type; /* DVOA/B/C output register */ u32 dvo_reg; /* GPIO register used for i2c bus to control this device */ u32 gpio; int slave_addr; - struct i2c_adapter *i2c_bus; const struct intel_dvo_dev_ops *dev_ops; void *dev_priv; - - struct drm_display_mode *panel_fixed_mode; - bool panel_wants_dither; + struct i2c_adapter *i2c_bus; }; struct intel_dvo_dev_ops { diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index ee0732b222a1..cfcf85496e30 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -508,17 +508,8 @@ static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs .best_encoder = intel_attached_encoder, }; -static void intel_crt_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - intel_i2c_destroy(intel_encoder->ddc_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_crt_enc_funcs = { - .destroy = intel_crt_enc_destroy, + .destroy = intel_encoder_destroy, }; void intel_crt_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c7f19ec88f98..9839494528ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2537,6 +2537,20 @@ void intel_encoder_commit (struct drm_encoder *encoder) encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } +void intel_encoder_destroy(struct drm_encoder *encoder) +{ + struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + + if (intel_encoder->ddc_bus) + intel_i2c_destroy(intel_encoder->ddc_bus); + + if (intel_encoder->i2c_bus) + intel_i2c_destroy(intel_encoder->i2c_bus); + + drm_encoder_cleanup(encoder); + kfree(intel_encoder); +} + static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 40be1fa65be1..c4c5868a8aa0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -42,10 +42,11 @@ #define DP_LINK_CONFIGURATION_SIZE 9 -#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP) -#define IS_PCH_eDP(dp_priv) ((dp_priv)->is_pch_edp) +#define IS_eDP(i) ((i)->base.type == INTEL_OUTPUT_EDP) +#define IS_PCH_eDP(i) ((i)->is_pch_edp) -struct intel_dp_priv { +struct intel_dp { + struct intel_encoder base; uint32_t output_reg; uint32_t DP; uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; @@ -54,40 +55,39 @@ struct intel_dp_priv { uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[4]; - struct intel_encoder *intel_encoder; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; }; -static void -intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, - uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]); +static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base); +} -static void -intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP); +static void intel_dp_link_train(struct intel_dp *intel_dp); +static void intel_dp_link_down(struct intel_dp *intel_dp); void intel_edp_link_config (struct intel_encoder *intel_encoder, - int *lane_num, int *link_bw) + int *lane_num, int *link_bw) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); - *lane_num = dp_priv->lane_count; - if (dp_priv->link_bw == DP_LINK_BW_1_62) + *lane_num = intel_dp->lane_count; + if (intel_dp->link_bw == DP_LINK_BW_1_62) *link_bw = 162000; - else if (dp_priv->link_bw == DP_LINK_BW_2_7) + else if (intel_dp->link_bw == DP_LINK_BW_2_7) *link_bw = 270000; } static int -intel_dp_max_lane_count(struct intel_encoder *intel_encoder) +intel_dp_max_lane_count(struct intel_dp *intel_dp) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; int max_lane_count = 4; - if (dp_priv->dpcd[0] >= 0x11) { - max_lane_count = dp_priv->dpcd[2] & 0x1f; + if (intel_dp->dpcd[0] >= 0x11) { + max_lane_count = intel_dp->dpcd[2] & 0x1f; switch (max_lane_count) { case 1: case 2: case 4: break; @@ -99,10 +99,9 @@ intel_dp_max_lane_count(struct intel_encoder *intel_encoder) } static int -intel_dp_max_link_bw(struct intel_encoder *intel_encoder) +intel_dp_max_link_bw(struct intel_dp *intel_dp) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - int max_link_bw = dp_priv->dpcd[1]; + int max_link_bw = intel_dp->dpcd[1]; switch (max_link_bw) { case DP_LINK_BW_1_62: @@ -126,13 +125,11 @@ intel_dp_link_clock(uint8_t link_bw) /* I think this is a fiction */ static int -intel_dp_link_required(struct drm_device *dev, - struct intel_encoder *intel_encoder, int pixel_clock) +intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pixel_clock) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) return (pixel_clock * dev_priv->edp_bpp) / 8; else return pixel_clock * 3; @@ -149,14 +146,13 @@ intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder)); - int max_lanes = intel_dp_max_lane_count(intel_encoder); + int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); + int max_lanes = intel_dp_max_lane_count(intel_dp); - if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && dev_priv->panel_fixed_mode) { if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay) return MODE_PANEL; @@ -167,8 +163,8 @@ intel_dp_mode_valid(struct drm_connector *connector, /* only refuse the mode on non eDP since we have seen some wierd eDP panels which are outside spec tolerances but somehow work by magic */ - if (!IS_eDP(intel_encoder) && - (intel_dp_link_required(connector->dev, intel_encoder, mode->clock) + if (!IS_eDP(intel_dp) && + (intel_dp_link_required(connector->dev, intel_dp, mode->clock) > intel_dp_max_data_rate(max_link_clock, max_lanes))) return MODE_CLOCK_HIGH; @@ -232,13 +228,12 @@ intel_hrawclk(struct drm_device *dev) } static int -intel_dp_aux_ch(struct intel_encoder *intel_encoder, +intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, uint8_t *recv, int recv_size) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - uint32_t output_reg = dp_priv->output_reg; - struct drm_device *dev = intel_encoder->enc.dev; + uint32_t output_reg = intel_dp->output_reg; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t ch_ctl = output_reg + 0x10; uint32_t ch_data = ch_ctl + 4; @@ -253,7 +248,7 @@ intel_dp_aux_ch(struct intel_encoder *intel_encoder, * and would like to run at 2MHz. So, take the * hrawclk value and divide by 2 and use that */ - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_dp)) { if (IS_GEN6(dev)) aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */ else @@ -344,7 +339,7 @@ intel_dp_aux_ch(struct intel_encoder *intel_encoder, /* Write data to the aux channel in native mode */ static int -intel_dp_aux_native_write(struct intel_encoder *intel_encoder, +intel_dp_aux_native_write(struct intel_dp *intel_dp, uint16_t address, uint8_t *send, int send_bytes) { int ret; @@ -361,7 +356,7 @@ intel_dp_aux_native_write(struct intel_encoder *intel_encoder, memcpy(&msg[4], send, send_bytes); msg_bytes = send_bytes + 4; for (;;) { - ret = intel_dp_aux_ch(intel_encoder, msg, msg_bytes, &ack, 1); + ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1); if (ret < 0) return ret; if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) @@ -376,15 +371,15 @@ intel_dp_aux_native_write(struct intel_encoder *intel_encoder, /* Write a single byte to the aux channel in native mode */ static int -intel_dp_aux_native_write_1(struct intel_encoder *intel_encoder, +intel_dp_aux_native_write_1(struct intel_dp *intel_dp, uint16_t address, uint8_t byte) { - return intel_dp_aux_native_write(intel_encoder, address, &byte, 1); + return intel_dp_aux_native_write(intel_dp, address, &byte, 1); } /* read bytes from a native aux channel */ static int -intel_dp_aux_native_read(struct intel_encoder *intel_encoder, +intel_dp_aux_native_read(struct intel_dp *intel_dp, uint16_t address, uint8_t *recv, int recv_bytes) { uint8_t msg[4]; @@ -403,7 +398,7 @@ intel_dp_aux_native_read(struct intel_encoder *intel_encoder, reply_bytes = recv_bytes + 1; for (;;) { - ret = intel_dp_aux_ch(intel_encoder, msg, msg_bytes, + ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, reply, reply_bytes); if (ret == 0) return -EPROTO; @@ -426,10 +421,9 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, uint8_t write_byte, uint8_t *read_byte) { struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; - struct intel_dp_priv *dp_priv = container_of(adapter, - struct intel_dp_priv, - adapter); - struct intel_encoder *intel_encoder = dp_priv->intel_encoder; + struct intel_dp *intel_dp = container_of(adapter, + struct intel_dp, + adapter); uint16_t address = algo_data->address; uint8_t msg[5]; uint8_t reply[2]; @@ -468,7 +462,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } for (;;) { - ret = intel_dp_aux_ch(intel_encoder, + ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, reply, reply_bytes); if (ret < 0) { @@ -496,41 +490,38 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } static int -intel_dp_i2c_init(struct intel_encoder *intel_encoder, +intel_dp_i2c_init(struct intel_dp *intel_dp, struct intel_connector *intel_connector, const char *name) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - DRM_DEBUG_KMS("i2c_init %s\n", name); - dp_priv->algo.running = false; - dp_priv->algo.address = 0; - dp_priv->algo.aux_ch = intel_dp_i2c_aux_ch; - - memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter)); - dp_priv->adapter.owner = THIS_MODULE; - dp_priv->adapter.class = I2C_CLASS_DDC; - strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1); - dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0'; - dp_priv->adapter.algo_data = &dp_priv->algo; - dp_priv->adapter.dev.parent = &intel_connector->base.kdev; - - return i2c_dp_aux_add_bus(&dp_priv->adapter); + intel_dp->algo.running = false; + intel_dp->algo.address = 0; + intel_dp->algo.aux_ch = intel_dp_i2c_aux_ch; + + memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter)); + intel_dp->adapter.owner = THIS_MODULE; + intel_dp->adapter.class = I2C_CLASS_DDC; + strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1); + intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0'; + intel_dp->adapter.algo_data = &intel_dp->algo; + intel_dp->adapter.dev.parent = &intel_connector->base.kdev; + + return i2c_dp_aux_add_bus(&intel_dp->adapter); } static bool intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int lane_count, clock; - int max_lane_count = intel_dp_max_lane_count(intel_encoder); - int max_clock = intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0; + int max_lane_count = intel_dp_max_lane_count(intel_dp); + int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; - if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && dev_priv->panel_fixed_mode) { struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; @@ -558,28 +549,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); - if (intel_dp_link_required(encoder->dev, intel_encoder, mode->clock) + if (intel_dp_link_required(encoder->dev, intel_dp, mode->clock) <= link_avail) { - dp_priv->link_bw = bws[clock]; - dp_priv->lane_count = lane_count; - adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); + intel_dp->link_bw = bws[clock]; + intel_dp->lane_count = lane_count; + adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); DRM_DEBUG_KMS("Display port link bw %02x lane " "count %d clock %d\n", - dp_priv->link_bw, dp_priv->lane_count, + intel_dp->link_bw, intel_dp->lane_count, adjusted_mode->clock); return true; } } } - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { /* okay we failed just pick the highest */ - dp_priv->lane_count = max_lane_count; - dp_priv->link_bw = bws[max_clock]; - adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); + intel_dp->lane_count = max_lane_count; + intel_dp->link_bw = bws[max_clock]; + adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); DRM_DEBUG_KMS("Force picking display port link bw %02x lane " "count %d clock %d\n", - dp_priv->link_bw, dp_priv->lane_count, + intel_dp->link_bw, intel_dp->lane_count, adjusted_mode->clock); return true; } @@ -626,17 +617,14 @@ bool intel_pch_has_edp(struct drm_crtc *crtc) struct drm_encoder *encoder; list_for_each_entry(encoder, &mode_config->encoder_list, head) { - struct intel_encoder *intel_encoder; - struct intel_dp_priv *dp_priv; + struct intel_dp *intel_dp; - if (!encoder || encoder->crtc != crtc) + if (encoder->crtc != crtc) continue; - intel_encoder = enc_to_intel_encoder(encoder); - dp_priv = intel_encoder->dev_priv; - - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) - return dp_priv->is_pch_edp; + intel_dp = enc_to_intel_dp(encoder); + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) + return intel_dp->is_pch_edp; } return false; } @@ -657,18 +645,15 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, * Find the lane count in the intel_encoder private */ list_for_each_entry(encoder, &mode_config->encoder_list, head) { - struct intel_encoder *intel_encoder; - struct intel_dp_priv *dp_priv; + struct intel_dp *intel_dp; if (encoder->crtc != crtc) continue; - intel_encoder = enc_to_intel_encoder(encoder); - dp_priv = intel_encoder->dev_priv; - - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { - lane_count = dp_priv->lane_count; - if (IS_PCH_eDP(dp_priv)) + intel_dp = enc_to_intel_dp(encoder); + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) { + lane_count = intel_dp->lane_count; + if (IS_PCH_eDP(intel_dp)) bpp = dev_priv->edp_bpp; break; } @@ -724,61 +709,60 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - struct drm_crtc *crtc = intel_encoder->enc.crtc; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_crtc *crtc = intel_dp->base.enc.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - dp_priv->DP = (DP_VOLTAGE_0_4 | + intel_dp->DP = (DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0); if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - dp_priv->DP |= DP_SYNC_HS_HIGH; + intel_dp->DP |= DP_SYNC_HS_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - dp_priv->DP |= DP_SYNC_VS_HIGH; + intel_dp->DP |= DP_SYNC_VS_HIGH; - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) - dp_priv->DP |= DP_LINK_TRAIN_OFF_CPT; + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) + intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; else - dp_priv->DP |= DP_LINK_TRAIN_OFF; + intel_dp->DP |= DP_LINK_TRAIN_OFF; - switch (dp_priv->lane_count) { + switch (intel_dp->lane_count) { case 1: - dp_priv->DP |= DP_PORT_WIDTH_1; + intel_dp->DP |= DP_PORT_WIDTH_1; break; case 2: - dp_priv->DP |= DP_PORT_WIDTH_2; + intel_dp->DP |= DP_PORT_WIDTH_2; break; case 4: - dp_priv->DP |= DP_PORT_WIDTH_4; + intel_dp->DP |= DP_PORT_WIDTH_4; break; } - if (dp_priv->has_audio) - dp_priv->DP |= DP_AUDIO_OUTPUT_ENABLE; + if (intel_dp->has_audio) + intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; - memset(dp_priv->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); - dp_priv->link_configuration[0] = dp_priv->link_bw; - dp_priv->link_configuration[1] = dp_priv->lane_count; + memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); + intel_dp->link_configuration[0] = intel_dp->link_bw; + intel_dp->link_configuration[1] = intel_dp->lane_count; /* * Check for DPCD version > 1.1 and enhanced framing support */ - if (dp_priv->dpcd[0] >= 0x11 && (dp_priv->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { - dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - dp_priv->DP |= DP_ENHANCED_FRAMING; + if (intel_dp->dpcd[0] >= 0x11 && (intel_dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { + intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + intel_dp->DP |= DP_ENHANCED_FRAMING; } /* CPT DP's pipe select is decided in TRANS_DP_CTL */ if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev)) - dp_priv->DP |= DP_PIPEB_SELECT; + intel_dp->DP |= DP_PIPEB_SELECT; - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_dp)) { /* don't miss out required setting for eDP */ - dp_priv->DP |= DP_PLL_ENABLE; + intel_dp->DP |= DP_PLL_ENABLE; if (adjusted_mode->clock < 200000) - dp_priv->DP |= DP_PLL_FREQ_160MHZ; + intel_dp->DP |= DP_PLL_FREQ_160MHZ; else - dp_priv->DP |= DP_PLL_FREQ_270MHZ; + intel_dp->DP |= DP_PLL_FREQ_270MHZ; } } @@ -852,30 +836,29 @@ static void ironlake_edp_backlight_off (struct drm_device *dev) static void intel_dp_dpms(struct drm_encoder *encoder, int mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dp_reg = I915_READ(dp_priv->output_reg); + uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { if (dp_reg & DP_PORT_EN) { - intel_dp_link_down(intel_encoder, dp_priv->DP); - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + intel_dp_link_down(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { ironlake_edp_backlight_off(dev); ironlake_edp_panel_off(dev); } } } else { if (!(dp_reg & DP_PORT_EN)) { - intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + intel_dp_link_train(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { ironlake_edp_panel_on(dev); ironlake_edp_backlight_on(dev); } } } - dp_priv->dpms_mode = mode; + intel_dp->dpms_mode = mode; } /* @@ -883,12 +866,12 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) * link status information */ static bool -intel_dp_get_link_status(struct intel_encoder *intel_encoder, +intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { int ret; - ret = intel_dp_aux_native_read(intel_encoder, + ret = intel_dp_aux_native_read(intel_dp, DP_LANE0_1_STATUS, link_status, DP_LINK_STATUS_SIZE); if (ret != DP_LINK_STATUS_SIZE) @@ -965,7 +948,7 @@ intel_dp_pre_emphasis_max(uint8_t voltage_swing) } static void -intel_get_adjust_train(struct intel_encoder *intel_encoder, +intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count, uint8_t train_set[4]) @@ -1101,27 +1084,26 @@ intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count) } static bool -intel_dp_set_link_train(struct intel_encoder *intel_encoder, +intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, uint8_t dp_train_pat, uint8_t train_set[4], bool first) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; int ret; - I915_WRITE(dp_priv->output_reg, dp_reg_value); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, dp_reg_value); + POSTING_READ(intel_dp->output_reg); if (first) intel_wait_for_vblank(dev); - intel_dp_aux_native_write_1(intel_encoder, + intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, dp_train_pat); - ret = intel_dp_aux_native_write(intel_encoder, + ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET, train_set, 4); if (ret != 4) return false; @@ -1130,12 +1112,10 @@ intel_dp_set_link_train(struct intel_encoder *intel_encoder, } static void -intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, - uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]) +intel_dp_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; uint8_t train_set[4]; uint8_t link_status[DP_LINK_STATUS_SIZE]; int i; @@ -1145,13 +1125,15 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, bool first = true; int tries; u32 reg; + uint32_t DP = intel_dp->DP; /* Write the link configuration data */ - intel_dp_aux_native_write(intel_encoder, DP_LINK_BW_SET, - link_configuration, DP_LINK_CONFIGURATION_SIZE); + intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, + intel_dp->link_configuration, + DP_LINK_CONFIGURATION_SIZE); DP |= DP_PORT_EN; - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) DP &= ~DP_LINK_TRAIN_MASK_CPT; else DP &= ~DP_LINK_TRAIN_MASK; @@ -1162,39 +1144,39 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, for (;;) { /* Use train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; - if (IS_GEN6(dev) && IS_eDP(intel_encoder)) { + if (IS_GEN6(dev) && IS_eDP(intel_dp)) { signal_levels = intel_gen6_edp_signal_levels(train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count); + signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) reg = DP | DP_LINK_TRAIN_PAT_1_CPT; else reg = DP | DP_LINK_TRAIN_PAT_1; - if (!intel_dp_set_link_train(intel_encoder, reg, + if (!intel_dp_set_link_train(intel_dp, reg, DP_TRAINING_PATTERN_1, train_set, first)) break; first = false; /* Set training pattern 1 */ udelay(100); - if (!intel_dp_get_link_status(intel_encoder, link_status)) + if (!intel_dp_get_link_status(intel_dp, link_status)) break; - if (intel_clock_recovery_ok(link_status, dp_priv->lane_count)) { + if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) { clock_recovery = true; break; } /* Check to see if we've tried the max voltage */ - for (i = 0; i < dp_priv->lane_count; i++) + for (i = 0; i < intel_dp->lane_count; i++) if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; - if (i == dp_priv->lane_count) + if (i == intel_dp->lane_count) break; /* Check to see if we've tried the same voltage 5 times */ @@ -1207,7 +1189,7 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; /* Compute new train_set as requested by target */ - intel_get_adjust_train(intel_encoder, link_status, dp_priv->lane_count, train_set); + intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); } /* channel equalization */ @@ -1217,30 +1199,30 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, /* Use train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; - if (IS_GEN6(dev) && IS_eDP(intel_encoder)) { + if (IS_GEN6(dev) && IS_eDP(intel_dp)) { signal_levels = intel_gen6_edp_signal_levels(train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count); + signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) reg = DP | DP_LINK_TRAIN_PAT_2_CPT; else reg = DP | DP_LINK_TRAIN_PAT_2; /* channel eq pattern */ - if (!intel_dp_set_link_train(intel_encoder, reg, + if (!intel_dp_set_link_train(intel_dp, reg, DP_TRAINING_PATTERN_2, train_set, false)) break; udelay(400); - if (!intel_dp_get_link_status(intel_encoder, link_status)) + if (!intel_dp_get_link_status(intel_dp, link_status)) break; - if (intel_channel_eq_ok(link_status, dp_priv->lane_count)) { + if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) { channel_eq = true; break; } @@ -1250,53 +1232,53 @@ intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP, break; /* Compute new train_set as requested by target */ - intel_get_adjust_train(intel_encoder, link_status, dp_priv->lane_count, train_set); + intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set); ++tries; } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) reg = DP | DP_LINK_TRAIN_OFF_CPT; else reg = DP | DP_LINK_TRAIN_OFF; - I915_WRITE(dp_priv->output_reg, reg); - POSTING_READ(dp_priv->output_reg); - intel_dp_aux_native_write_1(intel_encoder, + I915_WRITE(intel_dp->output_reg, reg); + POSTING_READ(intel_dp->output_reg); + intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); } static void -intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP) +intel_dp_link_down(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + uint32_t DP = intel_dp->DP; DRM_DEBUG_KMS("\n"); - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_dp)) { DP &= ~DP_PLL_ENABLE; - I915_WRITE(dp_priv->output_reg, DP); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP); + POSTING_READ(intel_dp->output_reg); udelay(100); } - if (HAS_PCH_CPT(dev) && !IS_eDP(intel_encoder)) { + if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) { DP &= ~DP_LINK_TRAIN_MASK_CPT; - I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); + POSTING_READ(intel_dp->output_reg); } else { DP &= ~DP_LINK_TRAIN_MASK; - I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); + POSTING_READ(intel_dp->output_reg); } udelay(17000); - if (IS_eDP(intel_encoder)) + if (IS_eDP(intel_dp)) DP |= DP_LINK_TRAIN_OFF; - I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN); - POSTING_READ(dp_priv->output_reg); + I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); + POSTING_READ(intel_dp->output_reg); } /* @@ -1309,41 +1291,39 @@ intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP) */ static void -intel_dp_check_link_status(struct intel_encoder *intel_encoder) +intel_dp_check_link_status(struct intel_dp *intel_dp) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; uint8_t link_status[DP_LINK_STATUS_SIZE]; - if (!intel_encoder->enc.crtc) + if (!intel_dp->base.enc.crtc) return; - if (!intel_dp_get_link_status(intel_encoder, link_status)) { - intel_dp_link_down(intel_encoder, dp_priv->DP); + if (!intel_dp_get_link_status(intel_dp, link_status)) { + intel_dp_link_down(intel_dp); return; } - if (!intel_channel_eq_ok(link_status, dp_priv->lane_count)) - intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); + if (!intel_channel_eq_ok(link_status, intel_dp->lane_count)) + intel_dp_link_train(intel_dp); } static enum drm_connector_status ironlake_dp_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); enum drm_connector_status status; status = connector_status_disconnected; - if (intel_dp_aux_native_read(intel_encoder, - 0x000, dp_priv->dpcd, - sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) + if (intel_dp_aux_native_read(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) { - if (dp_priv->dpcd[0] != 0) + if (intel_dp->dpcd[0] != 0) status = connector_status_connected; } - DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", dp_priv->dpcd[0], - dp_priv->dpcd[1], dp_priv->dpcd[2], dp_priv->dpcd[3]); + DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], + intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); return status; } @@ -1357,19 +1337,18 @@ static enum drm_connector_status intel_dp_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct drm_device *dev = intel_encoder->enc.dev; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; uint32_t temp, bit; enum drm_connector_status status; - dp_priv->has_audio = false; + intel_dp->has_audio = false; if (HAS_PCH_SPLIT(dev)) return ironlake_dp_detect(connector); - switch (dp_priv->output_reg) { + switch (intel_dp->output_reg) { case DP_B: bit = DPB_HOTPLUG_INT_STATUS; break; @@ -1389,11 +1368,11 @@ intel_dp_detect(struct drm_connector *connector) return connector_status_disconnected; status = connector_status_disconnected; - if (intel_dp_aux_native_read(intel_encoder, - 0x000, dp_priv->dpcd, - sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) + if (intel_dp_aux_native_read(intel_dp, + 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) { - if (dp_priv->dpcd[0] != 0) + if (intel_dp->dpcd[0] != 0) status = connector_status_connected; } return status; @@ -1402,18 +1381,17 @@ intel_dp_detect(struct drm_connector *connector) static int intel_dp_get_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct drm_device *dev = intel_encoder->enc.dev; + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; int ret; /* We should parse the EDID data and find out if it has an audio sink */ - ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus); if (ret) { - if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && !dev_priv->panel_fixed_mode) { struct drm_display_mode *newmode; list_for_each_entry(newmode, &connector->probed_modes, @@ -1430,7 +1408,7 @@ static int intel_dp_get_modes(struct drm_connector *connector) } /* if eDP has no EDID, try to use fixed panel mode from VBT */ - if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { if (dev_priv->panel_fixed_mode != NULL) { struct drm_display_mode *mode; mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); @@ -1470,27 +1448,17 @@ static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = .best_encoder = intel_attached_encoder, }; -static void intel_dp_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_dp_enc_funcs = { - .destroy = intel_dp_enc_destroy, + .destroy = intel_encoder_destroy, }; void intel_dp_hot_plug(struct intel_encoder *intel_encoder) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); - if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON) - intel_dp_check_link_status(intel_encoder); + if (intel_dp->dpms_mode == DRM_MODE_DPMS_ON) + intel_dp_check_link_status(intel_dp); } /* Return which DP Port should be selected for Transcoder DP control */ @@ -1500,18 +1468,18 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_encoder *encoder; - struct intel_encoder *intel_encoder = NULL; list_for_each_entry(encoder, &mode_config->encoder_list, head) { + struct intel_dp *intel_dp; + if (encoder->crtc != crtc) continue; - intel_encoder = enc_to_intel_encoder(encoder); - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { - struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - return dp_priv->output_reg; - } + intel_dp = enc_to_intel_dp(encoder); + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) + return intel_dp->output_reg; } + return -1; } @@ -1540,30 +1508,28 @@ intel_dp_init(struct drm_device *dev, int output_reg) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; + struct intel_dp *intel_dp; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; - struct intel_dp_priv *dp_priv; const char *name = NULL; int type; - intel_encoder = kcalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_dp_priv), 1, GFP_KERNEL); - if (!intel_encoder) + intel_dp = kzalloc(sizeof(struct intel_dp), GFP_KERNEL); + if (!intel_dp) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_dp); return; } + intel_encoder = &intel_dp->base; - dp_priv = (struct intel_dp_priv *)(intel_encoder + 1); - - if (HAS_PCH_SPLIT(dev) && (output_reg == PCH_DP_D)) + if (HAS_PCH_SPLIT(dev) && output_reg == PCH_DP_D) if (intel_dpd_is_edp(dev)) - dp_priv->is_pch_edp = true; + intel_dp->is_pch_edp = true; - if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) { + if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) { type = DRM_MODE_CONNECTOR_eDP; intel_encoder->type = INTEL_OUTPUT_EDP; } else { @@ -1584,18 +1550,16 @@ intel_dp_init(struct drm_device *dev, int output_reg) else if (output_reg == DP_D || output_reg == PCH_DP_D) intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT); - if (IS_eDP(intel_encoder)) + if (IS_eDP(intel_dp)) intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT); intel_encoder->crtc_mask = (1 << 0) | (1 << 1); connector->interlace_allowed = true; connector->doublescan_allowed = 0; - dp_priv->intel_encoder = intel_encoder; - dp_priv->output_reg = output_reg; - dp_priv->has_audio = false; - dp_priv->dpms_mode = DRM_MODE_DPMS_ON; - intel_encoder->dev_priv = dp_priv; + intel_dp->output_reg = output_reg; + intel_dp->has_audio = false; + intel_dp->dpms_mode = DRM_MODE_DPMS_ON; drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); @@ -1630,12 +1594,12 @@ intel_dp_init(struct drm_device *dev, int output_reg) break; } - intel_dp_i2c_init(intel_encoder, intel_connector, name); + intel_dp_i2c_init(intel_dp, intel_connector, name); - intel_encoder->ddc_bus = &dp_priv->adapter; + intel_encoder->ddc_bus = &intel_dp->adapter; intel_encoder->hot_plug = intel_dp_hot_plug; - if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) { + if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) { /* initialize panel mode from VBT if available for eDP */ if (dev_priv->lfp_lvds_vbt_mode) { dev_priv->panel_fixed_mode = diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b2190148703a..520b22cd708e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -102,7 +102,6 @@ struct intel_encoder { struct i2c_adapter *ddc_bus; bool load_detect_temp; bool needs_tv_clock; - void *dev_priv; void (*hot_plug)(struct intel_encoder *); int crtc_mask; int clone_mask; @@ -192,6 +191,7 @@ extern int intel_panel_fitter_pipe (struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); extern void intel_encoder_commit (struct drm_encoder *encoder); +extern void intel_encoder_destroy(struct drm_encoder *encoder); extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 227feca7cf8d..a399f4b2c1c5 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -38,7 +38,7 @@ #define CH7xxx_ADDR 0x76 #define TFP410_ADDR 0x38 -static struct intel_dvo_device intel_dvo_devices[] = { +static const struct intel_dvo_device intel_dvo_devices[] = { { .type = INTEL_DVO_CHIP_TMDS, .name = "sil164", @@ -77,20 +77,33 @@ static struct intel_dvo_device intel_dvo_devices[] = { } }; +struct intel_dvo { + struct intel_encoder base; + + struct intel_dvo_device dev; + + struct drm_display_mode *panel_fixed_mode; + bool panel_wants_dither; +}; + +static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base); +} + static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; - u32 dvo_reg = dvo->dvo_reg; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + u32 dvo_reg = intel_dvo->dev.dvo_reg; u32 temp = I915_READ(dvo_reg); if (mode == DRM_MODE_DPMS_ON) { I915_WRITE(dvo_reg, temp | DVO_ENABLE); I915_READ(dvo_reg); - dvo->dev_ops->dpms(dvo, mode); + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode); } else { - dvo->dev_ops->dpms(dvo, mode); + intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode); I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); I915_READ(dvo_reg); } @@ -100,38 +113,36 @@ static int intel_dvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; /* XXX: Validate clock range */ - if (dvo->panel_fixed_mode) { - if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay) + if (intel_dvo->panel_fixed_mode) { + if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay) + if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay) return MODE_PANEL; } - return dvo->dev_ops->mode_valid(dvo, mode); + return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); } static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); /* If we have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - if (dvo->panel_fixed_mode != NULL) { -#define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x + if (intel_dvo->panel_fixed_mode != NULL) { +#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x C(hdisplay); C(hsync_start); C(hsync_end); @@ -145,8 +156,8 @@ static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, #undef C } - if (dvo->dev_ops->mode_fixup) - return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode); + if (intel_dvo->dev.dev_ops->mode_fixup) + return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev, mode, adjusted_mode); return true; } @@ -158,11 +169,10 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); int pipe = intel_crtc->pipe; u32 dvo_val; - u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg; + u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; switch (dvo_reg) { @@ -178,7 +188,7 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, break; } - dvo->dev_ops->mode_set(dvo, mode, adjusted_mode); + intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, mode, adjusted_mode); /* Save the data order, since I don't know what it should be set to. */ dvo_val = I915_READ(dvo_reg) & @@ -214,40 +224,38 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); - return dvo->dev_ops->detect(dvo); + return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev); } static int intel_dvo_get_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); /* We should probably have an i2c driver get_modes function for those * devices which will have a fixed set of modes determined by the chip * (TV-out, for example), but for now with just TMDS and LVDS, * that's not the case. */ - intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus); if (!list_empty(&connector->probed_modes)) return 1; - - if (dvo->panel_fixed_mode != NULL) { + if (intel_dvo->panel_fixed_mode != NULL) { struct drm_display_mode *mode; - mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode); + mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode); if (mode) { drm_mode_probed_add(connector, mode); return 1; } } + return 0; } -static void intel_dvo_destroy (struct drm_connector *connector) +static void intel_dvo_destroy(struct drm_connector *connector) { drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -277,28 +285,20 @@ static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs static void intel_dvo_enc_destroy(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; - - if (dvo) { - if (dvo->dev_ops->destroy) - dvo->dev_ops->destroy(dvo); - if (dvo->panel_fixed_mode) - kfree(dvo->panel_fixed_mode); - } - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + + if (intel_dvo->dev.dev_ops->destroy) + intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev); + + kfree(intel_dvo->panel_fixed_mode); + + intel_encoder_destroy(encoder); } static const struct drm_encoder_funcs intel_dvo_enc_funcs = { .destroy = intel_dvo_enc_destroy, }; - /** * Attempts to get a fixed panel timing for LVDS (currently only the i830). * @@ -306,15 +306,13 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = { * chip being on DVOB/C and having multiple pipes. */ static struct drm_display_mode * -intel_dvo_get_current_mode (struct drm_connector *connector) +intel_dvo_get_current_mode(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_dvo_device *dvo = intel_encoder->dev_priv; - uint32_t dvo_reg = dvo->dvo_reg; - uint32_t dvo_val = I915_READ(dvo_reg); + struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); + uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg); struct drm_display_mode *mode = NULL; /* If the DVO port is active, that'll be the LVDS, so we can pull out @@ -327,7 +325,6 @@ intel_dvo_get_current_mode (struct drm_connector *connector) crtc = intel_get_crtc_from_pipe(dev, pipe); if (crtc) { mode = intel_crtc_mode_get(dev, crtc); - if (mode) { mode->type |= DRM_MODE_TYPE_PREFERRED; if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) @@ -337,28 +334,32 @@ intel_dvo_get_current_mode (struct drm_connector *connector) } } } + return mode; } void intel_dvo_init(struct drm_device *dev) { struct intel_encoder *intel_encoder; + struct intel_dvo *intel_dvo; struct intel_connector *intel_connector; - struct intel_dvo_device *dvo; struct i2c_adapter *i2cbus = NULL; int ret = 0; int i; int encoder_type = DRM_MODE_ENCODER_NONE; - intel_encoder = kzalloc (sizeof(struct intel_encoder), GFP_KERNEL); - if (!intel_encoder) + + intel_dvo = kzalloc(sizeof(struct intel_dvo), GFP_KERNEL); + if (!intel_dvo) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_dvo); return; } + intel_encoder = &intel_dvo->base; + /* Set up the DDC bus */ intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); if (!intel_encoder->ddc_bus) @@ -367,10 +368,9 @@ void intel_dvo_init(struct drm_device *dev) /* Now, try to find a controller */ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { struct drm_connector *connector = &intel_connector->base; + const struct intel_dvo_device *dvo = &intel_dvo_devices[i]; int gpio; - dvo = &intel_dvo_devices[i]; - /* Allow the I2C driver info to specify the GPIO to be used in * special cases, but otherwise default to what's defined * in the spec. @@ -393,11 +393,8 @@ void intel_dvo_init(struct drm_device *dev) continue; } - if (dvo->dev_ops!= NULL) - ret = dvo->dev_ops->init(dvo, i2cbus); - else - ret = false; - + intel_dvo->dev = *dvo; + ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus); if (!ret) continue; @@ -429,9 +426,6 @@ void intel_dvo_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; - intel_encoder->dev_priv = dvo; - intel_encoder->i2c_bus = i2cbus; - drm_encoder_init(dev, &intel_encoder->enc, &intel_dvo_enc_funcs, encoder_type); drm_encoder_helper_add(&intel_encoder->enc, @@ -447,9 +441,9 @@ void intel_dvo_init(struct drm_device *dev) * headers, likely), so for now, just get the current * mode being output through DVO. */ - dvo->panel_fixed_mode = + intel_dvo->panel_fixed_mode = intel_dvo_get_current_mode(connector); - dvo->panel_wants_dither = true; + intel_dvo->panel_wants_dither = true; } drm_sysfs_connector_add(connector); @@ -461,6 +455,6 @@ void intel_dvo_init(struct drm_device *dev) if (i2cbus != NULL) intel_i2c_destroy(i2cbus); free_intel: - kfree(intel_encoder); + kfree(intel_dvo); kfree(intel_connector); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 197887ed1823..ccd4c97e6524 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -37,11 +37,17 @@ #include "i915_drm.h" #include "i915_drv.h" -struct intel_hdmi_priv { +struct intel_hdmi { + struct intel_encoder base; u32 sdvox_reg; bool has_hdmi_sink; }; +static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base); +} + static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -50,8 +56,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 sdvox; sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; @@ -60,7 +65,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) sdvox |= SDVO_HSYNC_ACTIVE_HIGH; - if (hdmi_priv->has_hdmi_sink) { + if (intel_hdmi->has_hdmi_sink) { sdvox |= SDVO_AUDIO_ENABLE; if (HAS_PCH_CPT(dev)) sdvox |= HDMI_MODE_SELECT; @@ -73,26 +78,25 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, sdvox |= SDVO_PIPE_B_SELECT; } - I915_WRITE(hdmi_priv->sdvox_reg, sdvox); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, sdvox); + POSTING_READ(intel_hdmi->sdvox_reg); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 temp; - temp = I915_READ(hdmi_priv->sdvox_reg); + temp = I915_READ(intel_hdmi->sdvox_reg); /* HW workaround, need to toggle enable bit off and on for 12bpc, but * we do this anyway which shows more stable in testing. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->sdvox_reg); } if (mode != DRM_MODE_DPMS_ON) { @@ -101,15 +105,15 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) temp |= SDVO_ENABLE; } - I915_WRITE(hdmi_priv->sdvox_reg, temp); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); /* HW workaround, need to write this twice for issue that may result * in first write getting masked. */ if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(hdmi_priv->sdvox_reg, temp); - POSTING_READ(hdmi_priv->sdvox_reg); + I915_WRITE(intel_hdmi->sdvox_reg, temp); + POSTING_READ(intel_hdmi->sdvox_reg); } } @@ -138,19 +142,17 @@ static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct edid *edid = NULL; enum drm_connector_status status = connector_status_disconnected; - hdmi_priv->has_hdmi_sink = false; - edid = drm_get_edid(connector, - intel_encoder->ddc_bus); + intel_hdmi->has_hdmi_sink = false; + edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus); if (edid) { if (edid->input & DRM_EDID_INPUT_DIGITAL) { status = connector_status_connected; - hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid); + intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); } connector->display_info.raw_edid = NULL; kfree(edid); @@ -162,13 +164,13 @@ intel_hdmi_detect(struct drm_connector *connector) static int intel_hdmi_get_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); /* We should parse the EDID data and find out if it's an HDMI sink so * we can send audio to it. */ - return intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus); } static void intel_hdmi_destroy(struct drm_connector *connector) @@ -199,18 +201,8 @@ static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs .best_encoder = intel_attached_encoder, }; -static void intel_hdmi_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { - .destroy = intel_hdmi_enc_destroy, + .destroy = intel_encoder_destroy, }; void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) @@ -219,21 +211,19 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) struct drm_connector *connector; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; - struct intel_hdmi_priv *hdmi_priv; + struct intel_hdmi *intel_hdmi; - intel_encoder = kcalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL); - if (!intel_encoder) + intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL); + if (!intel_hdmi) return; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_hdmi); return; } - hdmi_priv = (struct intel_hdmi_priv *)(intel_encoder + 1); - + intel_encoder = &intel_hdmi->base; connector = &intel_connector->base; drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -274,8 +264,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) if (!intel_encoder->ddc_bus) goto err_connector; - hdmi_priv->sdvox_reg = sdvox_reg; - intel_encoder->dev_priv = hdmi_priv; + intel_hdmi->sdvox_reg = sdvox_reg; drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS); @@ -298,7 +287,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) err_connector: drm_connector_cleanup(connector); - kfree(intel_encoder); + kfree(intel_hdmi); kfree(intel_connector); return; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 0a2e60059fb3..312ac306469a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -41,12 +41,18 @@ #include /* Private structure for the integrated LVDS support */ -struct intel_lvds_priv { +struct intel_lvds { + struct intel_encoder base; int fitting_mode; u32 pfit_control; u32 pfit_pgm_ratios; }; +static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base); +} + /** * Sets the backlight level. * @@ -219,9 +225,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); struct drm_encoder *tmp_encoder; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; /* Should never happen!! */ @@ -293,7 +298,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, I915_WRITE(BCLRPAT_B, 0); } - switch (lvds_priv->fitting_mode) { + switch (intel_lvds->fitting_mode) { case DRM_MODE_SCALE_CENTER: /* * For centered modes, we have to calculate border widths & @@ -378,8 +383,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } out: - lvds_priv->pfit_control = pfit_control; - lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios; + intel_lvds->pfit_control = pfit_control; + intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios; dev_priv->lvds_border_bits = border; /* @@ -427,8 +432,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv; + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); /* * The LVDS pin pair will already have been turned on in the @@ -444,8 +448,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * screen. Should be enabled before the pipe is enabled, according to * register description and PRM. */ - I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control); + I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); } /** @@ -600,18 +604,17 @@ static int intel_lvds_set_property(struct drm_connector *connector, connector->encoder) { struct drm_crtc *crtc = connector->encoder->crtc; struct drm_encoder *encoder = connector->encoder; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv; + struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder); if (value == DRM_MODE_SCALE_NONE) { DRM_DEBUG_KMS("no scaling not supported\n"); return 0; } - if (lvds_priv->fitting_mode == value) { + if (intel_lvds->fitting_mode == value) { /* the LVDS scaling property is not changed */ return 0; } - lvds_priv->fitting_mode = value; + intel_lvds->fitting_mode = value; if (crtc && crtc->enabled) { /* * If the CRTC is enabled, the display will be changed @@ -647,19 +650,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { .destroy = intel_lvds_destroy, }; - -static void intel_lvds_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_lvds_enc_funcs = { - .destroy = intel_lvds_enc_destroy, + .destroy = intel_encoder_destroy, }; static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) @@ -843,13 +835,13 @@ static int lvds_is_present_in_vbt(struct drm_device *dev) void intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_lvds *intel_lvds; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; - struct intel_lvds_priv *lvds_priv; u32 lvds; int pipe, gpio = GPIOC; @@ -872,20 +864,20 @@ void intel_lvds_init(struct drm_device *dev) gpio = PCH_GPIOC; } - intel_encoder = kzalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_lvds_priv), GFP_KERNEL); - if (!intel_encoder) { + intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); + if (!intel_lvds) { return; } intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_lvds); return; } - connector = &intel_connector->base; + intel_encoder = &intel_lvds->base; encoder = &intel_encoder->enc; + connector = &intel_connector->base; drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs, DRM_MODE_CONNECTOR_LVDS); @@ -905,8 +897,6 @@ void intel_lvds_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; - lvds_priv = (struct intel_lvds_priv *)(intel_encoder + 1); - intel_encoder->dev_priv = lvds_priv; /* create the scaling mode property */ drm_mode_create_scaling_mode_property(dev); /* @@ -916,7 +906,7 @@ void intel_lvds_init(struct drm_device *dev) drm_connector_attach_property(&intel_connector->base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_ASPECT); - lvds_priv->fitting_mode = DRM_MODE_SCALE_ASPECT; + intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT; /* * LVDS discovery: * 1) check for EDID on DDC @@ -1024,6 +1014,6 @@ failed: intel_i2c_destroy(intel_encoder->ddc_bus); drm_connector_cleanup(connector); drm_encoder_cleanup(encoder); - kfree(intel_encoder); + kfree(intel_lvds); kfree(intel_connector); } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d9d4d51aa89e..2fc9da4c0791 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -31,8 +31,8 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" -#include "intel_drv.h" #include "drm_edid.h" +#include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" #include "intel_sdvo_regs.h" @@ -61,7 +61,9 @@ static char *tv_format_names[] = { #define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names)) -struct intel_sdvo_priv { +struct intel_sdvo { + struct intel_encoder base; + u8 slave_addr; /* Register for the SDVO device: SDVOB or SDVOC */ @@ -173,9 +175,13 @@ struct intel_sdvo_connector { u32 cur_hue, max_hue; }; +static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base); +} + static bool -intel_sdvo_output_setup(struct intel_encoder *intel_encoder, - uint16_t flags); +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags); static void intel_sdvo_tv_create_property(struct drm_connector *connector, int type); static void @@ -186,21 +192,20 @@ intel_sdvo_create_enhance_property(struct drm_connector *connector); * SDVOB and SDVOC to work around apparent hardware issues (according to * comments in the BIOS). */ -static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val) +static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) { - struct drm_device *dev = intel_encoder->enc.dev; + struct drm_device *dev = intel_sdvo->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u32 bval = val, cval = val; int i; - if (sdvo_priv->sdvo_reg == PCH_SDVOB) { - I915_WRITE(sdvo_priv->sdvo_reg, val); - I915_READ(sdvo_priv->sdvo_reg); + if (intel_sdvo->sdvo_reg == PCH_SDVOB) { + I915_WRITE(intel_sdvo->sdvo_reg, val); + I915_READ(intel_sdvo->sdvo_reg); return; } - if (sdvo_priv->sdvo_reg == SDVOB) { + if (intel_sdvo->sdvo_reg == SDVOB) { cval = I915_READ(SDVOC); } else { bval = I915_READ(SDVOB); @@ -219,23 +224,22 @@ static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val) } } -static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, +static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u8 out_buf[2]; u8 buf[2]; int ret; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 1, .buf = out_buf, }, { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, .buf = buf, @@ -245,7 +249,7 @@ static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, out_buf[0] = addr; out_buf[1] = 0; - if ((ret = i2c_transfer(intel_encoder->i2c_bus, msgs, 2)) == 2) + if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2) { *ch = buf[0]; return true; @@ -255,14 +259,13 @@ static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr, return false; } -static bool intel_sdvo_write_byte(struct intel_encoder *intel_encoder, int addr, +static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u8 out_buf[2]; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 2, .buf = out_buf, @@ -272,7 +275,7 @@ static bool intel_sdvo_write_byte(struct intel_encoder *intel_encoder, int addr, out_buf[0] = addr; out_buf[1] = ch; - if (i2c_transfer(intel_encoder->i2c_bus, msgs, 1) == 1) + if (i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1) { return true; } @@ -377,17 +380,15 @@ static const struct _sdvo_cmd_name { }; #define IS_SDVOB(reg) (reg == SDVOB || reg == PCH_SDVOB) -#define SDVO_NAME(dev_priv) (IS_SDVOB((dev_priv)->sdvo_reg) ? "SDVOB" : "SDVOC") -#define SDVO_PRIV(encoder) ((struct intel_sdvo_priv *) (encoder)->dev_priv) +#define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") -static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd, +static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, void *args, int args_len) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; int i; DRM_DEBUG_KMS("%s: W: %02X ", - SDVO_NAME(sdvo_priv), cmd); + SDVO_NAME(intel_sdvo), cmd); for (i = 0; i < args_len; i++) DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) @@ -403,19 +404,19 @@ static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd, DRM_LOG_KMS("\n"); } -static void intel_sdvo_write_cmd(struct intel_encoder *intel_encoder, u8 cmd, +static void intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, void *args, int args_len) { int i; - intel_sdvo_debug_write(intel_encoder, cmd, args, args_len); + intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); for (i = 0; i < args_len; i++) { - intel_sdvo_write_byte(intel_encoder, SDVO_I2C_ARG_0 - i, + intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]); } - intel_sdvo_write_byte(intel_encoder, SDVO_I2C_OPCODE, cmd); + intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd); } static const char *cmd_status_names[] = { @@ -428,14 +429,13 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; -static void intel_sdvo_debug_response(struct intel_encoder *intel_encoder, +static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo, void *response, int response_len, u8 status) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; int i; - DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_priv)); + DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo)); for (i = 0; i < response_len; i++) DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); for (; i < 8; i++) @@ -447,7 +447,7 @@ static void intel_sdvo_debug_response(struct intel_encoder *intel_encoder, DRM_LOG_KMS("\n"); } -static u8 intel_sdvo_read_response(struct intel_encoder *intel_encoder, +static u8 intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, void *response, int response_len) { int i; @@ -457,16 +457,16 @@ static u8 intel_sdvo_read_response(struct intel_encoder *intel_encoder, while (retry--) { /* Read the command response */ for (i = 0; i < response_len; i++) { - intel_sdvo_read_byte(intel_encoder, + intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i]); } /* read the return status */ - intel_sdvo_read_byte(intel_encoder, SDVO_I2C_CMD_STATUS, + intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, &status); - intel_sdvo_debug_response(intel_encoder, response, response_len, + intel_sdvo_debug_response(intel_sdvo, response, response_len, status); if (status != SDVO_CMD_STATUS_PENDING) return status; @@ -494,37 +494,36 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) * another I2C transaction after issuing the DDC bus switch, it will be * switched to the internal SDVO register. */ -static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encoder, +static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, u8 target) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; u8 out_buf[2], cmd_buf[2], ret_value[2], ret; struct i2c_msg msgs[] = { { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 2, .buf = out_buf, }, /* the following two are to read the response */ { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = 0, .len = 1, .buf = cmd_buf, }, { - .addr = sdvo_priv->slave_addr >> 1, + .addr = intel_sdvo->slave_addr >> 1, .flags = I2C_M_RD, .len = 1, .buf = ret_value, }, }; - intel_sdvo_debug_write(intel_encoder, SDVO_CMD_SET_CONTROL_BUS_SWITCH, + intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); /* write the DDC switch command argument */ - intel_sdvo_write_byte(intel_encoder, SDVO_I2C_ARG_0, target); + intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target); out_buf[0] = SDVO_I2C_OPCODE; out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH; @@ -533,7 +532,7 @@ static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encode ret_value[0] = 0; ret_value[1] = 0; - ret = i2c_transfer(intel_encoder->i2c_bus, msgs, 3); + ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3); if (ret != 3) { /* failure in I2C transfer */ DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); @@ -547,7 +546,7 @@ static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encode return; } -static bool intel_sdvo_set_target_input(struct intel_encoder *intel_encoder, bool target_0, bool target_1) +static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo, bool target_0, bool target_1) { struct intel_sdvo_set_target_input_args targets = {0}; u8 status; @@ -558,10 +557,10 @@ static bool intel_sdvo_set_target_input(struct intel_encoder *intel_encoder, boo if (target_1) targets.target_1 = 1; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TARGET_INPUT, &targets, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_INPUT, &targets, sizeof(targets)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } @@ -572,13 +571,13 @@ static bool intel_sdvo_set_target_input(struct intel_encoder *intel_encoder, boo * This function is making an assumption about the layout of the response, * which should be checked against the docs. */ -static bool intel_sdvo_get_trained_inputs(struct intel_encoder *intel_encoder, bool *input_1, bool *input_2) +static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2) { struct intel_sdvo_get_trained_inputs_response response; u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &response, sizeof(response)); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &response, sizeof(response)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -587,18 +586,18 @@ static bool intel_sdvo_get_trained_inputs(struct intel_encoder *intel_encoder, b return true; } -static bool intel_sdvo_set_active_outputs(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo, u16 outputs) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, sizeof(outputs)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_encoder_power_state(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, int mode) { u8 status, state = SDVO_ENCODER_STATE_ON; @@ -618,24 +617,24 @@ static bool intel_sdvo_set_encoder_power_state(struct intel_encoder *intel_encod break; } - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_get_input_pixel_clock_range(struct intel_encoder *intel_encoder, +static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo, int *clock_min, int *clock_max) { struct intel_sdvo_pixel_clock_range clocks; u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &clocks, sizeof(clocks)); + status = intel_sdvo_read_response(intel_sdvo, &clocks, sizeof(clocks)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -647,58 +646,57 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct intel_encoder *intel_e return true; } -static bool intel_sdvo_set_target_output(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo, u16 outputs) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, sizeof(outputs)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_timing(struct intel_encoder *intel_encoder, u8 cmd, +static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd, struct intel_sdvo_dtd *dtd) { u8 status; - intel_sdvo_write_cmd(intel_encoder, cmd, &dtd->part1, sizeof(dtd->part1)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; - intel_sdvo_write_cmd(intel_encoder, cmd + 1, &dtd->part2, sizeof(dtd->part2)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static bool intel_sdvo_set_input_timing(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_set_timing(intel_encoder, + return intel_sdvo_set_timing(intel_sdvo, SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); } -static bool intel_sdvo_set_output_timing(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_set_timing(intel_encoder, + return intel_sdvo_set_timing(intel_sdvo, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); } static bool -intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder, +intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, uint16_t clock, uint16_t width, uint16_t height) { struct intel_sdvo_preferred_input_timing_args args; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; uint8_t status; memset(&args, 0, sizeof(args)); @@ -707,38 +705,38 @@ intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder, args.height = height; args.interlace = 0; - if (sdvo_priv->is_lvds && - (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width || - sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height)) + if (intel_sdvo->is_lvds && + (intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width || + intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height)) args.scaled = 1; - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, &args, sizeof(args)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static bool intel_sdvo_get_preferred_input_timing(struct intel_encoder *intel_encoder, +static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { bool status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &dtd->part1, + status = intel_sdvo_read_response(intel_sdvo, &dtd->part1, sizeof(dtd->part1)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &dtd->part2, + status = intel_sdvo_read_response(intel_sdvo, &dtd->part2, sizeof(dtd->part2)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -746,12 +744,12 @@ static bool intel_sdvo_get_preferred_input_timing(struct intel_encoder *intel_en return false; } -static bool intel_sdvo_set_clock_rate_mult(struct intel_encoder *intel_encoder, u8 val) +static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -840,13 +838,13 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, mode->flags |= DRM_MODE_FLAG_PVSYNC; } -static bool intel_sdvo_get_supp_encode(struct intel_encoder *intel_encoder, +static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo, struct intel_sdvo_encode *encode) { uint8_t status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, encode, sizeof(*encode)); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, encode, sizeof(*encode)); if (status != SDVO_CMD_STATUS_SUCCESS) { /* non-support means DVI */ memset(encode, 0, sizeof(*encode)); return false; @@ -855,30 +853,30 @@ static bool intel_sdvo_get_supp_encode(struct intel_encoder *intel_encoder, return true; } -static bool intel_sdvo_set_encode(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo, uint8_t mode) { uint8_t status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ENCODE, &mode, 1); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_colorimetry(struct intel_encoder *intel_encoder, +static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo, uint8_t mode) { uint8_t status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_COLORIMETRY, &mode, 1); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } #if 0 -static void intel_sdvo_dump_hdmi_buf(struct intel_encoder *intel_encoder) +static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) { int i, j; uint8_t set_buf_index[2]; @@ -908,7 +906,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_encoder *intel_encoder) } #endif -static void intel_sdvo_set_hdmi_buf(struct intel_encoder *intel_encoder, +static void intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, int index, uint8_t *data, int8_t size, uint8_t tx_rate) { @@ -917,15 +915,15 @@ static void intel_sdvo_set_hdmi_buf(struct intel_encoder *intel_encoder, set_buf_index[0] = index; set_buf_index[1] = 0; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_INDEX, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2); for (; size > 0; size -= 8) { - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_DATA, data, 8); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8); data += 8; } - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); } static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size) @@ -1000,7 +998,7 @@ struct dip_infoframe { } __attribute__ ((packed)) u; } __attribute__((packed)); -static void intel_sdvo_set_avi_infoframe(struct intel_encoder *intel_encoder, +static void intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, struct drm_display_mode * mode) { struct dip_infoframe avi_if = { @@ -1011,21 +1009,20 @@ static void intel_sdvo_set_avi_infoframe(struct intel_encoder *intel_encoder, avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if, 4 + avi_if.len); - intel_sdvo_set_hdmi_buf(intel_encoder, 1, (uint8_t *)&avi_if, + intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, 4 + avi_if.len, SDVO_HBUF_TX_VSYNC); } -static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder) +static void intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) { struct intel_sdvo_tv_format format; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; uint32_t format_map, i; uint8_t status; for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == sdvo_priv->tv_format_name) + if (tv_format_names[i] == intel_sdvo->tv_format_name) break; format_map = 1 << i; @@ -1033,23 +1030,22 @@ static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder) memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ? sizeof(format) : sizeof(format_map)); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TV_FORMAT, &format, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TV_FORMAT, &format, sizeof(format)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) DRM_DEBUG_KMS("%s: Failed to set TV format\n", - SDVO_NAME(sdvo_priv)); + SDVO_NAME(intel_sdvo)); } static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *dev_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - if (dev_priv->is_tv) { + if (intel_sdvo->is_tv) { struct intel_sdvo_dtd output_dtd; bool success; @@ -1062,25 +1058,25 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, /* Set output timings */ intel_sdvo_get_dtd_from_mode(&output_dtd, mode); - intel_sdvo_set_target_output(intel_encoder, - dev_priv->attached_output); - intel_sdvo_set_output_timing(intel_encoder, &output_dtd); + intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output); + intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); - success = intel_sdvo_create_preferred_input_timing(intel_encoder, + success = intel_sdvo_create_preferred_input_timing(intel_sdvo, mode->clock / 10, mode->hdisplay, mode->vdisplay); if (success) { struct intel_sdvo_dtd input_dtd; - intel_sdvo_get_preferred_input_timing(intel_encoder, + intel_sdvo_get_preferred_input_timing(intel_sdvo, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -1091,25 +1087,25 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, } else { return false; } - } else if (dev_priv->is_lvds) { + } else if (intel_sdvo->is_lvds) { struct intel_sdvo_dtd output_dtd; bool success; - drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0); + drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0); /* Set output timings */ intel_sdvo_get_dtd_from_mode(&output_dtd, - dev_priv->sdvo_lvds_fixed_mode); + intel_sdvo->sdvo_lvds_fixed_mode); - intel_sdvo_set_target_output(intel_encoder, - dev_priv->attached_output); - intel_sdvo_set_output_timing(intel_encoder, &output_dtd); + intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output); + intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); success = intel_sdvo_create_preferred_input_timing( - intel_encoder, + intel_sdvo, mode->clock / 10, mode->hdisplay, mode->vdisplay); @@ -1117,10 +1113,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, if (success) { struct intel_sdvo_dtd input_dtd; - intel_sdvo_get_preferred_input_timing(intel_encoder, + intel_sdvo_get_preferred_input_timing(intel_sdvo, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; + intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; drm_mode_set_crtcinfo(adjusted_mode, 0); @@ -1149,8 +1145,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); u32 sdvox = 0; int sdvo_pixel_multiply; struct intel_sdvo_in_out_map in_out; @@ -1166,41 +1161,41 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, * channel on the motherboard. In a two-input device, the first input * will be SDVOB and the second SDVOC. */ - in_out.in0 = sdvo_priv->attached_output; + in_out.in0 = intel_sdvo->attached_output; in_out.in1 = 0; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_IN_OUT_MAP, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_IN_OUT_MAP, &in_out, sizeof(in_out)); - status = intel_sdvo_read_response(intel_encoder, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (sdvo_priv->is_hdmi) { - intel_sdvo_set_avi_infoframe(intel_encoder, mode); + if (intel_sdvo->is_hdmi) { + intel_sdvo_set_avi_infoframe(intel_sdvo, mode); sdvox |= SDVO_AUDIO_ENABLE; } /* We have tried to get input timing in mode_fixup, and filled into adjusted_mode */ - if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { + if (intel_sdvo->is_tv || intel_sdvo->is_lvds) { intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); - input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags; + input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags; } else intel_sdvo_get_dtd_from_mode(&input_dtd, mode); /* If it's a TV, we already set the output timing in mode_fixup. * Otherwise, the output timing is equal to the input timing. */ - if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) { + if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) { /* Set the output timing to the screen */ - intel_sdvo_set_target_output(intel_encoder, - sdvo_priv->attached_output); - intel_sdvo_set_output_timing(intel_encoder, &input_dtd); + intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output); + intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); } /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); - if (sdvo_priv->is_tv) - intel_sdvo_set_tv_format(intel_encoder); + if (intel_sdvo->is_tv) + intel_sdvo_set_tv_format(intel_sdvo); /* We would like to use intel_sdvo_create_preferred_input_timing() to * provide the device with a timing it can support, if it supports that @@ -1217,20 +1212,20 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_input_timing(encoder, &input_dtd); } #else - intel_sdvo_set_input_timing(intel_encoder, &input_dtd); + intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); #endif switch (intel_sdvo_get_pixel_multiplier(mode)) { case 1: - intel_sdvo_set_clock_rate_mult(intel_encoder, + intel_sdvo_set_clock_rate_mult(intel_sdvo, SDVO_CLOCK_RATE_MULT_1X); break; case 2: - intel_sdvo_set_clock_rate_mult(intel_encoder, + intel_sdvo_set_clock_rate_mult(intel_sdvo, SDVO_CLOCK_RATE_MULT_2X); break; case 4: - intel_sdvo_set_clock_rate_mult(intel_encoder, + intel_sdvo_set_clock_rate_mult(intel_sdvo, SDVO_CLOCK_RATE_MULT_4X); break; } @@ -1243,8 +1238,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) sdvox |= SDVO_HSYNC_ACTIVE_HIGH; } else { - sdvox |= I915_READ(sdvo_priv->sdvo_reg); - switch (sdvo_priv->sdvo_reg) { + sdvox |= I915_READ(intel_sdvo->sdvo_reg); + switch (intel_sdvo->sdvo_reg) { case SDVOB: sdvox &= SDVOB_PRESERVE_MASK; break; @@ -1266,28 +1261,27 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL) + if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL) sdvox |= SDVO_STALL_SELECT; - intel_sdvo_write_sdvox(intel_encoder, sdvox); + intel_sdvo_write_sdvox(intel_sdvo, sdvox); } static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); u32 temp; if (mode != DRM_MODE_DPMS_ON) { - intel_sdvo_set_active_outputs(intel_encoder, 0); + intel_sdvo_set_active_outputs(intel_sdvo, 0); if (0) - intel_sdvo_set_encoder_power_state(intel_encoder, mode); + intel_sdvo_set_encoder_power_state(intel_sdvo, mode); if (mode == DRM_MODE_DPMS_OFF) { - temp = I915_READ(sdvo_priv->sdvo_reg); + temp = I915_READ(intel_sdvo->sdvo_reg); if ((temp & SDVO_ENABLE) != 0) { - intel_sdvo_write_sdvox(intel_encoder, temp & ~SDVO_ENABLE); + intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE); } } } else { @@ -1295,13 +1289,13 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) int i; u8 status; - temp = I915_READ(sdvo_priv->sdvo_reg); + temp = I915_READ(intel_sdvo->sdvo_reg); if ((temp & SDVO_ENABLE) == 0) - intel_sdvo_write_sdvox(intel_encoder, temp | SDVO_ENABLE); + intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); for (i = 0; i < 2; i++) intel_wait_for_vblank(dev); - status = intel_sdvo_get_trained_inputs(intel_encoder, &input1, + status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); @@ -1311,12 +1305,12 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) */ if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { DRM_DEBUG_KMS("First %s output reported failure to " - "sync\n", SDVO_NAME(sdvo_priv)); + "sync\n", SDVO_NAME(intel_sdvo)); } if (0) - intel_sdvo_set_encoder_power_state(intel_encoder, mode); - intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->attached_output); + intel_sdvo_set_encoder_power_state(intel_sdvo, mode); + intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); } return; } @@ -1325,38 +1319,37 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; - if (sdvo_priv->pixel_clock_min > mode->clock) + if (intel_sdvo->pixel_clock_min > mode->clock) return MODE_CLOCK_LOW; - if (sdvo_priv->pixel_clock_max < mode->clock) + if (intel_sdvo->pixel_clock_max < mode->clock) return MODE_CLOCK_HIGH; - if (sdvo_priv->is_lvds == true) { - if (sdvo_priv->sdvo_lvds_fixed_mode == NULL) + if (intel_sdvo->is_lvds == true) { + if (intel_sdvo->sdvo_lvds_fixed_mode == NULL) return MODE_PANEL; - if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay) + if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay) + if (mode->vdisplay > intel_sdvo->sdvo_lvds_fixed_mode->vdisplay) return MODE_PANEL; } return MODE_OK; } -static bool intel_sdvo_get_capabilities(struct intel_encoder *intel_encoder, struct intel_sdvo_caps *caps) +static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) { u8 status; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, caps, sizeof(*caps)); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, caps, sizeof(*caps)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -1368,12 +1361,12 @@ static bool intel_sdvo_get_capabilities(struct intel_encoder *intel_encoder, str struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB) { struct drm_connector *connector = NULL; - struct intel_encoder *iout = NULL; - struct intel_sdvo_priv *sdvo; + struct intel_sdvo *iout = NULL; + struct intel_sdvo *sdvo; /* find the sdvo connector */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_intel_encoder(connector); + iout = to_intel_sdvo(connector); if (iout->type != INTEL_OUTPUT_SDVO) continue; @@ -1395,16 +1388,16 @@ int intel_sdvo_supports_hotplug(struct drm_connector *connector) { u8 response[2]; u8 status; - struct intel_encoder *intel_encoder; + struct intel_sdvo *intel_sdvo; DRM_DEBUG_KMS("\n"); if (!connector) return 0; - intel_encoder = to_intel_encoder(connector); + intel_sdvo = to_intel_sdvo(connector); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (response[0] !=0) return 1; @@ -1416,54 +1409,53 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) { u8 response[2]; u8 status; - struct intel_encoder *intel_encoder = to_intel_encoder(connector); + struct intel_sdvo *intel_sdvo = to_intel_sdvo(connector); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(intel_sdvo, &response, 2); if (on) { - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &response, 2); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } else { response[0] = 0; response[1] = 0; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(intel_encoder, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(intel_sdvo, &response, 2); } #endif static bool -intel_sdvo_multifunc_encoder(struct intel_encoder *intel_encoder) +intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; int caps = 0; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1)) caps++; - if (sdvo_priv->caps.output_flags & + if (intel_sdvo->caps.output_flags & (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)) caps++; @@ -1475,11 +1467,11 @@ intel_find_analog_connector(struct drm_device *dev) { struct drm_connector *connector; struct drm_encoder *encoder; - struct intel_encoder *intel_encoder; + struct intel_sdvo *intel_sdvo; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - intel_encoder = enc_to_intel_encoder(encoder); - if (intel_encoder->type == INTEL_OUTPUT_ANALOG) { + intel_sdvo = enc_to_intel_sdvo(encoder); + if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (encoder == intel_attached_encoder(connector)) return connector; @@ -1509,46 +1501,45 @@ enum drm_connector_status intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; - edid = drm_get_edid(connector, intel_encoder->ddc_bus); + edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); /* This is only applied to SDVO cards with multiple outputs */ - if (edid == NULL && intel_sdvo_multifunc_encoder(intel_encoder)) { + if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) { uint8_t saved_ddc, temp_ddc; - saved_ddc = sdvo_priv->ddc_bus; - temp_ddc = sdvo_priv->ddc_bus >> 1; + saved_ddc = intel_sdvo->ddc_bus; + temp_ddc = intel_sdvo->ddc_bus >> 1; /* * Don't use the 1 as the argument of DDC bus switch to get * the EDID. It is used for SDVO SPD ROM. */ while(temp_ddc > 1) { - sdvo_priv->ddc_bus = temp_ddc; - edid = drm_get_edid(connector, intel_encoder->ddc_bus); + intel_sdvo->ddc_bus = temp_ddc; + edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus); if (edid) { /* * When we can get the EDID, maybe it is the * correct DDC bus. Update it. */ - sdvo_priv->ddc_bus = temp_ddc; + intel_sdvo->ddc_bus = temp_ddc; break; } temp_ddc >>= 1; } if (edid == NULL) - sdvo_priv->ddc_bus = saved_ddc; + intel_sdvo->ddc_bus = saved_ddc; } /* when there is no edid and no monitor is connected with VGA * port, try to use the CRT ddc to read the EDID for DVI-connector */ - if (edid == NULL && sdvo_priv->analog_ddc_bus && + if (edid == NULL && intel_sdvo->analog_ddc_bus && !intel_analog_is_connected(connector->dev)) - edid = drm_get_edid(connector, sdvo_priv->analog_ddc_bus); + edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus); if (edid != NULL) { bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); @@ -1556,7 +1547,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) /* DDC bus is shared, match EDID to connector type */ if (is_digital && need_digital) - sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid); + intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid); else if (is_digital != need_digital) status = connector_status_disconnected; @@ -1574,19 +1565,18 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect uint16_t response; u8 status; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; enum drm_connector_status ret; - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); - if (sdvo_priv->is_tv) { + if (intel_sdvo->is_tv) { /* add 30ms delay when the output type is SDVO-TV */ mdelay(30); } - status = intel_sdvo_read_response(intel_encoder, &response, 2); + status = intel_sdvo_read_response(intel_sdvo, &response, 2); DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8); @@ -1596,7 +1586,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect if (response == 0) return connector_status_disconnected; - sdvo_priv->attached_output = response; + intel_sdvo->attached_output = response; if ((sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; @@ -1607,16 +1597,16 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect /* May update encoder flag for like clock for SDVO TV, etc.*/ if (ret == connector_status_connected) { - sdvo_priv->is_tv = false; - sdvo_priv->is_lvds = false; - intel_encoder->needs_tv_clock = false; + intel_sdvo->is_tv = false; + intel_sdvo->is_lvds = false; + intel_sdvo->base.needs_tv_clock = false; if (response & SDVO_TV_MASK) { - sdvo_priv->is_tv = true; - intel_encoder->needs_tv_clock = true; + intel_sdvo->is_tv = true; + intel_sdvo->base.needs_tv_clock = true; } if (response & SDVO_LVDS_MASK) - sdvo_priv->is_lvds = true; + intel_sdvo->is_lvds = true; } return ret; @@ -1625,12 +1615,11 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); int num_modes; /* set the bus switch and get the modes */ - num_modes = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); /* * Mac mini hack. On this device, the DVI-I connector shares one DDC @@ -1639,11 +1628,11 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) * which case we'll look there for the digital DDC data. */ if (num_modes == 0 && - sdvo_priv->analog_ddc_bus && + intel_sdvo->analog_ddc_bus && !intel_analog_is_connected(connector->dev)) { /* Switch to the analog ddc bus and try that */ - (void) intel_ddc_get_modes(connector, sdvo_priv->analog_ddc_bus); + (void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus); } } @@ -1715,8 +1704,7 @@ struct drm_display_mode sdvo_tv_modes[] = { static void intel_sdvo_get_tv_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0, format_map = 0; int i; @@ -1727,7 +1715,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) * format. */ for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == sdvo_priv->tv_format_name) + if (tv_format_names[i] == intel_sdvo->tv_format_name) break; format_map = (1 << i); @@ -1736,11 +1724,11 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) sizeof(format_map) ? sizeof(format_map) : sizeof(struct intel_sdvo_sdtv_resolution_request)); - intel_sdvo_set_target_output(intel_encoder, sdvo_priv->attached_output); + intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output); - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, &tv_res, sizeof(tv_res)); - status = intel_sdvo_read_response(intel_encoder, &reply, 3); + status = intel_sdvo_read_response(intel_sdvo, &reply, 3); if (status != SDVO_CMD_STATUS_SUCCESS) return; @@ -1758,9 +1746,8 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; struct drm_display_mode *newmode; /* @@ -1768,7 +1755,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) * Assume that the preferred modes are * arranged in priority order. */ - intel_ddc_get_modes(connector, intel_encoder->ddc_bus); + intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus); if (list_empty(&connector->probed_modes) == false) goto end; @@ -1787,7 +1774,7 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) end: list_for_each_entry(newmode, &connector->probed_modes, head) { if (newmode->type & DRM_MODE_TYPE_PREFERRED) { - sdvo_priv->sdvo_lvds_fixed_mode = + intel_sdvo->sdvo_lvds_fixed_mode = drm_mode_duplicate(connector->dev, newmode); break; } @@ -1816,35 +1803,35 @@ static void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) { struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_priv = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo = intel_connector->dev_priv; struct drm_device *dev = connector->dev; - if (IS_TV(sdvo_priv)) { - if (sdvo_priv->left_property) - drm_property_destroy(dev, sdvo_priv->left_property); - if (sdvo_priv->right_property) - drm_property_destroy(dev, sdvo_priv->right_property); - if (sdvo_priv->top_property) - drm_property_destroy(dev, sdvo_priv->top_property); - if (sdvo_priv->bottom_property) - drm_property_destroy(dev, sdvo_priv->bottom_property); - if (sdvo_priv->hpos_property) - drm_property_destroy(dev, sdvo_priv->hpos_property); - if (sdvo_priv->vpos_property) - drm_property_destroy(dev, sdvo_priv->vpos_property); - if (sdvo_priv->saturation_property) + if (IS_TV(intel_sdvo)) { + if (intel_sdvo->left_property) + drm_property_destroy(dev, intel_sdvo->left_property); + if (intel_sdvo->right_property) + drm_property_destroy(dev, intel_sdvo->right_property); + if (intel_sdvo->top_property) + drm_property_destroy(dev, intel_sdvo->top_property); + if (intel_sdvo->bottom_property) + drm_property_destroy(dev, intel_sdvo->bottom_property); + if (intel_sdvo->hpos_property) + drm_property_destroy(dev, intel_sdvo->hpos_property); + if (intel_sdvo->vpos_property) + drm_property_destroy(dev, intel_sdvo->vpos_property); + if (intel_sdvo->saturation_property) drm_property_destroy(dev, - sdvo_priv->saturation_property); - if (sdvo_priv->contrast_property) + intel_sdvo->saturation_property); + if (intel_sdvo->contrast_property) drm_property_destroy(dev, - sdvo_priv->contrast_property); - if (sdvo_priv->hue_property) - drm_property_destroy(dev, sdvo_priv->hue_property); + intel_sdvo->contrast_property); + if (intel_sdvo->hue_property) + drm_property_destroy(dev, intel_sdvo->hue_property); } - if (IS_TV(sdvo_priv) || IS_LVDS(sdvo_priv)) { - if (sdvo_priv->brightness_property) + if (IS_TV(intel_sdvo) || IS_LVDS(intel_sdvo)) { + if (intel_sdvo->brightness_property) drm_property_destroy(dev, - sdvo_priv->brightness_property); + intel_sdvo->brightness_property); } return; } @@ -1870,8 +1857,7 @@ intel_sdvo_set_property(struct drm_connector *connector, uint64_t val) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct drm_crtc *crtc = encoder->crtc; @@ -1889,11 +1875,11 @@ intel_sdvo_set_property(struct drm_connector *connector, ret = -EINVAL; goto out; } - if (sdvo_priv->tv_format_name == + if (intel_sdvo->tv_format_name == sdvo_connector->tv_format_supported[val]) goto out; - sdvo_priv->tv_format_name = sdvo_connector->tv_format_supported[val]; + intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[val]; changed = true; } @@ -1981,8 +1967,8 @@ intel_sdvo_set_property(struct drm_connector *connector, sdvo_connector->cur_brightness = temp_value; } if (cmd) { - intel_sdvo_write_cmd(intel_encoder, cmd, &temp_value, 2); - status = intel_sdvo_read_response(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, cmd, &temp_value, 2); + status = intel_sdvo_read_response(intel_sdvo, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO command \n"); @@ -2022,22 +2008,16 @@ static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) { - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - if (intel_encoder->i2c_bus) - intel_i2c_destroy(intel_encoder->i2c_bus); - if (intel_encoder->ddc_bus) - intel_i2c_destroy(intel_encoder->ddc_bus); - if (sdvo_priv->analog_ddc_bus) - intel_i2c_destroy(sdvo_priv->analog_ddc_bus); + if (intel_sdvo->analog_ddc_bus) + intel_i2c_destroy(intel_sdvo->analog_ddc_bus); - if (sdvo_priv->sdvo_lvds_fixed_mode != NULL) + if (intel_sdvo->sdvo_lvds_fixed_mode != NULL) drm_mode_destroy(encoder->dev, - sdvo_priv->sdvo_lvds_fixed_mode); + intel_sdvo->sdvo_lvds_fixed_mode); - drm_encoder_cleanup(encoder); - kfree(intel_encoder); + intel_encoder_destroy(encoder); } static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { @@ -2054,7 +2034,7 @@ static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { */ static void intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, - struct intel_sdvo_priv *sdvo, u32 reg) + struct intel_sdvo *sdvo, u32 reg) { struct sdvo_device_mapping *mapping; @@ -2067,57 +2047,54 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, } static bool -intel_sdvo_get_digital_encoding_mode(struct intel_encoder *output, int device) +intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) { - struct intel_sdvo_priv *sdvo_priv = output->dev_priv; uint8_t status; if (device == 0) - intel_sdvo_set_target_output(output, SDVO_OUTPUT_TMDS0); + intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS0); else - intel_sdvo_set_target_output(output, SDVO_OUTPUT_TMDS1); + intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS1); - intel_sdvo_write_cmd(output, SDVO_CMD_GET_ENCODE, NULL, 0); - status = intel_sdvo_read_response(output, &sdvo_priv->is_hdmi, 1); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ENCODE, NULL, 0); + status = intel_sdvo_read_response(intel_sdvo, &intel_sdvo->is_hdmi, 1); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static struct intel_encoder * -intel_sdvo_chan_to_intel_encoder(struct intel_i2c_chan *chan) +static struct intel_sdvo * +intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan) { struct drm_device *dev = chan->drm_dev; struct drm_encoder *encoder; - struct intel_encoder *intel_encoder = NULL; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - intel_encoder = enc_to_intel_encoder(encoder); - if (intel_encoder->ddc_bus == &chan->adapter) - break; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + if (intel_sdvo->base.ddc_bus == &chan->adapter) + return intel_sdvo; } - return intel_encoder; + + return NULL;; } static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { - struct intel_encoder *intel_encoder; - struct intel_sdvo_priv *sdvo_priv; + struct intel_sdvo *intel_sdvo; struct i2c_algo_bit_data *algo_data; const struct i2c_algorithm *algo; algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data; - intel_encoder = - intel_sdvo_chan_to_intel_encoder( - (struct intel_i2c_chan *)(algo_data->data)); - if (intel_encoder == NULL) + intel_sdvo = + intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *) + (algo_data->data)); + if (intel_sdvo == NULL) return -EINVAL; - sdvo_priv = intel_encoder->dev_priv; - algo = intel_encoder->i2c_bus->algo; + algo = intel_sdvo->base.i2c_bus->algo; - intel_sdvo_set_control_bus_switch(intel_encoder, sdvo_priv->ddc_bus); + intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus); return algo->master_xfer(i2c_adap, msgs, num); } @@ -2198,10 +2175,9 @@ intel_sdvo_connector_create (struct drm_encoder *encoder, } static bool -intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) +intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2212,10 +2188,10 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) sdvo_connector = intel_connector->dev_priv; if (device == 0) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_TMDS0; + intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; } else if (device == 1) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_TMDS1; + intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1; sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; } @@ -2224,17 +2200,17 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; - if (intel_sdvo_get_supp_encode(intel_encoder, &sdvo_priv->encode) - && intel_sdvo_get_digital_encoding_mode(intel_encoder, device) - && sdvo_priv->is_hdmi) { + if (intel_sdvo_get_supp_encode(intel_sdvo, &intel_sdvo->encode) + && intel_sdvo_get_digital_encoding_mode(intel_sdvo, device) + && intel_sdvo->is_hdmi) { /* enable hdmi encoding mode if supported */ - intel_sdvo_set_encode(intel_encoder, SDVO_ENCODE_HDMI); - intel_sdvo_set_colorimetry(intel_encoder, + intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); + intel_sdvo_set_colorimetry(intel_sdvo, SDVO_COLORIMETRY_RGB256); connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; } - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); + intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | + (1 << INTEL_ANALOG_CLONE_BIT)); intel_sdvo_connector_create(encoder, connector); @@ -2242,10 +2218,9 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device) } static bool -intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type) +intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2258,12 +2233,12 @@ intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type) connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; sdvo_connector = intel_connector->dev_priv; - sdvo_priv->controlled_output |= type; + intel_sdvo->controlled_output |= type; sdvo_connector->output_flag = type; - sdvo_priv->is_tv = true; - intel_encoder->needs_tv_clock = true; - intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; + intel_sdvo->is_tv = true; + intel_sdvo->base.needs_tv_clock = true; + intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; intel_sdvo_connector_create(encoder, connector); @@ -2275,10 +2250,9 @@ intel_sdvo_tv_init(struct intel_encoder *intel_encoder, int type) } static bool -intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device) +intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2293,25 +2267,24 @@ intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device) sdvo_connector = intel_connector->dev_priv; if (device == 0) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_RGB0; + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; } else if (device == 1) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_RGB1; + intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; } - intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) | - (1 << INTEL_ANALOG_CLONE_BIT); + intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | + (1 << INTEL_ANALOG_CLONE_BIT)); intel_sdvo_connector_create(encoder, connector); return true; } static bool -intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device) +intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) { - struct drm_encoder *encoder = &intel_encoder->enc; - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *sdvo_connector; @@ -2324,18 +2297,18 @@ intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device) connector->connector_type = DRM_MODE_CONNECTOR_LVDS; sdvo_connector = intel_connector->dev_priv; - sdvo_priv->is_lvds = true; + intel_sdvo->is_lvds = true; if (device == 0) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_LVDS0; + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; } else if (device == 1) { - sdvo_priv->controlled_output |= SDVO_OUTPUT_LVDS1; + intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; } - intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) | - (1 << INTEL_SDVO_LVDS_CLONE_BIT); + intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | + (1 << INTEL_SDVO_LVDS_CLONE_BIT)); intel_sdvo_connector_create(encoder, connector); intel_sdvo_create_enhance_property(connector); @@ -2343,60 +2316,58 @@ intel_sdvo_lvds_init(struct intel_encoder *intel_encoder, int device) } static bool -intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags) +intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) { - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; - - sdvo_priv->is_tv = false; - intel_encoder->needs_tv_clock = false; - sdvo_priv->is_lvds = false; + intel_sdvo->is_tv = false; + intel_sdvo->base.needs_tv_clock = false; + intel_sdvo->is_lvds = false; /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ if (flags & SDVO_OUTPUT_TMDS0) - if (!intel_sdvo_dvi_init(intel_encoder, 0)) + if (!intel_sdvo_dvi_init(intel_sdvo, 0)) return false; if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK) - if (!intel_sdvo_dvi_init(intel_encoder, 1)) + if (!intel_sdvo_dvi_init(intel_sdvo, 1)) return false; /* TV has no XXX1 function block */ if (flags & SDVO_OUTPUT_SVID0) - if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_SVID0)) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0)) return false; if (flags & SDVO_OUTPUT_CVBS0) - if (!intel_sdvo_tv_init(intel_encoder, SDVO_OUTPUT_CVBS0)) + if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0)) return false; if (flags & SDVO_OUTPUT_RGB0) - if (!intel_sdvo_analog_init(intel_encoder, 0)) + if (!intel_sdvo_analog_init(intel_sdvo, 0)) return false; if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK) - if (!intel_sdvo_analog_init(intel_encoder, 1)) + if (!intel_sdvo_analog_init(intel_sdvo, 1)) return false; if (flags & SDVO_OUTPUT_LVDS0) - if (!intel_sdvo_lvds_init(intel_encoder, 0)) + if (!intel_sdvo_lvds_init(intel_sdvo, 0)) return false; if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK) - if (!intel_sdvo_lvds_init(intel_encoder, 1)) + if (!intel_sdvo_lvds_init(intel_sdvo, 1)) return false; if ((flags & SDVO_OUTPUT_MASK) == 0) { unsigned char bytes[2]; - sdvo_priv->controlled_output = 0; - memcpy(bytes, &sdvo_priv->caps.output_flags, 2); + intel_sdvo->controlled_output = 0; + memcpy(bytes, &intel_sdvo->caps.output_flags, 2); DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(sdvo_priv), + SDVO_NAME(intel_sdvo), bytes[0], bytes[1]); return false; } - intel_encoder->crtc_mask = (1 << 0) | (1 << 1); + intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1); return true; } @@ -2404,19 +2375,18 @@ intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags) static void intel_sdvo_tv_create_property(struct drm_connector *connector, int type) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv; + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; struct intel_sdvo_tv_format format; uint32_t format_map, i; uint8_t status; - intel_sdvo_set_target_output(intel_encoder, type); + intel_sdvo_set_target_output(intel_sdvo, type); - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &format, sizeof(format)); if (status != SDVO_CMD_STATUS_SUCCESS) return; @@ -2446,7 +2416,7 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t sdvo_connector->tv_format_property, i, i, sdvo_connector->tv_format_supported[i]); - sdvo_priv->tv_format_name = sdvo_connector->tv_format_supported[0]; + intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[0]; drm_connector_attach_property( connector, sdvo_connector->tv_format_property, 0); @@ -2455,17 +2425,17 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t static void intel_sdvo_create_enhance_property(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_priv = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = intel_connector->dev_priv; struct intel_sdvo_enhancements_reply sdvo_data; struct drm_device *dev = connector->dev; uint8_t status; uint16_t response, data_value[2]; - intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, &sdvo_data, + status = intel_sdvo_read_response(intel_sdvo, &sdvo_data, sizeof(sdvo_data)); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS(" incorrect response is returned\n"); @@ -2476,278 +2446,278 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) DRM_DEBUG_KMS("No enhancement is supported\n"); return; } - if (IS_TV(sdvo_priv)) { + if (IS_TV(intel_sdvo_connector)) { /* when horizontal overscan is supported, Add the left/right * property */ if (sdvo_data.overscan_h) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO max " "h_overscan\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO h_overscan\n"); return; } - sdvo_priv->max_hscan = data_value[0]; - sdvo_priv->left_margin = data_value[0] - response; - sdvo_priv->right_margin = sdvo_priv->left_margin; - sdvo_priv->left_property = + intel_sdvo_connector->max_hscan = data_value[0]; + intel_sdvo_connector->left_margin = data_value[0] - response; + intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; + intel_sdvo_connector->left_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "left_margin", 2); - sdvo_priv->left_property->values[0] = 0; - sdvo_priv->left_property->values[1] = data_value[0]; + intel_sdvo_connector->left_property->values[0] = 0; + intel_sdvo_connector->left_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->left_property, - sdvo_priv->left_margin); - sdvo_priv->right_property = + intel_sdvo_connector->left_property, + intel_sdvo_connector->left_margin); + intel_sdvo_connector->right_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "right_margin", 2); - sdvo_priv->right_property->values[0] = 0; - sdvo_priv->right_property->values[1] = data_value[0]; + intel_sdvo_connector->right_property->values[0] = 0; + intel_sdvo_connector->right_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->right_property, - sdvo_priv->right_margin); + intel_sdvo_connector->right_property, + intel_sdvo_connector->right_margin); DRM_DEBUG_KMS("h_overscan: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.overscan_v) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO max " "v_overscan\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO v_overscan\n"); return; } - sdvo_priv->max_vscan = data_value[0]; - sdvo_priv->top_margin = data_value[0] - response; - sdvo_priv->bottom_margin = sdvo_priv->top_margin; - sdvo_priv->top_property = + intel_sdvo_connector->max_vscan = data_value[0]; + intel_sdvo_connector->top_margin = data_value[0] - response; + intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; + intel_sdvo_connector->top_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "top_margin", 2); - sdvo_priv->top_property->values[0] = 0; - sdvo_priv->top_property->values[1] = data_value[0]; + intel_sdvo_connector->top_property->values[0] = 0; + intel_sdvo_connector->top_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->top_property, - sdvo_priv->top_margin); - sdvo_priv->bottom_property = + intel_sdvo_connector->top_property, + intel_sdvo_connector->top_margin); + intel_sdvo_connector->bottom_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "bottom_margin", 2); - sdvo_priv->bottom_property->values[0] = 0; - sdvo_priv->bottom_property->values[1] = data_value[0]; + intel_sdvo_connector->bottom_property->values[0] = 0; + intel_sdvo_connector->bottom_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->bottom_property, - sdvo_priv->bottom_margin); + intel_sdvo_connector->bottom_property, + intel_sdvo_connector->bottom_margin); DRM_DEBUG_KMS("v_overscan: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.position_h) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max h_pos\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get h_postion\n"); return; } - sdvo_priv->max_hpos = data_value[0]; - sdvo_priv->cur_hpos = response; - sdvo_priv->hpos_property = + intel_sdvo_connector->max_hpos = data_value[0]; + intel_sdvo_connector->cur_hpos = response; + intel_sdvo_connector->hpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hpos", 2); - sdvo_priv->hpos_property->values[0] = 0; - sdvo_priv->hpos_property->values[1] = data_value[0]; + intel_sdvo_connector->hpos_property->values[0] = 0; + intel_sdvo_connector->hpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->hpos_property, - sdvo_priv->cur_hpos); + intel_sdvo_connector->hpos_property, + intel_sdvo_connector->cur_hpos); DRM_DEBUG_KMS("h_position: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.position_v) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max v_pos\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get v_postion\n"); return; } - sdvo_priv->max_vpos = data_value[0]; - sdvo_priv->cur_vpos = response; - sdvo_priv->vpos_property = + intel_sdvo_connector->max_vpos = data_value[0]; + intel_sdvo_connector->cur_vpos = response; + intel_sdvo_connector->vpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "vpos", 2); - sdvo_priv->vpos_property->values[0] = 0; - sdvo_priv->vpos_property->values[1] = data_value[0]; + intel_sdvo_connector->vpos_property->values[0] = 0; + intel_sdvo_connector->vpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->vpos_property, - sdvo_priv->cur_vpos); + intel_sdvo_connector->vpos_property, + intel_sdvo_connector->cur_vpos); DRM_DEBUG_KMS("v_position: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.saturation) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max sat\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get sat\n"); return; } - sdvo_priv->max_saturation = data_value[0]; - sdvo_priv->cur_saturation = response; - sdvo_priv->saturation_property = + intel_sdvo_connector->max_saturation = data_value[0]; + intel_sdvo_connector->cur_saturation = response; + intel_sdvo_connector->saturation_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "saturation", 2); - sdvo_priv->saturation_property->values[0] = 0; - sdvo_priv->saturation_property->values[1] = + intel_sdvo_connector->saturation_property->values[0] = 0; + intel_sdvo_connector->saturation_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->saturation_property, - sdvo_priv->cur_saturation); + intel_sdvo_connector->saturation_property, + intel_sdvo_connector->cur_saturation); DRM_DEBUG_KMS("saturation: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.contrast) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max contrast\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get contrast\n"); return; } - sdvo_priv->max_contrast = data_value[0]; - sdvo_priv->cur_contrast = response; - sdvo_priv->contrast_property = + intel_sdvo_connector->max_contrast = data_value[0]; + intel_sdvo_connector->cur_contrast = response; + intel_sdvo_connector->contrast_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "contrast", 2); - sdvo_priv->contrast_property->values[0] = 0; - sdvo_priv->contrast_property->values[1] = data_value[0]; + intel_sdvo_connector->contrast_property->values[0] = 0; + intel_sdvo_connector->contrast_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->contrast_property, - sdvo_priv->cur_contrast); + intel_sdvo_connector->contrast_property, + intel_sdvo_connector->cur_contrast); DRM_DEBUG_KMS("contrast: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); } if (sdvo_data.hue) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max hue\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get hue\n"); return; } - sdvo_priv->max_hue = data_value[0]; - sdvo_priv->cur_hue = response; - sdvo_priv->hue_property = + intel_sdvo_connector->max_hue = data_value[0]; + intel_sdvo_connector->cur_hue = response; + intel_sdvo_connector->hue_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hue", 2); - sdvo_priv->hue_property->values[0] = 0; - sdvo_priv->hue_property->values[1] = + intel_sdvo_connector->hue_property->values[0] = 0; + intel_sdvo_connector->hue_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->hue_property, - sdvo_priv->cur_hue); + intel_sdvo_connector->hue_property, + intel_sdvo_connector->cur_hue); DRM_DEBUG_KMS("hue: max %d, default %d, current %d\n", data_value[0], data_value[1], response); } } - if (IS_TV(sdvo_priv) || IS_LVDS(sdvo_priv)) { + if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { if (sdvo_data.brightness) { - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &data_value, 4); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO Max bright\n"); return; } - intel_sdvo_write_cmd(intel_encoder, + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_encoder, + status = intel_sdvo_read_response(intel_sdvo, &response, 2); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG_KMS("Incorrect SDVO get brigh\n"); return; } - sdvo_priv->max_brightness = data_value[0]; - sdvo_priv->cur_brightness = response; - sdvo_priv->brightness_property = + intel_sdvo_connector->max_brightness = data_value[0]; + intel_sdvo_connector->cur_brightness = response; + intel_sdvo_connector->brightness_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "brightness", 2); - sdvo_priv->brightness_property->values[0] = 0; - sdvo_priv->brightness_property->values[1] = + intel_sdvo_connector->brightness_property->values[0] = 0; + intel_sdvo_connector->brightness_property->values[1] = data_value[0]; drm_connector_attach_property(connector, - sdvo_priv->brightness_property, - sdvo_priv->cur_brightness); + intel_sdvo_connector->brightness_property, + intel_sdvo_connector->cur_brightness); DRM_DEBUG_KMS("brightness: max %d, " "default %d, current %d\n", data_value[0], data_value[1], response); @@ -2760,20 +2730,18 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; - struct intel_sdvo_priv *sdvo_priv; + struct intel_sdvo *intel_sdvo; u8 ch[0x40]; int i; u32 i2c_reg, ddc_reg, analog_ddc_reg; - intel_encoder = kcalloc(sizeof(struct intel_encoder)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); - if (!intel_encoder) { + intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); + if (!intel_sdvo) return false; - } - sdvo_priv = (struct intel_sdvo_priv *)(intel_encoder + 1); - sdvo_priv->sdvo_reg = sdvo_reg; + intel_sdvo->sdvo_reg = sdvo_reg; - intel_encoder->dev_priv = sdvo_priv; + intel_encoder = &intel_sdvo->base; intel_encoder->type = INTEL_OUTPUT_SDVO; if (HAS_PCH_SPLIT(dev)) { @@ -2795,14 +2763,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) if (!intel_encoder->i2c_bus) goto err_inteloutput; - sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg); + intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg); /* Save the bit-banging i2c functionality for use by the DDC wrapper */ intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality; /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { - if (!intel_sdvo_read_byte(intel_encoder, i, &ch[i])) { + if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) { DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); goto err_i2c; @@ -2812,12 +2780,12 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) /* setup the DDC bus. */ if (IS_SDVOB(sdvo_reg)) { intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, + intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, "SDVOB/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS; } else { intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS"); - sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, + intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg, "SDVOC/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; } @@ -2833,53 +2801,53 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ - intel_sdvo_get_capabilities(intel_encoder, &sdvo_priv->caps); + intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps); - if (intel_sdvo_output_setup(intel_encoder, - sdvo_priv->caps.output_flags) != true) { + if (intel_sdvo_output_setup(intel_sdvo, + intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); goto err_i2c; } - intel_sdvo_select_ddc_bus(dev_priv, sdvo_priv, sdvo_reg); + intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_encoder, true, false); + intel_sdvo_set_target_input(intel_sdvo, true, false); - intel_sdvo_get_input_pixel_clock_range(intel_encoder, - &sdvo_priv->pixel_clock_min, - &sdvo_priv->pixel_clock_max); + intel_sdvo_get_input_pixel_clock_range(intel_sdvo, + &intel_sdvo->pixel_clock_min, + &intel_sdvo->pixel_clock_max); DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " "input 1: %c, input 2: %c, " "output 1: %c, output 2: %c\n", - SDVO_NAME(sdvo_priv), - sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, - sdvo_priv->caps.device_rev_id, - sdvo_priv->pixel_clock_min / 1000, - sdvo_priv->pixel_clock_max / 1000, - (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', - (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + SDVO_NAME(intel_sdvo), + intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id, + intel_sdvo->caps.device_rev_id, + intel_sdvo->pixel_clock_min / 1000, + intel_sdvo->pixel_clock_max / 1000, + (intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', /* check currently supported outputs */ - sdvo_priv->caps.output_flags & + intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', - sdvo_priv->caps.output_flags & + intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; err_i2c: - if (sdvo_priv->analog_ddc_bus != NULL) - intel_i2c_destroy(sdvo_priv->analog_ddc_bus); + if (intel_sdvo->analog_ddc_bus != NULL) + intel_i2c_destroy(intel_sdvo->analog_ddc_bus); if (intel_encoder->ddc_bus != NULL) intel_i2c_destroy(intel_encoder->ddc_bus); if (intel_encoder->i2c_bus != NULL) intel_i2c_destroy(intel_encoder->i2c_bus); err_inteloutput: - kfree(intel_encoder); + kfree(intel_sdvo); return false; } diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index cc3726a4a1cb..1bd6e8795011 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -44,7 +44,9 @@ enum tv_margin { }; /** Private structure for the integrated TV support */ -struct intel_tv_priv { +struct intel_tv { + struct intel_encoder base; + int type; char *tv_format; int margin[4]; @@ -896,6 +898,11 @@ static const struct tv_mode tv_modes[] = { }, }; +static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder) +{ + return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base); +} + static void intel_tv_dpms(struct drm_encoder *encoder, int mode) { @@ -929,19 +936,17 @@ intel_tv_mode_lookup (char *tv_format) } static const struct tv_mode * -intel_tv_mode_find (struct intel_encoder *intel_encoder) +intel_tv_mode_find (struct intel_tv *intel_tv) { - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - - return intel_tv_mode_lookup(tv_priv->tv_format); + return intel_tv_mode_lookup(intel_tv->tv_format); } static enum drm_mode_status intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); /* Ensure TV refresh is close to desired refresh */ if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000) @@ -957,8 +962,8 @@ intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, { struct drm_device *dev = encoder->dev; struct drm_mode_config *drm_config = &dev->mode_config; - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find (intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); struct drm_encoder *other_encoder; if (!tv_mode) @@ -983,9 +988,8 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); u32 tv_ctl; u32 hctl1, hctl2, hctl3; u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; @@ -1001,7 +1005,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, tv_ctl = I915_READ(TV_CTL); tv_ctl &= TV_CTL_SAVE; - switch (tv_priv->type) { + switch (intel_tv->type) { default: case DRM_MODE_CONNECTOR_Unknown: case DRM_MODE_CONNECTOR_Composite: @@ -1168,12 +1172,12 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, else ysize = 2*tv_mode->nbr_end + 1; - xpos += tv_priv->margin[TV_MARGIN_LEFT]; - ypos += tv_priv->margin[TV_MARGIN_TOP]; - xsize -= (tv_priv->margin[TV_MARGIN_LEFT] + - tv_priv->margin[TV_MARGIN_RIGHT]); - ysize -= (tv_priv->margin[TV_MARGIN_TOP] + - tv_priv->margin[TV_MARGIN_BOTTOM]); + xpos += intel_tv->margin[TV_MARGIN_LEFT]; + ypos += intel_tv->margin[TV_MARGIN_TOP]; + xsize -= (intel_tv->margin[TV_MARGIN_LEFT] + + intel_tv->margin[TV_MARGIN_RIGHT]); + ysize -= (intel_tv->margin[TV_MARGIN_TOP] + + intel_tv->margin[TV_MARGIN_BOTTOM]); I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); @@ -1222,9 +1226,9 @@ static const struct drm_display_mode reported_modes[] = { * \return false if TV is disconnected. */ static int -intel_tv_detect_type (struct drm_crtc *crtc, struct intel_encoder *intel_encoder) +intel_tv_detect_type (struct intel_tv *intel_tv) { - struct drm_encoder *encoder = &intel_encoder->enc; + struct drm_encoder *encoder = &intel_tv->base.enc; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; @@ -1304,12 +1308,11 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_encoder *intel_encoder static void intel_tv_find_better_format(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); int i; - if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) == + if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) == tv_mode->component_only) return; @@ -1317,12 +1320,12 @@ static void intel_tv_find_better_format(struct drm_connector *connector) for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) { tv_mode = tv_modes + i; - if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) == + if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) == tv_mode->component_only) break; } - tv_priv->tv_format = tv_mode->name; + intel_tv->tv_format = tv_mode->name; drm_connector_property_set_value(connector, connector->dev->mode_config.tv_mode_property, i); } @@ -1336,31 +1339,31 @@ static void intel_tv_find_better_format(struct drm_connector *connector) static enum drm_connector_status intel_tv_detect(struct drm_connector *connector) { - struct drm_crtc *crtc; struct drm_display_mode mode; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; - int dpms_mode; - int type = tv_priv->type; + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + int type; mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); if (encoder->crtc && encoder->crtc->enabled) { - type = intel_tv_detect_type(encoder->crtc, intel_encoder); + type = intel_tv_detect_type(intel_tv); } else { - crtc = intel_get_load_detect_pipe(intel_encoder, connector, + struct drm_crtc *crtc; + int dpms_mode; + + crtc = intel_get_load_detect_pipe(&intel_tv->base, connector, &mode, &dpms_mode); if (crtc) { - type = intel_tv_detect_type(crtc, intel_encoder); - intel_release_load_detect_pipe(intel_encoder, connector, + type = intel_tv_detect_type(intel_tv); + intel_release_load_detect_pipe(&intel_tv->base, connector, dpms_mode); } else type = -1; } - tv_priv->type = type; + intel_tv->type = type; if (type < 0) return connector_status_disconnected; @@ -1391,8 +1394,8 @@ intel_tv_chose_preferred_modes(struct drm_connector *connector, struct drm_display_mode *mode_ptr) { struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480) mode_ptr->type |= DRM_MODE_TYPE_PREFERRED; @@ -1417,8 +1420,8 @@ intel_tv_get_modes(struct drm_connector *connector) { struct drm_display_mode *mode_ptr; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder); + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv); int j, count = 0; u64 tmp; @@ -1483,8 +1486,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop { struct drm_device *dev = connector->dev; struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - struct intel_tv_priv *tv_priv = intel_encoder->dev_priv; + struct intel_tv *intel_tv = enc_to_intel_tv(encoder); struct drm_crtc *crtc = encoder->crtc; int ret = 0; bool changed = false; @@ -1494,30 +1496,30 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop goto out; if (property == dev->mode_config.tv_left_margin_property && - tv_priv->margin[TV_MARGIN_LEFT] != val) { - tv_priv->margin[TV_MARGIN_LEFT] = val; + intel_tv->margin[TV_MARGIN_LEFT] != val) { + intel_tv->margin[TV_MARGIN_LEFT] = val; changed = true; } else if (property == dev->mode_config.tv_right_margin_property && - tv_priv->margin[TV_MARGIN_RIGHT] != val) { - tv_priv->margin[TV_MARGIN_RIGHT] = val; + intel_tv->margin[TV_MARGIN_RIGHT] != val) { + intel_tv->margin[TV_MARGIN_RIGHT] = val; changed = true; } else if (property == dev->mode_config.tv_top_margin_property && - tv_priv->margin[TV_MARGIN_TOP] != val) { - tv_priv->margin[TV_MARGIN_TOP] = val; + intel_tv->margin[TV_MARGIN_TOP] != val) { + intel_tv->margin[TV_MARGIN_TOP] = val; changed = true; } else if (property == dev->mode_config.tv_bottom_margin_property && - tv_priv->margin[TV_MARGIN_BOTTOM] != val) { - tv_priv->margin[TV_MARGIN_BOTTOM] = val; + intel_tv->margin[TV_MARGIN_BOTTOM] != val) { + intel_tv->margin[TV_MARGIN_BOTTOM] = val; changed = true; } else if (property == dev->mode_config.tv_mode_property) { if (val >= ARRAY_SIZE(tv_modes)) { ret = -EINVAL; goto out; } - if (!strcmp(tv_priv->tv_format, tv_modes[val].name)) + if (!strcmp(intel_tv->tv_format, tv_modes[val].name)) goto out; - tv_priv->tv_format = tv_modes[val].name; + intel_tv->tv_format = tv_modes[val].name; changed = true; } else { ret = -EINVAL; @@ -1553,16 +1555,8 @@ static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = .best_encoder = intel_attached_encoder, }; -static void intel_tv_enc_destroy(struct drm_encoder *encoder) -{ - struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); - - drm_encoder_cleanup(encoder); - kfree(intel_encoder); -} - static const struct drm_encoder_funcs intel_tv_enc_funcs = { - .destroy = intel_tv_enc_destroy, + .destroy = intel_encoder_destroy, }; /* @@ -1606,9 +1600,9 @@ intel_tv_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_connector *connector; + struct intel_tv *intel_tv; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; - struct intel_tv_priv *tv_priv; u32 tv_dac_on, tv_dac_off, save_tv_dac; char **tv_format_names; int i, initial_mode = 0; @@ -1647,18 +1641,18 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - intel_encoder = kzalloc(sizeof(struct intel_encoder) + - sizeof(struct intel_tv_priv), GFP_KERNEL); - if (!intel_encoder) { + intel_tv = kzalloc(sizeof(struct intel_tv), GFP_KERNEL); + if (!intel_tv) { return; } intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { - kfree(intel_encoder); + kfree(intel_tv); return; } + intel_encoder = &intel_tv->base; connector = &intel_connector->base; drm_connector_init(dev, connector, &intel_tv_connector_funcs, @@ -1668,22 +1662,20 @@ intel_tv_init(struct drm_device *dev) DRM_MODE_ENCODER_TVDAC); drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc); - tv_priv = (struct intel_tv_priv *)(intel_encoder + 1); intel_encoder->type = INTEL_OUTPUT_TVOUT; intel_encoder->crtc_mask = (1 << 0) | (1 << 1); intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT); intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1)); intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); - intel_encoder->dev_priv = tv_priv; - tv_priv->type = DRM_MODE_CONNECTOR_Unknown; + intel_tv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ - tv_priv->margin[TV_MARGIN_LEFT] = 54; - tv_priv->margin[TV_MARGIN_TOP] = 36; - tv_priv->margin[TV_MARGIN_RIGHT] = 46; - tv_priv->margin[TV_MARGIN_BOTTOM] = 37; + intel_tv->margin[TV_MARGIN_LEFT] = 54; + intel_tv->margin[TV_MARGIN_TOP] = 36; + intel_tv->margin[TV_MARGIN_RIGHT] = 46; + intel_tv->margin[TV_MARGIN_BOTTOM] = 37; - tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); + intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs); drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); @@ -1703,16 +1695,16 @@ intel_tv_init(struct drm_device *dev) initial_mode); drm_connector_attach_property(connector, dev->mode_config.tv_left_margin_property, - tv_priv->margin[TV_MARGIN_LEFT]); + intel_tv->margin[TV_MARGIN_LEFT]); drm_connector_attach_property(connector, dev->mode_config.tv_top_margin_property, - tv_priv->margin[TV_MARGIN_TOP]); + intel_tv->margin[TV_MARGIN_TOP]); drm_connector_attach_property(connector, dev->mode_config.tv_right_margin_property, - tv_priv->margin[TV_MARGIN_RIGHT]); + intel_tv->margin[TV_MARGIN_RIGHT]); drm_connector_attach_property(connector, dev->mode_config.tv_bottom_margin_property, - tv_priv->margin[TV_MARGIN_BOTTOM]); + intel_tv->margin[TV_MARGIN_BOTTOM]); out: drm_sysfs_connector_add(connector); } -- cgit v1.2.3-59-g8ed1b From 615fb93f6d99cce2ab36dcf09986e321e17c356f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:24 +0100 Subject: drm/i915: Subclass intel_connector. Make the code that tiny bit clearer by reducing the pointer dance. 2 files changed, 130 insertions(+), 147 deletions(-) Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_sdvo.c | 276 ++++++++++++++++++-------------------- 2 files changed, 130 insertions(+), 147 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 520b22cd708e..1075d4386b87 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -109,7 +109,6 @@ struct intel_encoder { struct intel_connector { struct drm_connector base; - void *dev_priv; }; struct intel_crtc; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2fc9da4c0791..dca123527d5f 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -134,6 +134,8 @@ struct intel_sdvo { }; struct intel_sdvo_connector { + struct intel_connector base; + /* Mark the type of connector */ uint16_t output_flag; @@ -180,6 +182,11 @@ static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base); } +static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector) +{ + return container_of(to_intel_connector(connector), struct intel_sdvo_connector, base); +} + static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags); static void @@ -1502,8 +1509,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status status = connector_status_connected; struct edid *edid = NULL; @@ -1543,7 +1549,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) if (edid != NULL) { bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); - bool need_digital = !!(sdvo_connector->output_flag & SDVO_TMDS_MASK); + bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK); /* DDC bus is shared, match EDID to connector type */ if (is_digital && need_digital) @@ -1566,8 +1572,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect u8 status; struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status ret; intel_sdvo_write_cmd(intel_sdvo, @@ -1588,7 +1593,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect intel_sdvo->attached_output = response; - if ((sdvo_connector->output_flag & response) == 0) + if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; else if (response & SDVO_TMDS_MASK) ret = intel_sdvo_hdmi_sink_detect(connector); @@ -1784,12 +1789,11 @@ end: static int intel_sdvo_get_modes(struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - if (IS_TV(sdvo_connector)) + if (IS_TV(intel_sdvo_connector)) intel_sdvo_get_tv_modes(connector); - else if (IS_LVDS(sdvo_connector)) + else if (IS_LVDS(intel_sdvo_connector)) intel_sdvo_get_lvds_modes(connector); else intel_sdvo_get_ddc_modes(connector); @@ -1802,48 +1806,46 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) static void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *intel_sdvo = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_device *dev = connector->dev; - if (IS_TV(intel_sdvo)) { - if (intel_sdvo->left_property) - drm_property_destroy(dev, intel_sdvo->left_property); - if (intel_sdvo->right_property) - drm_property_destroy(dev, intel_sdvo->right_property); - if (intel_sdvo->top_property) - drm_property_destroy(dev, intel_sdvo->top_property); - if (intel_sdvo->bottom_property) - drm_property_destroy(dev, intel_sdvo->bottom_property); - if (intel_sdvo->hpos_property) - drm_property_destroy(dev, intel_sdvo->hpos_property); - if (intel_sdvo->vpos_property) - drm_property_destroy(dev, intel_sdvo->vpos_property); - if (intel_sdvo->saturation_property) + if (IS_TV(intel_sdvo_connector)) { + if (intel_sdvo_connector->left_property) + drm_property_destroy(dev, intel_sdvo_connector->left_property); + if (intel_sdvo_connector->right_property) + drm_property_destroy(dev, intel_sdvo_connector->right_property); + if (intel_sdvo_connector->top_property) + drm_property_destroy(dev, intel_sdvo_connector->top_property); + if (intel_sdvo_connector->bottom_property) + drm_property_destroy(dev, intel_sdvo_connector->bottom_property); + if (intel_sdvo_connector->hpos_property) + drm_property_destroy(dev, intel_sdvo_connector->hpos_property); + if (intel_sdvo_connector->vpos_property) + drm_property_destroy(dev, intel_sdvo_connector->vpos_property); + if (intel_sdvo_connector->saturation_property) drm_property_destroy(dev, - intel_sdvo->saturation_property); - if (intel_sdvo->contrast_property) + intel_sdvo_connector->saturation_property); + if (intel_sdvo_connector->contrast_property) drm_property_destroy(dev, - intel_sdvo->contrast_property); - if (intel_sdvo->hue_property) - drm_property_destroy(dev, intel_sdvo->hue_property); + intel_sdvo_connector->contrast_property); + if (intel_sdvo_connector->hue_property) + drm_property_destroy(dev, intel_sdvo_connector->hue_property); } - if (IS_TV(intel_sdvo) || IS_LVDS(intel_sdvo)) { - if (intel_sdvo->brightness_property) + if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + if (intel_sdvo_connector->brightness_property) drm_property_destroy(dev, - intel_sdvo->brightness_property); + intel_sdvo_connector->brightness_property); } return; } static void intel_sdvo_destroy(struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - if (sdvo_connector->tv_format_property) + if (intel_sdvo_connector->tv_format_property) drm_property_destroy(connector->dev, - sdvo_connector->tv_format_property); + intel_sdvo_connector->tv_format_property); intel_sdvo_destroy_enhance_property(connector); drm_sysfs_connector_remove(connector); @@ -1858,8 +1860,7 @@ intel_sdvo_set_property(struct drm_connector *connector, { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_crtc *crtc = encoder->crtc; int ret = 0; bool changed = false; @@ -1870,101 +1871,101 @@ intel_sdvo_set_property(struct drm_connector *connector, if (ret < 0) goto out; - if (property == sdvo_connector->tv_format_property) { + if (property == intel_sdvo_connector->tv_format_property) { if (val >= TV_FORMAT_NUM) { ret = -EINVAL; goto out; } if (intel_sdvo->tv_format_name == - sdvo_connector->tv_format_supported[val]) + intel_sdvo_connector->tv_format_supported[val]) goto out; - intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[val]; + intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[val]; changed = true; } - if (IS_TV(sdvo_connector) || IS_LVDS(sdvo_connector)) { + if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { cmd = 0; temp_value = val; - if (sdvo_connector->left_property == property) { + if (intel_sdvo_connector->left_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->right_property, val); - if (sdvo_connector->left_margin == temp_value) + intel_sdvo_connector->right_property, val); + if (intel_sdvo_connector->left_margin == temp_value) goto out; - sdvo_connector->left_margin = temp_value; - sdvo_connector->right_margin = temp_value; - temp_value = sdvo_connector->max_hscan - - sdvo_connector->left_margin; + intel_sdvo_connector->left_margin = temp_value; + intel_sdvo_connector->right_margin = temp_value; + temp_value = intel_sdvo_connector->max_hscan - + intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (sdvo_connector->right_property == property) { + } else if (intel_sdvo_connector->right_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->left_property, val); - if (sdvo_connector->right_margin == temp_value) + intel_sdvo_connector->left_property, val); + if (intel_sdvo_connector->right_margin == temp_value) goto out; - sdvo_connector->left_margin = temp_value; - sdvo_connector->right_margin = temp_value; - temp_value = sdvo_connector->max_hscan - - sdvo_connector->left_margin; + intel_sdvo_connector->left_margin = temp_value; + intel_sdvo_connector->right_margin = temp_value; + temp_value = intel_sdvo_connector->max_hscan - + intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (sdvo_connector->top_property == property) { + } else if (intel_sdvo_connector->top_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->bottom_property, val); - if (sdvo_connector->top_margin == temp_value) + intel_sdvo_connector->bottom_property, val); + if (intel_sdvo_connector->top_margin == temp_value) goto out; - sdvo_connector->top_margin = temp_value; - sdvo_connector->bottom_margin = temp_value; - temp_value = sdvo_connector->max_vscan - - sdvo_connector->top_margin; + intel_sdvo_connector->top_margin = temp_value; + intel_sdvo_connector->bottom_margin = temp_value; + temp_value = intel_sdvo_connector->max_vscan - + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (sdvo_connector->bottom_property == property) { + } else if (intel_sdvo_connector->bottom_property == property) { drm_connector_property_set_value(connector, - sdvo_connector->top_property, val); - if (sdvo_connector->bottom_margin == temp_value) + intel_sdvo_connector->top_property, val); + if (intel_sdvo_connector->bottom_margin == temp_value) goto out; - sdvo_connector->top_margin = temp_value; - sdvo_connector->bottom_margin = temp_value; - temp_value = sdvo_connector->max_vscan - - sdvo_connector->top_margin; + intel_sdvo_connector->top_margin = temp_value; + intel_sdvo_connector->bottom_margin = temp_value; + temp_value = intel_sdvo_connector->max_vscan - + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (sdvo_connector->hpos_property == property) { - if (sdvo_connector->cur_hpos == temp_value) + } else if (intel_sdvo_connector->hpos_property == property) { + if (intel_sdvo_connector->cur_hpos == temp_value) goto out; cmd = SDVO_CMD_SET_POSITION_H; - sdvo_connector->cur_hpos = temp_value; - } else if (sdvo_connector->vpos_property == property) { - if (sdvo_connector->cur_vpos == temp_value) + intel_sdvo_connector->cur_hpos = temp_value; + } else if (intel_sdvo_connector->vpos_property == property) { + if (intel_sdvo_connector->cur_vpos == temp_value) goto out; cmd = SDVO_CMD_SET_POSITION_V; - sdvo_connector->cur_vpos = temp_value; - } else if (sdvo_connector->saturation_property == property) { - if (sdvo_connector->cur_saturation == temp_value) + intel_sdvo_connector->cur_vpos = temp_value; + } else if (intel_sdvo_connector->saturation_property == property) { + if (intel_sdvo_connector->cur_saturation == temp_value) goto out; cmd = SDVO_CMD_SET_SATURATION; - sdvo_connector->cur_saturation = temp_value; - } else if (sdvo_connector->contrast_property == property) { - if (sdvo_connector->cur_contrast == temp_value) + intel_sdvo_connector->cur_saturation = temp_value; + } else if (intel_sdvo_connector->contrast_property == property) { + if (intel_sdvo_connector->cur_contrast == temp_value) goto out; cmd = SDVO_CMD_SET_CONTRAST; - sdvo_connector->cur_contrast = temp_value; - } else if (sdvo_connector->hue_property == property) { - if (sdvo_connector->cur_hue == temp_value) + intel_sdvo_connector->cur_contrast = temp_value; + } else if (intel_sdvo_connector->hue_property == property) { + if (intel_sdvo_connector->cur_hue == temp_value) goto out; cmd = SDVO_CMD_SET_HUE; - sdvo_connector->cur_hue = temp_value; - } else if (sdvo_connector->brightness_property == property) { - if (sdvo_connector->cur_brightness == temp_value) + intel_sdvo_connector->cur_hue = temp_value; + } else if (intel_sdvo_connector->brightness_property == property) { + if (intel_sdvo_connector->cur_brightness == temp_value) goto out; cmd = SDVO_CMD_SET_BRIGHTNESS; - sdvo_connector->cur_brightness = temp_value; + intel_sdvo_connector->cur_brightness = temp_value; } if (cmd) { intel_sdvo_write_cmd(intel_sdvo, cmd, &temp_value, 2); @@ -2139,24 +2140,6 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) return 0x72; } -static bool -intel_sdvo_connector_alloc (struct intel_connector **ret) -{ - struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; - - *ret = kzalloc(sizeof(*intel_connector) + - sizeof(*sdvo_connector), GFP_KERNEL); - if (!*ret) - return false; - - intel_connector = *ret; - sdvo_connector = (struct intel_sdvo_connector *)(intel_connector + 1); - intel_connector->dev_priv = sdvo_connector; - - return true; -} - static void intel_sdvo_connector_create (struct drm_encoder *encoder, struct drm_connector *connector) @@ -2180,21 +2163,21 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) return false; - sdvo_connector = intel_connector->dev_priv; - if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; - sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0; } else if (device == 1) { intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1; - sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1; } + intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; encoder->encoder_type = DRM_MODE_ENCODER_TMDS; @@ -2223,18 +2206,19 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) - return false; + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; - sdvo_connector = intel_connector->dev_priv; intel_sdvo->controlled_output |= type; - sdvo_connector->output_flag = type; + intel_sdvo_connector->output_flag = type; intel_sdvo->is_tv = true; intel_sdvo->base.needs_tv_clock = true; @@ -2255,23 +2239,24 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) - return false; + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; + intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; - sdvo_connector = intel_connector->dev_priv; if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0; - sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0; } else if (device == 1) { intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1; - sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; } intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | @@ -2287,24 +2272,25 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) struct drm_encoder *encoder = &intel_sdvo->base.enc; struct drm_connector *connector; struct intel_connector *intel_connector; - struct intel_sdvo_connector *sdvo_connector; + struct intel_sdvo_connector *intel_sdvo_connector; - if (!intel_sdvo_connector_alloc(&intel_connector)) - return false; + intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL); + if (!intel_sdvo_connector) + return false; - connector = &intel_connector->base; + intel_connector = &intel_sdvo_connector->base; + connector = &intel_connector->base; encoder->encoder_type = DRM_MODE_ENCODER_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - sdvo_connector = intel_connector->dev_priv; intel_sdvo->is_lvds = true; if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; - sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; } else if (device == 1) { intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1; - sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; + intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; } intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | @@ -2376,8 +2362,7 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct intel_sdvo_tv_format format; uint32_t format_map, i; uint8_t status; @@ -2397,28 +2382,28 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t if (format_map == 0) return; - sdvo_connector->format_supported_num = 0; + intel_sdvo_connector->format_supported_num = 0; for (i = 0 ; i < TV_FORMAT_NUM; i++) if (format_map & (1 << i)) { - sdvo_connector->tv_format_supported - [sdvo_connector->format_supported_num++] = + intel_sdvo_connector->tv_format_supported + [intel_sdvo_connector->format_supported_num++] = tv_format_names[i]; } - sdvo_connector->tv_format_property = + intel_sdvo_connector->tv_format_property = drm_property_create( connector->dev, DRM_MODE_PROP_ENUM, - "mode", sdvo_connector->format_supported_num); + "mode", intel_sdvo_connector->format_supported_num); - for (i = 0; i < sdvo_connector->format_supported_num; i++) + for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( - sdvo_connector->tv_format_property, i, - i, sdvo_connector->tv_format_supported[i]); + intel_sdvo_connector->tv_format_property, i, + i, intel_sdvo_connector->tv_format_supported[i]); - intel_sdvo->tv_format_name = sdvo_connector->tv_format_supported[0]; + intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[0]; drm_connector_attach_property( - connector, sdvo_connector->tv_format_property, 0); + connector, intel_sdvo_connector->tv_format_property, 0); } @@ -2426,8 +2411,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_connector *intel_connector = to_intel_connector(connector); - struct intel_sdvo_connector *intel_sdvo_connector = intel_connector->dev_priv; + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct intel_sdvo_enhancements_reply sdvo_data; struct drm_device *dev = connector->dev; uint8_t status; -- cgit v1.2.3-59-g8ed1b From 32aad86fe88e7323d4fc5e9e423abcee0d55a03d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:25 +0100 Subject: drm/i915/sdvo: Propagate errors from reading/writing control bus. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 930 ++++++++++++++------------------- drivers/gpu/drm/i915/intel_sdvo_regs.h | 2 +- 2 files changed, 380 insertions(+), 552 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index dca123527d5f..300f110fd180 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -47,6 +47,7 @@ #define IS_TV(c) (c->output_flag & SDVO_TV_MASK) #define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) +#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) static char *tv_format_names[] = { @@ -189,10 +190,13 @@ static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags); -static void -intel_sdvo_tv_create_property(struct drm_connector *connector, int type); -static void -intel_sdvo_create_enhance_property(struct drm_connector *connector); +static bool +intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + int type); +static bool +intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector); /** * Writes the SDVOB or SDVOC with the given value, but always writes both @@ -231,13 +235,10 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) } } -static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, - u8 *ch) +static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch) { - u8 out_buf[2]; + u8 out_buf[2] = { addr, 0 }; u8 buf[2]; - int ret; - struct i2c_msg msgs[] = { { .addr = intel_sdvo->slave_addr >> 1, @@ -252,9 +253,7 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, .buf = buf, } }; - - out_buf[0] = addr; - out_buf[1] = 0; + int ret; if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2) { @@ -266,10 +265,9 @@ static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, return false; } -static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, - u8 ch) +static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch) { - u8 out_buf[2]; + u8 out_buf[2] = { addr, ch }; struct i2c_msg msgs[] = { { .addr = intel_sdvo->slave_addr >> 1, @@ -279,14 +277,7 @@ static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, } }; - out_buf[0] = addr; - out_buf[1] = ch; - - if (i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1) - { - return true; - } - return false; + return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1; } #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} @@ -390,7 +381,7 @@ static const struct _sdvo_cmd_name { #define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC") static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, - void *args, int args_len) + const void *args, int args_len) { int i; @@ -411,19 +402,20 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, DRM_LOG_KMS("\n"); } -static void intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, - void *args, int args_len) +static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, + const void *args, int args_len) { int i; intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); for (i = 0; i < args_len; i++) { - intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i, - ((u8*)args)[i]); + if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i, + ((u8*)args)[i])) + return false; } - intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd); + return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd); } static const char *cmd_status_names[] = { @@ -454,8 +446,8 @@ static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo, DRM_LOG_KMS("\n"); } -static u8 intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, - void *response, int response_len) +static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, + void *response, int response_len) { int i; u8 status; @@ -464,24 +456,26 @@ static u8 intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, while (retry--) { /* Read the command response */ for (i = 0; i < response_len; i++) { - intel_sdvo_read_byte(intel_sdvo, - SDVO_I2C_RETURN_0 + i, - &((u8 *)response)[i]); + if (!intel_sdvo_read_byte(intel_sdvo, + SDVO_I2C_RETURN_0 + i, + &((u8 *)response)[i])) + return false; } /* read the return status */ - intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, - &status); + if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS, + &status)) + return false; intel_sdvo_debug_response(intel_sdvo, response, response_len, status); if (status != SDVO_CMD_STATUS_PENDING) - return status; + break; mdelay(50); } - return status; + return status == SDVO_CMD_STATUS_SUCCESS; } static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) @@ -553,23 +547,29 @@ static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo, return; } -static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo, bool target_0, bool target_1) +static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len) { - struct intel_sdvo_set_target_input_args targets = {0}; - u8 status; - - if (target_0 && target_1) - return SDVO_CMD_STATUS_NOTSUPP; + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len)) + return false; - if (target_1) - targets.target_1 = 1; + return intel_sdvo_read_response(intel_sdvo, NULL, 0); +} - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_INPUT, &targets, - sizeof(targets)); +static bool +intel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len) +{ + if (!intel_sdvo_write_cmd(intel_sdvo, cmd, NULL, 0)) + return false; - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); + return intel_sdvo_read_response(intel_sdvo, value, len); +} - return (status == SDVO_CMD_STATUS_SUCCESS); +static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo) +{ + struct intel_sdvo_set_target_input_args targets = {0}; + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TARGET_INPUT, + &targets, sizeof(targets)); } /** @@ -581,11 +581,9 @@ static bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo, bool targ static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2) { struct intel_sdvo_get_trained_inputs_response response; - u8 status; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &response, sizeof(response)); - if (status != SDVO_CMD_STATUS_SUCCESS) + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, + &response, sizeof(response))) return false; *input_1 = response.input0_trained; @@ -596,18 +594,15 @@ static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *i static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo, u16 outputs) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, - sizeof(outputs)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_ACTIVE_OUTPUTS, + &outputs, sizeof(outputs)); } static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, int mode) { - u8 status, state = SDVO_ENCODER_STATE_ON; + u8 state = SDVO_ENCODER_STATE_ON; switch (mode) { case DRM_MODE_DPMS_ON: @@ -624,11 +619,8 @@ static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, break; } - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, - sizeof(state)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state)); } static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo, @@ -636,51 +628,31 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo int *clock_max) { struct intel_sdvo_pixel_clock_range clocks; - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, - NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &clocks, sizeof(clocks)); - - if (status != SDVO_CMD_STATUS_SUCCESS) + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, + &clocks, sizeof(clocks))) return false; /* Convert the values from units of 10 kHz to kHz. */ *clock_min = clocks.min * 10; *clock_max = clocks.max * 10; - return true; } static bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo, u16 outputs) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, - sizeof(outputs)); - - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TARGET_OUTPUT, + &outputs, sizeof(outputs)); } static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd, struct intel_sdvo_dtd *dtd) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - intel_sdvo_write_cmd(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_set_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2)); } static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo, @@ -704,7 +676,6 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, uint16_t height) { struct intel_sdvo_preferred_input_timing_args args; - uint8_t status; memset(&args, 0, sizeof(args)); args.clock = clock; @@ -717,54 +688,27 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height)) args.scaled = 1; - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, - &args, sizeof(args)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, + &args, sizeof(args)); } static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { - bool status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, - NULL, 0); - - status = intel_sdvo_read_response(intel_sdvo, &dtd->part1, - sizeof(dtd->part1)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, - NULL, 0); - - status = intel_sdvo_read_response(intel_sdvo, &dtd->part2, - sizeof(dtd->part2)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return false; + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + &dtd->part1, sizeof(dtd->part1)) && + intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + &dtd->part2, sizeof(dtd->part2)); } static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); } static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, - struct drm_display_mode *mode) + const struct drm_display_mode *mode) { uint16_t width, height; uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len; @@ -813,7 +757,7 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, } static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, - struct intel_sdvo_dtd *dtd) + const struct intel_sdvo_dtd *dtd) { mode->hdisplay = dtd->part1.h_active; mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8; @@ -848,38 +792,26 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo, struct intel_sdvo_encode *encode) { - uint8_t status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, encode, sizeof(*encode)); - if (status != SDVO_CMD_STATUS_SUCCESS) { /* non-support means DVI */ - memset(encode, 0, sizeof(*encode)); - return false; - } + if (intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPP_ENCODE, + encode, sizeof(*encode))) + return true; - return true; + /* non-support means DVI */ + memset(encode, 0, sizeof(*encode)); + return false; } static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo, uint8_t mode) { - uint8_t status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1); } static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo, uint8_t mode) { - uint8_t status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - - return (status == SDVO_CMD_STATUS_SUCCESS); + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); } #if 0 @@ -892,8 +824,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) uint8_t buf[48]; uint8_t *pos; - intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, NULL, 0); - intel_sdvo_read_response(encoder, &av_split, 1); + intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1); for (i = 0; i <= av_split; i++) { set_buf_index[0] = i; set_buf_index[1] = 0; @@ -913,7 +844,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) } #endif -static void intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, +static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, int index, uint8_t *data, int8_t size, uint8_t tx_rate) { @@ -922,15 +853,18 @@ static void intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo, set_buf_index[0] = index; set_buf_index[1] = 0; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, - set_buf_index, 2); + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX, + set_buf_index, 2)) + return false; for (; size > 0; size -= 8) { - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8); + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8)) + return false; + data += 8; } - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); + return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1); } static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size) @@ -1005,7 +939,7 @@ struct dip_infoframe { } __attribute__ ((packed)) u; } __attribute__((packed)); -static void intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, +static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, struct drm_display_mode * mode) { struct dip_infoframe avi_if = { @@ -1016,17 +950,15 @@ static void intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if, 4 + avi_if.len); - intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, - 4 + avi_if.len, - SDVO_HBUF_TX_VSYNC); + return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if, + 4 + avi_if.len, + SDVO_HBUF_TX_VSYNC); } -static void intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) +static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) { - struct intel_sdvo_tv_format format; uint32_t format_map, i; - uint8_t status; for (i = 0; i < TV_FORMAT_NUM; i++) if (tv_format_names[i] == intel_sdvo->tv_format_name) @@ -1034,113 +966,93 @@ static void intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) format_map = 1 << i; memset(&format, 0, sizeof(format)); - memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ? - sizeof(format) : sizeof(format_map)); - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_TV_FORMAT, &format, - sizeof(format)); + memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) - DRM_DEBUG_KMS("%s: Failed to set TV format\n", - SDVO_NAME(intel_sdvo)); + BUILD_BUG_ON(sizeof(format) != 6); + return intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_TV_FORMAT, + &format, sizeof(format)); } -static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool +intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo, + struct drm_display_mode *mode) { - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_sdvo_dtd output_dtd; - if (intel_sdvo->is_tv) { - struct intel_sdvo_dtd output_dtd; - bool success; + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output)) + return false; - /* We need to construct preferred input timings based on our - * output timings. To do that, we have to set the output - * timings, even though this isn't really the right place in - * the sequence to do it. Oh well. - */ + intel_sdvo_get_dtd_from_mode(&output_dtd, mode); + if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd)) + return false; + return true; +} + +static bool +intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_sdvo_dtd input_dtd; - /* Set output timings */ - intel_sdvo_get_dtd_from_mode(&output_dtd, mode); - intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output); - intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); + /* Reset the input timing to the screen. Assume always input 0. */ + if (!intel_sdvo_set_target_input(intel_sdvo)) + return false; - /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); + if (!intel_sdvo_create_preferred_input_timing(intel_sdvo, + mode->clock / 10, + mode->hdisplay, + mode->vdisplay)) + return false; + if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, + &input_dtd)) + return false; - success = intel_sdvo_create_preferred_input_timing(intel_sdvo, - mode->clock / 10, - mode->hdisplay, - mode->vdisplay); - if (success) { - struct intel_sdvo_dtd input_dtd; + intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; - intel_sdvo_get_preferred_input_timing(intel_sdvo, - &input_dtd); - intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; + drm_mode_set_crtcinfo(adjusted_mode, 0); + mode->clock = adjusted_mode->clock; + return true; +} - drm_mode_set_crtcinfo(adjusted_mode, 0); +static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - mode->clock = adjusted_mode->clock; + /* We need to construct preferred input timings based on our + * output timings. To do that, we have to set the output + * timings, even though this isn't really the right place in + * the sequence to do it. Oh well. + */ + if (intel_sdvo->is_tv) { + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) + return false; - adjusted_mode->clock *= - intel_sdvo_get_pixel_multiplier(mode); - } else { + if (!intel_sdvo_set_input_timings_for_mode(intel_sdvo, mode, adjusted_mode)) return false; - } } else if (intel_sdvo->is_lvds) { - struct intel_sdvo_dtd output_dtd; - bool success; - drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0); - /* Set output timings */ - intel_sdvo_get_dtd_from_mode(&output_dtd, - intel_sdvo->sdvo_lvds_fixed_mode); - - intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output); - intel_sdvo_set_output_timing(intel_sdvo, &output_dtd); - - /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); - - - success = intel_sdvo_create_preferred_input_timing( - intel_sdvo, - mode->clock / 10, - mode->hdisplay, - mode->vdisplay); - - if (success) { - struct intel_sdvo_dtd input_dtd; - - intel_sdvo_get_preferred_input_timing(intel_sdvo, - &input_dtd); - intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); - intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags; - drm_mode_set_crtcinfo(adjusted_mode, 0); - - mode->clock = adjusted_mode->clock; - - adjusted_mode->clock *= - intel_sdvo_get_pixel_multiplier(mode); - } else { + if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, + intel_sdvo->sdvo_lvds_fixed_mode)) return false; - } - } else { - /* Make the CRTC code factor in the SDVO pixel multiplier. The - * SDVO device will be told of the multiplier during mode_set. - */ - adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); + if (!intel_sdvo_set_input_timings_for_mode(intel_sdvo, mode, adjusted_mode)) + return false; } + + /* Make the CRTC code factor in the SDVO pixel multiplier. The + * SDVO device will be told of the multiplier during mode_set. + */ + adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); + return true; } @@ -1154,10 +1066,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); u32 sdvox = 0; - int sdvo_pixel_multiply; + int sdvo_pixel_multiply, rate; struct intel_sdvo_in_out_map in_out; struct intel_sdvo_dtd input_dtd; - u8 status; if (!mode) return; @@ -1171,12 +1082,15 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, in_out.in0 = intel_sdvo->attached_output; in_out.in1 = 0; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_IN_OUT_MAP, - &in_out, sizeof(in_out)); - status = intel_sdvo_read_response(intel_sdvo, NULL, 0); + if (!intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_IN_OUT_MAP, + &in_out, sizeof(in_out))) + return; if (intel_sdvo->is_hdmi) { - intel_sdvo_set_avi_infoframe(intel_sdvo, mode); + if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) + return; + sdvox |= SDVO_AUDIO_ENABLE; } @@ -1193,16 +1107,22 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, */ if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) { /* Set the output timing to the screen */ - intel_sdvo_set_target_output(intel_sdvo, - intel_sdvo->attached_output); - intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); + if (!intel_sdvo_set_target_output(intel_sdvo, + intel_sdvo->attached_output)) + return; + + if (!intel_sdvo_set_output_timing(intel_sdvo, &input_dtd)) + return; } /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); + if (!intel_sdvo_set_target_input(intel_sdvo)) + return; - if (intel_sdvo->is_tv) - intel_sdvo_set_tv_format(intel_sdvo); + if (intel_sdvo->is_tv) { + if (!intel_sdvo_set_tv_format(intel_sdvo)) + return; + } /* We would like to use intel_sdvo_create_preferred_input_timing() to * provide the device with a timing it can support, if it supports that @@ -1219,23 +1139,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_input_timing(encoder, &input_dtd); } #else - intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); + if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd)) + return; #endif - switch (intel_sdvo_get_pixel_multiplier(mode)) { - case 1: - intel_sdvo_set_clock_rate_mult(intel_sdvo, - SDVO_CLOCK_RATE_MULT_1X); - break; - case 2: - intel_sdvo_set_clock_rate_mult(intel_sdvo, - SDVO_CLOCK_RATE_MULT_2X); - break; - case 4: - intel_sdvo_set_clock_rate_mult(intel_sdvo, - SDVO_CLOCK_RATE_MULT_4X); - break; + sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); + switch (sdvo_pixel_multiply) { + case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; + case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; + case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; } + if (!intel_sdvo_set_clock_rate_mult(intel_sdvo, rate)) + return; /* Set the SDVO control regs. */ if (IS_I965G(dev)) { @@ -1259,7 +1174,6 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, if (intel_crtc->pipe == 1) sdvox |= SDVO_PIPE_B_SELECT; - sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); if (IS_I965G(dev)) { /* done in crtc_mode_set as the dpll_md reg must be written early */ } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { @@ -1302,10 +1216,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) for (i = 0; i < 2; i++) intel_wait_for_vblank(dev); - status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, - &input2); - - + status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); /* Warn if the device reported failure to sync. * A lot of SDVO devices fail to notify of sync, but it's * a given it the status is a success, we succeeded. @@ -1353,14 +1264,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) { - u8 status; - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, caps, sizeof(*caps)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - - return true; + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps)); } /* No use! */ @@ -1403,13 +1307,8 @@ int intel_sdvo_supports_hotplug(struct drm_connector *connector) intel_sdvo = to_intel_sdvo(connector); - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &response, 2); - - if (response[0] !=0) - return 1; - - return 0; + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, + &response, 2) && response[0]; } void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) @@ -1492,8 +1391,8 @@ static int intel_analog_is_connected(struct drm_device *dev) { struct drm_connector *analog_connector; - analog_connector = intel_find_analog_connector(dev); + analog_connector = intel_find_analog_connector(dev); if (!analog_connector) return false; @@ -1569,25 +1468,23 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) { uint16_t response; - u8 status; struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); enum drm_connector_status ret; - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + if (!intel_sdvo_write_cmd(intel_sdvo, + SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0)) + return connector_status_unknown; if (intel_sdvo->is_tv) { /* add 30ms delay when the output type is SDVO-TV */ mdelay(30); } - status = intel_sdvo_read_response(intel_sdvo, &response, 2); + if (!intel_sdvo_read_response(intel_sdvo, &response, 2)) + return connector_status_unknown; DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8); - if (status != SDVO_CMD_STATUS_SUCCESS) - return connector_status_unknown; - if (response == 0) return connector_status_disconnected; @@ -1713,8 +1610,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0, format_map = 0; int i; - uint8_t status; - /* Read the list of supported input resolutions for the selected TV * format. @@ -1725,23 +1620,23 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) format_map = (1 << i); memcpy(&tv_res, &format_map, - sizeof(struct intel_sdvo_sdtv_resolution_request) > - sizeof(format_map) ? sizeof(format_map) : - sizeof(struct intel_sdvo_sdtv_resolution_request)); + min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); - intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output); + if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output)) + return; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, - &tv_res, sizeof(tv_res)); - status = intel_sdvo_read_response(intel_sdvo, &reply, 3); - if (status != SDVO_CMD_STATUS_SUCCESS) + BUILD_BUG_ON(sizeof(tv_res) != 3); + if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, + &tv_res, sizeof(tv_res))) + return; + if (!intel_sdvo_read_response(intel_sdvo, &reply, 3)) return; for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++) if (reply & (1 << i)) { struct drm_display_mode *nmode; nmode = drm_mode_duplicate(connector->dev, - &sdvo_tv_modes[i]); + &sdvo_tv_modes[i]); if (nmode) drm_mode_probed_add(connector, nmode); } @@ -1798,9 +1693,7 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) else intel_sdvo_get_ddc_modes(connector); - if (list_empty(&connector->probed_modes)) - return 0; - return 1; + return !list_empty(&connector->probed_modes); } static @@ -1831,7 +1724,7 @@ void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) if (intel_sdvo_connector->hue_property) drm_property_destroy(dev, intel_sdvo_connector->hue_property); } - if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + if (IS_TV_OR_LVDS(intel_sdvo_connector)) { if (intel_sdvo_connector->brightness_property) drm_property_destroy(dev, intel_sdvo_connector->brightness_property); @@ -1862,36 +1755,33 @@ intel_sdvo_set_property(struct drm_connector *connector, struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_crtc *crtc = encoder->crtc; - int ret = 0; bool changed = false; - uint8_t cmd, status; uint16_t temp_value; + uint8_t cmd; + int ret; ret = drm_connector_property_set_value(connector, property, val); - if (ret < 0) - goto out; + if (ret) + return ret; if (property == intel_sdvo_connector->tv_format_property) { - if (val >= TV_FORMAT_NUM) { - ret = -EINVAL; - goto out; - } + if (val >= TV_FORMAT_NUM) + return -EINVAL; + if (intel_sdvo->tv_format_name == intel_sdvo_connector->tv_format_supported[val]) - goto out; + return 0; intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[val]; changed = true; - } - - if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { cmd = 0; temp_value = val; if (intel_sdvo_connector->left_property == property) { drm_connector_property_set_value(connector, intel_sdvo_connector->right_property, val); if (intel_sdvo_connector->left_margin == temp_value) - goto out; + return 0; intel_sdvo_connector->left_margin = temp_value; intel_sdvo_connector->right_margin = temp_value; @@ -1902,7 +1792,7 @@ intel_sdvo_set_property(struct drm_connector *connector, drm_connector_property_set_value(connector, intel_sdvo_connector->left_property, val); if (intel_sdvo_connector->right_margin == temp_value) - goto out; + return 0; intel_sdvo_connector->left_margin = temp_value; intel_sdvo_connector->right_margin = temp_value; @@ -1913,7 +1803,7 @@ intel_sdvo_set_property(struct drm_connector *connector, drm_connector_property_set_value(connector, intel_sdvo_connector->bottom_property, val); if (intel_sdvo_connector->top_margin == temp_value) - goto out; + return 0; intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; @@ -1924,7 +1814,8 @@ intel_sdvo_set_property(struct drm_connector *connector, drm_connector_property_set_value(connector, intel_sdvo_connector->top_property, val); if (intel_sdvo_connector->bottom_margin == temp_value) - goto out; + return 0; + intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; temp_value = intel_sdvo_connector->max_vscan - @@ -1932,57 +1823,52 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_V; } else if (intel_sdvo_connector->hpos_property == property) { if (intel_sdvo_connector->cur_hpos == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_POSITION_H; intel_sdvo_connector->cur_hpos = temp_value; } else if (intel_sdvo_connector->vpos_property == property) { if (intel_sdvo_connector->cur_vpos == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_POSITION_V; intel_sdvo_connector->cur_vpos = temp_value; } else if (intel_sdvo_connector->saturation_property == property) { if (intel_sdvo_connector->cur_saturation == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_SATURATION; intel_sdvo_connector->cur_saturation = temp_value; } else if (intel_sdvo_connector->contrast_property == property) { if (intel_sdvo_connector->cur_contrast == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_CONTRAST; intel_sdvo_connector->cur_contrast = temp_value; } else if (intel_sdvo_connector->hue_property == property) { if (intel_sdvo_connector->cur_hue == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_HUE; intel_sdvo_connector->cur_hue = temp_value; } else if (intel_sdvo_connector->brightness_property == property) { if (intel_sdvo_connector->cur_brightness == temp_value) - goto out; + return 0; cmd = SDVO_CMD_SET_BRIGHTNESS; intel_sdvo_connector->cur_brightness = temp_value; } if (cmd) { - intel_sdvo_write_cmd(intel_sdvo, cmd, &temp_value, 2); - status = intel_sdvo_read_response(intel_sdvo, - NULL, 0); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO command \n"); + if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) return -EINVAL; - } + changed = true; } } if (changed && crtc) drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); -out: - return ret; + return 0; } static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { @@ -2050,18 +1936,10 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, static bool intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device) { - uint8_t status; - - if (device == 0) - intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS0); - else - intel_sdvo_set_target_output(intel_sdvo, SDVO_OUTPUT_TMDS1); - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ENCODE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &intel_sdvo->is_hdmi, 1); - if (status != SDVO_CMD_STATUS_SUCCESS) - return false; - return true; + return intel_sdvo_set_target_output(intel_sdvo, + device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) && + intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, + &intel_sdvo->is_hdmi, 1); } static struct intel_sdvo * @@ -2076,7 +1954,7 @@ intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan) return intel_sdvo; } - return NULL;; + return NULL; } static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, @@ -2141,8 +2019,8 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg) } static void -intel_sdvo_connector_create (struct drm_encoder *encoder, - struct drm_connector *connector) +intel_sdvo_connector_init(struct drm_encoder *encoder, + struct drm_connector *connector) { drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs, connector->connector_type); @@ -2195,7 +2073,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); - intel_sdvo_connector_create(encoder, connector); + intel_sdvo_connector_init(encoder, connector); return true; } @@ -2224,13 +2102,19 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) intel_sdvo->base.needs_tv_clock = true; intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT; - intel_sdvo_connector_create(encoder, connector); + intel_sdvo_connector_init(encoder, connector); - intel_sdvo_tv_create_property(connector, type); + if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type)) + goto err; - intel_sdvo_create_enhance_property(connector); + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + goto err; return true; + +err: + kfree(intel_sdvo_connector); + return false; } static bool @@ -2262,7 +2146,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); - intel_sdvo_connector_create(encoder, connector); + intel_sdvo_connector_init(encoder, connector); return true; } @@ -2296,9 +2180,15 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) | (1 << INTEL_SDVO_LVDS_CLONE_BIT)); - intel_sdvo_connector_create(encoder, connector); - intel_sdvo_create_enhance_property(connector); - return true; + intel_sdvo_connector_init(encoder, connector); + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + goto err; + + return true; + +err: + kfree(intel_sdvo_connector); + return false; } static bool @@ -2358,29 +2248,26 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) return true; } -static void intel_sdvo_tv_create_property(struct drm_connector *connector, int type) +static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + int type) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + struct drm_device *dev = intel_sdvo->base.enc.dev; struct intel_sdvo_tv_format format; uint32_t format_map, i; - uint8_t status; - intel_sdvo_set_target_output(intel_sdvo, type); + if (!intel_sdvo_set_target_output(intel_sdvo, type)) + return false; - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &format, sizeof(format)); - if (status != SDVO_CMD_STATUS_SUCCESS) - return; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_TV_FORMATS, + &format, sizeof(format))) + return false; - memcpy(&format_map, &format, sizeof(format) > sizeof(format_map) ? - sizeof(format_map) : sizeof(format)); + memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format))); if (format_map == 0) - return; + return false; intel_sdvo_connector->format_supported_num = 0; for (i = 0 ; i < TV_FORMAT_NUM; i++) @@ -2392,9 +2279,8 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t intel_sdvo_connector->tv_format_property = - drm_property_create( - connector->dev, DRM_MODE_PROP_ENUM, - "mode", intel_sdvo_connector->format_supported_num); + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "mode", intel_sdvo_connector->format_supported_num); for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( @@ -2402,56 +2288,45 @@ static void intel_sdvo_tv_create_property(struct drm_connector *connector, int t i, intel_sdvo_connector->tv_format_supported[i]); intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[0]; - drm_connector_attach_property( - connector, intel_sdvo_connector->tv_format_property, 0); + drm_connector_attach_property(&intel_sdvo_connector->base.base, + intel_sdvo_connector->tv_format_property, 0); + return true; } -static void intel_sdvo_create_enhance_property(struct drm_connector *connector) +static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector) { - struct drm_encoder *encoder = intel_attached_encoder(connector); - struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); - struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_connector *connector = &intel_sdvo_connector->base.base; struct intel_sdvo_enhancements_reply sdvo_data; - struct drm_device *dev = connector->dev; - uint8_t status; uint16_t response, data_value[2]; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, - NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &sdvo_data, - sizeof(sdvo_data)); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS(" incorrect response is returned\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + &sdvo_data, sizeof(sdvo_data))) + return false; + response = *((uint16_t *)&sdvo_data); if (!response) { DRM_DEBUG_KMS("No enhancement is supported\n"); - return; + return true; } if (IS_TV(intel_sdvo_connector)) { /* when horizontal overscan is supported, Add the left/right * property */ if (sdvo_data.overscan_h) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO max " - "h_overscan\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO h_overscan\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_H, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_H, + &response, 2)) + return false; + intel_sdvo_connector->max_hscan = data_value[0]; intel_sdvo_connector->left_margin = data_value[0] - response; intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; @@ -2476,23 +2351,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.overscan_v) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO max " - "v_overscan\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO v_overscan\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_V, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_V, + &response, 2)) + return false; + intel_sdvo_connector->max_vscan = data_value[0]; intel_sdvo_connector->top_margin = data_value[0] - response; intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; @@ -2517,22 +2385,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.position_h) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max h_pos\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_POSITION_H, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get h_postion\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_POSITION_H, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_POSITION_H, + &response, 2)) + return false; + intel_sdvo_connector->max_hpos = data_value[0]; intel_sdvo_connector->cur_hpos = response; intel_sdvo_connector->hpos_property = @@ -2548,22 +2410,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.position_v) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max v_pos\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_POSITION_V, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get v_postion\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_POSITION_V, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_POSITION_V, + &response, 2)) + return false; + intel_sdvo_connector->max_vpos = data_value[0]; intel_sdvo_connector->cur_vpos = response; intel_sdvo_connector->vpos_property = @@ -2579,22 +2435,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.saturation) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max sat\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_SATURATION, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get sat\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_SATURATION, + &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SATURATION, + &response, 2)) + return false; + intel_sdvo_connector->max_saturation = data_value[0]; intel_sdvo_connector->cur_saturation = response; intel_sdvo_connector->saturation_property = @@ -2611,22 +2461,14 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.contrast) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max contrast\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_CONTRAST, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get contrast\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_CONTRAST, &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_CONTRAST, &response, 2)) + return false; + intel_sdvo_connector->max_contrast = data_value[0]; intel_sdvo_connector->cur_contrast = response; intel_sdvo_connector->contrast_property = @@ -2642,22 +2484,14 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } if (sdvo_data.hue) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max hue\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_HUE, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get hue\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_HUE, &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_HUE, &response, 2)) + return false; + intel_sdvo_connector->max_hue = data_value[0]; intel_sdvo_connector->cur_hue = response; intel_sdvo_connector->hue_property = @@ -2673,24 +2507,16 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } } - if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) { + if (IS_TV_OR_LVDS(intel_sdvo_connector)) { if (sdvo_data.brightness) { - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &data_value, 4); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO Max bright\n"); - return; - } - intel_sdvo_write_cmd(intel_sdvo, - SDVO_CMD_GET_BRIGHTNESS, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, - &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) { - DRM_DEBUG_KMS("Incorrect SDVO get brigh\n"); - return; - } + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_BRIGHTNESS, &data_value, 4)) + return false; + + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_BRIGHTNESS, &response, 2)) + return false; + intel_sdvo_connector->max_brightness = data_value[0]; intel_sdvo_connector->cur_brightness = response; intel_sdvo_connector->brightness_property = @@ -2707,7 +2533,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) data_value[0], data_value[1], response); } } - return; + return true; } bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) @@ -2773,8 +2599,7 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) "SDVOC/VGA DDC BUS"); dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS; } - - if (intel_encoder->ddc_bus == NULL) + if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL) goto err_i2c; /* Wrap with our custom algo which switches to DDC mode */ @@ -2785,24 +2610,26 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs); /* In default case sdvo lvds is false */ - intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps); + if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) + goto err_enc; if (intel_sdvo_output_setup(intel_sdvo, intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", IS_SDVOB(sdvo_reg) ? 'B' : 'C'); - goto err_i2c; + goto err_enc; } intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(intel_sdvo, true, false); - - intel_sdvo_get_input_pixel_clock_range(intel_sdvo, - &intel_sdvo->pixel_clock_min, - &intel_sdvo->pixel_clock_max); + if (!intel_sdvo_set_target_input(intel_sdvo)) + goto err_enc; + if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo, + &intel_sdvo->pixel_clock_min, + &intel_sdvo->pixel_clock_max)) + goto err_enc; DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, " "clock range %dMHz - %dMHz, " @@ -2820,9 +2647,10 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', intel_sdvo->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); - return true; +err_enc: + drm_encoder_cleanup(&intel_encoder->enc); err_i2c: if (intel_sdvo->analog_ddc_bus != NULL) intel_i2c_destroy(intel_sdvo->analog_ddc_bus); diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index ba5cdf8ae40b..4988660f661b 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -312,7 +312,7 @@ struct intel_sdvo_set_target_input_args { # define SDVO_CLOCK_RATE_MULT_4X (1 << 3) #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 -/** 5 bytes of bit flags for TV formats shared by all TV format functions */ +/** 6 bytes of bit flags for TV formats shared by all TV format functions */ struct intel_sdvo_tv_format { unsigned int ntsc_m:1; unsigned int ntsc_j:1; -- cgit v1.2.3-59-g8ed1b From 400397506f96466a7f57911b33b4b9c075880994 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:26 +0100 Subject: drm/i915/sdvo: Use an integer mapping for supported tv format modes Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 300f110fd180..ce8e4432d1c5 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -98,7 +98,7 @@ struct intel_sdvo { bool is_tv; /* This is for current tv format name */ - char *tv_format_name; + int tv_format_index; /** * This is set if we treat the device as HDMI, instead of DVI. @@ -141,7 +141,7 @@ struct intel_sdvo_connector { uint16_t output_flag; /* This contains all current supported TV format */ - char *tv_format_supported[TV_FORMAT_NUM]; + u8 tv_format_supported[TV_FORMAT_NUM]; int format_supported_num; struct drm_property *tv_format_property; struct drm_property *tv_format_name_property[TV_FORMAT_NUM]; @@ -958,13 +958,9 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) { struct intel_sdvo_tv_format format; - uint32_t format_map, i; - - for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == intel_sdvo->tv_format_name) - break; + uint32_t format_map; - format_map = 1 << i; + format_map = 1 << intel_sdvo->tv_format_index; memset(&format, 0, sizeof(format)); memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); @@ -1614,11 +1610,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) /* Read the list of supported input resolutions for the selected TV * format. */ - for (i = 0; i < TV_FORMAT_NUM; i++) - if (tv_format_names[i] == intel_sdvo->tv_format_name) - break; - - format_map = (1 << i); + format_map = 1 << intel_sdvo->tv_format_index; memcpy(&tv_res, &format_map, min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request))); @@ -1640,7 +1632,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) if (nmode) drm_mode_probed_add(connector, nmode); } - } static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) @@ -1768,11 +1759,11 @@ intel_sdvo_set_property(struct drm_connector *connector, if (val >= TV_FORMAT_NUM) return -EINVAL; - if (intel_sdvo->tv_format_name == + if (intel_sdvo->tv_format_index == intel_sdvo_connector->tv_format_supported[val]) return 0; - intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[val]; + intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val]; changed = true; } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { cmd = 0; @@ -2271,11 +2262,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->format_supported_num = 0; for (i = 0 ; i < TV_FORMAT_NUM; i++) - if (format_map & (1 << i)) { - intel_sdvo_connector->tv_format_supported - [intel_sdvo_connector->format_supported_num++] = - tv_format_names[i]; - } + if (format_map & (1 << i)) + intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i; intel_sdvo_connector->tv_format_property = @@ -2285,9 +2273,9 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( intel_sdvo_connector->tv_format_property, i, - i, intel_sdvo_connector->tv_format_supported[i]); + i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); - intel_sdvo->tv_format_name = intel_sdvo_connector->tv_format_supported[0]; + intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; drm_connector_attach_property(&intel_sdvo_connector->base.base, intel_sdvo_connector->tv_format_property, 0); return true; -- cgit v1.2.3-59-g8ed1b From fcc8d6721cef2158398139d66cc99b5e843126a0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:27 +0100 Subject: drm/i915/sdvo: Check for allocation failure when constructing properties Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 40 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index ce8e4432d1c5..72fec054c264 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1687,8 +1687,8 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) return !list_empty(&connector->probed_modes); } -static -void intel_sdvo_destroy_enhance_property(struct drm_connector *connector) +static void +intel_sdvo_destroy_enhance_property(struct drm_connector *connector) { struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_device *dev = connector->dev; @@ -2104,6 +2104,7 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) return true; err: + intel_sdvo_destroy_enhance_property(connector); kfree(intel_sdvo_connector); return false; } @@ -2178,6 +2179,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) return true; err: + intel_sdvo_destroy_enhance_property(connector); kfree(intel_sdvo_connector); return false; } @@ -2269,6 +2271,8 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->tv_format_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "mode", intel_sdvo_connector->format_supported_num); + if (!intel_sdvo_connector->tv_format_property) + return false; for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( @@ -2321,14 +2325,21 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->left_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "left_margin", 2); + if (!intel_sdvo_connector->left_property) + return false; + intel_sdvo_connector->left_property->values[0] = 0; intel_sdvo_connector->left_property->values[1] = data_value[0]; drm_connector_attach_property(connector, intel_sdvo_connector->left_property, intel_sdvo_connector->left_margin); + intel_sdvo_connector->right_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "right_margin", 2); + if (!intel_sdvo_connector->right_property) + return false; + intel_sdvo_connector->right_property->values[0] = 0; intel_sdvo_connector->right_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2355,14 +2366,21 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->top_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "top_margin", 2); + if (!intel_sdvo_connector->top_property) + return false; + intel_sdvo_connector->top_property->values[0] = 0; intel_sdvo_connector->top_property->values[1] = data_value[0]; drm_connector_attach_property(connector, intel_sdvo_connector->top_property, intel_sdvo_connector->top_margin); + intel_sdvo_connector->bottom_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "bottom_margin", 2); + if (!intel_sdvo_connector->bottom_property) + return false; + intel_sdvo_connector->bottom_property->values[0] = 0; intel_sdvo_connector->bottom_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2388,6 +2406,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->hpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hpos", 2); + if (!intel_sdvo_connector->hpos_property) + return false; + intel_sdvo_connector->hpos_property->values[0] = 0; intel_sdvo_connector->hpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2413,6 +2434,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->vpos_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "vpos", 2); + if (!intel_sdvo_connector->vpos_property) + return false; + intel_sdvo_connector->vpos_property->values[0] = 0; intel_sdvo_connector->vpos_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2438,6 +2462,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->saturation_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "saturation", 2); + if (!intel_sdvo_connector->saturation_property) + return false; + intel_sdvo_connector->saturation_property->values[0] = 0; intel_sdvo_connector->saturation_property->values[1] = data_value[0]; @@ -2462,6 +2489,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->contrast_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "contrast", 2); + if (!intel_sdvo_connector->contrast_property) + return false; + intel_sdvo_connector->contrast_property->values[0] = 0; intel_sdvo_connector->contrast_property->values[1] = data_value[0]; drm_connector_attach_property(connector, @@ -2485,6 +2515,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->hue_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "hue", 2); + if (!intel_sdvo_connector->hue_property) + return false; + intel_sdvo_connector->hue_property->values[0] = 0; intel_sdvo_connector->hue_property->values[1] = data_value[0]; @@ -2510,6 +2543,9 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->brightness_property = drm_property_create(dev, DRM_MODE_PROP_RANGE, "brightness", 2); + if (!intel_sdvo_connector->brightness_property) + return false; + intel_sdvo_connector->brightness_property->values[0] = 0; intel_sdvo_connector->brightness_property->values[1] = data_value[0]; -- cgit v1.2.3-59-g8ed1b From c55217064eb728fc9348de781979b533e7cc116c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:28 +0100 Subject: drm/i915/sdvo: Add missing TV filters Reference: Bug 28634 - missing TV parameter "Flicker Filter" https://bugs.freedesktop.org/show_bug.cgi?id=28634 Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 644 +++++++++++++++------------------ drivers/gpu/drm/i915/intel_sdvo_regs.h | 48 +-- 2 files changed, 308 insertions(+), 384 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 72fec054c264..2344fb056793 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -143,31 +143,31 @@ struct intel_sdvo_connector { /* This contains all current supported TV format */ u8 tv_format_supported[TV_FORMAT_NUM]; int format_supported_num; - struct drm_property *tv_format_property; - struct drm_property *tv_format_name_property[TV_FORMAT_NUM]; - - /** - * Returned SDTV resolutions allowed for the current format, if the - * device reported it. - */ - struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions; + struct drm_property *tv_format; /* add the property for the SDVO-TV */ - struct drm_property *left_property; - struct drm_property *right_property; - struct drm_property *top_property; - struct drm_property *bottom_property; - struct drm_property *hpos_property; - struct drm_property *vpos_property; + struct drm_property *left; + struct drm_property *right; + struct drm_property *top; + struct drm_property *bottom; + struct drm_property *hpos; + struct drm_property *vpos; + struct drm_property *contrast; + struct drm_property *saturation; + struct drm_property *hue; + struct drm_property *sharpness; + struct drm_property *flicker_filter; + struct drm_property *flicker_filter_adaptive; + struct drm_property *flicker_filter_2d; + struct drm_property *tv_chroma_filter; + struct drm_property *tv_luma_filter; /* add the property for the SDVO-TV/LVDS */ - struct drm_property *brightness_property; - struct drm_property *contrast_property; - struct drm_property *saturation_property; - struct drm_property *hue_property; + struct drm_property *brightness; /* Add variable to record current setting for the above property */ u32 left_margin, right_margin, top_margin, bottom_margin; + /* this is to get the range of margin.*/ u32 max_hscan, max_vscan; u32 max_hpos, cur_hpos; @@ -176,6 +176,12 @@ struct intel_sdvo_connector { u32 cur_contrast, max_contrast; u32 cur_saturation, max_saturation; u32 cur_hue, max_hue; + u32 cur_sharpness, max_sharpness; + u32 cur_flicker_filter, max_flicker_filter; + u32 cur_flicker_filter_adaptive, max_flicker_filter_adaptive; + u32 cur_flicker_filter_2d, max_flicker_filter_2d; + u32 cur_tv_chroma_filter, max_tv_chroma_filter; + u32 cur_tv_luma_filter, max_tv_luma_filter; }; static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) @@ -329,13 +335,14 @@ static const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS), + /* Add the op code for SDVO enhancements */ - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_POSITION_H), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POSITION_H), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_POSITION_H), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_POSITION_V), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POSITION_V), - SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_POSITION_V), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_VPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_VPOS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_VPOS), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION), SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION), @@ -354,6 +361,27 @@ static const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V), SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_2D), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SHARPNESS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DOT_CRAWL), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DOT_CRAWL), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_CHROMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_LUMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_LUMA_FILTER), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_LUMA_FILTER), + /* HDMI op code */ SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE), @@ -1693,43 +1721,47 @@ intel_sdvo_destroy_enhance_property(struct drm_connector *connector) struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); struct drm_device *dev = connector->dev; - if (IS_TV(intel_sdvo_connector)) { - if (intel_sdvo_connector->left_property) - drm_property_destroy(dev, intel_sdvo_connector->left_property); - if (intel_sdvo_connector->right_property) - drm_property_destroy(dev, intel_sdvo_connector->right_property); - if (intel_sdvo_connector->top_property) - drm_property_destroy(dev, intel_sdvo_connector->top_property); - if (intel_sdvo_connector->bottom_property) - drm_property_destroy(dev, intel_sdvo_connector->bottom_property); - if (intel_sdvo_connector->hpos_property) - drm_property_destroy(dev, intel_sdvo_connector->hpos_property); - if (intel_sdvo_connector->vpos_property) - drm_property_destroy(dev, intel_sdvo_connector->vpos_property); - if (intel_sdvo_connector->saturation_property) - drm_property_destroy(dev, - intel_sdvo_connector->saturation_property); - if (intel_sdvo_connector->contrast_property) - drm_property_destroy(dev, - intel_sdvo_connector->contrast_property); - if (intel_sdvo_connector->hue_property) - drm_property_destroy(dev, intel_sdvo_connector->hue_property); - } - if (IS_TV_OR_LVDS(intel_sdvo_connector)) { - if (intel_sdvo_connector->brightness_property) - drm_property_destroy(dev, - intel_sdvo_connector->brightness_property); - } - return; + if (intel_sdvo_connector->left) + drm_property_destroy(dev, intel_sdvo_connector->left); + if (intel_sdvo_connector->right) + drm_property_destroy(dev, intel_sdvo_connector->right); + if (intel_sdvo_connector->top) + drm_property_destroy(dev, intel_sdvo_connector->top); + if (intel_sdvo_connector->bottom) + drm_property_destroy(dev, intel_sdvo_connector->bottom); + if (intel_sdvo_connector->hpos) + drm_property_destroy(dev, intel_sdvo_connector->hpos); + if (intel_sdvo_connector->vpos) + drm_property_destroy(dev, intel_sdvo_connector->vpos); + if (intel_sdvo_connector->saturation) + drm_property_destroy(dev, intel_sdvo_connector->saturation); + if (intel_sdvo_connector->contrast) + drm_property_destroy(dev, intel_sdvo_connector->contrast); + if (intel_sdvo_connector->hue) + drm_property_destroy(dev, intel_sdvo_connector->hue); + if (intel_sdvo_connector->sharpness) + drm_property_destroy(dev, intel_sdvo_connector->sharpness); + if (intel_sdvo_connector->flicker_filter) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter); + if (intel_sdvo_connector->flicker_filter_2d) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_2d); + if (intel_sdvo_connector->flicker_filter_adaptive) + drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_adaptive); + if (intel_sdvo_connector->tv_luma_filter) + drm_property_destroy(dev, intel_sdvo_connector->tv_luma_filter); + if (intel_sdvo_connector->tv_chroma_filter) + drm_property_destroy(dev, intel_sdvo_connector->tv_chroma_filter); + if (intel_sdvo_connector->brightness) + drm_property_destroy(dev, intel_sdvo_connector->brightness); } static void intel_sdvo_destroy(struct drm_connector *connector) { struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - if (intel_sdvo_connector->tv_format_property) + if (intel_sdvo_connector->tv_format) drm_property_destroy(connector->dev, - intel_sdvo_connector->tv_format_property); + intel_sdvo_connector->tv_format); intel_sdvo_destroy_enhance_property(connector); drm_sysfs_connector_remove(connector); @@ -1745,8 +1777,6 @@ intel_sdvo_set_property(struct drm_connector *connector, struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - struct drm_crtc *crtc = encoder->crtc; - bool changed = false; uint16_t temp_value; uint8_t cmd; int ret; @@ -1755,7 +1785,16 @@ intel_sdvo_set_property(struct drm_connector *connector, if (ret) return ret; - if (property == intel_sdvo_connector->tv_format_property) { +#define CHECK_PROPERTY(name, NAME) \ + if (intel_sdvo_connector->name == property) { \ + if (intel_sdvo_connector->cur_##name == temp_value) return 0; \ + if (intel_sdvo_connector->max_##name < temp_value) return -EINVAL; \ + cmd = SDVO_CMD_SET_##NAME; \ + intel_sdvo_connector->cur_##name = temp_value; \ + goto set_value; \ + } + + if (property == intel_sdvo_connector->tv_format) { if (val >= TV_FORMAT_NUM) return -EINVAL; @@ -1764,24 +1803,24 @@ intel_sdvo_set_property(struct drm_connector *connector, return 0; intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val]; - changed = true; + goto done; } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { - cmd = 0; temp_value = val; - if (intel_sdvo_connector->left_property == property) { + if (intel_sdvo_connector->left == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->right_property, val); + intel_sdvo_connector->right, val); if (intel_sdvo_connector->left_margin == temp_value) return 0; intel_sdvo_connector->left_margin = temp_value; intel_sdvo_connector->right_margin = temp_value; temp_value = intel_sdvo_connector->max_hscan - - intel_sdvo_connector->left_margin; + intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (intel_sdvo_connector->right_property == property) { + goto set_value; + } else if (intel_sdvo_connector->right == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->left_property, val); + intel_sdvo_connector->left, val); if (intel_sdvo_connector->right_margin == temp_value) return 0; @@ -1790,76 +1829,63 @@ intel_sdvo_set_property(struct drm_connector *connector, temp_value = intel_sdvo_connector->max_hscan - intel_sdvo_connector->left_margin; cmd = SDVO_CMD_SET_OVERSCAN_H; - } else if (intel_sdvo_connector->top_property == property) { + goto set_value; + } else if (intel_sdvo_connector->top == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->bottom_property, val); + intel_sdvo_connector->bottom, val); if (intel_sdvo_connector->top_margin == temp_value) return 0; intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; temp_value = intel_sdvo_connector->max_vscan - - intel_sdvo_connector->top_margin; + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (intel_sdvo_connector->bottom_property == property) { + goto set_value; + } else if (intel_sdvo_connector->bottom == property) { drm_connector_property_set_value(connector, - intel_sdvo_connector->top_property, val); + intel_sdvo_connector->top, val); if (intel_sdvo_connector->bottom_margin == temp_value) return 0; intel_sdvo_connector->top_margin = temp_value; intel_sdvo_connector->bottom_margin = temp_value; temp_value = intel_sdvo_connector->max_vscan - - intel_sdvo_connector->top_margin; + intel_sdvo_connector->top_margin; cmd = SDVO_CMD_SET_OVERSCAN_V; - } else if (intel_sdvo_connector->hpos_property == property) { - if (intel_sdvo_connector->cur_hpos == temp_value) - return 0; - - cmd = SDVO_CMD_SET_POSITION_H; - intel_sdvo_connector->cur_hpos = temp_value; - } else if (intel_sdvo_connector->vpos_property == property) { - if (intel_sdvo_connector->cur_vpos == temp_value) - return 0; - - cmd = SDVO_CMD_SET_POSITION_V; - intel_sdvo_connector->cur_vpos = temp_value; - } else if (intel_sdvo_connector->saturation_property == property) { - if (intel_sdvo_connector->cur_saturation == temp_value) - return 0; + goto set_value; + } + CHECK_PROPERTY(hpos, HPOS) + CHECK_PROPERTY(vpos, VPOS) + CHECK_PROPERTY(saturation, SATURATION) + CHECK_PROPERTY(contrast, CONTRAST) + CHECK_PROPERTY(hue, HUE) + CHECK_PROPERTY(brightness, BRIGHTNESS) + CHECK_PROPERTY(sharpness, SHARPNESS) + CHECK_PROPERTY(flicker_filter, FLICKER_FILTER) + CHECK_PROPERTY(flicker_filter_2d, FLICKER_FILTER_2D) + CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE) + CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER) + CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER) + } - cmd = SDVO_CMD_SET_SATURATION; - intel_sdvo_connector->cur_saturation = temp_value; - } else if (intel_sdvo_connector->contrast_property == property) { - if (intel_sdvo_connector->cur_contrast == temp_value) - return 0; + return -EINVAL; /* unknown property */ - cmd = SDVO_CMD_SET_CONTRAST; - intel_sdvo_connector->cur_contrast = temp_value; - } else if (intel_sdvo_connector->hue_property == property) { - if (intel_sdvo_connector->cur_hue == temp_value) - return 0; +set_value: + if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) + return -EIO; - cmd = SDVO_CMD_SET_HUE; - intel_sdvo_connector->cur_hue = temp_value; - } else if (intel_sdvo_connector->brightness_property == property) { - if (intel_sdvo_connector->cur_brightness == temp_value) - return 0; - cmd = SDVO_CMD_SET_BRIGHTNESS; - intel_sdvo_connector->cur_brightness = temp_value; - } - if (cmd) { - if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2)) - return -EINVAL; +done: + if (encoder->crtc) { + struct drm_crtc *crtc = encoder->crtc; - changed = true; - } - } - if (changed && crtc) drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + crtc->y, crtc->fb); + } + return 0; +#undef CHECK_PROPERTY } static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { @@ -2268,296 +2294,194 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i; - intel_sdvo_connector->tv_format_property = + intel_sdvo_connector->tv_format = drm_property_create(dev, DRM_MODE_PROP_ENUM, "mode", intel_sdvo_connector->format_supported_num); - if (!intel_sdvo_connector->tv_format_property) + if (!intel_sdvo_connector->tv_format) return false; for (i = 0; i < intel_sdvo_connector->format_supported_num; i++) drm_property_add_enum( - intel_sdvo_connector->tv_format_property, i, + intel_sdvo_connector->tv_format, i, i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; drm_connector_attach_property(&intel_sdvo_connector->base.base, - intel_sdvo_connector->tv_format_property, 0); + intel_sdvo_connector->tv_format, 0); return true; } -static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, - struct intel_sdvo_connector *intel_sdvo_connector) +#define ENHANCEMENT(name, NAME) do { \ + if (enhancements.name) { \ + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \ + !intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \ + return false; \ + intel_sdvo_connector->max_##name = data_value[0]; \ + intel_sdvo_connector->cur_##name = response; \ + intel_sdvo_connector->name = \ + drm_property_create(dev, DRM_MODE_PROP_RANGE, #name, 2); \ + if (!intel_sdvo_connector->name) return false; \ + intel_sdvo_connector->name->values[0] = 0; \ + intel_sdvo_connector->name->values[1] = data_value[0]; \ + drm_connector_attach_property(connector, \ + intel_sdvo_connector->name, \ + intel_sdvo_connector->cur_##name); \ + DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ + data_value[0], data_value[1], response); \ + } \ +} while(0) + +static bool +intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + struct intel_sdvo_enhancements_reply enhancements) { struct drm_device *dev = intel_sdvo->base.enc.dev; struct drm_connector *connector = &intel_sdvo_connector->base.base; - struct intel_sdvo_enhancements_reply sdvo_data; uint16_t response, data_value[2]; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, - &sdvo_data, sizeof(sdvo_data))) - return false; - - response = *((uint16_t *)&sdvo_data); - if (!response) { - DRM_DEBUG_KMS("No enhancement is supported\n"); - return true; - } - if (IS_TV(intel_sdvo_connector)) { - /* when horizontal overscan is supported, Add the left/right - * property - */ - if (sdvo_data.overscan_h) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_H, - &data_value, 4)) - return false; - - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_H, - &response, 2)) - return false; - - intel_sdvo_connector->max_hscan = data_value[0]; - intel_sdvo_connector->left_margin = data_value[0] - response; - intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; - intel_sdvo_connector->left_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "left_margin", 2); - if (!intel_sdvo_connector->left_property) - return false; - - intel_sdvo_connector->left_property->values[0] = 0; - intel_sdvo_connector->left_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->left_property, - intel_sdvo_connector->left_margin); - - intel_sdvo_connector->right_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "right_margin", 2); - if (!intel_sdvo_connector->right_property) - return false; - - intel_sdvo_connector->right_property->values[0] = 0; - intel_sdvo_connector->right_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->right_property, - intel_sdvo_connector->right_margin); - DRM_DEBUG_KMS("h_overscan: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.overscan_v) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_OVERSCAN_V, - &data_value, 4)) - return false; - - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_OVERSCAN_V, - &response, 2)) - return false; + /* when horizontal overscan is supported, Add the left/right property */ + if (enhancements.overscan_h) { + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_H, + &data_value, 4)) + return false; - intel_sdvo_connector->max_vscan = data_value[0]; - intel_sdvo_connector->top_margin = data_value[0] - response; - intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; - intel_sdvo_connector->top_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "top_margin", 2); - if (!intel_sdvo_connector->top_property) - return false; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_H, + &response, 2)) + return false; - intel_sdvo_connector->top_property->values[0] = 0; - intel_sdvo_connector->top_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->top_property, - intel_sdvo_connector->top_margin); + intel_sdvo_connector->max_hscan = data_value[0]; + intel_sdvo_connector->left_margin = data_value[0] - response; + intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin; + intel_sdvo_connector->left = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "left_margin", 2); + if (!intel_sdvo_connector->left) + return false; - intel_sdvo_connector->bottom_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "bottom_margin", 2); - if (!intel_sdvo_connector->bottom_property) - return false; + intel_sdvo_connector->left->values[0] = 0; + intel_sdvo_connector->left->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->left, + intel_sdvo_connector->left_margin); - intel_sdvo_connector->bottom_property->values[0] = 0; - intel_sdvo_connector->bottom_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->bottom_property, - intel_sdvo_connector->bottom_margin); - DRM_DEBUG_KMS("v_overscan: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.position_h) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_H, - &data_value, 4)) - return false; + intel_sdvo_connector->right = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "right_margin", 2); + if (!intel_sdvo_connector->right) + return false; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_POSITION_H, - &response, 2)) - return false; + intel_sdvo_connector->right->values[0] = 0; + intel_sdvo_connector->right->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->right, + intel_sdvo_connector->right_margin); + DRM_DEBUG_KMS("h_overscan: max %d, " + "default %d, current %d\n", + data_value[0], data_value[1], response); + } - intel_sdvo_connector->max_hpos = data_value[0]; - intel_sdvo_connector->cur_hpos = response; - intel_sdvo_connector->hpos_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "hpos", 2); - if (!intel_sdvo_connector->hpos_property) - return false; + if (enhancements.overscan_v) { + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_MAX_OVERSCAN_V, + &data_value, 4)) + return false; - intel_sdvo_connector->hpos_property->values[0] = 0; - intel_sdvo_connector->hpos_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->hpos_property, - intel_sdvo_connector->cur_hpos); - DRM_DEBUG_KMS("h_position: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.position_v) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_POSITION_V, - &data_value, 4)) - return false; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_OVERSCAN_V, + &response, 2)) + return false; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_POSITION_V, - &response, 2)) - return false; + intel_sdvo_connector->max_vscan = data_value[0]; + intel_sdvo_connector->top_margin = data_value[0] - response; + intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin; + intel_sdvo_connector->top = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "top_margin", 2); + if (!intel_sdvo_connector->top) + return false; - intel_sdvo_connector->max_vpos = data_value[0]; - intel_sdvo_connector->cur_vpos = response; - intel_sdvo_connector->vpos_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "vpos", 2); - if (!intel_sdvo_connector->vpos_property) - return false; + intel_sdvo_connector->top->values[0] = 0; + intel_sdvo_connector->top->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->top, + intel_sdvo_connector->top_margin); - intel_sdvo_connector->vpos_property->values[0] = 0; - intel_sdvo_connector->vpos_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->vpos_property, - intel_sdvo_connector->cur_vpos); - DRM_DEBUG_KMS("v_position: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.saturation) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_SATURATION, - &data_value, 4)) - return false; + intel_sdvo_connector->bottom = + drm_property_create(dev, DRM_MODE_PROP_RANGE, + "bottom_margin", 2); + if (!intel_sdvo_connector->bottom) + return false; - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_SATURATION, - &response, 2)) - return false; + intel_sdvo_connector->bottom->values[0] = 0; + intel_sdvo_connector->bottom->values[1] = data_value[0]; + drm_connector_attach_property(connector, + intel_sdvo_connector->bottom, + intel_sdvo_connector->bottom_margin); + DRM_DEBUG_KMS("v_overscan: max %d, " + "default %d, current %d\n", + data_value[0], data_value[1], response); + } - intel_sdvo_connector->max_saturation = data_value[0]; - intel_sdvo_connector->cur_saturation = response; - intel_sdvo_connector->saturation_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "saturation", 2); - if (!intel_sdvo_connector->saturation_property) - return false; + ENHANCEMENT(hpos, HPOS); + ENHANCEMENT(vpos, VPOS); + ENHANCEMENT(saturation, SATURATION); + ENHANCEMENT(contrast, CONTRAST); + ENHANCEMENT(hue, HUE); + ENHANCEMENT(sharpness, SHARPNESS); + ENHANCEMENT(brightness, BRIGHTNESS); + ENHANCEMENT(flicker_filter, FLICKER_FILTER); + ENHANCEMENT(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE); + ENHANCEMENT(flicker_filter_2d, FLICKER_FILTER_2D); + ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER); + ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER); - intel_sdvo_connector->saturation_property->values[0] = 0; - intel_sdvo_connector->saturation_property->values[1] = - data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->saturation_property, - intel_sdvo_connector->cur_saturation); - DRM_DEBUG_KMS("saturation: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.contrast) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_CONTRAST, &data_value, 4)) - return false; + return true; +} - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_CONTRAST, &response, 2)) - return false; +static bool +intel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, + struct intel_sdvo_enhancements_reply enhancements) +{ + struct drm_device *dev = intel_sdvo->base.enc.dev; + struct drm_connector *connector = &intel_sdvo_connector->base.base; + uint16_t response, data_value[2]; - intel_sdvo_connector->max_contrast = data_value[0]; - intel_sdvo_connector->cur_contrast = response; - intel_sdvo_connector->contrast_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "contrast", 2); - if (!intel_sdvo_connector->contrast_property) - return false; + ENHANCEMENT(brightness, BRIGHTNESS); - intel_sdvo_connector->contrast_property->values[0] = 0; - intel_sdvo_connector->contrast_property->values[1] = data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->contrast_property, - intel_sdvo_connector->cur_contrast); - DRM_DEBUG_KMS("contrast: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - if (sdvo_data.hue) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_HUE, &data_value, 4)) - return false; + return true; +} +#undef ENHANCEMENT - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_HUE, &response, 2)) - return false; +static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector) +{ + union { + struct intel_sdvo_enhancements_reply reply; + uint16_t response; + } enhancements; - intel_sdvo_connector->max_hue = data_value[0]; - intel_sdvo_connector->cur_hue = response; - intel_sdvo_connector->hue_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "hue", 2); - if (!intel_sdvo_connector->hue_property) - return false; + if (!intel_sdvo_get_value(intel_sdvo, + SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, + &enhancements, sizeof(enhancements))) + return false; - intel_sdvo_connector->hue_property->values[0] = 0; - intel_sdvo_connector->hue_property->values[1] = - data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->hue_property, - intel_sdvo_connector->cur_hue); - DRM_DEBUG_KMS("hue: max %d, default %d, current %d\n", - data_value[0], data_value[1], response); - } + if (enhancements.response == 0) { + DRM_DEBUG_KMS("No enhancement is supported\n"); + return true; } - if (IS_TV_OR_LVDS(intel_sdvo_connector)) { - if (sdvo_data.brightness) { - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_MAX_BRIGHTNESS, &data_value, 4)) - return false; - - if (!intel_sdvo_get_value(intel_sdvo, - SDVO_CMD_GET_BRIGHTNESS, &response, 2)) - return false; - intel_sdvo_connector->max_brightness = data_value[0]; - intel_sdvo_connector->cur_brightness = response; - intel_sdvo_connector->brightness_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE, - "brightness", 2); - if (!intel_sdvo_connector->brightness_property) - return false; + if (IS_TV(intel_sdvo_connector)) + return intel_sdvo_create_enhance_property_tv(intel_sdvo, intel_sdvo_connector, enhancements.reply); + else if(IS_LVDS(intel_sdvo_connector)) + return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply); + else + return true; - intel_sdvo_connector->brightness_property->values[0] = 0; - intel_sdvo_connector->brightness_property->values[1] = - data_value[0]; - drm_connector_attach_property(connector, - intel_sdvo_connector->brightness_property, - intel_sdvo_connector->cur_brightness); - DRM_DEBUG_KMS("brightness: max %d, " - "default %d, current %d\n", - data_value[0], data_value[1], response); - } - } - return true; } bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 4988660f661b..a386b022e538 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -596,32 +596,32 @@ struct intel_sdvo_enhancements_reply { unsigned int overscan_h:1; unsigned int overscan_v:1; - unsigned int position_h:1; - unsigned int position_v:1; + unsigned int hpos:1; + unsigned int vpos:1; unsigned int sharpness:1; unsigned int dot_crawl:1; unsigned int dither:1; - unsigned int max_tv_chroma_filter:1; - unsigned int max_tv_luma_filter:1; + unsigned int tv_chroma_filter:1; + unsigned int tv_luma_filter:1; } __attribute__((packed)); /* Picture enhancement limits below are dependent on the current TV format, * and thus need to be queried and set after it. */ -#define SDVO_CMD_GET_MAX_FLICKER_FITER 0x4d -#define SDVO_CMD_GET_MAX_ADAPTIVE_FLICKER_FITER 0x7b -#define SDVO_CMD_GET_MAX_2D_FLICKER_FITER 0x52 +#define SDVO_CMD_GET_MAX_FLICKER_FILTER 0x4d +#define SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE 0x7b +#define SDVO_CMD_GET_MAX_FLICKER_FILTER_2D 0x52 #define SDVO_CMD_GET_MAX_SATURATION 0x55 #define SDVO_CMD_GET_MAX_HUE 0x58 #define SDVO_CMD_GET_MAX_BRIGHTNESS 0x5b #define SDVO_CMD_GET_MAX_CONTRAST 0x5e #define SDVO_CMD_GET_MAX_OVERSCAN_H 0x61 #define SDVO_CMD_GET_MAX_OVERSCAN_V 0x64 -#define SDVO_CMD_GET_MAX_POSITION_H 0x67 -#define SDVO_CMD_GET_MAX_POSITION_V 0x6a -#define SDVO_CMD_GET_MAX_SHARPNESS_V 0x6d -#define SDVO_CMD_GET_MAX_TV_CHROMA 0x74 -#define SDVO_CMD_GET_MAX_TV_LUMA 0x77 +#define SDVO_CMD_GET_MAX_HPOS 0x67 +#define SDVO_CMD_GET_MAX_VPOS 0x6a +#define SDVO_CMD_GET_MAX_SHARPNESS 0x6d +#define SDVO_CMD_GET_MAX_TV_CHROMA_FILTER 0x74 +#define SDVO_CMD_GET_MAX_TV_LUMA_FILTER 0x77 struct intel_sdvo_enhancement_limits_reply { u16 max_value; u16 default_value; @@ -638,10 +638,10 @@ struct intel_sdvo_enhancement_limits_reply { #define SDVO_CMD_GET_FLICKER_FILTER 0x4e #define SDVO_CMD_SET_FLICKER_FILTER 0x4f -#define SDVO_CMD_GET_ADAPTIVE_FLICKER_FITER 0x50 -#define SDVO_CMD_SET_ADAPTIVE_FLICKER_FITER 0x51 -#define SDVO_CMD_GET_2D_FLICKER_FITER 0x53 -#define SDVO_CMD_SET_2D_FLICKER_FITER 0x54 +#define SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE 0x50 +#define SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE 0x51 +#define SDVO_CMD_GET_FLICKER_FILTER_2D 0x53 +#define SDVO_CMD_SET_FLICKER_FILTER_2D 0x54 #define SDVO_CMD_GET_SATURATION 0x56 #define SDVO_CMD_SET_SATURATION 0x57 #define SDVO_CMD_GET_HUE 0x59 @@ -654,16 +654,16 @@ struct intel_sdvo_enhancement_limits_reply { #define SDVO_CMD_SET_OVERSCAN_H 0x63 #define SDVO_CMD_GET_OVERSCAN_V 0x65 #define SDVO_CMD_SET_OVERSCAN_V 0x66 -#define SDVO_CMD_GET_POSITION_H 0x68 -#define SDVO_CMD_SET_POSITION_H 0x69 -#define SDVO_CMD_GET_POSITION_V 0x6b -#define SDVO_CMD_SET_POSITION_V 0x6c +#define SDVO_CMD_GET_HPOS 0x68 +#define SDVO_CMD_SET_HPOS 0x69 +#define SDVO_CMD_GET_VPOS 0x6b +#define SDVO_CMD_SET_VPOS 0x6c #define SDVO_CMD_GET_SHARPNESS 0x6e #define SDVO_CMD_SET_SHARPNESS 0x6f -#define SDVO_CMD_GET_TV_CHROMA 0x75 -#define SDVO_CMD_SET_TV_CHROMA 0x76 -#define SDVO_CMD_GET_TV_LUMA 0x78 -#define SDVO_CMD_SET_TV_LUMA 0x79 +#define SDVO_CMD_GET_TV_CHROMA_FILTER 0x75 +#define SDVO_CMD_SET_TV_CHROMA_FILTER 0x76 +#define SDVO_CMD_GET_TV_LUMA_FILTER 0x78 +#define SDVO_CMD_SET_TV_LUMA_FILTER 0x79 struct intel_sdvo_enhancements_arg { u16 value; }__attribute__((packed)); -- cgit v1.2.3-59-g8ed1b From e044218a8ecb560b6fad65912a4e7e509db40414 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:50:29 +0100 Subject: drm/i915/sdvo: Add dot crawl property This property is slightly unusual in that it is a boolean and so has no GET_MAX command. Reference: Bug 28636 - missing TV parameter "Dot Crawl freeze" https://bugs.freedesktop.org/show_bug.cgi?id=28636 Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2344fb056793..1e31724d1616 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -161,6 +161,7 @@ struct intel_sdvo_connector { struct drm_property *flicker_filter_2d; struct drm_property *tv_chroma_filter; struct drm_property *tv_luma_filter; + struct drm_property *dot_crawl; /* add the property for the SDVO-TV/LVDS */ struct drm_property *brightness; @@ -182,6 +183,7 @@ struct intel_sdvo_connector { u32 cur_flicker_filter_2d, max_flicker_filter_2d; u32 cur_tv_chroma_filter, max_tv_chroma_filter; u32 cur_tv_luma_filter, max_tv_luma_filter; + u32 cur_dot_crawl, max_dot_crawl; }; static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder) @@ -1751,6 +1753,8 @@ intel_sdvo_destroy_enhance_property(struct drm_connector *connector) drm_property_destroy(dev, intel_sdvo_connector->tv_luma_filter); if (intel_sdvo_connector->tv_chroma_filter) drm_property_destroy(dev, intel_sdvo_connector->tv_chroma_filter); + if (intel_sdvo_connector->dot_crawl) + drm_property_destroy(dev, intel_sdvo_connector->dot_crawl); if (intel_sdvo_connector->brightness) drm_property_destroy(dev, intel_sdvo_connector->brightness); } @@ -1867,6 +1871,7 @@ intel_sdvo_set_property(struct drm_connector *connector, CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE) CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER) CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER) + CHECK_PROPERTY(dot_crawl, DOT_CRAWL) } return -EINVAL; /* unknown property */ @@ -2439,6 +2444,25 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER); ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER); + if (enhancements.dot_crawl) { + if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2)) + return false; + + intel_sdvo_connector->max_dot_crawl = 1; + intel_sdvo_connector->cur_dot_crawl = response & 0x1; + intel_sdvo_connector->dot_crawl = + drm_property_create(dev, DRM_MODE_PROP_RANGE, "dot_crawl", 2); + if (!intel_sdvo_connector->dot_crawl) + return false; + + intel_sdvo_connector->dot_crawl->values[0] = 0; + intel_sdvo_connector->dot_crawl->values[1] = 1; + drm_connector_attach_property(connector, + intel_sdvo_connector->dot_crawl, + intel_sdvo_connector->cur_dot_crawl); + DRM_DEBUG_KMS("dot crawl: current %d\n", response); + } + return true; } -- cgit v1.2.3-59-g8ed1b From 88f356b725c8a18c4da3ee0b6dcbc647418268f2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 13:55:32 +0100 Subject: drm/i915: Only emit flushes on active rings. This avoids the excess flush and requests on idle rings (and spamming the debug log ;-) Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem.c | 26 ++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 906663b9929e..e7fb37995652 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -285,6 +285,9 @@ typedef struct drm_i915_private { unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; int num_pipe; + u32 flush_rings; +#define FLUSH_RENDER_RING 0x1 +#define FLUSH_BSD_RING 0x2 /* For hangcheck timer */ #define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 2a4ed7ca8b4e..fc61542cce8a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3117,6 +3117,7 @@ static void i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); uint32_t invalidate_domains = 0; uint32_t flush_domains = 0; @@ -3179,6 +3180,13 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) obj->pending_write_domain = obj->write_domain; obj->read_domains = obj->pending_read_domains; + if (flush_domains & I915_GEM_GPU_DOMAINS) { + if (obj_priv->ring == &dev_priv->render_ring) + dev_priv->flush_rings |= FLUSH_RENDER_RING; + else if (obj_priv->ring == &dev_priv->bsd_ring) + dev_priv->flush_rings |= FLUSH_BSD_RING; + } + dev->invalidate_domains |= invalidate_domains; dev->flush_domains |= flush_domains; #if WATCH_BUF @@ -3718,7 +3726,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ring = &dev_priv->render_ring; } - if (args->buffer_count < 1) { DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); return -EINVAL; @@ -3892,6 +3899,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ dev->invalidate_domains = 0; dev->flush_domains = 0; + dev_priv->flush_rings = 0; for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -3912,16 +3920,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, i915_gem_flush(dev, dev->invalidate_domains, dev->flush_domains); - if (dev->flush_domains & I915_GEM_GPU_DOMAINS) { + if (dev_priv->flush_rings & FLUSH_RENDER_RING) (void)i915_add_request(dev, file_priv, - dev->flush_domains, - &dev_priv->render_ring); - - if (HAS_BSD(dev)) - (void)i915_add_request(dev, file_priv, - dev->flush_domains, - &dev_priv->bsd_ring); - } + dev->flush_domains, + &dev_priv->render_ring); + if (dev_priv->flush_rings & FLUSH_BSD_RING) + (void)i915_add_request(dev, file_priv, + dev->flush_domains, + &dev_priv->bsd_ring); } for (i = 0; i < args->buffer_count; i++) { -- cgit v1.2.3-59-g8ed1b From 403c89ff3960c540ac4d203035078f82082411cb Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:25:31 +0100 Subject: drm/i915: Mark the static memory latency tables const. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9839494528ae..f3b014fe3508 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2882,7 +2882,7 @@ struct cxsr_latency { unsigned long cursor_hpll_disable; }; -static struct cxsr_latency cxsr_latency_table[] = { +static const struct cxsr_latency cxsr_latency_table[] = { {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ @@ -2920,11 +2920,13 @@ static struct cxsr_latency cxsr_latency_table[] = { {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ }; -static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3, - int fsb, int mem) +static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, + int is_ddr3, + int fsb, + int mem) { + const struct cxsr_latency *latency; int i; - struct cxsr_latency *latency; if (fsb == 0 || mem == 0) return NULL; @@ -3035,12 +3037,12 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; + const struct cxsr_latency *latency; u32 reg; unsigned long wm; - struct cxsr_latency *latency; int sr_clock; - latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, + latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, dev_priv->fsb_freq, dev_priv->mem_freq); if (!latency) { DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); -- cgit v1.2.3-59-g8ed1b From 0be555b66a871d711a89c301b37e763058d34d33 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:36:30 +0100 Subject: drm/i915: report all active objects as busy Incorporates a similar patch by Daniel Vetter, the alteration being to report the current busy state after retiring. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index fc61542cce8a..24ee4622484f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4365,22 +4365,34 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, } mutex_lock(&dev->struct_mutex); - /* Update the active list for the hardware's current position. - * Otherwise this only updates on a delayed timer or when irqs are - * actually unmasked, and our working set ends up being larger than - * required. - */ - i915_gem_retire_requests(dev); - obj_priv = to_intel_bo(obj); - /* Don't count being on the flushing list against the object being - * done. Otherwise, a buffer left on the flushing list but not getting - * flushed (because nobody's flushing that domain) won't ever return - * unbusy and get reused by libdrm's bo cache. The other expected - * consumer of this interface, OpenGL's occlusion queries, also specs - * that the objects get unbusy "eventually" without any interference. + /* Count all active objects as busy, even if they are currently not used + * by the gpu. Users of this interface expect objects to eventually + * become non-busy without any further actions, therefore emit any + * necessary flushes here. */ - args->busy = obj_priv->active && obj_priv->last_rendering_seqno != 0; + obj_priv = to_intel_bo(obj); + args->busy = obj_priv->active; + if (args->busy) { + /* Unconditionally flush objects, even when the gpu still uses this + * object. Userspace calling this function indicates that it wants to + * use this buffer rather sooner than later, so issuing the required + * flush earlier is beneficial. + */ + if (obj->write_domain) { + i915_gem_flush(dev, 0, obj->write_domain); + (void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring); + } + + /* Update the active list for the hardware's current position. + * Otherwise this only updates on a delayed timer or when irqs + * are actually unmasked, and our working set ends up being + * larger than required. + */ + i915_gem_retire_requests_ring(dev, obj_priv->ring); + + args->busy = obj_priv->active; + } drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3-59-g8ed1b From 69d0b96c095468526009cb3104eee561c9252a84 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Aug 2010 21:22:09 +0200 Subject: drm/i915: fixup pageflip ringbuffer commands for i8xx Add a new path for 2nd gen chips that uses the commands for i81x chips (where public docs do exist) augmented with the plane bits from i915. It seems to work and doesn't result in a black screen like before. Signed-off-by: Daniel Vetter Cc: stable@kernel.org [anholt: resolved against conflict] Reviewed-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f3b014fe3508..ce7a46b6909b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5119,12 +5119,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, OUT_RING(offset | obj_priv->tiling_mode); pipesrc = I915_READ(pipesrc_reg); OUT_RING(pipesrc & 0x0fff0fff); - } else { + } else if (IS_GEN3(dev)) { OUT_RING(MI_DISPLAY_FLIP_I915 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); OUT_RING(offset); OUT_RING(MI_NOOP); + } else { + OUT_RING(MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + OUT_RING(fb->pitch); + OUT_RING(offset); + OUT_RING(MI_NOOP); } ADVANCE_LP_RING(); -- cgit v1.2.3-59-g8ed1b From 6146b3d61925116e3fecce36c2fd873665bd6614 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 4 Aug 2010 21:22:10 +0200 Subject: drm/i915: i8xx also doesn't like multiple oustanding pageflips My i855GM suffers from a 80k/s interrupt storm without this. So add 2nd gen to the list of things that don't like more than one outstanding pageflip request. Furthermore I've changed the busy loop into a ringbuffer wait. Busy-loops that don't check whether the chip died are simply evil. And performance should actually improve, because there's usually a decent amount of rendering queued on the gpu, hopefully rendering that MI_WAIT into a noop by the time it's executed. The current code holds dev->struct_mutex while executing this loop, hence stalling all other gem activity anyway. Signed-off-by: Daniel Vetter Cc: stable@kernel.org Reviewed-by: Jesse Barnes [anholt: resolved against conflict] Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce7a46b6909b..22966bd9aa96 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5098,14 +5098,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->pending_flip_obj = obj; if (intel_crtc->plane) - flip_mask = I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT; + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; else - flip_mask = I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT; + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - /* Wait for any previous flip to finish */ - if (IS_GEN3(dev)) - while (I915_READ(ISR) & flip_mask) - ; + if (IS_GEN3(dev) || IS_GEN2(dev)) { + BEGIN_LP_RING(2); + OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); + OUT_RING(0); + ADVANCE_LP_RING(); + } /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = obj_priv->gtt_offset; -- cgit v1.2.3-59-g8ed1b From 87f8ebf309b2df69b57be96bf36d2d61009fd296 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 12:24:42 +0100 Subject: drm/i915: Disable the cursor for DPMS_OFF The comments have long desired that we should switch off the cursor along with the display plane, make it so. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 22966bd9aa96..24fbd0f24507 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2470,9 +2470,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) /** * Sets the power management mode of the pipe and plane. - * - * This code should probably grow support for turning the cursor off and back - * on appropriately at the same time as we're turning the pipe off/on. */ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) { @@ -2487,6 +2484,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc->dpms_mode = mode; + intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON; + intel_crtc_update_cursor(crtc); + if (!dev->primary->master) return; @@ -4242,7 +4242,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) pos = 0; - if (crtc->fb) { + if (intel_crtc->cursor_on && crtc->fb) { base = intel_crtc->cursor_addr; if (x > (int) crtc->fb->width) base = 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1075d4386b87..a44b8cb4d2cc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -154,7 +154,7 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; - bool cursor_visble; + bool cursor_visble, cursor_on; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) -- cgit v1.2.3-59-g8ed1b From ae7d49d879fd196bded306e9465e0aa5a203e971 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 12:37:41 +0100 Subject: drm/i915: Emit a backtrace if we attempt to rebind a pinned buffer This debugging trace was useful for finding the fbcon regression on i965, and it may prove useful again in future. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 24ee4622484f..b0fb394b9ff4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4198,6 +4198,10 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (alignment == 0) alignment = i915_gem_get_gtt_alignment(obj); if (obj_priv->gtt_offset & (alignment - 1)) { + WARN(obj_priv->pin_count, + "bo is already pinned with incorrect alignment:" + " offset=%x, req.alignment=%x\n", + obj_priv->gtt_offset, alignment); ret = i915_gem_object_unbind(obj); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 1741dd4aa7552055659bf74ab829a21579407f10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:12 +0100 Subject: drm/i915: Unroll wrapping of the ringbuffer. The tail is quadword aligned, so we can add two MI_NOOP as a time. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 26362f8495a8..df8302a11eb5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -682,9 +682,11 @@ int intel_wrap_ring_buffer(struct drm_device *dev, } virt = (unsigned int *)(ring->virtual_start + ring->tail); - rem /= 4; - while (rem--) + rem /= 8; + while (rem--) { *virt++ = MI_NOOP; + *virt++ = MI_NOOP; + } ring->tail = 0; ring->space = ring->head - 8; -- cgit v1.2.3-59-g8ed1b From d97ed3396399126cfca1e12e2b2e2d8bbc4924e5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:13 +0100 Subject: drm/i915: Move ringbuffer accounting to begin/advance. As we check that the ringbuffer will not wrap upon emission, we do not need to check that incrementing the tail wrapped every time. However, we do upon advancing just in case the tail is now pointing at the very end of the ring. Likewise we can account for the space used during emission in begin() and avoid decrementing it for every emit. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_ringbuffer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index df8302a11eb5..7ab72af045ec 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -731,6 +731,8 @@ void intel_ring_begin(struct drm_device *dev, intel_wrap_ring_buffer(dev, ring); if (unlikely(ring->space < n)) intel_wait_ring_buffer(dev, ring, n); + + ring->space -= n; } void intel_ring_emit(struct drm_device *dev, @@ -739,13 +741,12 @@ void intel_ring_emit(struct drm_device *dev, unsigned int *virt = ring->virtual_start + ring->tail; *virt = data; ring->tail += 4; - ring->tail &= ring->size - 1; - ring->space -= 4; } void intel_ring_advance(struct drm_device *dev, struct intel_ring_buffer *ring) { + ring->tail &= ring->size - 1; ring->advance_ring(dev, ring); } -- cgit v1.2.3-59-g8ed1b From e898cd221db65273bfc102fa20e4e228e0b8c7e1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:14 +0100 Subject: drm/i915: Inline ringbuffer_emit() As the function has been reduced to a store plus increment, the body is now smaller than the call so inline it. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 -------- drivers/gpu/drm/i915/intel_ringbuffer.h | 12 ++++++++++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7ab72af045ec..a5d664e0b176 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -735,14 +735,6 @@ void intel_ring_begin(struct drm_device *dev, ring->space -= n; } -void intel_ring_emit(struct drm_device *dev, - struct intel_ring_buffer *ring, unsigned int data) -{ - unsigned int *virt = ring->virtual_start + ring->tail; - *virt = data; - ring->tail += 4; -} - void intel_ring_advance(struct drm_device *dev, struct intel_ring_buffer *ring) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d5568d3766de..9b67eead187e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -106,8 +106,16 @@ int intel_wrap_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring); void intel_ring_begin(struct drm_device *dev, struct intel_ring_buffer *ring, int n); -void intel_ring_emit(struct drm_device *dev, - struct intel_ring_buffer *ring, u32 data); + +static inline void intel_ring_emit(struct drm_device *dev, + struct intel_ring_buffer *ring, + unsigned int data) +{ + unsigned int *virt = ring->virtual_start + ring->tail; + *virt = data; + ring->tail += 4; +} + void intel_fill_struct(struct drm_device *dev, struct intel_ring_buffer *ring, void *data, -- cgit v1.2.3-59-g8ed1b From dbd7ac9661ba321fe9c1f1b7cb5f4471a6e59570 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 15:18:15 +0100 Subject: drm/i915: Use an uncommon name for the local dev_priv in macros Using dev_priv__ avoids sparse complaining about shadowed variables in the *LP_RING() macros. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e7fb37995652..5cd593f826ef 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1095,26 +1095,26 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define I915_VERBOSE 0 #define BEGIN_LP_RING(n) do { \ - drm_i915_private_t *dev_priv = dev->dev_private; \ + drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \ - intel_ring_begin(dev, &dev_priv->render_ring, (n)); \ + intel_ring_begin(dev, &dev_priv__->render_ring, (n)); \ } while (0) #define OUT_RING(x) do { \ - drm_i915_private_t *dev_priv = dev->dev_private; \ + drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \ - intel_ring_emit(dev, &dev_priv->render_ring, x); \ + intel_ring_emit(dev, &dev_priv__->render_ring, x); \ } while (0) #define ADVANCE_LP_RING() do { \ - drm_i915_private_t *dev_priv = dev->dev_private; \ + drm_i915_private_t *dev_priv__ = dev->dev_private; \ if (I915_VERBOSE) \ DRM_DEBUG("ADVANCE_LP_RING %x\n", \ - dev_priv->render_ring.tail); \ - intel_ring_advance(dev, &dev_priv->render_ring); \ + dev_priv__->render_ring.tail); \ + intel_ring_advance(dev, &dev_priv__->render_ring); \ } while(0) /** -- cgit v1.2.3-59-g8ed1b From 6ef3d4278034982c13df87c4a51e0445f762d316 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 4 Aug 2010 20:26:07 +0100 Subject: drm/i915: Capture the overlay status upon a GPU hang. v2: Add the interrupt status and address. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_debugfs.c | 3 ++ drivers/gpu/drm/i915/i915_drv.h | 10 +++- drivers/gpu/drm/i915/i915_irq.c | 3 ++ drivers/gpu/drm/i915/intel_overlay.c | 96 ++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9214119c0154..92d5605a34d1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -467,6 +467,9 @@ static int i915_error_state(struct seq_file *m, void *unused) } } + if (error->overlay) + intel_overlay_print_error_state(m, error->overlay); + out: spin_unlock_irqrestore(&dev_priv->error_lock, flags); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5cd593f826ef..151056501a5f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -113,6 +113,9 @@ struct intel_opregion { int enabled; }; +struct intel_overlay; +struct intel_overlay_error_state; + struct drm_i915_master_private { drm_local_map_t *sarea; struct _drm_i915_sarea *sarea_priv; @@ -166,6 +169,7 @@ struct drm_i915_error_state { u32 purgeable:1; } *active_bo; u32 active_bo_count; + struct intel_overlay_error_state *overlay; }; struct drm_i915_display_funcs { @@ -186,8 +190,6 @@ struct drm_i915_display_funcs { /* clock gating init */ }; -struct intel_overlay; - struct intel_device_info { u8 is_mobile : 1; u8 is_i8xx : 1; @@ -1069,6 +1071,10 @@ extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); +/* overlay */ +extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); +extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error); + /** * Lock test for when it's just for synchronization of ring access. * diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 85785a8844ed..854ab1e92fd9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -489,6 +489,7 @@ i915_error_state_free(struct drm_device *dev, i915_error_object_free(error->batchbuffer[1]); i915_error_object_free(error->ringbuffer); kfree(error->active_bo); + kfree(error->overlay); kfree(error); } @@ -667,6 +668,8 @@ static void i915_capture_error_state(struct drm_device *dev) do_gettimeofday(&error->time); + error->overlay = intel_overlay_capture_error_state(dev); + spin_lock_irqsave(&dev_priv->error_lock, flags); if (dev_priv->first_error == NULL) { dev_priv->first_error = error; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index d39aea24eabe..9ae61aa05a1f 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1416,3 +1416,99 @@ void intel_cleanup_overlay(struct drm_device *dev) kfree(dev_priv->overlay); } } + +struct intel_overlay_error_state { + struct overlay_registers regs; + unsigned long base; + u32 dovsta; + u32 isr; +}; + +struct intel_overlay_error_state * +intel_overlay_capture_error_state(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_overlay *overlay = dev_priv->overlay; + struct intel_overlay_error_state *error; + struct overlay_registers __iomem *regs; + + if (!overlay || !overlay->active) + return NULL; + + error = kmalloc(sizeof(*error), GFP_ATOMIC); + if (error == NULL) + return NULL; + + error->dovsta = I915_READ(DOVSTA); + error->isr = I915_READ(ISR); + if (OVERLAY_NONPHYSICAL(overlay->dev)) + error->base = (long) overlay->reg_bo->gtt_offset; + else + error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr; + + regs = intel_overlay_map_regs_atomic(overlay); + if (!regs) + goto err; + + memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers)); + intel_overlay_unmap_regs_atomic(overlay); + + return error; + +err: + kfree(error); + return NULL; +} + +void +intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error) +{ + seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n", + error->dovsta, error->isr); + seq_printf(m, " Register file at 0x%08lx:\n", + error->base); + +#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x) + P(OBUF_0Y); + P(OBUF_1Y); + P(OBUF_0U); + P(OBUF_0V); + P(OBUF_1U); + P(OBUF_1V); + P(OSTRIDE); + P(YRGB_VPH); + P(UV_VPH); + P(HORZ_PH); + P(INIT_PHS); + P(DWINPOS); + P(DWINSZ); + P(SWIDTH); + P(SWIDTHSW); + P(SHEIGHT); + P(YRGBSCALE); + P(UVSCALE); + P(OCLRC0); + P(OCLRC1); + P(DCLRKV); + P(DCLRKM); + P(SCLRKVH); + P(SCLRKVL); + P(SCLRKEN); + P(OCONFIG); + P(OCMD); + P(OSTART_0Y); + P(OSTART_1Y); + P(OSTART_0U); + P(OSTART_0V); + P(OSTART_1U); + P(OSTART_1V); + P(OTILEOFF_0Y); + P(OTILEOFF_1Y); + P(OTILEOFF_0U); + P(OTILEOFF_0V); + P(OTILEOFF_1U); + P(OTILEOFF_1V); + P(FASTHSCALE); + P(UVSCALEV); +#undef P +} -- cgit v1.2.3-59-g8ed1b From bf1a10923920f56da23a118de2511a72af341d61 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:20 +0100 Subject: drm/i915: Append the object onto the inactive list on binding. In order to properly track bound objects, they need to exist on one of the inactive/active lists or be pinned. As this is a requirement, do the work inside i915_gem_bind_to_gtt() rather than dotted around the callsites. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b0fb394b9ff4..75e7b899e033 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1137,7 +1137,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_gem_object *obj = vma->vm_private_data; struct drm_device *dev = obj->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); pgoff_t page_offset; unsigned long pfn; @@ -1155,8 +1154,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (ret) goto unlock; - list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); - ret = i915_gem_object_set_to_gtt_domain(obj, write); if (ret) goto unlock; @@ -1363,7 +1360,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_gem_mmap_gtt *args = data; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; int ret; @@ -1409,7 +1405,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, mutex_unlock(&dev->struct_mutex); return ret; } - list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); } drm_gem_object_unreference(obj); @@ -2723,6 +2718,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) atomic_inc(&dev->gtt_count); atomic_add(obj->size, &dev->gtt_memory); + /* keep track of bounds object by adding it to the inactive list */ + list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + /* Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in * a GPU cache @@ -4223,8 +4221,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) atomic_inc(&dev->pin_count); atomic_add(obj->size, &dev->pin_memory); if (!obj_priv->active && - (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 && - !list_empty(&obj_priv->list)) + (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) list_del_init(&obj_priv->list); } i915_verify_inactive(dev, __FILE__, __LINE__); -- cgit v1.2.3-59-g8ed1b From 0108a3edd5c2e3b150a550d565b6aa1a67c0edbe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 7 Aug 2010 11:01:21 +0100 Subject: drm/i915: prepare for fair lru eviction This does two little changes: - Add an alignment parameter for evict_something. It's not really great to whack a carefully sized hole into the gtt with the wrong alignment. Especially since the fallback path is a full evict. - With the inactive scan stuff we need to evict more that one object, so move the unbind call into the helper function that scans for the object to be evicted, too. And adjust its name. No functional changes in this patch, just preparation. Signed-Off-by: Daniel Vetter Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 67 +++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 75e7b899e033..f150bfd2c851 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,6 +35,7 @@ #include #include +static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj); static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); @@ -48,7 +49,8 @@ static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); -static int i915_gem_evict_something(struct drm_device *dev, int min_size); +static int i915_gem_evict_something(struct drm_device *dev, int min_size, + unsigned alignment); static int i915_gem_evict_from_inactive_list(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -313,7 +315,8 @@ i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) if (ret == -ENOMEM) { struct drm_device *dev = obj->dev; - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, + i915_gem_get_gtt_alignment(obj)); if (ret) return ret; @@ -2005,10 +2008,12 @@ i915_gem_object_unbind(struct drm_gem_object *obj) return ret; } -static struct drm_gem_object * -i915_gem_find_inactive_object(struct drm_device *dev, int min_size) +static int +i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, + unsigned alignment, int *found) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; struct drm_gem_object *best = NULL; struct drm_gem_object *first = NULL; @@ -2022,14 +2027,31 @@ i915_gem_find_inactive_object(struct drm_device *dev, int min_size) (!best || obj->size < best->size)) { best = obj; if (best->size == min_size) - return best; + break; } if (!first) first = obj; } } - return best ? best : first; + obj = best ? best : first; + + if (!obj) { + *found = 0; + return 0; + } + + *found = 1; + +#if WATCH_LRU + DRM_INFO("%s: evicting %p\n", __func__, obj); +#endif + obj_priv = to_intel_bo(obj); + BUG_ON(obj_priv->pin_count != 0); + BUG_ON(obj_priv->active); + + /* Wait on the rendering and unbind the buffer. */ + return i915_gem_object_unbind(obj); } static int @@ -2115,11 +2137,11 @@ i915_gem_evict_everything(struct drm_device *dev) } static int -i915_gem_evict_something(struct drm_device *dev, int min_size) +i915_gem_evict_something(struct drm_device *dev, + int min_size, unsigned alignment) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - int ret; + int ret, found; struct intel_ring_buffer *render_ring = &dev_priv->render_ring; struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; @@ -2129,20 +2151,11 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) /* If there's an inactive buffer available now, grab it * and be done. */ - obj = i915_gem_find_inactive_object(dev, min_size); - if (obj) { - struct drm_i915_gem_object *obj_priv; - -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, obj); -#endif - obj_priv = to_intel_bo(obj); - BUG_ON(obj_priv->pin_count != 0); - BUG_ON(obj_priv->active); - - /* Wait on the rendering and unbind the buffer. */ - return i915_gem_object_unbind(obj); - } + ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, + alignment, + &found); + if (found) + return ret; /* If we didn't get anything, but the ring is still processing * things, wait for the next to finish and hopefully leave us @@ -2184,6 +2197,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) * will get moved to inactive. */ if (!list_empty(&dev_priv->mm.flushing_list)) { + struct drm_gem_object *obj = NULL; struct drm_i915_gem_object *obj_priv; /* Find an object that we can immediately reuse */ @@ -2661,7 +2675,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) #if WATCH_LRU DRM_INFO("%s: GTT full, evicting something\n", __func__); #endif - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, alignment); if (ret) return ret; @@ -2679,7 +2693,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) if (ret == -ENOMEM) { /* first try to clear up some space from the GTT */ - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, + alignment); if (ret) { /* now try to shrink everyone else */ if (gfpmask) { @@ -2709,7 +2724,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) drm_mm_put_block(obj_priv->gtt_space); obj_priv->gtt_space = NULL; - ret = i915_gem_evict_something(dev, obj->size); + ret = i915_gem_evict_something(dev, obj->size, alignment); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 6f392d548658a17600da7faaf8a5df25ee5f01f6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:22 +0100 Subject: drm/i915: Use a common seqno for all rings. This will be used by the eviction logic to maintain fairness between the rings. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 3 +-- drivers/gpu/drm/i915/i915_gem.c | 2 ++ drivers/gpu/drm/i915/intel_ringbuffer.c | 46 +++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 151056501a5f..def6ee0a3524 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -244,6 +244,7 @@ typedef struct drm_i915_private { struct pci_dev *bridge_dev; struct intel_ring_buffer render_ring; struct intel_ring_buffer bsd_ring; + uint32_t next_seqno; drm_dma_handle_t *status_page_dmah; void *seqno_page; @@ -573,8 +574,6 @@ typedef struct drm_i915_private { */ struct delayed_work retire_work; - uint32_t next_gem_seqno; - /** * Waiting sequence number, if any */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f150bfd2c851..45b998218d0c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4714,6 +4714,8 @@ i915_gem_init_ringbuffer(struct drm_device *dev) goto cleanup_render_ring; } + dev_priv->next_seqno = 1; + return 0; cleanup_render_ring: diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a5d664e0b176..3a0242557220 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -33,18 +33,35 @@ #include "i915_drm.h" #include "i915_trace.h" +static u32 i915_gem_get_seqno(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 seqno; + + seqno = dev_priv->next_seqno; + + /* reserve 0 for non-seqno */ + if (++dev_priv->next_seqno == 0) + dev_priv->next_seqno = 1; + + return seqno; +} + static void render_ring_flush(struct drm_device *dev, struct intel_ring_buffer *ring, u32 invalidate_domains, u32 flush_domains) { + drm_i915_private_t *dev_priv = dev->dev_private; + u32 cmd; + #if WATCH_EXEC DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, invalidate_domains, flush_domains); #endif - u32 cmd; - trace_i915_gem_request_flush(dev, ring->next_seqno, + + trace_i915_gem_request_flush(dev, dev_priv->next_seqno, invalidate_domains, flush_domains); if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { @@ -233,9 +250,10 @@ render_ring_add_request(struct drm_device *dev, struct drm_file *file_priv, u32 flush_domains) { - u32 seqno; drm_i915_private_t *dev_priv = dev->dev_private; - seqno = intel_ring_get_seqno(dev, ring); + u32 seqno; + + seqno = i915_gem_get_seqno(dev); if (IS_GEN6(dev)) { BEGIN_LP_RING(6); @@ -405,7 +423,9 @@ bsd_ring_add_request(struct drm_device *dev, u32 flush_domains) { u32 seqno; - seqno = intel_ring_get_seqno(dev, ring); + + seqno = i915_gem_get_seqno(dev); + intel_ring_begin(dev, ring, 4); intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX); intel_ring_emit(dev, ring, @@ -479,7 +499,7 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; - trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1); + trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1); count = nbox ? nbox : 1; @@ -757,18 +777,6 @@ void intel_fill_struct(struct drm_device *dev, intel_ring_advance(dev, ring); } -u32 intel_ring_get_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) -{ - u32 seqno; - seqno = ring->next_seqno; - - /* reserve 0 for non-seqno */ - if (++ring->next_seqno == 0) - ring->next_seqno = 1; - return seqno; -} - struct intel_ring_buffer render_ring = { .name = "render ring", .regs = { @@ -786,7 +794,6 @@ struct intel_ring_buffer render_ring = { .head = 0, .tail = 0, .space = 0, - .next_seqno = 1, .user_irq_refcount = 0, .irq_gem_seqno = 0, .waiting_gem_seqno = 0, @@ -825,7 +832,6 @@ struct intel_ring_buffer bsd_ring = { .head = 0, .tail = 0, .space = 0, - .next_seqno = 1, .user_irq_refcount = 0, .irq_gem_seqno = 0, .waiting_gem_seqno = 0, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 9b67eead187e..525e7d3edda8 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -26,7 +26,6 @@ struct intel_ring_buffer { unsigned int head; unsigned int tail; unsigned int space; - u32 next_seqno; struct intel_hw_status_page status_page; u32 irq_gem_seqno; /* last seq seem at irq time */ -- cgit v1.2.3-59-g8ed1b From b47eb4a2b302f33adaed2a27d2b3bfc74fe35ac5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:23 +0100 Subject: drm/i915: Move the eviction logic to its own file. The eviction code is the gnarly underbelly of memory management, and is clearer if kept separated from the normal domain management in GEM. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 6 + drivers/gpu/drm/i915/i915_gem.c | 231 +----------------------------- drivers/gpu/drm/i915/i915_gem_evict.c | 260 ++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+), 229 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gem_evict.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index da78f2c0d909..384fd4535796 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -8,6 +8,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ i915_suspend.o \ i915_gem.o \ i915_gem_debug.o \ + i915_gem_evict.o \ i915_gem_tiling.o \ i915_trace_points.o \ intel_display.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index def6ee0a3524..12c8f47f984b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -982,6 +982,7 @@ int i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end); +int i915_gpu_idle(struct drm_device *dev); int i915_gem_idle(struct drm_device *dev); uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv, @@ -1007,6 +1008,11 @@ int i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); +/* i915_gem_evict.c */ +int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment); +int i915_gem_evict_everything(struct drm_device *dev); +int i915_gem_evict_inactive(struct drm_device *dev); + /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 45b998218d0c..b5a7b00264a6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -49,9 +49,6 @@ static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); -static int i915_gem_evict_something(struct drm_device *dev, int min_size, - unsigned alignment); -static int i915_gem_evict_from_inactive_list(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file_priv); @@ -1885,19 +1882,6 @@ i915_gem_flush(struct drm_device *dev, flush_domains); } -static void -i915_gem_flush_ring(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains, - struct intel_ring_buffer *ring) -{ - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - ring->flush(dev, ring, - invalidate_domains, - flush_domains); -} - /** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. @@ -2008,53 +1992,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) return ret; } -static int -i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, - unsigned alignment, int *found) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *best = NULL; - struct drm_gem_object *first = NULL; - - /* Try to find the smallest clean object */ - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { - struct drm_gem_object *obj = &obj_priv->base; - if (obj->size >= min_size) { - if ((!obj_priv->dirty || - i915_gem_object_is_purgeable(obj_priv)) && - (!best || obj->size < best->size)) { - best = obj; - if (best->size == min_size) - break; - } - if (!first) - first = obj; - } - } - - obj = best ? best : first; - - if (!obj) { - *found = 0; - return 0; - } - - *found = 1; - -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, obj); -#endif - obj_priv = to_intel_bo(obj); - BUG_ON(obj_priv->pin_count != 0); - BUG_ON(obj_priv->active); - - /* Wait on the rendering and unbind the buffer. */ - return i915_gem_object_unbind(obj); -} - -static int +int i915_gpu_idle(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -2095,147 +2033,6 @@ i915_gpu_idle(struct drm_device *dev) return ret; } -static int -i915_gem_evict_everything(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret; - bool lists_empty; - - spin_lock(&dev_priv->mm.active_list_lock); - lists_empty = (list_empty(&dev_priv->mm.inactive_list) && - list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list) && - (!HAS_BSD(dev) - || list_empty(&dev_priv->bsd_ring.active_list))); - spin_unlock(&dev_priv->mm.active_list_lock); - - if (lists_empty) - return -ENOSPC; - - /* Flush everything (on to the inactive lists) and evict */ - ret = i915_gpu_idle(dev); - if (ret) - return ret; - - BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); - - ret = i915_gem_evict_from_inactive_list(dev); - if (ret) - return ret; - - spin_lock(&dev_priv->mm.active_list_lock); - lists_empty = (list_empty(&dev_priv->mm.inactive_list) && - list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->render_ring.active_list) && - (!HAS_BSD(dev) - || list_empty(&dev_priv->bsd_ring.active_list))); - spin_unlock(&dev_priv->mm.active_list_lock); - BUG_ON(!lists_empty); - - return 0; -} - -static int -i915_gem_evict_something(struct drm_device *dev, - int min_size, unsigned alignment) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret, found; - - struct intel_ring_buffer *render_ring = &dev_priv->render_ring; - struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; - for (;;) { - i915_gem_retire_requests(dev); - - /* If there's an inactive buffer available now, grab it - * and be done. - */ - ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, - alignment, - &found); - if (found) - return ret; - - /* If we didn't get anything, but the ring is still processing - * things, wait for the next to finish and hopefully leave us - * a buffer to evict. - */ - if (!list_empty(&render_ring->request_list)) { - struct drm_i915_gem_request *request; - - request = list_first_entry(&render_ring->request_list, - struct drm_i915_gem_request, - list); - - ret = i915_wait_request(dev, - request->seqno, request->ring); - if (ret) - return ret; - - continue; - } - - if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { - struct drm_i915_gem_request *request; - - request = list_first_entry(&bsd_ring->request_list, - struct drm_i915_gem_request, - list); - - ret = i915_wait_request(dev, - request->seqno, request->ring); - if (ret) - return ret; - - continue; - } - - /* If we didn't have anything on the request list but there - * are buffers awaiting a flush, emit one and try again. - * When we wait on it, those buffers waiting for that flush - * will get moved to inactive. - */ - if (!list_empty(&dev_priv->mm.flushing_list)) { - struct drm_gem_object *obj = NULL; - struct drm_i915_gem_object *obj_priv; - - /* Find an object that we can immediately reuse */ - list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { - obj = &obj_priv->base; - if (obj->size >= min_size) - break; - - obj = NULL; - } - - if (obj != NULL) { - uint32_t seqno; - - i915_gem_flush_ring(dev, - obj->write_domain, - obj->write_domain, - obj_priv->ring); - seqno = i915_add_request(dev, NULL, - obj->write_domain, - obj_priv->ring); - if (seqno == 0) - return -ENOMEM; - continue; - } - } - - /* If we didn't do any of the above, there's no single buffer - * large enough to swap out for the new one, so just evict - * everything and start again. (This should be rare.) - */ - if (!list_empty (&dev_priv->mm.inactive_list)) - return i915_gem_evict_from_inactive_list(dev); - else - return i915_gem_evict_everything(dev); - } -} - int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask) @@ -4548,30 +4345,6 @@ void i915_gem_free_object(struct drm_gem_object *obj) i915_gem_free_object_tail(obj); } -/** Unbinds all inactive objects. */ -static int -i915_gem_evict_from_inactive_list(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - while (!list_empty(&dev_priv->mm.inactive_list)) { - struct drm_gem_object *obj; - int ret; - - obj = &list_first_entry(&dev_priv->mm.inactive_list, - struct drm_i915_gem_object, - list)->base; - - ret = i915_gem_object_unbind(obj); - if (ret != 0) { - DRM_ERROR("Error unbinding object: %d\n", ret); - return ret; - } - } - - return 0; -} - int i915_gem_idle(struct drm_device *dev) { @@ -4596,7 +4369,7 @@ i915_gem_idle(struct drm_device *dev) /* Under UMS, be paranoid and evict. */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = i915_gem_evict_from_inactive_list(dev); + ret = i915_gem_evict_inactive(dev); if (ret) { mutex_unlock(&dev->struct_mutex); return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c new file mode 100644 index 000000000000..479e450f931b --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -0,0 +1,260 @@ +/* + * Copyright © 2008-2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Chris Wilson + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drv.h" +#include "i915_drm.h" + +static inline int +i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv) +{ + return obj_priv->madv == I915_MADV_DONTNEED; +} + +static int +i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, + unsigned alignment, int *found) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *best = NULL; + struct drm_gem_object *first = NULL; + + /* Try to find the smallest clean object */ + list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { + struct drm_gem_object *obj = &obj_priv->base; + if (obj->size >= min_size) { + if ((!obj_priv->dirty || + i915_gem_object_is_purgeable(obj_priv)) && + (!best || obj->size < best->size)) { + best = obj; + if (best->size == min_size) + break; + } + if (!first) + first = obj; + } + } + + obj = best ? best : first; + + if (!obj) { + *found = 0; + return 0; + } + + *found = 1; + +#if WATCH_LRU + DRM_INFO("%s: evicting %p\n", __func__, obj); +#endif + obj_priv = to_intel_bo(obj); + BUG_ON(obj_priv->pin_count != 0); + BUG_ON(obj_priv->active); + + /* Wait on the rendering and unbind the buffer. */ + return i915_gem_object_unbind(obj); +} + +static void +i915_gem_flush_ring(struct drm_device *dev, + uint32_t invalidate_domains, + uint32_t flush_domains, + struct intel_ring_buffer *ring) +{ + if (flush_domains & I915_GEM_DOMAIN_CPU) + drm_agp_chipset_flush(dev); + ring->flush(dev, ring, + invalidate_domains, + flush_domains); +} + +int +i915_gem_evict_something(struct drm_device *dev, + int min_size, unsigned alignment) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret, found; + + struct intel_ring_buffer *render_ring = &dev_priv->render_ring; + struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; + for (;;) { + i915_gem_retire_requests(dev); + + /* If there's an inactive buffer available now, grab it + * and be done. + */ + ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, + alignment, + &found); + if (found) + return ret; + + /* If we didn't get anything, but the ring is still processing + * things, wait for the next to finish and hopefully leave us + * a buffer to evict. + */ + if (!list_empty(&render_ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&render_ring->request_list, + struct drm_i915_gem_request, + list); + + ret = i915_do_wait_request(dev, request->seqno, true, request->ring); + if (ret) + return ret; + + continue; + } + + if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&bsd_ring->request_list, + struct drm_i915_gem_request, + list); + + ret = i915_do_wait_request(dev, request->seqno, true, request->ring); + if (ret) + return ret; + + continue; + } + + /* If we didn't have anything on the request list but there + * are buffers awaiting a flush, emit one and try again. + * When we wait on it, those buffers waiting for that flush + * will get moved to inactive. + */ + if (!list_empty(&dev_priv->mm.flushing_list)) { + struct drm_gem_object *obj = NULL; + struct drm_i915_gem_object *obj_priv; + + /* Find an object that we can immediately reuse */ + list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { + obj = &obj_priv->base; + if (obj->size >= min_size) + break; + + obj = NULL; + } + + if (obj != NULL) { + uint32_t seqno; + + i915_gem_flush_ring(dev, + obj->write_domain, + obj->write_domain, + obj_priv->ring); + seqno = i915_add_request(dev, NULL, + obj->write_domain, + obj_priv->ring); + if (seqno == 0) + return -ENOMEM; + continue; + } + } + + /* If we didn't do any of the above, there's no single buffer + * large enough to swap out for the new one, so just evict + * everything and start again. (This should be rare.) + */ + if (!list_empty(&dev_priv->mm.inactive_list)) + return i915_gem_evict_inactive(dev); + else + return i915_gem_evict_everything(dev); + } +} + +int +i915_gem_evict_everything(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + bool lists_empty; + + spin_lock(&dev_priv->mm.active_list_lock); + lists_empty = (list_empty(&dev_priv->mm.inactive_list) && + list_empty(&dev_priv->mm.flushing_list) && + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); + spin_unlock(&dev_priv->mm.active_list_lock); + + if (lists_empty) + return -ENOSPC; + + /* Flush everything (on to the inactive lists) and evict */ + ret = i915_gpu_idle(dev); + if (ret) + return ret; + + BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); + + ret = i915_gem_evict_inactive(dev); + if (ret) + return ret; + + spin_lock(&dev_priv->mm.active_list_lock); + lists_empty = (list_empty(&dev_priv->mm.inactive_list) && + list_empty(&dev_priv->mm.flushing_list) && + list_empty(&dev_priv->render_ring.active_list) && + (!HAS_BSD(dev) + || list_empty(&dev_priv->bsd_ring.active_list))); + spin_unlock(&dev_priv->mm.active_list_lock); + BUG_ON(!lists_empty); + + return 0; +} + +/** Unbinds all inactive objects. */ +int +i915_gem_evict_inactive(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + while (!list_empty(&dev_priv->mm.inactive_list)) { + struct drm_gem_object *obj; + int ret; + + obj = &list_first_entry(&dev_priv->mm.inactive_list, + struct drm_i915_gem_object, + list)->base; + + ret = i915_gem_object_unbind(obj); + if (ret != 0) { + DRM_ERROR("Error unbinding object: %d\n", ret); + return ret; + } + } + + return 0; +} -- cgit v1.2.3-59-g8ed1b From cd377ea93f34cbd6ec49c868b66a5a7ab184775c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:24 +0100 Subject: drm/i915: Implement fair lru eviction across both rings. (v2) Based in a large part upon Daniel Vetter's implementation and adapted for handling multiple rings in a single pass. This should lead to better gtt usage and fixes the page-fault-of-doom triggered. The fairness is provided by scanning through the GTT space amalgamating space in rendering order. As soon as we have a contiguous space in the GTT large enough for the new object (and its alignment), evict any object which lies within that space. This should keep more objects resident in the GTT. Doing throughput testing on a PineView machine with cairo-perf-trace indicates that there is very little difference with the new LRU scan, perhaps a small improvement... Except oddly for the poppler trace. Reference: Bug 15911 - Intermittent X crash (freeze) https://bugzilla.kernel.org/show_bug.cgi?id=15911 Bug 20152 - cannot view JPG in firefox when running UXA https://bugs.freedesktop.org/show_bug.cgi?id=20152 Bug 24369 - Hang when scrolling firefox page with window in front https://bugs.freedesktop.org/show_bug.cgi?id=24369 Bug 28478 - Intermittent graphics lockups due to overflow/loop https://bugs.freedesktop.org/show_bug.cgi?id=28478 v2: Attempt to clarify the logic and order of eviction through the use of comments and macros. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/i915_gem_evict.c | 277 ++++++++++++++++++---------------- 2 files changed, 146 insertions(+), 133 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 12c8f47f984b..6221f239fa5e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -673,6 +673,8 @@ struct drm_i915_gem_object { struct list_head list; /** This object's place on GPU write list */ struct list_head gpu_write_list; + /** This object's place on eviction list */ + struct list_head evict_list; /** * This is set if the object is on the active or flushing lists diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 479e450f931b..72cae3cccad8 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -31,167 +31,178 @@ #include "i915_drv.h" #include "i915_drm.h" -static inline int -i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv) -{ - return obj_priv->madv == I915_MADV_DONTNEED; -} - -static int -i915_gem_scan_inactive_list_and_evict(struct drm_device *dev, int min_size, - unsigned alignment, int *found) +static struct drm_i915_gem_object * +i915_gem_next_active_object(struct drm_device *dev, + struct list_head **render_iter, + struct list_head **bsd_iter) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_i915_gem_object *obj_priv; - struct drm_gem_object *best = NULL; - struct drm_gem_object *first = NULL; - - /* Try to find the smallest clean object */ - list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { - struct drm_gem_object *obj = &obj_priv->base; - if (obj->size >= min_size) { - if ((!obj_priv->dirty || - i915_gem_object_is_purgeable(obj_priv)) && - (!best || obj->size < best->size)) { - best = obj; - if (best->size == min_size) - break; - } - if (!first) - first = obj; - } - } + struct drm_i915_gem_object *render_obj = NULL, *bsd_obj = NULL; - obj = best ? best : first; + if (*render_iter != &dev_priv->render_ring.active_list) + render_obj = list_entry(*render_iter, + struct drm_i915_gem_object, + list); - if (!obj) { - *found = 0; - return 0; - } + if (HAS_BSD(dev)) { + if (*bsd_iter != &dev_priv->bsd_ring.active_list) + bsd_obj = list_entry(*bsd_iter, + struct drm_i915_gem_object, + list); - *found = 1; + if (render_obj == NULL) { + *bsd_iter = (*bsd_iter)->next; + return bsd_obj; + } -#if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, obj); -#endif - obj_priv = to_intel_bo(obj); - BUG_ON(obj_priv->pin_count != 0); - BUG_ON(obj_priv->active); + if (bsd_obj == NULL) { + *render_iter = (*render_iter)->next; + return render_obj; + } - /* Wait on the rendering and unbind the buffer. */ - return i915_gem_object_unbind(obj); + /* XXX can we handle seqno wrapping? */ + if (render_obj->last_rendering_seqno < bsd_obj->last_rendering_seqno) { + *render_iter = (*render_iter)->next; + return render_obj; + } else { + *bsd_iter = (*bsd_iter)->next; + return bsd_obj; + } + } else { + *render_iter = (*render_iter)->next; + return render_obj; + } } -static void -i915_gem_flush_ring(struct drm_device *dev, - uint32_t invalidate_domains, - uint32_t flush_domains, - struct intel_ring_buffer *ring) +static bool +mark_free(struct drm_i915_gem_object *obj_priv, + struct list_head *unwind) { - if (flush_domains & I915_GEM_DOMAIN_CPU) - drm_agp_chipset_flush(dev); - ring->flush(dev, ring, - invalidate_domains, - flush_domains); + list_add(&obj_priv->evict_list, unwind); + return drm_mm_scan_add_block(obj_priv->gtt_space); } +#define i915_for_each_active_object(OBJ, R, B) \ + *(R) = dev_priv->render_ring.active_list.next; \ + *(B) = dev_priv->bsd_ring.active_list.next; \ + while (((OBJ) = i915_gem_next_active_object(dev, (R), (B))) != NULL) + int -i915_gem_evict_something(struct drm_device *dev, - int min_size, unsigned alignment) +i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment) { drm_i915_private_t *dev_priv = dev->dev_private; - int ret, found; - - struct intel_ring_buffer *render_ring = &dev_priv->render_ring; - struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; - for (;;) { - i915_gem_retire_requests(dev); - - /* If there's an inactive buffer available now, grab it - * and be done. - */ - ret = i915_gem_scan_inactive_list_and_evict(dev, min_size, - alignment, - &found); - if (found) - return ret; + struct list_head eviction_list, unwind_list; + struct drm_i915_gem_object *obj_priv, *tmp_obj_priv; + struct list_head *render_iter, *bsd_iter; + int ret = 0; - /* If we didn't get anything, but the ring is still processing - * things, wait for the next to finish and hopefully leave us - * a buffer to evict. - */ - if (!list_empty(&render_ring->request_list)) { - struct drm_i915_gem_request *request; + i915_gem_retire_requests(dev); - request = list_first_entry(&render_ring->request_list, - struct drm_i915_gem_request, - list); + /* Re-check for free space after retiring requests */ + if (drm_mm_search_free(&dev_priv->mm.gtt_space, + min_size, alignment, 0)) + return 0; - ret = i915_do_wait_request(dev, request->seqno, true, request->ring); - if (ret) - return ret; + /* + * The goal is to evict objects and amalgamate space in LRU order. + * The oldest idle objects reside on the inactive list, which is in + * retirement order. The next objects to retire are those on the (per + * ring) active list that do not have an outstanding flush. Once the + * hardware reports completion (the seqno is updated after the + * batchbuffer has been finished) the clean buffer objects would + * be retired to the inactive list. Any dirty objects would be added + * to the tail of the flushing list. So after processing the clean + * active objects we need to emit a MI_FLUSH to retire the flushing + * list, hence the retirement order of the flushing list is in + * advance of the dirty objects on the active lists. + * + * The retirement sequence is thus: + * 1. Inactive objects (already retired) + * 2. Clean active objects + * 3. Flushing list + * 4. Dirty active objects. + * + * On each list, the oldest objects lie at the HEAD with the freshest + * object on the TAIL. + */ + + INIT_LIST_HEAD(&unwind_list); + drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); + + /* First see if there is a large enough contiguous idle region... */ + list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { + if (mark_free(obj_priv, &unwind_list)) + goto found; + } + /* Now merge in the soon-to-be-expired objects... */ + i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) { + /* Does the object require an outstanding flush? */ + if (obj_priv->base.write_domain || obj_priv->pin_count) continue; - } - if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) { - struct drm_i915_gem_request *request; - - request = list_first_entry(&bsd_ring->request_list, - struct drm_i915_gem_request, - list); + if (mark_free(obj_priv, &unwind_list)) + goto found; + } - ret = i915_do_wait_request(dev, request->seqno, true, request->ring); - if (ret) - return ret; + /* Finally add anything with a pending flush (in order of retirement) */ + list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { + if (obj_priv->pin_count) + continue; + if (mark_free(obj_priv, &unwind_list)) + goto found; + } + i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) { + if (! obj_priv->base.write_domain || obj_priv->pin_count) continue; - } - /* If we didn't have anything on the request list but there - * are buffers awaiting a flush, emit one and try again. - * When we wait on it, those buffers waiting for that flush - * will get moved to inactive. - */ - if (!list_empty(&dev_priv->mm.flushing_list)) { - struct drm_gem_object *obj = NULL; - struct drm_i915_gem_object *obj_priv; - - /* Find an object that we can immediately reuse */ - list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { - obj = &obj_priv->base; - if (obj->size >= min_size) - break; - - obj = NULL; - } - - if (obj != NULL) { - uint32_t seqno; - - i915_gem_flush_ring(dev, - obj->write_domain, - obj->write_domain, - obj_priv->ring); - seqno = i915_add_request(dev, NULL, - obj->write_domain, - obj_priv->ring); - if (seqno == 0) - return -ENOMEM; - continue; - } + if (mark_free(obj_priv, &unwind_list)) + goto found; + } + + /* Nothing found, clean up and bail out! */ + list_for_each_entry(obj_priv, &unwind_list, evict_list) { + ret = drm_mm_scan_remove_block(obj_priv->gtt_space); + BUG_ON(ret); + } + + /* We expect the caller to unpin, evict all and try again, or give up. + * So calling i915_gem_evict_everything() is unnecessary. + */ + return -ENOSPC; + +found: + INIT_LIST_HEAD(&eviction_list); + list_for_each_entry_safe(obj_priv, tmp_obj_priv, + &unwind_list, evict_list) { + if (drm_mm_scan_remove_block(obj_priv->gtt_space)) { + /* drm_mm doesn't allow any other other operations while + * scanning, therefore store to be evicted objects on a + * temporary list. */ + list_move(&obj_priv->evict_list, &eviction_list); } + } - /* If we didn't do any of the above, there's no single buffer - * large enough to swap out for the new one, so just evict - * everything and start again. (This should be rare.) - */ - if (!list_empty(&dev_priv->mm.inactive_list)) - return i915_gem_evict_inactive(dev); - else - return i915_gem_evict_everything(dev); + /* Unbinding will emit any required flushes */ + list_for_each_entry_safe(obj_priv, tmp_obj_priv, + &eviction_list, evict_list) { +#if WATCH_LRU + DRM_INFO("%s: evicting %p\n", __func__, obj); +#endif + ret = i915_gem_object_unbind(&obj_priv->base); + if (ret) + return ret; } + + /* The just created free hole should be on the top of the free stack + * maintained by drm_mm, so this BUG_ON actually executes in O(1). + * Furthermore all accessed data has just recently been used, so it + * should be really fast, too. */ + BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size, + alignment, 0)); + + return 0; } int -- cgit v1.2.3-59-g8ed1b From 7d1c4804ae98cdee572d7d10d8a5deaa2e686285 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 21:45:03 +0100 Subject: drm/i915: Maintain LRU order of inactive objects upon access by CPU (v2) In order to reduce the penalty of fallbacks under memory pressure and to avoid a potential immediate ping-pong of evicting a mmaped buffer, we move the object to the tail of the inactive list when a page is freshly faulted or the object is moved into the CPU domain. We choose not to protect the CPU objects from casual eviction, preferring to keep the GPU active for as long as possible. v2: Daniel Vetter found a bug where I forgot that pinned objects are kept off the inactive list. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b5a7b00264a6..8f3e0c10c080 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -57,6 +57,14 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj); static LIST_HEAD(shrink_list); static DEFINE_SPINLOCK(shrink_list_lock); +static inline bool +i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) +{ + return obj_priv->gtt_space && + !obj_priv->active && + obj_priv->pin_count == 0; +} + int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end) { @@ -1036,6 +1044,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); } + + /* Maintain LRU order of "inactive" objects */ + if (ret == 0 && i915_gem_object_is_inactive(obj_priv)) + list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); return ret; @@ -1137,6 +1150,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_gem_object *obj = vma->vm_private_data; struct drm_device *dev = obj->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); pgoff_t page_offset; unsigned long pfn; @@ -1166,6 +1180,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) goto unlock; } + if (i915_gem_object_is_inactive(obj_priv)) + list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); + pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) + page_offset; -- cgit v1.2.3-59-g8ed1b From e56660ddfb48ccc6777f31cb235db218e0cf5b83 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:26 +0100 Subject: drm/i915: Record error batch buffers using iomem Directly read the GTT mapping for the contents of the batch buffers rather than relying on possibly stale CPU caches. Also for completeness scan the flushing/inactive lists for the current buffers - we are collecting error state after all. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 64 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 854ab1e92fd9..5161cea7a4ef 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -425,9 +425,11 @@ static struct drm_i915_error_object * i915_error_object_create(struct drm_device *dev, struct drm_gem_object *src) { + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_object *dst; struct drm_i915_gem_object *src_priv; int page, page_count; + u32 reloc_offset; if (src == NULL) return NULL; @@ -442,18 +444,27 @@ i915_error_object_create(struct drm_device *dev, if (dst == NULL) return NULL; + reloc_offset = src_priv->gtt_offset; for (page = 0; page < page_count; page++) { - void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC); unsigned long flags; + void __iomem *s; + void *d; + d = kmalloc(PAGE_SIZE, GFP_ATOMIC); if (d == NULL) goto unwind; + local_irq_save(flags); - s = kmap_atomic(src_priv->pages[page], KM_IRQ0); - memcpy(d, s, PAGE_SIZE); - kunmap_atomic(s, KM_IRQ0); + s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + reloc_offset, + KM_IRQ0); + memcpy_fromio(d, s, PAGE_SIZE); + io_mapping_unmap_atomic(s, KM_IRQ0); local_irq_restore(flags); + dst->pages[page] = d; + + reloc_offset += PAGE_SIZE; } dst->page_count = page_count; dst->gtt_offset = src_priv->gtt_offset; @@ -613,18 +624,57 @@ static void i915_capture_error_state(struct drm_device *dev) if (batchbuffer[1] == NULL && error->acthd >= obj_priv->gtt_offset && - error->acthd < obj_priv->gtt_offset + obj->size && - batchbuffer[0] != obj) + error->acthd < obj_priv->gtt_offset + obj->size) batchbuffer[1] = obj; count++; } + /* Scan the other lists for completeness for those bizarre errors. */ + if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { + list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) { + struct drm_gem_object *obj = &obj_priv->base; + + if (batchbuffer[0] == NULL && + bbaddr >= obj_priv->gtt_offset && + bbaddr < obj_priv->gtt_offset + obj->size) + batchbuffer[0] = obj; + + if (batchbuffer[1] == NULL && + error->acthd >= obj_priv->gtt_offset && + error->acthd < obj_priv->gtt_offset + obj->size) + batchbuffer[1] = obj; + + if (batchbuffer[0] && batchbuffer[1]) + break; + } + } + if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) { + list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) { + struct drm_gem_object *obj = &obj_priv->base; + + if (batchbuffer[0] == NULL && + bbaddr >= obj_priv->gtt_offset && + bbaddr < obj_priv->gtt_offset + obj->size) + batchbuffer[0] = obj; + + if (batchbuffer[1] == NULL && + error->acthd >= obj_priv->gtt_offset && + error->acthd < obj_priv->gtt_offset + obj->size) + batchbuffer[1] = obj; + + if (batchbuffer[0] && batchbuffer[1]) + break; + } + } /* We need to copy these to an anonymous buffer as the simplest * method to avoid being overwritten by userpace. */ error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]); - error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); + if (batchbuffer[1] != batchbuffer[0]) + error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); + else + error->batchbuffer[1] = NULL; /* Record the ringbuffer */ error->ringbuffer = i915_error_object_create(dev, -- cgit v1.2.3-59-g8ed1b From 2e88e40bed136a7b7cb1c77d8dc6bd181d0d2732 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:27 +0100 Subject: drm/i915/sdvo: Markup a few constant strings. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 1e31724d1616..69cf7241c3e0 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -50,7 +50,7 @@ #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) -static char *tv_format_names[] = { +static const char *tv_format_names[] = { "NTSC_M" , "NTSC_J" , "NTSC_443", "PAL_B" , "PAL_D" , "PAL_G" , "PAL_H" , "PAL_I" , "PAL_M" , @@ -292,7 +292,7 @@ static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch /** Mapping of command numbers to names, for debug output */ static const struct _sdvo_cmd_name { u8 cmd; - char *name; + const char *name; } sdvo_cmd_names[] = { SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), -- cgit v1.2.3-59-g8ed1b From 1d8e1c75ffa84400758aef9cc59298920b8801f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:28 +0100 Subject: drm/i915: Enable aspect/centering panel fitting for Ironlake. v2: Hook in DP paths to keep FULLSCREEN panel fitting on eDP. Signed-off-by: Chris Wilson Reviewed-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 16 +++-- drivers/gpu/drm/i915/intel_dp.c | 20 ++----- drivers/gpu/drm/i915/intel_drv.h | 7 +++ drivers/gpu/drm/i915/intel_lvds.c | 32 ++++------ drivers/gpu/drm/i915/intel_panel.c | 111 +++++++++++++++++++++++++++++++++++ 7 files changed, 143 insertions(+), 46 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_panel.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 384fd4535796..5c8e53458edb 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -19,6 +19,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ intel_hdmi.o \ intel_sdvo.o \ intel_modes.o \ + intel_panel.o \ intel_i2c.o \ intel_fb.o \ intel_tv.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6221f239fa5e..4b0ffb6c5561 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -614,6 +614,8 @@ typedef struct drm_i915_private { struct sdvo_device_mapping sdvo_mappings[2]; /* indicate whether the LVDS_BORDER should be enabled or not */ unsigned int lvds_border_bits; + /* Panel fitter placement and size for Ironlake+ */ + u32 pch_pf_pos, pch_pf_size; struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 24fbd0f24507..25e3866f9159 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2005,15 +2005,13 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) /* Enable panel fitting for LVDS */ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP || intel_pch_has_edp(crtc)) { - temp = I915_READ(pf_ctl_reg); - I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); - - /* currently full aspect */ - I915_WRITE(pf_win_pos, 0); - - I915_WRITE(pf_win_size, - (dev_priv->panel_fixed_mode->hdisplay << 16) | - (dev_priv->panel_fixed_mode->vdisplay)); + if (dev_priv->pch_pf_size) { + temp = I915_READ(pf_ctl_reg); + I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(pf_win_pos, dev_priv->pch_pf_pos); + I915_WRITE(pf_win_size, dev_priv->pch_pf_size); + } else + I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); } /* Enable CPU pipe */ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c4c5868a8aa0..cee5d9ceb3b8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -523,21 +523,9 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) && dev_priv->panel_fixed_mode) { - struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; - - adjusted_mode->hdisplay = fixed_mode->hdisplay; - adjusted_mode->hsync_start = fixed_mode->hsync_start; - adjusted_mode->hsync_end = fixed_mode->hsync_end; - adjusted_mode->htotal = fixed_mode->htotal; - - adjusted_mode->vdisplay = fixed_mode->vdisplay; - adjusted_mode->vsync_start = fixed_mode->vsync_start; - adjusted_mode->vsync_end = fixed_mode->vsync_end; - adjusted_mode->vtotal = fixed_mode->vtotal; - - adjusted_mode->clock = fixed_mode->clock; - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - + intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); + intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, + mode, adjusted_mode); /* * the mode->clock is used to calculate the Data&Link M/N * of the pipe. For the eDP the fixed clock should be used. @@ -572,8 +560,10 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, "count %d clock %d\n", intel_dp->link_bw, intel_dp->lane_count, adjusted_mode->clock); + return true; } + return false; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a44b8cb4d2cc..c552b06e5d21 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -186,6 +186,13 @@ extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config (struct intel_encoder *, int *, int *); +extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, + struct drm_display_mode *adjusted_mode); +extern void intel_pch_panel_fitting(struct drm_device *dev, + int fitting_mode, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + extern int intel_panel_fitter_pipe (struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 312ac306469a..cb5821eb59b6 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -246,26 +246,20 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, /* If we don't have a panel mode, there is nothing we can do */ if (dev_priv->panel_fixed_mode == NULL) return true; + /* * We have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; - adjusted_mode->hsync_start = - dev_priv->panel_fixed_mode->hsync_start; - adjusted_mode->hsync_end = - dev_priv->panel_fixed_mode->hsync_end; - adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; - adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; - adjusted_mode->vsync_start = - dev_priv->panel_fixed_mode->vsync_start; - adjusted_mode->vsync_end = - dev_priv->panel_fixed_mode->vsync_end; - adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; - adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); + + if (HAS_PCH_SPLIT(dev)) { + intel_pch_panel_fitting(dev, intel_lvds->fitting_mode, + mode, adjusted_mode); + return true; + } /* Make sure pre-965s set dither correctly */ if (!IS_I965G(dev)) { @@ -278,10 +272,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, adjusted_mode->vdisplay == mode->vdisplay) goto out; - /* full screen scale for now */ - if (HAS_PCH_SPLIT(dev)) - goto out; - /* 965+ wants fuzzy fitting */ if (IS_I965G(dev)) pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | @@ -293,10 +283,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * to register description and PRM. * Change the value here to see the borders for debugging */ - if (!HAS_PCH_SPLIT(dev)) { - I915_WRITE(BCLRPAT_A, 0); - I915_WRITE(BCLRPAT_B, 0); - } + I915_WRITE(BCLRPAT_A, 0); + I915_WRITE(BCLRPAT_B, 0); switch (intel_lvds->fitting_mode) { case DRM_MODE_SCALE_CENTER: diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c new file mode 100644 index 000000000000..e7f5299d9d57 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2006-2010 Intel Corporation + * Copyright (c) 2006 Dave Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Dave Airlie + * Jesse Barnes + * Chris Wilson + */ + +#include "intel_drv.h" + +void +intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, + struct drm_display_mode *adjusted_mode) +{ + adjusted_mode->hdisplay = fixed_mode->hdisplay; + adjusted_mode->hsync_start = fixed_mode->hsync_start; + adjusted_mode->hsync_end = fixed_mode->hsync_end; + adjusted_mode->htotal = fixed_mode->htotal; + + adjusted_mode->vdisplay = fixed_mode->vdisplay; + adjusted_mode->vsync_start = fixed_mode->vsync_start; + adjusted_mode->vsync_end = fixed_mode->vsync_end; + adjusted_mode->vtotal = fixed_mode->vtotal; + + adjusted_mode->clock = fixed_mode->clock; + + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); +} + +/* adjusted_mode has been preset to be the panel's fixed mode */ +void +intel_pch_panel_fitting(struct drm_device *dev, + int fitting_mode, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int x, y, width, height; + + x = y = width = height = 0; + + /* Native modes don't need fitting */ + if (adjusted_mode->hdisplay == mode->hdisplay && + adjusted_mode->vdisplay == mode->vdisplay) + goto done; + + switch (fitting_mode) { + case DRM_MODE_SCALE_CENTER: + width = mode->hdisplay; + height = mode->vdisplay; + x = (adjusted_mode->hdisplay - width + 1)/2; + y = (adjusted_mode->vdisplay - height + 1)/2; + break; + + case DRM_MODE_SCALE_ASPECT: + /* Scale but preserve the aspect ratio */ + { + u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; + u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; + if (scaled_width > scaled_height) { /* pillar */ + width = scaled_height / mode->vdisplay; + x = (adjusted_mode->hdisplay - width + 1) / 2; + y = 0; + height = adjusted_mode->vdisplay; + } else if (scaled_width < scaled_height) { /* letter */ + height = scaled_width / mode->hdisplay; + y = (adjusted_mode->vdisplay - height + 1) / 2; + x = 0; + width = adjusted_mode->hdisplay; + } else { + x = y = 0; + width = adjusted_mode->hdisplay; + height = adjusted_mode->vdisplay; + } + } + break; + + default: + case DRM_MODE_SCALE_FULLSCREEN: + x = y = 0; + width = adjusted_mode->hdisplay; + height = adjusted_mode->vdisplay; + break; + } + +done: + dev_priv->pch_pf_pos = (x << 16) | y; + dev_priv->pch_pf_size = (width << 16) | height; +} -- cgit v1.2.3-59-g8ed1b From 20a0945951705246278f43641bb13611c030e112 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:29 +0100 Subject: drm/i915: Write to display base last. Writing to the DSPBASE register triggers the double-buffered update to all the control registers, so always write it last in the update sequence. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 25e3866f9159..874ae30d5e4a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1585,15 +1585,13 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, Start, Offset, x, y, crtc->fb->pitch); I915_WRITE(dspstride, crtc->fb->pitch); if (IS_I965G(dev)) { - I915_WRITE(dspbase, Offset); - I915_READ(dspbase); I915_WRITE(dspsurf, Start); - I915_READ(dspsurf); I915_WRITE(dsptileoff, (y << 16) | x); + I915_WRITE(dspbase, Offset); } else { I915_WRITE(dspbase, Start + Offset); - I915_READ(dspbase); } + POSTING_READ(dspbase); if ((IS_I965G(dev) || plane == 0)) intel_update_fbc(crtc, &crtc->mode); -- cgit v1.2.3-59-g8ed1b From ae9fed6b601821d70928797c56da0e2008ef840d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:30 +0100 Subject: drm/i915: Truncate the shmem backing pages on purge shmfs doesn't actually implement i_ops->truncate() so we were not immedatiately releasing the backing pages when shrinking the gfx cache under OOM. Instead use a combination of truncate_inode_pages() and i_ops->truncate_range() as is used by shmem_delete_inode(). Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8f3e0c10c080..41306217bd7a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1505,9 +1505,16 @@ i915_gem_object_truncate(struct drm_gem_object *obj) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct inode *inode; + /* Our goal here is to return as much of the memory as + * is possible back to the system as we are called from OOM. + * To do this we must instruct the shmfs to drop all of its + * backing pages, *now*. Here we mirror the actions taken + * when by shmem_delete_inode() to release the backing store. + */ inode = obj->filp->f_path.dentry->d_inode; - if (inode->i_op->truncate) - inode->i_op->truncate (inode); + truncate_inode_pages(inode->i_mapping, 0); + if (inode->i_op->truncate_range) + inode->i_op->truncate_range(inode, 0, (loff_t)-1); obj_priv->madv = __I915_MADV_PURGED; } -- cgit v1.2.3-59-g8ed1b From 868dc58fbfda73493d62eae353b6b13649550e10 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:31 +0100 Subject: drm/i915/display: Add pipe/plane information to dpms debugging Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 874ae30d5e4a..07f19967687b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1956,7 +1956,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: - DRM_DEBUG_KMS("crtc %d dpms on\n", pipe); + DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane); if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { temp = I915_READ(PCH_LVDS); @@ -2142,10 +2142,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_load_lut(crtc); intel_update_fbc(crtc, &crtc->mode); + break; - break; case DRM_MODE_DPMS_OFF: - DRM_DEBUG_KMS("crtc %d dpms off\n", pipe); + DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane); drm_vblank_off(dev, pipe); /* Disable display plane */ -- cgit v1.2.3-59-g8ed1b From 862daefcc9a1eb9ff3e4c3d8076c31535f710cf9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:32 +0100 Subject: drm/i915/opregion: Use ASLE response codes defined in 0.1 Within i915_opregion.c there are two blocks of semantically identical ASLE response codes defined. Only one of those matches the ACPI IGD OpRegion Specification 0.1, use those. Signed-off-by: Chris Wilson Acked-by: Matthew Garrett Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_opregion.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index 8fcc75c1aa28..ce402b2568be 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c @@ -114,10 +114,6 @@ struct opregion_asle { #define ASLE_REQ_MSK 0xf /* response bits of ASLE irq request */ -#define ASLE_ALS_ILLUM_FAIL (2<<10) -#define ASLE_BACKLIGHT_FAIL (2<<12) -#define ASLE_PFIT_FAIL (2<<14) -#define ASLE_PWM_FREQ_FAIL (2<<16) #define ASLE_ALS_ILLUM_FAILED (1<<10) #define ASLE_BACKLIGHT_FAILED (1<<12) #define ASLE_PFIT_FAILED (1<<14) @@ -155,11 +151,11 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) u32 max_backlight, level, shift; if (!(bclp & ASLE_BCLP_VALID)) - return ASLE_BACKLIGHT_FAIL; + return ASLE_BACKLIGHT_FAILED; bclp &= ASLE_BCLP_MSK; if (bclp < 0 || bclp > 255) - return ASLE_BACKLIGHT_FAIL; + return ASLE_BACKLIGHT_FAILED; blc_pwm_ctl = I915_READ(BLC_PWM_CTL); blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2); @@ -211,7 +207,7 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) /* Panel fitting is currently controlled by the X code, so this is a noop until modesetting support works fully */ if (!(pfit & ASLE_PFIT_VALID)) - return ASLE_PFIT_FAIL; + return ASLE_PFIT_FAILED; return 0; } -- cgit v1.2.3-59-g8ed1b From debcaddcbd92387137b87f2c1c640571753915e0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:33 +0100 Subject: drm/i915: Update watermarks for Ironlake after dpms changes Previously, we only remembered to update the watermarks for i9xx, and incorrectly assumed that the crtc->enabled flag was valid at that point in the dpms cycle. Note that on my x201s this makes a SR bug on pipe 1 much easier to hit. (Since before this patch when disabling pipe 0, we either didn't update the watermarks at all, or when we did we still thought we had two pipes enabled and so disabled SR.) References: Bug 28969 - [Arrandale] Screen flickers, suspect Self-Refresh https://bugs.freedesktop.org/show_bug.cgi?id=28969 Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 07f19967687b..1eae234ff485 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2369,8 +2369,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: - intel_update_watermarks(dev); - /* Enable the DPLL */ temp = I915_READ(dpll_reg); if ((temp & DPLL_VCO_ENABLE) == 0) { @@ -2410,8 +2408,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_dpms_overlay(intel_crtc, true); break; case DRM_MODE_DPMS_OFF: - intel_update_watermarks(dev); - /* Give the overlay scaler a chance to disable if it's on this pipe */ intel_crtc_dpms_overlay(intel_crtc, false); drm_vblank_off(dev, pipe); @@ -2476,12 +2472,26 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) int pipe = intel_crtc->pipe; bool enabled; - dev_priv->display.dpms(crtc, mode); - intel_crtc->dpms_mode = mode; - intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON; - intel_crtc_update_cursor(crtc); + + /* When switching on the display, ensure that SR is disabled + * with multiple pipes prior to enabling to new pipe. + * + * When switching off the display, make sure the cursor is + * properly hidden prior to disabling the pipe. + */ + if (mode == DRM_MODE_DPMS_ON) + intel_update_watermarks(dev); + else + intel_crtc_update_cursor(crtc); + + dev_priv->display.dpms(crtc, mode); + + if (mode == DRM_MODE_DPMS_ON) + intel_crtc_update_cursor(crtc); + else + intel_update_watermarks(dev); if (!dev->primary->master) return; @@ -3362,12 +3372,11 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, int line_count; int planea_htotal = 0, planeb_htotal = 0; struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; /* Need htotal for all active display plane */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - if (crtc->enabled) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) { if (intel_crtc->plane == 0) planea_htotal = crtc->mode.htotal; else @@ -3527,7 +3536,6 @@ static void intel_update_watermarks(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; - struct intel_crtc *intel_crtc; int sr_hdisplay = 0; unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0; int enabled = 0, pixel_size = 0; @@ -3538,8 +3546,8 @@ static void intel_update_watermarks(struct drm_device *dev) /* Get the clock config from both planes */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = to_intel_crtc(crtc); - if (crtc->enabled) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) { enabled++; if (intel_crtc->plane == 0) { DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n", -- cgit v1.2.3-59-g8ed1b From dd785e35cb3c430c2290d351e67715864f7e5db5 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:34 +0100 Subject: drm/i915/ringbuffer: Set ring->gem_buffer = NULL on init unwind The cleanup path for early abort failed to nullify the gem_buffer. The likely consequence of this is zero, since a failure here should mean aborting the module load. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_ringbuffer.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 3a0242557220..7823b9648176 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -608,9 +608,10 @@ err: int intel_init_ring_buffer(struct drm_device *dev, struct intel_ring_buffer *ring) { - int ret; struct drm_i915_gem_object *obj_priv; struct drm_gem_object *obj; + int ret; + ring->dev = dev; if (I915_NEED_GFX_HWS(dev)) { @@ -623,16 +624,14 @@ int intel_init_ring_buffer(struct drm_device *dev, if (obj == NULL) { DRM_ERROR("Failed to allocate ringbuffer\n"); ret = -ENOMEM; - goto cleanup; + goto err_hws; } ring->gem_object = obj; ret = i915_gem_object_pin(obj, ring->alignment); - if (ret != 0) { - drm_gem_object_unreference(obj); - goto cleanup; - } + if (ret) + goto err_unref; obj_priv = to_intel_bo(obj); ring->map.size = ring->size; @@ -644,18 +643,14 @@ int intel_init_ring_buffer(struct drm_device *dev, drm_core_ioremap_wc(&ring->map, dev); if (ring->map.handle == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); ret = -EINVAL; - goto cleanup; + goto err_unpin; } ring->virtual_start = ring->map.handle; ret = ring->init(dev, ring); - if (ret != 0) { - intel_cleanup_ring_buffer(dev, ring); - return ret; - } + if (ret) + goto err_unmap; if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_kernel_lost_context(dev); @@ -669,7 +664,15 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); return ret; -cleanup: + +err_unmap: + drm_core_ioremapfree(&ring->map, dev); +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(obj); + ring->gem_object = NULL; +err_hws: cleanup_status_page(dev, ring); return ret; } -- cgit v1.2.3-59-g8ed1b From 913d8d110078788c14812dce8bb62c37946821d2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:35 +0100 Subject: drm/i915: Ensure that while(INREG()) are bounded (v2) Add a new macro, wait_for, to simplify the act of waiting on a register to change state. wait_for() takes three arguments, the condition to inspect on every loop, the maximum amount of time to wait and whether to yield the cpu for a length of time after each check. v2: Upgrade failure messages to DRM_ERROR on the suggestion of Eric Anholt. We do not expect to hit these conditions as they reflect programming errors, so if we do we want to be notified. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_crt.c | 17 +++++------ drivers/gpu/drm/i915/intel_display.c | 58 ++++++++---------------------------- drivers/gpu/drm/i915/intel_dp.c | 25 ++++++---------- drivers/gpu/drm/i915/intel_drv.h | 14 +++++++++ drivers/gpu/drm/i915/intel_lvds.c | 12 ++++---- 5 files changed, 48 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index cfcf85496e30..c43176d77549 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -185,8 +185,9 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); I915_WRITE(PCH_ADPA, adpa); - while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0) - ; + if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + 1000, 1)) + DRM_ERROR("timed out waiting for FORCE_TRIGGER"); if (HAS_PCH_CPT(dev)) { I915_WRITE(PCH_ADPA, temp); @@ -237,17 +238,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; for (i = 0; i < tries ; i++) { - unsigned long timeout; /* turn on the FORCE_DETECT */ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - timeout = jiffies + msecs_to_jiffies(1000); /* wait for FORCE_DETECT to go off */ - do { - if (!(I915_READ(PORT_HOTPLUG_EN) & - CRT_HOTPLUG_FORCE_DETECT)) - break; - msleep(1); - } while (time_after(timeout, jiffies)); + if (wait_for((I915_READ(PORT_HOTPLUG_EN) & + CRT_HOTPLUG_FORCE_DETECT) == 0, + 1000, 1)) + DRM_ERROR("timed out waiting for FORCE_DETECT to go off"); } stat = I915_READ(PORT_HOTPLUG_STAT); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1eae234ff485..0bf683dd512c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1037,7 +1037,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) void i8xx_disable_fbc(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long timeout = jiffies + msecs_to_jiffies(1); u32 fbc_ctl; if (!I915_HAS_FBC(dev)) @@ -1052,12 +1051,9 @@ void i8xx_disable_fbc(struct drm_device *dev) I915_WRITE(FBC_CONTROL, fbc_ctl); /* Wait for compressing bit to clear */ - while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) { - if (time_after(jiffies, timeout)) { - DRM_DEBUG_DRIVER("FBC idle timed out\n"); - break; - } - ; /* do nothing */ + if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) { + DRM_DEBUG_KMS("FBC idle timed out\n"); + return; } intel_wait_for_vblank(dev); @@ -1943,7 +1939,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; int trans_dpll_sel = (pipe == 0) ? 0 : 1; u32 temp; - int n; u32 pipe_bpc; temp = I915_READ(pipeconf_reg); @@ -2134,9 +2129,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(transconf_reg, temp | TRANS_ENABLE); I915_READ(transconf_reg); - while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) - ; - + if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 10, 0)) + DRM_ERROR("failed to enable transcoder\n"); } intel_crtc_load_lut(crtc); @@ -2167,20 +2161,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) temp = I915_READ(pipeconf_reg); if ((temp & PIPEACONF_ENABLE) != 0) { I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); - I915_READ(pipeconf_reg); - n = 0; + /* wait for cpu pipe off, pipe state */ - while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) { - n++; - if (n < 60) { - udelay(500); - continue; - } else { - DRM_DEBUG_KMS("pipe %d off delay\n", - pipe); - break; - } - } + if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1)) + DRM_ERROR("failed to turn off cpu pipe\n"); } else DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); @@ -2241,20 +2225,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) temp = I915_READ(transconf_reg); if ((temp & TRANS_ENABLE) != 0) { I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); - I915_READ(transconf_reg); - n = 0; + /* wait for PCH transcoder off, transcoder state */ - while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) { - n++; - if (n < 60) { - udelay(500); - continue; - } else { - DRM_DEBUG_KMS("transcoder %d off " - "delay\n", pipe); - break; - } - } + if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1)) + DRM_ERROR("failed to disable transcoder\n"); } temp = I915_READ(transconf_reg); @@ -5521,7 +5495,6 @@ void ironlake_enable_drps(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 rgvmodectl = I915_READ(MEMMODECTL); u8 fmax, fmin, fstart, vstart; - int i = 0; /* 100ms RC evaluation intervals */ I915_WRITE(RCUPEI, 100000); @@ -5565,13 +5538,8 @@ void ironlake_enable_drps(struct drm_device *dev) rgvmodectl |= MEMMODE_SWMODE_EN; I915_WRITE(MEMMODECTL, rgvmodectl); - while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) { - if (i++ > 100) { - DRM_ERROR("stuck trying to change perf mode\n"); - break; - } - msleep(1); - } + if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0)) + DRM_ERROR("stuck trying to change perf mode\n"); msleep(1); ironlake_set_drps(dev, fstart); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cee5d9ceb3b8..c6629bd9430f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -759,22 +759,18 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, static void ironlake_edp_panel_on (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long timeout = jiffies + msecs_to_jiffies(5000); - u32 pp, pp_status; + u32 pp; - pp_status = I915_READ(PCH_PP_STATUS); - if (pp_status & PP_ON) + if (I915_READ(PCH_PP_STATUS) & PP_ON) return; pp = I915_READ(PCH_PP_CONTROL); pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); - do { - pp_status = I915_READ(PCH_PP_STATUS); - } while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout)); - if (time_after(jiffies, timeout)) - DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status); + if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10)) + DRM_ERROR("panel on wait timed out: 0x%08x\n", + I915_READ(PCH_PP_STATUS)); pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); I915_WRITE(PCH_PP_CONTROL, pp); @@ -783,18 +779,15 @@ static void ironlake_edp_panel_on (struct drm_device *dev) static void ironlake_edp_panel_off (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long timeout = jiffies + msecs_to_jiffies(5000); - u32 pp, pp_status; + u32 pp; pp = I915_READ(PCH_PP_CONTROL); pp &= ~POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); - do { - pp_status = I915_READ(PCH_PP_STATUS); - } while ((pp_status & PP_ON) && !time_after(jiffies, timeout)); - if (time_after(jiffies, timeout)) - DRM_DEBUG_KMS("panel off wait timed out\n"); + if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10)) + DRM_ERROR("panel off wait timed out: 0x%08x\n", + I915_READ(PCH_PP_STATUS)); /* Make sure VDD is enabled so DP AUX will work */ pp |= EDP_FORCE_VDD; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c552b06e5d21..2a3eaaf64b24 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -32,6 +32,20 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" + +#define wait_for(COND, MS, W) ({ \ + unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \ + int ret__ = 0; \ + while (! (COND)) { \ + if (time_after(jiffies, timeout__)) { \ + ret__ = -ETIMEDOUT; \ + break; \ + } \ + if (W) msleep(W); \ + } \ + ret__; \ +}) + /* * Display related stuff */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index cb5821eb59b6..b819c1081147 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -96,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) static void intel_lvds_set_power(struct drm_device *dev, bool on) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp_status, ctl_reg, status_reg, lvds_reg; + u32 ctl_reg, status_reg, lvds_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; @@ -114,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - do { - pp_status = I915_READ(status_reg); - } while ((pp_status & PP_ON) == 0); + if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0)) + DRM_ERROR("timed out waiting to enable LVDS pipe"); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); } else { @@ -124,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); - do { - pp_status = I915_READ(status_reg); - } while (pp_status & PP_ON); + if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0)) + DRM_ERROR("timed out waiting for LVDS pipe to turn off"); I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); POSTING_READ(lvds_reg); -- cgit v1.2.3-59-g8ed1b From 5ddb954b9ee50824977d2931e0ff58b3050b337d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:36 +0100 Subject: drm/i915/edp: Flush the write before waiting for PLLs Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bf683dd512c..2a32a7b60c96 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1665,6 +1665,7 @@ static void ironlake_enable_pll_edp (struct drm_crtc *crtc) dpa_ctl = I915_READ(DP_A); dpa_ctl |= DP_PLL_ENABLE; I915_WRITE(DP_A, dpa_ctl); + POSTING_READ(DP_A); udelay(200); } -- cgit v1.2.3-59-g8ed1b From c27ba48e629d2a845f26489fcddc9912673711e7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:37 +0100 Subject: drm/i915: FBC is updated within set_base() so remove second call in mode_set() The FBC is dependent upon a few details of the framebuffer so it is required to be updated within set_base(), so remove the redundant call from mode_set(). Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2a32a7b60c96..41b4caf3d1d8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4171,9 +4171,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Flush the plane changes */ ret = intel_pipe_set_base(crtc, x, y, old_fb); - if ((IS_I965G(dev) || plane == 0)) - intel_update_fbc(crtc, &crtc->mode); - intel_update_watermarks(dev); drm_vblank_post_modeset(dev, pipe); -- cgit v1.2.3-59-g8ed1b From 560b85bb750c3c539641993dd508b61260c9e874 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:38 +0100 Subject: drm/i915: Only update i845/i865 CURBASE when disabled (v2) The i845 and i865 have a peculiarlity in that CURBASE is not the trigger for the vsync update of the cursor registers but instead the modification of that register is prohibited whilst the cursor is enabled. Reorder the write sequence for CURPOS, CURCNTR and CURBASE on i845 to i865 to match. v2: Remove the checks for i845/i865 from within i9xx_cursor_update() Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 91 ++++++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 41b4caf3d1d8..6490d8b3867f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4204,6 +4204,62 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } } +static void i845_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + bool visible = base != 0; + u32 cntl; + + if (intel_crtc->cursor_visible == visible) + return; + + cntl = I915_READ(CURACNTR); + if (visible) { + /* On these chipsets we can only modify the base whilst + * the cursor is disabled. + */ + I915_WRITE(CURABASE, base); + + cntl &= ~(CURSOR_FORMAT_MASK); + /* XXX width must be 64, stride 256 => 0x00 << 28 */ + cntl |= CURSOR_ENABLE | + CURSOR_GAMMA_ENABLE | + CURSOR_FORMAT_ARGB; + } else + cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); + I915_WRITE(CURACNTR, cntl); + + intel_crtc->cursor_visible = visible; +} + +static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + bool visible = base != 0; + + if (intel_crtc->cursor_visible != visible) { + uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR); + if (base) { + cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); + cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + cntl |= pipe << 28; /* Connect to correct pipe */ + } else { + cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); + cntl |= CURSOR_MODE_DISABLE; + } + I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl); + + intel_crtc->cursor_visible = visible; + } + /* and commit changes on next vblank */ + I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base); +} + /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ static void intel_crtc_update_cursor(struct drm_crtc *crtc) { @@ -4213,7 +4269,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; int x = intel_crtc->cursor_x; int y = intel_crtc->cursor_y; - uint32_t base, pos; + u32 base, pos; bool visible; pos = 0; @@ -4247,37 +4303,14 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc) pos |= y << CURSOR_Y_SHIFT; visible = base != 0; - if (!visible && !intel_crtc->cursor_visble) + if (!visible && !intel_crtc->cursor_visible) return; I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos); - if (intel_crtc->cursor_visble != visible) { - uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR); - if (base) { - /* Hooray for CUR*CNTR differences */ - if (IS_MOBILE(dev) || IS_I9XX(dev)) { - cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); - cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; - cntl |= pipe << 28; /* Connect to correct pipe */ - } else { - cntl &= ~(CURSOR_FORMAT_MASK); - cntl |= CURSOR_ENABLE; - cntl |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE; - } - } else { - if (IS_MOBILE(dev) || IS_I9XX(dev)) { - cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); - cntl |= CURSOR_MODE_DISABLE; - } else { - cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); - } - } - I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl); - - intel_crtc->cursor_visble = visible; - } - /* and commit changes on next vblank */ - I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base); + if (IS_845G(dev) || IS_I865G(dev)) + i845_update_cursor(crtc, base); + else + i9xx_update_cursor(crtc, base); if (visible) intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2a3eaaf64b24..6ba56e1796ce 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -168,7 +168,7 @@ struct intel_crtc { uint32_t cursor_addr; int16_t cursor_x, cursor_y; int16_t cursor_width, cursor_height; - bool cursor_visble, cursor_on; + bool cursor_visible, cursor_on; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) -- cgit v1.2.3-59-g8ed1b From 6eeefaf3c86b8937db8ad930c48bfb592fc5e32e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 11:01:39 +0100 Subject: drm/i915: Apply i830 errata for cursor alignment i830 requires 32bpp cursors to be aligned to 16KB, so we have to expose the alignment parameter to i915_gem_attach_phys_object(). Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 4 +++- drivers/gpu/drm/i915/i915_gem.c | 11 ++++++----- drivers/gpu/drm/i915/intel_display.c | 4 +++- drivers/gpu/drm/i915/intel_overlay.c | 3 ++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4b0ffb6c5561..8df6ac735187 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1000,7 +1000,9 @@ int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write); int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj); int i915_gem_attach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj, int id); + struct drm_gem_object *obj, + int id, + int align); void i915_gem_detach_phys_object(struct drm_device *dev, struct drm_gem_object *obj); void i915_gem_free_all_phys_object(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 41306217bd7a..b4b25e17d4e9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4674,7 +4674,7 @@ i915_gem_load(struct drm_device *dev) * e.g. for cursor + overlay regs */ int i915_gem_init_phys_object(struct drm_device *dev, - int id, int size) + int id, int size, int align) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_phys_object *phys_obj; @@ -4689,7 +4689,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, phys_obj->id = id; - phys_obj->handle = drm_pci_alloc(dev, size, 0); + phys_obj->handle = drm_pci_alloc(dev, size, align); if (!phys_obj->handle) { ret = -ENOMEM; goto kfree_obj; @@ -4771,7 +4771,9 @@ out: int i915_gem_attach_phys_object(struct drm_device *dev, - struct drm_gem_object *obj, int id) + struct drm_gem_object *obj, + int id, + int align) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; @@ -4790,11 +4792,10 @@ i915_gem_attach_phys_object(struct drm_device *dev, i915_gem_detach_phys_object(dev, obj); } - /* create a new object */ if (!dev_priv->mm.phys_objs[id - 1]) { ret = i915_gem_init_phys_object(dev, id, - obj->size); + obj->size, align); if (ret) { DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size); goto out; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6490d8b3867f..53f3a98cc1ae 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4375,8 +4375,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, addr = obj_priv->gtt_offset; } else { + int align = IS_I830(dev) ? 16 * 1024 : 256; ret = i915_gem_attach_phys_object(dev, bo, - (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1); + (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1, + align); if (ret) { DRM_ERROR("failed to attach phys object\n"); goto fail_locked; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 9ae61aa05a1f..4f00390d7c61 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1367,7 +1367,8 @@ void intel_setup_overlay(struct drm_device *dev) overlay->flip_addr = overlay->reg_bo->gtt_offset; } else { ret = i915_gem_attach_phys_object(dev, reg_bo, - I915_GEM_PHYS_OVERLAY_REGS); + I915_GEM_PHYS_OVERLAY_REGS, + 0); if (ret) { DRM_ERROR("failed to attach phys overlay regs\n"); goto out_free_bo; -- cgit v1.2.3-59-g8ed1b From e78d73b16bcde921c9cf458d2e4de8e4fc2518f3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 7 Aug 2010 14:18:47 +0100 Subject: drm/i915: Wake-up wait_request() from elapsed hang-check (v2) If our watchdog fires and we see that the GPU is idle, but that we are still waiting on an interrupt, forcibly wake-up the waiter. i915_do_wait_request() should not be racy, yet there are persistent reports that 945GM hangs whilst the GPU is idle. This implies that the hardware is not quite as coherent as the documentation claims - a write followed by a flush is supposed to be coherent in main memory before the flush is retired and the irq is emitted. This seems to be a sensible and elegant guard to force the wait to timeout. v2: Daniel Vetter pointed out that a warning would be useful to explain why the machine appeared to stall. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5161cea7a4ef..69a36fc035dc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1304,6 +1304,16 @@ void i915_hangcheck_elapsed(unsigned long data) &dev_priv->render_ring), i915_get_tail_request(dev)->seqno)) { dev_priv->hangcheck_count = 0; + + /* Issue a wake-up to catch stuck h/w. */ + if (dev_priv->render_ring.waiting_gem_seqno | + dev_priv->bsd_ring.waiting_gem_seqno) { + DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n"); + if (dev_priv->render_ring.waiting_gem_seqno) + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); + if (dev_priv->bsd_ring.waiting_gem_seqno) + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + } return; } -- cgit v1.2.3-59-g8ed1b From 1cafd34731cd14e5a72edaf0f41717c8126cfce9 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 25 Jun 2010 13:40:24 +0800 Subject: drm/i915 invalidate indirect state pointers at end of ring exec This is required by the spec, and without this some 3D programs will hang after resume from RC6 we enable that. Signed-off-by: Zou Nan hai Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_dma.c | 7 +++++++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f19ffe87af3c..44af317731b6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -499,6 +499,13 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, } } + + if (IS_G4X(dev) || IS_IRONLAKE(dev)) { + BEGIN_LP_RING(2); + OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP); + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); + } i915_emit_breadcrumb(dev); return 0; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 97a35a42da28..21fd657663aa 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -170,6 +170,7 @@ #define MI_NO_WRITE_FLUSH (1 << 2) #define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ +#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */ #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_REPORT_HEAD MI_INSTR(0x07, 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11,0) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7823b9648176..51e9c9e718c4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -535,7 +535,16 @@ render_ring_dispatch_gem_execbuffer(struct drm_device *dev, intel_ring_advance(dev, ring); } + if (IS_G4X(dev) || IS_IRONLAKE(dev)) { + intel_ring_begin(dev, ring, 2); + intel_ring_emit(dev, ring, MI_FLUSH | + MI_NO_WRITE_FLUSH | + MI_INVALIDATE_ISP ); + intel_ring_emit(dev, ring, MI_NOOP); + intel_ring_advance(dev, ring); + } /* XXX breadcrumb */ + return 0; } -- cgit v1.2.3-59-g8ed1b From aa40d6bbb9cf88f3fb296a57e046a52e9a68ab72 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 25 Jun 2010 13:40:23 +0800 Subject: drm/i915: Set up a render context on Ironlake RC6 power state requires a logical render context in place for saving render context. Signed-off-by: Zou Nan hai Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_reg.h | 11 ++++++++ drivers/gpu/drm/i915/intel_display.c | 53 +++++++++++++++++++++++++++++------- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8df6ac735187..047cd7ce7e1b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -254,6 +254,7 @@ typedef struct drm_i915_private { drm_local_map_t hws_map; struct drm_gem_object *seqno_obj; struct drm_gem_object *pwrctx; + struct drm_gem_object *renderctx; struct resource mch_res; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 21fd657663aa..a63e9a176386 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -181,6 +181,12 @@ #define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) #define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) #define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) +#define MI_SET_CONTEXT MI_INSTR(0x18, 0) +#define MI_MM_SPACE_GTT (1<<8) +#define MI_MM_SPACE_PHYSICAL (0<<8) +#define MI_SAVE_EXT_STATE_EN (1<<3) +#define MI_RESTORE_EXT_STATE_EN (1<<2) +#define MI_RESTORE_INHIBIT (1<<0) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) @@ -1100,6 +1106,11 @@ #define DDRMPLL1 0X12c20 #define PEG_BAND_GAP_DATA 0x14d68 +/* + * Logical Context regs + */ +#define CCID 0x2180 +#define CCID_EN (1<<0) /* * Overlay regs */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 53f3a98cc1ae..4668e9bf67d8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5466,37 +5466,37 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { }; static struct drm_gem_object * -intel_alloc_power_context(struct drm_device *dev) +intel_alloc_context_page(struct drm_device *dev) { - struct drm_gem_object *pwrctx; + struct drm_gem_object *ctx; int ret; - pwrctx = i915_gem_alloc_object(dev, 4096); - if (!pwrctx) { + ctx = i915_gem_alloc_object(dev, 4096); + if (!ctx) { DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); return NULL; } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(pwrctx, 4096); + ret = i915_gem_object_pin(ctx, 4096); if (ret) { DRM_ERROR("failed to pin power context: %d\n", ret); goto err_unref; } - ret = i915_gem_object_set_to_gtt_domain(pwrctx, 1); + ret = i915_gem_object_set_to_gtt_domain(ctx, 1); if (ret) { DRM_ERROR("failed to set-domain on power context: %d\n", ret); goto err_unpin; } mutex_unlock(&dev->struct_mutex); - return pwrctx; + return ctx; err_unpin: - i915_gem_object_unpin(pwrctx); + i915_gem_object_unpin(ctx); err_unref: - drm_gem_object_unreference(pwrctx); + drm_gem_object_unreference(ctx); mutex_unlock(&dev->struct_mutex); return NULL; } @@ -5796,6 +5796,29 @@ void intel_init_clock_gating(struct drm_device *dev) * GPU can automatically power down the render unit if given a page * to save state. */ + if (IS_IRONLAKE_M(dev)) { + if (dev_priv->renderctx == NULL) + dev_priv->renderctx = intel_alloc_context_page(dev); + if (dev_priv->renderctx) { + struct drm_i915_gem_object *obj_priv; + obj_priv = to_intel_bo(dev_priv->renderctx); + if (obj_priv) { + BEGIN_LP_RING(4); + OUT_RING(MI_SET_CONTEXT); + OUT_RING(obj_priv->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); + ADVANCE_LP_RING(); + } + } else + DRM_DEBUG_KMS("Failed to allocate render context." + "Disable RC6\n"); + } + if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_i915_gem_object *obj_priv = NULL; @@ -5804,7 +5827,7 @@ void intel_init_clock_gating(struct drm_device *dev) } else { struct drm_gem_object *pwrctx; - pwrctx = intel_alloc_power_context(dev); + pwrctx = intel_alloc_context_page(dev); if (pwrctx) { dev_priv->pwrctx = pwrctx; obj_priv = to_intel_bo(pwrctx); @@ -6062,6 +6085,16 @@ void intel_modeset_cleanup(struct drm_device *dev) if (dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); + if (dev_priv->renderctx) { + struct drm_i915_gem_object *obj_priv; + + obj_priv = to_intel_bo(dev_priv->renderctx); + I915_WRITE(CCID, obj_priv->gtt_offset &~ CCID_EN); + I915_READ(CCID); + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(dev_priv->renderctx); + } + if (dev_priv->pwrctx) { struct drm_i915_gem_object *obj_priv; -- cgit v1.2.3-59-g8ed1b From 8545423a912cf500009cbadfae57f706cf2b28e8 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Aug 2010 14:28:23 +0100 Subject: drm/i915/sdvo: Only set is_lvds if we have a valid fixed mode. If we have failed to ascertain the fixed mode for the LVDS panel, then trust the pixel clock ranges reported for the connection when determing valid modes. This makes intel_sdvo_mode_valid() consistent with intel_lvds_mode_valid() which is also a no-op is there is no fixed mode defined. (Since the mode is both validated by SDVO and LVDS, why are checking against an LVDS fixed mode in SDVO...) By only defining is_lvds to be true when we actually have an LVDS output with a fixed mode, we avoid various potential NULL deferences where the assumption is made that all LVDS outputs have a fixed mode. References: Bug 29449 - [Q35] failure to read EDID/vbios for LVDS, no mode => no output https://bugs.freedesktop.org/show_bug.cgi?id=29449 The primary failure in this bug is not finding the EDID and determining the correct fixed panel mode. However, this patch should fix the secondary issue of not enabling any of the standard modes for the panel either. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_sdvo.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 69cf7241c3e0..5c765bb0845d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1274,10 +1274,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, if (intel_sdvo->pixel_clock_max < mode->clock) return MODE_CLOCK_HIGH; - if (intel_sdvo->is_lvds == true) { - if (intel_sdvo->sdvo_lvds_fixed_mode == NULL) - return MODE_PANEL; - + if (intel_sdvo->is_lvds) { if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) return MODE_PANEL; @@ -1534,7 +1531,7 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect intel_sdvo->base.needs_tv_clock = true; } if (response & SDVO_LVDS_MASK) - intel_sdvo->is_lvds = true; + intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL; } return ret; @@ -1697,6 +1694,7 @@ end: if (newmode->type & DRM_MODE_TYPE_PREFERRED) { intel_sdvo->sdvo_lvds_fixed_mode = drm_mode_duplicate(connector->dev, newmode); + intel_sdvo->is_lvds = true; break; } } @@ -2190,8 +2188,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) encoder->encoder_type = DRM_MODE_ENCODER_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS; - intel_sdvo->is_lvds = true; - if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0; intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0; -- cgit v1.2.3-59-g8ed1b From ce17178094f368d9e3f39b2cb4303da5ed633dd4 Mon Sep 17 00:00:00 2001 From: Zou Nan hai Date: Fri, 25 Jun 2010 13:40:22 +0800 Subject: drm/i915: Enable RC6 on Ironlake. RC6 allows the GPU to enter a lower power state when the GPU is idle. Signed-off-by: Zou Nan hai [anholt: Fixed the !renderctx error path to actually not enable RC6.] Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_display.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4668e9bf67d8..149c18b7c375 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5753,7 +5753,8 @@ void intel_init_clock_gating(struct drm_device *dev) ILK_DPFC_DIS2 | ILK_CLK_FBC); } - return; + if (IS_GEN6(dev)) + return; } else if (IS_G4X(dev)) { uint32_t dspclk_gate; I915_WRITE(RENCLK_GATE_D1, 0); @@ -5814,9 +5815,11 @@ void intel_init_clock_gating(struct drm_device *dev) OUT_RING(MI_FLUSH); ADVANCE_LP_RING(); } - } else + } else { DRM_DEBUG_KMS("Failed to allocate render context." - "Disable RC6\n"); + "Disable RC6\n"); + return; + } } if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { -- cgit v1.2.3-59-g8ed1b From 669502ff31d7dba1849aec7ee2450a3c61f57d39 Mon Sep 17 00:00:00 2001 From: Andy Chittenden Date: Tue, 10 Aug 2010 10:19:53 -0400 Subject: SUNRPC: fix NFS client over TCP hangs due to packet loss (Bug 16494) When reusing a TCP connection, ensure that it's aborted if a previous shutdown attempt has been made on that connection so that the RPC over TCP recovery mechanism succeeds. Signed-off-by: Andy Chittenden Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 7ca65c7005ea..66d136984d57 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1305,10 +1305,11 @@ static void xs_tcp_state_change(struct sock *sk) if (!(xprt = xprt_from_sock(sk))) goto out; dprintk("RPC: xs_tcp_state_change client %p...\n", xprt); - dprintk("RPC: state %x conn %d dead %d zapped %d\n", + dprintk("RPC: state %x conn %d dead %d zapped %d sk_shutdown %d\n", sk->sk_state, xprt_connected(xprt), sock_flag(sk, SOCK_DEAD), - sock_flag(sk, SOCK_ZAPPED)); + sock_flag(sk, SOCK_ZAPPED), + sk->sk_shutdown); switch (sk->sk_state) { case TCP_ESTABLISHED: @@ -1779,10 +1780,25 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt, struct sock_xprt *tra { unsigned int state = transport->inet->sk_state; - if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED) - return; - if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT)) - return; + if (state == TCP_CLOSE && transport->sock->state == SS_UNCONNECTED) { + /* we don't need to abort the connection if the socket + * hasn't undergone a shutdown + */ + if (transport->inet->sk_shutdown == 0) + return; + dprintk("RPC: %s: TCP_CLOSEd and sk_shutdown set to %d\n", + __func__, transport->inet->sk_shutdown); + } + if ((1 << state) & (TCPF_ESTABLISHED|TCPF_SYN_SENT)) { + /* we don't need to abort the connection if the socket + * hasn't undergone a shutdown + */ + if (transport->inet->sk_shutdown == 0) + return; + dprintk("RPC: %s: ESTABLISHED/SYN_SENT " + "sk_shutdown set to %d\n", + __func__, transport->inet->sk_shutdown); + } xs_abort_connection(xprt, transport); } -- cgit v1.2.3-59-g8ed1b From f5a73672d1811f2fb1dcb62ca90ceb12b2050ae7 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Tue, 10 Aug 2010 10:20:05 -0400 Subject: NFS: allow close-to-open cache semantics to apply to root of NFS filesystem To obey NFS cache semantics, the client must verify the cached attributes when a file is opened. In most cases this is done by a call to d_validate as one of the last steps in path_walk. However for the root of a filesystem, d_validate is only ever called on the mounted-on filesystem (except when the path ends '.' or '..'). So NFS has no chance to validate the attributes. So, in nfs_opendir, we revalidate the attributes if the opened directory is the mountpoint. This may cause double-validation for "." and ".." lookups, but that is better than missing regular /path/name lookups completely. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 29539ceeb745..bd91b2778315 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -140,6 +140,13 @@ nfs_opendir(struct inode *inode, struct file *filp) /* Call generic open code in order to cache credentials */ res = nfs_open(inode, filp); + if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { + /* This is a mountpoint, so d_revalidate will never + * have been called, so we need to refresh the + * inode (for close-open consistency) ourselves. + */ + __nfs_revalidate_inode(NFS_SERVER(inode), inode); + } return res; } -- cgit v1.2.3-59-g8ed1b From 9b00c64318cc337846a7a08a5678f5f19aeff188 Mon Sep 17 00:00:00 2001 From: "Patrick J. LoPresti" Date: Tue, 10 Aug 2010 17:28:01 -0400 Subject: nfs: Add "lookupcache" to displayed mount options Running "cat /proc/mounts" fails to display the "lookupcache" option. This oversight cost me a bunch of wasted time recently. The following simple patch fixes it. CC: stable Signed-off-by: Patrick LoPresti Signed-off-by: Trond Myklebust --- fs/nfs/super.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f1ae39f6cb02..3d0d63c00304 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -655,6 +655,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, if (nfss->options & NFS_OPTION_FSCACHE) seq_printf(m, ",fsc"); + + if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) { + if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) + seq_printf(m, ",lookupcache=none"); + else + seq_printf(m, ",lookupcache=pos"); + } } /* -- cgit v1.2.3-59-g8ed1b From 5d7ca35a182a626f8ed5596023ad42eb219a332e Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 11 Aug 2010 12:42:15 -0400 Subject: nfs: Remove redundant NULL check upon kfree() Signed-off-by: Davidlohr Bueso Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ffbb98ddec3..6b44bbfb7d8a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2273,8 +2273,7 @@ static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct out: if (page) __free_page(page); - if (locations) - kfree(locations); + kfree(locations); return status; } -- cgit v1.2.3-59-g8ed1b From 7a8b80eb38b248cfdf84048dad12073d5cfba3e6 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 11 Aug 2010 12:47:08 -0400 Subject: xprtrdma: Do not truncate iova_start values in frmr registrations. A bad cast causes the iova_start, which in this case is a 64b DMA bus address, to be truncated on 32b systems. This breaks frmrs on 32b systems. No cast is needed. Signed-off-by: Steve Wise Signed-off-by: Trond Myklebust --- net/sunrpc/xprtrdma/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 27015c6d8eb5..3bdbd9f3b88f 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1490,7 +1490,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, memset(&frmr_wr, 0, sizeof frmr_wr); frmr_wr.opcode = IB_WR_FAST_REG_MR; frmr_wr.send_flags = 0; /* unsignaled */ - frmr_wr.wr.fast_reg.iova_start = (unsigned long)seg1->mr_dma; + frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; frmr_wr.wr.fast_reg.page_list_len = i; frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; -- cgit v1.2.3-59-g8ed1b From 15cdc644b268a9a9ce73ce0b153129222c254b7b Mon Sep 17 00:00:00 2001 From: Tom Tucker Date: Wed, 11 Aug 2010 12:47:24 -0400 Subject: rpcrdma: Fix SQ size calculation when memreg is FRMR This patch updates the computation to include the worst case situation where three FRMR are required to map a single RPC REQ. Signed-off-by: Tom Tucker Signed-off-by: Trond Myklebust --- net/sunrpc/xprtrdma/rpc_rdma.c | 2 ++ net/sunrpc/xprtrdma/verbs.c | 20 ++++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index e5e28d1946a4..2ac3f6e8adff 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c @@ -249,6 +249,8 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, req->rl_nchunks = nchunks; BUG_ON(nchunks == 0); + BUG_ON((r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR) + && (nchunks > 3)); /* * finish off header. If write, marshal discrim and nchunks. diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 3bdbd9f3b88f..5f4c7b3bc711 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -650,10 +650,22 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia, ep->rep_attr.cap.max_send_wr = cdata->max_requests; switch (ia->ri_memreg_strategy) { case RPCRDMA_FRMR: - /* Add room for frmr register and invalidate WRs */ - ep->rep_attr.cap.max_send_wr *= 3; - if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr) - return -EINVAL; + /* Add room for frmr register and invalidate WRs. + * 1. FRMR reg WR for head + * 2. FRMR invalidate WR for head + * 3. FRMR reg WR for pagelist + * 4. FRMR invalidate WR for pagelist + * 5. FRMR reg WR for tail + * 6. FRMR invalidate WR for tail + * 7. The RDMA_SEND WR + */ + ep->rep_attr.cap.max_send_wr *= 7; + if (ep->rep_attr.cap.max_send_wr > devattr.max_qp_wr) { + cdata->max_requests = devattr.max_qp_wr / 7; + if (!cdata->max_requests) + return -EINVAL; + ep->rep_attr.cap.max_send_wr = cdata->max_requests * 7; + } break; case RPCRDMA_MEMWINDOWS_ASYNC: case RPCRDMA_MEMWINDOWS: -- cgit v1.2.3-59-g8ed1b From 0702099bd86c33c2dcdbd3963433a61f3f503901 Mon Sep 17 00:00:00 2001 From: "J. R. Okajima" Date: Wed, 11 Aug 2010 13:10:16 -0400 Subject: NFS: fix the return value of nfs_file_fsync() By the commit af7fa16 2010-08-03 NFS: Fix up the fsync code close(2) became returning the non-zero value even if it went well. nfs_file_fsync() should return 0 when "status" is positive. Signed-off-by: J. R. Okajima Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 2d141a74ae82..eb51bd6201da 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -323,7 +323,7 @@ nfs_file_fsync(struct file *file, int datasync) have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); if (have_error) ret = xchg(&ctx->error, 0); - if (!ret) + if (!ret && status < 0) ret = status; return ret; } -- cgit v1.2.3-59-g8ed1b From 2f81b47135a971a22ccad9f3cc8c68a583b93ea4 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 11 Aug 2010 16:11:00 -0400 Subject: ipw2100: register pm_qos request before registering pci driver It is necessary to call pm_qos_add_request prior to calling pm_qos_update_request. It was revealed that ipw2100 has been doing this wrong since "pm_qos: Get rid of the allocation in pm_qos_add_request()" (commit 82f682514a5df89ffb3890627eebf0897b7a84ec) added a WARN that results in the following backtrace: WARNING: at kernel/pm_qos_params.c:264 pm_qos_update_request+0x5e/0x70() pm_qos_update_request() called for unknown object Call Trace: [] ? warn_slowpath_common+0x78/0xb0 [] ? pm_qos_update_request+0x5e/0x70 [] ? pm_qos_update_request+0x5e/0x70 [] ? warn_slowpath_fmt+0x33/0x40 [] ? pm_qos_update_request+0x5e/0x70 [] ? ipw2100_up+0x3f/0xf10 [ipw2100] [] ? vsnprintf+0xc9/0x530 [] ? ipw2100_net_init+0x2c/0x1c0 [ipw2100] [] ? register_netdevice+0x7d/0x3c0 [] ? ipw2100_irq_tasklet+0x910/0x9a0 [ipw2100] [] ? register_netdev+0x2f/0x40 [] ? ipw2100_pci_init_one+0xd21/0x1060 [ipw2100] [] ? local_pci_probe+0xb/0x10 [] ? pci_device_probe+0x69/0x90 [] ? driver_probe_device+0x74/0x180 [] ? sysfs_create_dir+0x6a/0xb0 [] ? __driver_attach+0x79/0x80 [] ? __driver_attach+0x0/0x80 [] ? bus_for_each_dev+0x52/0x80 [] ? driver_attach+0x16/0x20 [] ? __driver_attach+0x0/0x80 [] ? bus_add_driver+0x17f/0x250 [] ? pci_device_shutdown+0x0/0x20 [] ? pci_device_remove+0x0/0x40 [] ? driver_register+0x63/0x120 [] ? __pci_register_driver+0x36/0xa0 [] ? ipw2100_init+0x48/0x67 [ipw2100] [] ? do_one_initcall+0x32/0x170 [] ? __vunmap+0xb8/0xf0 [] ? ipw2100_init+0x0/0x67 [ipw2100] [] ? sys_init_module+0x161/0x1000 [] ? sys_close+0x67/0xe0 [] ? syscall_call+0x7/0xb This patch moves pm_qos_add_request prior to pci_register_driver in ipw2100 in order to avoid this problem. Reported-by: Christoph Fritz Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 16bbfa3189a5..1189dbb6e2a6 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6665,12 +6665,13 @@ static int __init ipw2100_init(void) printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT); + pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + ret = pci_register_driver(&ipw2100_pci_driver); if (ret) goto out; - pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, - PM_QOS_DEFAULT_VALUE); #ifdef CONFIG_IPW2100_DEBUG ipw2100_debug_level = debug; ret = driver_create_file(&ipw2100_pci_driver.driver, -- cgit v1.2.3-59-g8ed1b From da93f10684bfba2983a70c10b5d417232b6a5245 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 11 Aug 2010 20:27:43 +0530 Subject: ath9k_htc: fix panic on packet injection using airbase-ng tool. This should fix the oops which occurs during the packet injection on monitor interface. EIP is at ath9k_htc_tx_start+0x69/0x220 [ath9k_htc] [] ? invoke_tx_handlers+0xa5a/0xee0 [mac80211] [] ? ath9k_htc_tx+0x44/0xe0 [ath9k_htc] [] ? __ieee80211_tx+0xf8/0x190 [mac80211] [] ? ieee80211_tx+0x9d/0x1a0 [mac80211] [] ? ieee80211_xmit+0x9c/0x1c0 [mac80211] [] ? ieee80211_monitor_start_xmit+0x85/0xb0 [mac80211] [] ? dev_hard_start_xmit+0x1ad/0x210 [] ? __alloc_skb+0x52/0x130 [] ? sch_direct_xmit+0x105/0x170 [] ? dev_queue_xmit+0x37f/0x4b0 [] ? packet_snd+0x21e/0x250 [] ? packet_sendmsg+0x32/0x40 [] ? sock_aio_write+0x113/0x130 [] ? do_sync_write+0xc4/0x100 [] ? autoremove_wake_function+0x0/0x50 [] ? security_file_permission+0x14/0x20 [] ? rw_verify_area+0x64/0xe0 [] ? handle_mm_fault+0x338/0x390 [] ? vfs_write+0x185/0x1a0 [] ? do_page_fault+0x160/0x3a0 [] ? sys_write+0x42/0x70 [] ? syscall_call+0x7/0xb Signed-off-by: Rajkumar Manoharan Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index bd0b4acc3ece..2a6e45a293a9 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -78,18 +78,23 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ath9k_htc_sta *ista; - struct ath9k_htc_vif *avp; struct ath9k_htc_tx_ctl tx_ctl; enum htc_endpoint_id epid; u16 qnum; __le16 fc; u8 *tx_fhdr; - u8 sta_idx; + u8 sta_idx, vif_idx; hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; - avp = (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv; + if (tx_info->control.vif && + (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv) + vif_idx = ((struct ath9k_htc_vif *) + tx_info->control.vif->drv_priv)->index; + else + vif_idx = priv->nvifs; + if (sta) { ista = (struct ath9k_htc_sta *) sta->drv_priv; sta_idx = ista->index; @@ -106,7 +111,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); tx_hdr.node_idx = sta_idx; - tx_hdr.vif_idx = avp->index; + tx_hdr.vif_idx = vif_idx; if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_ctl.type = ATH9K_HTC_AMPDU; @@ -169,7 +174,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) tx_ctl.type = ATH9K_HTC_NORMAL; mgmt_hdr.node_idx = sta_idx; - mgmt_hdr.vif_idx = avp->index; + mgmt_hdr.vif_idx = vif_idx; mgmt_hdr.tidno = 0; mgmt_hdr.flags = 0; -- cgit v1.2.3-59-g8ed1b From 465c6cca2668a2db2a4ffce3dca5714017873f2b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 6 Aug 2010 03:26:24 -0400 Subject: tracing: Extend recordmcount to better support Blackfin mcount The mcount call on Blackfin systems includes some stack manipulation around the actual call site, so extend the build time perl script to support this. This way we can avoid doing the calculation at runtime. Signed-off-by: Mike Frysinger LKML-Reference: <1281079584-21205-1-git-send-email-vapier@gentoo.org> Signed-off-by: Steven Rostedt --- scripts/recordmcount.pl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index f3c9c0a90b98..2c56539e5da2 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -159,6 +159,7 @@ my $section_regex; # Find the start of a section my $function_regex; # Find the name of a function # (return offset and func name) my $mcount_regex; # Find the call site to mcount (return offset) +my $mcount_adjust; # Address adjustment to mcount offset my $alignment; # The .align value to use for $mcount_section my $section_type; # Section header plus possible alignment command my $can_use_local = 0; # If we can use local function references @@ -213,6 +214,7 @@ $section_regex = "Disassembly of section\\s+(\\S+):"; $function_regex = "^([0-9a-fA-F]+)\\s+<(.*?)>:"; $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\smcount\$"; $section_type = '@progbits'; +$mcount_adjust = 0; $type = ".long"; if ($arch eq "x86_64") { @@ -351,6 +353,9 @@ if ($arch eq "x86_64") { } elsif ($arch eq "microblaze") { # Microblaze calls '_mcount' instead of plain 'mcount'. $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; +} elsif ($arch eq "blackfin") { + $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; + $mcount_adjust = -4; } else { die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; } @@ -511,7 +516,7 @@ while () { } # is this a call site to mcount? If so, record it to print later if ($text_found && /$mcount_regex/) { - push(@offsets, hex $1); + push(@offsets, (hex $1) + $mcount_adjust); } } -- cgit v1.2.3-59-g8ed1b From 2a37a3df57c44e947271758a1aa4bea7bff9feab Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 3 Jun 2010 15:21:34 -0400 Subject: tracing/events: Convert format output to seq_file Two new events were added that broke the current format output. Both from the SCSI system: scsi_dispatch_cmd_done and scsi_dispatch_cmd_timeout The reason is that their print_fmt exceeded a page size. Since the output of the format used simple_read_from_buffer and trace_seq, it was limited to a page size in output. This patch converts the printing of the format of an event into seq_file, which allows greater than a page size to be shown. I diffed all event formats comparing the output with and without this patch. All matched except for the above two, which showed just: FORMAT TOO BIG without this patch, but now properly displays the output with this patch. v2: Remove updating *pos in seq start function. [ Thanks to Li Zefan for pointing that out ] Reviewed-by: Li Zefan Cc: Martin K. Petersen Cc: Kei Tokunaga Cc: James Bottomley Cc: Tomohiro Kusumi Cc: Xiao Guangrong Signed-off-by: Steven Rostedt --- kernel/trace/trace_events.c | 208 ++++++++++++++++++++++++++++++-------------- 1 file changed, 141 insertions(+), 67 deletions(-) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 53cffc0b0801..45a8968707aa 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -29,6 +29,8 @@ DEFINE_MUTEX(event_mutex); LIST_HEAD(ftrace_events); +#define COMMON_FIELD_COUNT 5 + struct list_head * trace_get_fields(struct ftrace_event_call *event_call) { @@ -544,85 +546,155 @@ out: return ret; } -static ssize_t -event_format_read(struct file *filp, char __user *ubuf, size_t cnt, - loff_t *ppos) +enum { + FORMAT_HEADER = 1, + FORMAT_PRINTFMT = 2, +}; + +static void *f_next(struct seq_file *m, void *v, loff_t *pos) { - struct ftrace_event_call *call = filp->private_data; + struct ftrace_event_call *call = m->private; struct ftrace_event_field *field; struct list_head *head; - struct trace_seq *s; - int common_field_count = 5; - char *buf; - int r = 0; - - if (*ppos) - return 0; + loff_t index = *pos; - s = kmalloc(sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; + (*pos)++; - trace_seq_init(s); + head = trace_get_fields(call); - trace_seq_printf(s, "name: %s\n", call->name); - trace_seq_printf(s, "ID: %d\n", call->event.type); - trace_seq_printf(s, "format:\n"); + switch ((unsigned long)v) { + case FORMAT_HEADER: - head = trace_get_fields(call); - list_for_each_entry_reverse(field, head, link) { - /* - * Smartly shows the array type(except dynamic array). - * Normal: - * field:TYPE VAR - * If TYPE := TYPE[LEN], it is shown: - * field:TYPE VAR[LEN] - */ - const char *array_descriptor = strchr(field->type, '['); - - if (!strncmp(field->type, "__data_loc", 10)) - array_descriptor = NULL; - - if (!array_descriptor) { - r = trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" - "\tsize:%u;\tsigned:%d;\n", - field->type, field->name, field->offset, - field->size, !!field->is_signed); - } else { - r = trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" - "\tsize:%u;\tsigned:%d;\n", - (int)(array_descriptor - field->type), - field->type, field->name, - array_descriptor, field->offset, - field->size, !!field->is_signed); - } + if (unlikely(list_empty(head))) + return NULL; - if (--common_field_count == 0) - r = trace_seq_printf(s, "\n"); + field = list_entry(head->prev, struct ftrace_event_field, link); + return field; - if (!r) - break; + case FORMAT_PRINTFMT: + /* all done */ + return NULL; } - if (r) - r = trace_seq_printf(s, "\nprint fmt: %s\n", - call->print_fmt); + /* + * To separate common fields from event fields, the + * LSB is set on the first event field. Clear it in case. + */ + v = (void *)((unsigned long)v & ~1L); - if (!r) { - /* - * ug! The format output is bigger than a PAGE!! - */ - buf = "FORMAT TOO BIG\n"; - r = simple_read_from_buffer(ubuf, cnt, ppos, - buf, strlen(buf)); - goto out; + field = v; + if (field->link.prev == head) + return (void *)FORMAT_PRINTFMT; + + field = list_entry(field->link.prev, struct ftrace_event_field, link); + + /* Set the LSB to notify f_show to print an extra newline */ + if (index == COMMON_FIELD_COUNT) + field = (struct ftrace_event_field *) + ((unsigned long)field | 1); + + return field; +} + +static void *f_start(struct seq_file *m, loff_t *pos) +{ + loff_t l = 0; + void *p; + + /* Start by showing the header */ + if (!*pos) + return (void *)FORMAT_HEADER; + + p = (void *)FORMAT_HEADER; + do { + p = f_next(m, p, &l); + } while (p && l < *pos); + + return p; +} + +static int f_show(struct seq_file *m, void *v) +{ + struct ftrace_event_call *call = m->private; + struct ftrace_event_field *field; + const char *array_descriptor; + + switch ((unsigned long)v) { + case FORMAT_HEADER: + seq_printf(m, "name: %s\n", call->name); + seq_printf(m, "ID: %d\n", call->event.type); + seq_printf(m, "format:\n"); + return 0; + + case FORMAT_PRINTFMT: + seq_printf(m, "\nprint fmt: %s\n", + call->print_fmt); + return 0; } - r = simple_read_from_buffer(ubuf, cnt, ppos, - s->buffer, s->len); - out: - kfree(s); - return r; + /* + * To separate common fields from event fields, the + * LSB is set on the first event field. Clear it and + * print a newline if it is set. + */ + if ((unsigned long)v & 1) { + seq_putc(m, '\n'); + v = (void *)((unsigned long)v & ~1L); + } + + field = v; + + /* + * Smartly shows the array type(except dynamic array). + * Normal: + * field:TYPE VAR + * If TYPE := TYPE[LEN], it is shown: + * field:TYPE VAR[LEN] + */ + array_descriptor = strchr(field->type, '['); + + if (!strncmp(field->type, "__data_loc", 10)) + array_descriptor = NULL; + + if (!array_descriptor) + seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", + field->type, field->name, field->offset, + field->size, !!field->is_signed); + else + seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", + (int)(array_descriptor - field->type), + field->type, field->name, + array_descriptor, field->offset, + field->size, !!field->is_signed); + + return 0; +} + +static void f_stop(struct seq_file *m, void *p) +{ +} + +static const struct seq_operations trace_format_seq_ops = { + .start = f_start, + .next = f_next, + .stop = f_stop, + .show = f_show, +}; + +static int trace_format_open(struct inode *inode, struct file *file) +{ + struct ftrace_event_call *call = inode->i_private; + struct seq_file *m; + int ret; + + ret = seq_open(file, &trace_format_seq_ops); + if (ret < 0) + return ret; + + m = file->private_data; + m->private = call; + + return 0; } static ssize_t @@ -820,8 +892,10 @@ static const struct file_operations ftrace_enable_fops = { }; static const struct file_operations ftrace_event_format_fops = { - .open = tracing_open_generic, - .read = event_format_read, + .open = trace_format_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, }; static const struct file_operations ftrace_event_id_fops = { -- cgit v1.2.3-59-g8ed1b From 7032269e87ade34cc12891675371fa2ac150a620 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Thu, 12 Aug 2010 19:07:40 -0400 Subject: HID: hiddev: protect against disconnect/NULL-dereference race One of our users reports consistently hitting a NULL dereference that resolves to the "hid_to_usb_dev(hid);" call in hiddev_ioctl(), when disconnecting a Lego WeDo USB HID device from an OLPC XO running Scratch software. There's a FIXME comment and a guard against the dereference, but that happens farther down the function than the initial dereference does. This patch moves the call to be below the guard, and the user reports that it fixes the problem for him. OLPC bug report: http://dev.laptop.org/ticket/10174 Signed-off-by: Chris Ball Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 254a003af048..f2850171a69b 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -587,7 +587,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; - struct usb_device *dev = hid_to_usb_dev(hid); + struct usb_device *dev; struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; @@ -601,9 +601,11 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* Called without BKL by compat methods so no BKL taken */ /* FIXME: Who or what stop this racing with a disconnect ?? */ - if (!hiddev->exist) + if (!hiddev->exist || !hid) return -EIO; + dev = hid_to_usb_dev(hid); + switch (cmd) { case HIDIOCGVERSION: -- cgit v1.2.3-59-g8ed1b From 9c9e54a8df0be48aa359744f412377cc55c3b7d2 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 13 Aug 2010 12:19:45 +0200 Subject: HID: hiddev: fix memory corruption due to invalid intfdata Commit bd25f4dd6972755579d0 ("HID: hiddev: use usb_find_interface, get rid of BKL") introduced using of private intfdata in hiddev for purpose of storing hiddev pointer. This is a problem, because intf pointer is already being set to struct hid_device pointer by HID core. This obviously lead to memory corruptions at device disconnect time, such as WARNING: at lib/kobject.c:595 kobject_put+0x37/0x4b() kobject: '(null)' (ffff88011e9cd898): is not initialized, yet kobject_put() is being called. Convert hiddev into accessing hiddev through struct hid_device which is in intfdata already. Reported-and-tested-by: Markus Trippelsdorf Reported-and-tested-by: Heinz Diehl Reported-and-tested-by: Alan Ott Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index f2850171a69b..0a29c51114aa 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -266,13 +266,15 @@ static int hiddev_open(struct inode *inode, struct file *file) { struct hiddev_list *list; struct usb_interface *intf; + struct hid_device *hid; struct hiddev *hiddev; int res; intf = usb_find_interface(&hiddev_driver, iminor(inode)); if (!intf) return -ENODEV; - hiddev = usb_get_intfdata(intf); + hid = usb_get_intfdata(intf); + hiddev = hid->hiddev; if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) return -ENOMEM; @@ -890,7 +892,6 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) hid->hiddev = hiddev; hiddev->hid = hid; hiddev->exist = 1; - usb_set_intfdata(usbhid->intf, usbhid); retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { err_hid("Not able to get a minor for this device."); -- cgit v1.2.3-59-g8ed1b From 495311927ffbe3604e915aeafdf03325e9925b9d Mon Sep 17 00:00:00 2001 From: René Herman Date: Wed, 11 Aug 2010 13:08:06 +0200 Subject: ALSA: ISA: New Aztech Sound Galaxy driver This is a new driver for Aztech Sound Galaxy ISA soundcards based on the AZT1605 and AZT2316 chipsets. It's constructed as two seperate drivers for either chipset generated from the same source file, with (very) minimal ifdeffery. The drivers check the SB DSP version to decide if they are being loaded for the right chip. AZT1605 returns 2.1 by default and AZT2316 3.1. This isn't full-proof as the DSP version can actually be set through software but it's close enough -- as far as I've been able to see, the DSP version can not be stored in the EEPROM and the cards will therefore startup with the defaults. This distinction could (with the same success rate) also be used to decide which chip we're looking at at runtime meaning a single, merged driver is also an option but I feel it's actually nicer this way. A merged driver would have to postpone translating the passed in resource values to the card configuration until it knew which one it was looking at and would need to postpone erring out on mpu_irq=10 for azt1605 and mpu_irq=3 for azt2316. The drivers have been tested on various cards. For snd-azt1605: FCC-ID I38-MMSN811: Aztech Sound Galaxy Nova 16 Extra FCC-ID I38-MMSN822: Aztech Sound Galaxy Pro 16 II and for snd-azt2316: FCC-ID I38-MMSN824: Aztech Sound Galaxy Pro 16 AB FCC-ID I38-MMSN826: Trust Sound Expert DeLuxe Wave 32 (05201) FCC-ID I38-MMSN830: Trust Sound Expert DeLuxe 16+ (05202) FCC-ID I38-MMSN837: Packard Bell ISA Soundcard 030069 FCC-ID I38-MMSN846: Trust Sound Expert DeLuxe 16-3D (06300) FCC-ID I38-MMSN847: Trust Sound Expert DeLuxe Wave 32-3D (06301) FCC-ID I38-MMSN852: Aztech Sound Galaxy Waverider Pro 32-3D 826 and 846 were also marketed directly by Aztech and then known as: FCC-ID I38-MMSN826: Aztech Sound Galaxy Waverider 32+ FCC-ID I38-MMSN846: Aztech Sound Galaxy Nova 16 Extra II-3D Together, these cover the AZT1605 and AT2316A, AZT2316R and AZT2316-S chipsets. All cards work fully -- full-duplex PCM, MIDI and FM. Full duplex is a little flaky on some. I38-MSN811 tends to not work in full-duplex but sometimes does with the highest success rate being achieved when you first start the capture and then a playback instead of the other way around (it's a CS4231-KL codec). The cards with an AD1845XP codec (my I38-MMSN826 and one of my I38-MMSN830s) are also somewhat duplex-challenged. Sometimes full-duplex works, sometimes not and this varies from try to try. This seems likely to be a timing problem somewhere inside wss-lib. I38-MMSN826 has an additional "ICS2115 WaveFront" wavetable synth onboard that isn't supported yet. The wavetable synths on I38-MMSN847 and I38-MMSN852 are wired directly to the standard MPU-401 UART and the AUX1 input on the codec and work without problem. CD-ROM audio on the cards is routed to the codec "Line" input, Line-In to its Aux input, and FM/Wavetable to its AUX1 input. I did not rename the controls due to the capture source enumeration: I see that capture-source overrides are hardcoded in wss-lib and this is just too ugly to live. Versus the old snd-sgalaxy driver these drivers add support for the models without a configuration EEPROM (which are common), full-duplex, MPU-401 UART and OPL3. In the future they might grow support for that ICS2115 WaveFront synth on 826 and an hwdep interface to write to the EEPROM on the models that have one. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 68 +++ sound/isa/Kconfig | 26 + sound/isa/Makefile | 2 +- sound/isa/galaxy/Makefile | 10 + sound/isa/galaxy/azt1605.c | 91 ++++ sound/isa/galaxy/azt2316.c | 111 ++++ sound/isa/galaxy/galaxy.c | 652 ++++++++++++++++++++++++ 7 files changed, 959 insertions(+), 1 deletion(-) create mode 100644 sound/isa/galaxy/Makefile create mode 100644 sound/isa/galaxy/azt1605.c create mode 100644 sound/isa/galaxy/azt2316.c create mode 100644 sound/isa/galaxy/galaxy.c diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7f4dcebda9c6..e25555c02166 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. control correctly. If you have problems regarding this, try another ALSA compliant mixer (alsamixer works). + Module snd-azt1605 + ------------------ + + Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605 + chipset. + + port - port # for BASE (0x220,0x240,0x260,0x280) + wss_port - port # for WSS (0x530,0x604,0xe80,0xf40) + irq - IRQ # for WSS (7,9,10,11) + dma1 - DMA # for WSS playback (0,1,3) + dma2 - DMA # for WSS capture (0,1), -1 = disabled (default) + mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default) + mpu_irq - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default) + fm_port - port # for OPL3 (0x388), -1 = disabled (default) + + This module supports multiple cards. It does not support autoprobe: port, + wss_port, irq and dma1 have to be specified. The other values are + optional. + + "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240) + or the value stored in the card's EEPROM for cards that have an EEPROM and + their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can + be choosen freely from the options enumerated above. + + If dma2 is specified and different from dma1, the card will operate in + full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to + enable capture since only channels 0 and 1 are available for capture. + + Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0 + mpu_port=0x330 mpu_irq=9 fm_port=0x388". + + Whatever IRQ and DMA channels you pick, be sure to reserve them for + legacy ISA in your BIOS. + + Module snd-azt2316 + ------------------ + + Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316 + chipset. + + port - port # for BASE (0x220,0x240,0x260,0x280) + wss_port - port # for WSS (0x530,0x604,0xe80,0xf40) + irq - IRQ # for WSS (7,9,10,11) + dma1 - DMA # for WSS playback (0,1,3) + dma2 - DMA # for WSS capture (0,1), -1 = disabled (default) + mpu_port - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default) + mpu_irq - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default) + fm_port - port # for OPL3 (0x388), -1 = disabled (default) + + This module supports multiple cards. It does not support autoprobe: port, + wss_port, irq and dma1 have to be specified. The other values are + optional. + + "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240) + or the value stored in the card's EEPROM for cards that have an EEPROM and + their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can + be choosen freely from the options enumerated above. + + If dma2 is specified and different from dma1, the card will operate in + full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to + enable capture since only channels 0 and 1 are available for capture. + + Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0 + mpu_port=0x330 mpu_irq=9 fm_port=0x388". + + Whatever IRQ and DMA channels you pick, be sure to reserve them for + legacy ISA in your BIOS. + Module snd-aw2 -------------- diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index c6990c680796..f9aa13d8dacc 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -77,6 +77,32 @@ config SND_ALS100 To compile this driver as a module, choose M here: the module will be called snd-als100. +config SND_AZT1605 + tristate "Aztech AZT1605 Driver" + depends on SND + select SND_WSS_LIB + select SND_MPU401_UART + select SND_OPL3_LIB + help + Say Y here to include support for Aztech Sound Galaxy cards + based on the AZT1605 chipset. + + To compile this driver as a module, choose M here: the module + will be called snd-azt1605. + +config SND_AZT2316 + tristate "Aztech AZT2316 Driver" + depends on SND + select SND_WSS_LIB + select SND_MPU401_UART + select SND_OPL3_LIB + help + Say Y here to include support for Aztech Sound Galaxy cards + based on the AZT2316 chipset. + + To compile this driver as a module, choose M here: the module + will be called snd-azt2316. + config SND_AZT2320 tristate "Aztech Systems AZT2320" depends on PNP diff --git a/sound/isa/Makefile b/sound/isa/Makefile index c73d30c4f462..d2bd8f536dd8 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -24,5 +24,5 @@ obj-$(CONFIG_SND_SC6000) += snd-sc6000.o obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o -obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \ +obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \ sb/ wavefront/ wss/ diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile new file mode 100644 index 000000000000..e307066d4315 --- /dev/null +++ b/sound/isa/galaxy/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela +# + +snd-azt1605-objs := azt1605.o +snd-azt2316-objs := azt2316.o + +obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o +obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c new file mode 100644 index 000000000000..9a97643cb713 --- /dev/null +++ b/sound/isa/galaxy/azt1605.c @@ -0,0 +1,91 @@ +/* + * Aztech AZT1605 Driver + * Copyright (C) 2007,2010 Rene Herman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#define AZT1605 + +#define CRD_NAME "Aztech AZT1605" +#define DRV_NAME "AZT1605" +#define DEV_NAME "azt1605" + +#define GALAXY_DSP_MAJOR 2 +#define GALAXY_DSP_MINOR 1 + +#define GALAXY_CONFIG_SIZE 3 + +/* + * 24-bit config register + */ + +#define GALAXY_CONFIG_SBA_220 (0 << 0) +#define GALAXY_CONFIG_SBA_240 (1 << 0) +#define GALAXY_CONFIG_SBA_260 (2 << 0) +#define GALAXY_CONFIG_SBA_280 (3 << 0) +#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 + +#define GALAXY_CONFIG_MPUA_300 (0 << 2) +#define GALAXY_CONFIG_MPUA_330 (1 << 2) + +#define GALAXY_CONFIG_MPU_ENABLE (1 << 3) + +#define GALAXY_CONFIG_GAME_ENABLE (1 << 4) + +#define GALAXY_CONFIG_CD_PANASONIC (1 << 5) +#define GALAXY_CONFIG_CD_MITSUMI (1 << 6) +#define GALAXY_CONFIG_CD_MASK (\ + GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI) + +#define GALAXY_CONFIG_UNUSED (1 << 7) +#define GALAXY_CONFIG_UNUSED_MASK GALAXY_CONFIG_UNUSED + +#define GALAXY_CONFIG_SBIRQ_2 (1 << 8) +#define GALAXY_CONFIG_SBIRQ_3 (1 << 9) +#define GALAXY_CONFIG_SBIRQ_5 (1 << 10) +#define GALAXY_CONFIG_SBIRQ_7 (1 << 11) + +#define GALAXY_CONFIG_MPUIRQ_2 (1 << 12) +#define GALAXY_CONFIG_MPUIRQ_3 (1 << 13) +#define GALAXY_CONFIG_MPUIRQ_5 (1 << 14) +#define GALAXY_CONFIG_MPUIRQ_7 (1 << 15) + +#define GALAXY_CONFIG_WSSA_530 (0 << 16) +#define GALAXY_CONFIG_WSSA_604 (1 << 16) +#define GALAXY_CONFIG_WSSA_E80 (2 << 16) +#define GALAXY_CONFIG_WSSA_F40 (3 << 16) + +#define GALAXY_CONFIG_WSS_ENABLE (1 << 18) + +#define GALAXY_CONFIG_CDIRQ_11 (1 << 19) +#define GALAXY_CONFIG_CDIRQ_12 (1 << 20) +#define GALAXY_CONFIG_CDIRQ_15 (1 << 21) +#define GALAXY_CONFIG_CDIRQ_MASK (\ + GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\ + GALAXY_CONFIG_CDIRQ_15) + +#define GALAXY_CONFIG_CDDMA_DISABLE (0 << 22) +#define GALAXY_CONFIG_CDDMA_0 (1 << 22) +#define GALAXY_CONFIG_CDDMA_1 (2 << 22) +#define GALAXY_CONFIG_CDDMA_3 (3 << 22) +#define GALAXY_CONFIG_CDDMA_MASK GALAXY_CONFIG_CDDMA_3 + +#define GALAXY_CONFIG_MASK (\ + GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\ + GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\ + GALAXY_CONFIG_CDDMA_MASK) + +#include "galaxy.c" diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c new file mode 100644 index 000000000000..189441141df6 --- /dev/null +++ b/sound/isa/galaxy/azt2316.c @@ -0,0 +1,111 @@ +/* + * Aztech AZT2316 Driver + * Copyright (C) 2007,2010 Rene Herman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#define AZT2316 + +#define CRD_NAME "Aztech AZT2316" +#define DRV_NAME "AZT2316" +#define DEV_NAME "azt2316" + +#define GALAXY_DSP_MAJOR 3 +#define GALAXY_DSP_MINOR 1 + +#define GALAXY_CONFIG_SIZE 4 + +/* + * 32-bit config register + */ + +#define GALAXY_CONFIG_SBA_220 (0 << 0) +#define GALAXY_CONFIG_SBA_240 (1 << 0) +#define GALAXY_CONFIG_SBA_260 (2 << 0) +#define GALAXY_CONFIG_SBA_280 (3 << 0) +#define GALAXY_CONFIG_SBA_MASK GALAXY_CONFIG_SBA_280 + +#define GALAXY_CONFIG_SBIRQ_2 (1 << 2) +#define GALAXY_CONFIG_SBIRQ_5 (1 << 3) +#define GALAXY_CONFIG_SBIRQ_7 (1 << 4) +#define GALAXY_CONFIG_SBIRQ_10 (1 << 5) + +#define GALAXY_CONFIG_SBDMA_DISABLE (0 << 6) +#define GALAXY_CONFIG_SBDMA_0 (1 << 6) +#define GALAXY_CONFIG_SBDMA_1 (2 << 6) +#define GALAXY_CONFIG_SBDMA_3 (3 << 6) + +#define GALAXY_CONFIG_WSSA_530 (0 << 8) +#define GALAXY_CONFIG_WSSA_604 (1 << 8) +#define GALAXY_CONFIG_WSSA_E80 (2 << 8) +#define GALAXY_CONFIG_WSSA_F40 (3 << 8) + +#define GALAXY_CONFIG_WSS_ENABLE (1 << 10) + +#define GALAXY_CONFIG_GAME_ENABLE (1 << 11) + +#define GALAXY_CONFIG_MPUA_300 (0 << 12) +#define GALAXY_CONFIG_MPUA_330 (1 << 12) + +#define GALAXY_CONFIG_MPU_ENABLE (1 << 13) + +#define GALAXY_CONFIG_CDA_310 (0 << 14) +#define GALAXY_CONFIG_CDA_320 (1 << 14) +#define GALAXY_CONFIG_CDA_340 (2 << 14) +#define GALAXY_CONFIG_CDA_350 (3 << 14) +#define GALAXY_CONFIG_CDA_MASK GALAXY_CONFIG_CDA_350 + +#define GALAXY_CONFIG_CD_DISABLE (0 << 16) +#define GALAXY_CONFIG_CD_PANASONIC (1 << 16) +#define GALAXY_CONFIG_CD_SONY (2 << 16) +#define GALAXY_CONFIG_CD_MITSUMI (3 << 16) +#define GALAXY_CONFIG_CD_AZTECH (4 << 16) +#define GALAXY_CONFIG_CD_UNUSED_5 (5 << 16) +#define GALAXY_CONFIG_CD_UNUSED_6 (6 << 16) +#define GALAXY_CONFIG_CD_UNUSED_7 (7 << 16) +#define GALAXY_CONFIG_CD_MASK GALAXY_CONFIG_CD_UNUSED_7 + +#define GALAXY_CONFIG_CDDMA8_DISABLE (0 << 20) +#define GALAXY_CONFIG_CDDMA8_0 (1 << 20) +#define GALAXY_CONFIG_CDDMA8_1 (2 << 20) +#define GALAXY_CONFIG_CDDMA8_3 (3 << 20) +#define GALAXY_CONFIG_CDDMA8_MASK GALAXY_CONFIG_CDDMA8_3 + +#define GALAXY_CONFIG_CDDMA16_DISABLE (0 << 22) +#define GALAXY_CONFIG_CDDMA16_5 (1 << 22) +#define GALAXY_CONFIG_CDDMA16_6 (2 << 22) +#define GALAXY_CONFIG_CDDMA16_7 (3 << 22) +#define GALAXY_CONFIG_CDDMA16_MASK GALAXY_CONFIG_CDDMA16_7 + +#define GALAXY_CONFIG_MPUIRQ_2 (1 << 24) +#define GALAXY_CONFIG_MPUIRQ_5 (1 << 25) +#define GALAXY_CONFIG_MPUIRQ_7 (1 << 26) +#define GALAXY_CONFIG_MPUIRQ_10 (1 << 27) + +#define GALAXY_CONFIG_CDIRQ_5 (1 << 28) +#define GALAXY_CONFIG_CDIRQ_11 (1 << 29) +#define GALAXY_CONFIG_CDIRQ_12 (1 << 30) +#define GALAXY_CONFIG_CDIRQ_15 (1 << 31) +#define GALAXY_CONFIG_CDIRQ_MASK (\ + GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\ + GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15) + +#define GALAXY_CONFIG_MASK (\ + GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\ + GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\ + GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK) + +#include "galaxy.c" diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c new file mode 100644 index 000000000000..ee54df082b9c --- /dev/null +++ b/sound/isa/galaxy/galaxy.c @@ -0,0 +1,652 @@ +/* + * Aztech AZT1605/AZT2316 Driver + * Copyright (C) 2007,2010 Rene Herman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION(CRD_NAME); +MODULE_AUTHOR("Rene Herman"); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); + +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; + +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); +module_param_array(wss_port, long, NULL, 0444); +MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver."); +module_param_array(mpu_port, long, NULL, 0444); +MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); +module_param_array(fm_port, long, NULL, 0444); +MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver."); +module_param_array(irq, int, NULL, 0444); +MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); +module_param_array(mpu_irq, int, NULL, 0444); +MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); +module_param_array(dma1, int, NULL, 0444); +MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); +module_param_array(dma2, int, NULL, 0444); +MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); + +/* + * Generic SB DSP support routines + */ + +#define DSP_PORT_RESET 0x6 +#define DSP_PORT_READ 0xa +#define DSP_PORT_COMMAND 0xc +#define DSP_PORT_STATUS 0xc +#define DSP_PORT_DATA_AVAIL 0xe + +#define DSP_SIGNATURE 0xaa + +#define DSP_COMMAND_GET_VERSION 0xe1 + +static int __devinit dsp_get_byte(void __iomem *port, u8 *val) +{ + int loops = 1000; + + while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) { + if (!loops--) + return -EIO; + cpu_relax(); + } + *val = ioread8(port + DSP_PORT_READ); + return 0; +} + +static int __devinit dsp_reset(void __iomem *port) +{ + u8 val; + + iowrite8(1, port + DSP_PORT_RESET); + udelay(10); + iowrite8(0, port + DSP_PORT_RESET); + + if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE) + return -ENODEV; + + return 0; +} + +static int __devinit dsp_command(void __iomem *port, u8 cmd) +{ + int loops = 1000; + + while (ioread8(port + DSP_PORT_STATUS) & 0x80) { + if (!loops--) + return -EIO; + cpu_relax(); + } + iowrite8(cmd, port + DSP_PORT_COMMAND); + return 0; +} + +static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor) +{ + int err; + + err = dsp_command(port, DSP_COMMAND_GET_VERSION); + if (err < 0) + return err; + + err = dsp_get_byte(port, major); + if (err < 0) + return err; + + err = dsp_get_byte(port, minor); + if (err < 0) + return err; + + return 0; +} + +/* + * Generic WSS support routines + */ + +#define WSS_CONFIG_DMA_0 (1 << 0) +#define WSS_CONFIG_DMA_1 (2 << 0) +#define WSS_CONFIG_DMA_3 (3 << 0) +#define WSS_CONFIG_DUPLEX (1 << 2) +#define WSS_CONFIG_IRQ_7 (1 << 3) +#define WSS_CONFIG_IRQ_9 (2 << 3) +#define WSS_CONFIG_IRQ_10 (3 << 3) +#define WSS_CONFIG_IRQ_11 (4 << 3) + +#define WSS_PORT_CONFIG 0 +#define WSS_PORT_SIGNATURE 3 + +#define WSS_SIGNATURE 4 + +static int __devinit wss_detect(void __iomem *wss_port) +{ + if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) + return -ENODEV; + + return 0; +} + +static void wss_set_config(void __iomem *wss_port, u8 wss_config) +{ + iowrite8(wss_config, wss_port + WSS_PORT_CONFIG); +} + +/* + * Aztech Sound Galaxy specifics + */ + +#define GALAXY_PORT_CONFIG 1024 +#define CONFIG_PORT_SET 4 + +#define DSP_COMMAND_GALAXY_8 8 +#define GALAXY_COMMAND_GET_TYPE 5 + +#define DSP_COMMAND_GALAXY_9 9 +#define GALAXY_COMMAND_WSSMODE 0 +#define GALAXY_COMMAND_SB8MODE 1 + +#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE +#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE + +struct snd_galaxy { + void __iomem *port; + void __iomem *config_port; + void __iomem *wss_port; + u32 config; + struct resource *res_port; + struct resource *res_config_port; + struct resource *res_wss_port; +}; + +static u32 config[SNDRV_CARDS]; +static u8 wss_config[SNDRV_CARDS]; + +static int __devinit snd_galaxy_match(struct device *dev, unsigned int n) +{ + if (!enable[n]) + return 0; + + switch (port[n]) { + case SNDRV_AUTO_PORT: + dev_err(dev, "please specify port\n"); + return 0; + case 0x220: + config[n] |= GALAXY_CONFIG_SBA_220; + break; + case 0x240: + config[n] |= GALAXY_CONFIG_SBA_240; + break; + case 0x260: + config[n] |= GALAXY_CONFIG_SBA_260; + break; + case 0x280: + config[n] |= GALAXY_CONFIG_SBA_280; + break; + default: + dev_err(dev, "invalid port %#lx\n", port[n]); + return 0; + } + + switch (wss_port[n]) { + case SNDRV_AUTO_PORT: + dev_err(dev, "please specify wss_port\n"); + return 0; + case 0x530: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; + break; + case 0x604: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; + break; + case 0xe80: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; + break; + case 0xf40: + config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; + break; + default: + dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]); + return 0; + } + + switch (irq[n]) { + case SNDRV_AUTO_IRQ: + dev_err(dev, "please specify irq\n"); + return 0; + case 7: + wss_config[n] |= WSS_CONFIG_IRQ_7; + break; + case 2: + irq[n] = 9; + case 9: + wss_config[n] |= WSS_CONFIG_IRQ_9; + break; + case 10: + wss_config[n] |= WSS_CONFIG_IRQ_10; + break; + case 11: + wss_config[n] |= WSS_CONFIG_IRQ_11; + break; + default: + dev_err(dev, "invalid IRQ %d\n", irq[n]); + return 0; + } + + switch (dma1[n]) { + case SNDRV_AUTO_DMA: + dev_err(dev, "please specify dma1\n"); + return 0; + case 0: + wss_config[n] |= WSS_CONFIG_DMA_0; + break; + case 1: + wss_config[n] |= WSS_CONFIG_DMA_1; + break; + case 3: + wss_config[n] |= WSS_CONFIG_DMA_3; + break; + default: + dev_err(dev, "invalid playback DMA %d\n", dma1[n]); + return 0; + } + + if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { + dma2[n] = -1; + goto mpu; + } + + wss_config[n] |= WSS_CONFIG_DUPLEX; + switch (dma2[n]) { + case 0: + break; + case 1: + if (dma1[n] == 0) + break; + default: + dev_err(dev, "invalid capture DMA %d\n", dma2[n]); + return 0; + } + +mpu: + switch (mpu_port[n]) { + case SNDRV_AUTO_PORT: + dev_warn(dev, "mpu_port not specified; not using MPU-401\n"); + mpu_port[n] = -1; + goto fm; + case 0x300: + config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; + break; + case 0x330: + config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; + break; + default: + dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]); + return 0; + } + + switch (mpu_irq[n]) { + case SNDRV_AUTO_IRQ: + dev_warn(dev, "mpu_irq not specified: using polling mode\n"); + mpu_irq[n] = -1; + break; + case 2: + mpu_irq[n] = 9; + case 9: + config[n] |= GALAXY_CONFIG_MPUIRQ_2; + break; +#ifdef AZT1605 + case 3: + config[n] |= GALAXY_CONFIG_MPUIRQ_3; + break; +#endif + case 5: + config[n] |= GALAXY_CONFIG_MPUIRQ_5; + break; + case 7: + config[n] |= GALAXY_CONFIG_MPUIRQ_7; + break; +#ifdef AZT2316 + case 10: + config[n] |= GALAXY_CONFIG_MPUIRQ_10; + break; +#endif + default: + dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]); + return 0; + } + + if (mpu_irq[n] == irq[n]) { + dev_err(dev, "cannot share IRQ between WSS and MPU-401\n"); + return 0; + } + +fm: + switch (fm_port[n]) { + case SNDRV_AUTO_PORT: + dev_warn(dev, "fm_port not specified: not using OPL3\n"); + fm_port[n] = -1; + break; + case 0x388: + break; + default: + dev_err(dev, "illegal FM port %#lx\n", fm_port[n]); + return 0; + } + + config[n] |= GALAXY_CONFIG_GAME_ENABLE; + return 1; +} + +static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type) +{ + u8 major; + u8 minor; + int err; + + err = dsp_reset(galaxy->port); + if (err < 0) + return err; + + err = dsp_get_version(galaxy->port, &major, &minor); + if (err < 0) + return err; + + if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR) + return -ENODEV; + + err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8); + if (err < 0) + return err; + + err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE); + if (err < 0) + return err; + + err = dsp_get_byte(galaxy->port, type); + if (err < 0) + return err; + + return 0; +} + +static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) +{ + int err; + + err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9); + if (err < 0) + return err; + + err = dsp_command(galaxy->port, mode); + if (err < 0) + return err; + +#ifdef AZT1605 + /* + * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again + */ + err = dsp_reset(galaxy->port); + if (err < 0) + return err; +#endif + + return 0; +} + +static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) +{ + u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET); + int i; + + iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET); + for (i = 0; i < GALAXY_CONFIG_SIZE; i++) { + iowrite8(config, galaxy->config_port + i); + config >>= 8; + } + iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET); + msleep(10); +} + +static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config) +{ + int i; + + for (i = GALAXY_CONFIG_SIZE; i; i--) { + u8 tmp = ioread8(galaxy->config_port + i - 1); + galaxy->config = (galaxy->config << 8) | tmp; + } + config |= galaxy->config & GALAXY_CONFIG_MASK; + galaxy_set_config(galaxy, config); +} + +static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) +{ + int err; + + err = wss_detect(galaxy->wss_port); + if (err < 0) + return err; + + wss_set_config(galaxy->wss_port, wss_config); + + err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS); + if (err < 0) + return err; + + return 0; +} + +static void snd_galaxy_free(struct snd_card *card) +{ + struct snd_galaxy *galaxy = card->private_data; + + if (galaxy->wss_port) { + wss_set_config(galaxy->wss_port, 0); + ioport_unmap(galaxy->wss_port); + release_and_free_resource(galaxy->res_wss_port); + } + if (galaxy->config_port) { + galaxy_set_config(galaxy, galaxy->config); + ioport_unmap(galaxy->config_port); + release_and_free_resource(galaxy->res_config_port); + } + if (galaxy->port) { + ioport_unmap(galaxy->port); + release_and_free_resource(galaxy->res_port); + } +} + +static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n) +{ + struct snd_galaxy *galaxy; + struct snd_wss *chip; + struct snd_card *card; + u8 type; + int err; + + err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy, + &card); + if (err < 0) + return err; + + snd_card_set_dev(card, dev); + + card->private_free = snd_galaxy_free; + galaxy = card->private_data; + + galaxy->res_port = request_region(port[n], 16, DRV_NAME); + if (!galaxy->res_port) { + dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n], + port[n] + 15); + err = -EBUSY; + goto error; + } + galaxy->port = ioport_map(port[n], 16); + + err = galaxy_init(galaxy, &type); + if (err < 0) { + dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]); + goto error; + } + dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]); + + galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG, + 16, DRV_NAME); + if (!galaxy->res_config_port) { + dev_err(dev, "could not grab ports %#lx-%#lx\n", + port[n] + GALAXY_PORT_CONFIG, + port[n] + GALAXY_PORT_CONFIG + 15); + err = -EBUSY; + goto error; + } + galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16); + + galaxy_config(galaxy, config[n]); + + galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME); + if (!galaxy->res_wss_port) { + dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n], + wss_port[n] + 3); + err = -EBUSY; + goto error; + } + galaxy->wss_port = ioport_map(wss_port[n], 4); + + err = galaxy_wss_config(galaxy, wss_config[n]); + if (err < 0) { + dev_err(dev, "could not configure WSS\n"); + goto error; + } + + strcpy(card->driver, DRV_NAME); + strcpy(card->shortname, DRV_NAME); + sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", + card->shortname, port[n], wss_port[n], irq[n], dma1[n], + dma2[n]); + + err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], + dma2[n], WSS_HW_DETECT, 0, &chip); + if (err < 0) + goto error; + + err = snd_wss_pcm(chip, 0, NULL); + if (err < 0) + goto error; + + err = snd_wss_mixer(chip); + if (err < 0) + goto error; + + err = snd_wss_timer(chip, 0, NULL); + if (err < 0) + goto error; + + if (mpu_port[n] >= 0) { + err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port[n], 0, mpu_irq[n], + IRQF_DISABLED, NULL); + if (err < 0) + goto error; + } + + if (fm_port[n] >= 0) { + struct snd_opl3 *opl3; + + err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, + OPL3_HW_AUTO, 0, &opl3); + if (err < 0) { + dev_err(dev, "no OPL device at %#lx\n", fm_port[n]); + goto error; + } + err = snd_opl3_timer_new(opl3, 1, 2); + if (err < 0) + goto error; + + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) + goto error; + } + + err = snd_card_register(card); + if (err < 0) + goto error; + + dev_set_drvdata(dev, card); + return 0; + +error: + snd_card_free(card); + return err; +} + +static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n) +{ + snd_card_free(dev_get_drvdata(dev)); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct isa_driver snd_galaxy_driver = { + .match = snd_galaxy_match, + .probe = snd_galaxy_probe, + .remove = __devexit_p(snd_galaxy_remove), + + .driver = { + .name = DEV_NAME + } +}; + +static int __init alsa_card_galaxy_init(void) +{ + return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_galaxy_exit(void) +{ + isa_unregister_driver(&snd_galaxy_driver); +} + +module_init(alsa_card_galaxy_init); +module_exit(alsa_card_galaxy_exit); -- cgit v1.2.3-59-g8ed1b From cbaa9f60d5d5c3af10f94e0d49789d5b82341a4a Mon Sep 17 00:00:00 2001 From: René Herman Date: Fri, 13 Aug 2010 10:43:48 +0200 Subject: ALSA: ISA: Remove snd-sgalaxy Its hardware is handled more fully by the new azt1605/azt2316 drivers. Signed-off-by: Rene Herman Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 14 - sound/isa/Kconfig | 10 - sound/isa/Makefile | 2 - sound/isa/sgalaxy.c | 369 ------------------------ 4 files changed, 395 deletions(-) delete mode 100644 sound/isa/sgalaxy.c diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index e25555c02166..d0eb696d32e8 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1709,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This card is also known as Audio Excel DSP 16 or Zoltrix AV302. - Module snd-sgalaxy - ------------------ - - Module for Aztech Sound Galaxy sound card. - - sbport - Port # for SB16 interface (0x220,0x240) - wssport - Port # for WSS interface (0x530,0xe80,0xf40,0x604) - irq - IRQ # (7,9,10,11) - dma1 - DMA # - - This module supports multiple cards. - - The power-management is supported. - Module snd-sscape ----------------- diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index f9aa13d8dacc..52064cfa91f3 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -377,16 +377,6 @@ config SND_SB16_CSP coprocessor can do variable tasks like various compression and decompression algorithms. -config SND_SGALAXY - tristate "Aztech Sound Galaxy" - select SND_WSS_LIB - help - Say Y here to include support for Aztech Sound Galaxy - soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-sgalaxy. - config SND_SSCAPE tristate "Ensoniq SoundScape driver" select SND_MPU401_UART diff --git a/sound/isa/Makefile b/sound/isa/Makefile index d2bd8f536dd8..8d781e419e2e 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o snd-sc6000-objs := sc6000.o -snd-sgalaxy-objs := sgalaxy.o snd-sscape-objs := sscape.o # Toplevel Module Dependency @@ -21,7 +20,6 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o obj-$(CONFIG_SND_SC6000) += snd-sc6000.o -obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \ diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c deleted file mode 100644 index 6fe27b9d9440..000000000000 --- a/sound/isa/sgalaxy.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Driver for Aztech Sound Galaxy cards - * Copyright (c) by Christopher Butler -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define SNDRV_LEGACY_FIND_FREE_IRQ -#define SNDRV_LEGACY_FIND_FREE_DMA -#include - -MODULE_AUTHOR("Christopher Butler "); -MODULE_DESCRIPTION("Aztech Sound Galaxy"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}"); - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ -static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240 */ -static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */ -static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 7,9,10,11 */ -static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard."); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard."); -module_param_array(sbport, long, NULL, 0444); -MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver."); -module_param_array(wssport, long, NULL, 0444); -MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver."); -module_param_array(irq, int, NULL, 0444); -MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver."); -module_param_array(dma1, int, NULL, 0444); -MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver."); - -#define SGALAXY_AUXC_LEFT 18 -#define SGALAXY_AUXC_RIGHT 19 - -#define PFX "sgalaxy: " - -/* - - */ - -#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x ) - -/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */ -/* short time we actually need it.. */ - -static int snd_sgalaxy_sbdsp_reset(unsigned long port) -{ - int i; - - outb(1, SBP1(port, RESET)); - udelay(10); - outb(0, SBP1(port, RESET)); - udelay(30); - for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++); - if (inb(SBP1(port, READ)) != 0xaa) { - snd_printd("sb_reset: failed at 0x%lx!!!\n", port); - return -ENODEV; - } - return 0; -} - -static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port, - unsigned char val) -{ - int i; - - for (i = 10000; i; i--) - if ((inb(SBP1(port, STATUS)) & 0x80) == 0) { - outb(val, SBP1(port, COMMAND)); - return 1; - } - - return 0; -} - -static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id) -{ - return IRQ_NONE; -} - -static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) -{ - static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, - 0x10, 0x18, 0x20, -1, -1, -1, -1}; - static int dma_bits[] = {1, 2, 0, 3}; - int tmp, tmp1; - - if ((tmp = inb(port + 3)) == 0xff) - { - snd_printdd("I/O address dead (0x%lx)\n", port); - return 0; - } -#if 0 - snd_printdd("WSS signature = 0x%x\n", tmp); -#endif - - if ((tmp & 0x3f) != 0x04 && - (tmp & 0x3f) != 0x0f && - (tmp & 0x3f) != 0x00) { - snd_printdd("No WSS signature detected on port 0x%lx\n", - port + 3); - return 0; - } - -#if 0 - snd_printdd(PFX "setting up IRQ/DMA for WSS\n"); -#endif - - /* initialize IRQ for WSS codec */ - tmp = interrupt_bits[irq % 16]; - if (tmp < 0) - return -EINVAL; - - if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) { - snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq); - return -EIO; - } - - outb(tmp | 0x40, port); - tmp1 = dma_bits[dma % 4]; - outb(tmp | tmp1, port); - - free_irq(irq, NULL); - - return 0; -} - -static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma) -{ -#if 0 - snd_printdd(PFX "switching to WSS mode\n"); -#endif - - /* switch to WSS mode */ - snd_sgalaxy_sbdsp_reset(sbport[dev]); - - snd_sgalaxy_sbdsp_command(sbport[dev], 9); - snd_sgalaxy_sbdsp_command(sbport[dev], 0); - - udelay(400); - return snd_sgalaxy_setup_wss(wssport[dev], irq, dma); -} - -static struct snd_kcontrol_new snd_sgalaxy_controls[] = { -WSS_DOUBLE("Aux Playback Switch", 0, - SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0) -}; - -static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip) -{ - struct snd_card *card = chip->card; - struct snd_ctl_elem_id id1, id2; - unsigned int idx; - int err; - - memset(&id1, 0, sizeof(id1)); - memset(&id2, 0, sizeof(id2)); - id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - /* reassign AUX0 to LINE */ - strcpy(id1.name, "Aux Playback Switch"); - strcpy(id2.name, "Line Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "Line Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - /* reassign AUX1 to FM */ - strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; - strcpy(id2.name, "FM Playback Switch"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - strcpy(id1.name, "Aux Playback Volume"); - strcpy(id2.name, "FM Playback Volume"); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) - return err; - /* build AUX2 input */ - for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_sgalaxy_controls[idx], chip)); - if (err < 0) - return err; - } - return 0; -} - -static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev) -{ - if (!enable[dev]) - return 0; - if (sbport[dev] == SNDRV_AUTO_PORT) { - snd_printk(KERN_ERR PFX "specify SB port\n"); - return 0; - } - if (wssport[dev] == SNDRV_AUTO_PORT) { - snd_printk(KERN_ERR PFX "specify WSS port\n"); - return 0; - } - return 1; -} - -static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev) -{ - static int possible_irqs[] = {7, 9, 10, 11, -1}; - static int possible_dmas[] = {1, 3, 0, -1}; - int err, xirq, xdma1; - struct snd_card *card; - struct snd_wss *chip; - - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); - if (err < 0) - return err; - - xirq = irq[dev]; - if (xirq == SNDRV_AUTO_IRQ) { - if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); - err = -EBUSY; - goto _err; - } - } - xdma1 = dma1[dev]; - if (xdma1 == SNDRV_AUTO_DMA) { - if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); - err = -EBUSY; - goto _err; - } - } - - if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) - goto _err; - - err = snd_wss_create(card, wssport[dev] + 4, -1, - xirq, xdma1, -1, - WSS_HW_DETECT, 0, &chip); - if (err < 0) - goto _err; - card->private_data = chip; - - err = snd_wss_pcm(chip, 0, NULL); - if (err < 0) { - snd_printdd(PFX "error creating new WSS PCM device\n"); - goto _err; - } - err = snd_wss_mixer(chip); - if (err < 0) { - snd_printdd(PFX "error creating new WSS mixer\n"); - goto _err; - } - if ((err = snd_sgalaxy_mixer(chip)) < 0) { - snd_printdd(PFX "the mixer rewrite failed\n"); - goto _err; - } - - strcpy(card->driver, "Sound Galaxy"); - strcpy(card->shortname, "Sound Galaxy"); - sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d", - wssport[dev], xirq, xdma1); - - snd_card_set_dev(card, devptr); - - if ((err = snd_card_register(card)) < 0) - goto _err; - - dev_set_drvdata(devptr, card); - return 0; - - _err: - snd_card_free(card); - return err; -} - -static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev) -{ - snd_card_free(dev_get_drvdata(devptr)); - dev_set_drvdata(devptr, NULL); - return 0; -} - -#ifdef CONFIG_PM -static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n, - pm_message_t state) -{ - struct snd_card *card = dev_get_drvdata(pdev); - struct snd_wss *chip = card->private_data; - - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - chip->suspend(chip); - return 0; -} - -static int snd_sgalaxy_resume(struct device *pdev, unsigned int n) -{ - struct snd_card *card = dev_get_drvdata(pdev); - struct snd_wss *chip = card->private_data; - - chip->resume(chip); - snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); - snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); - - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - return 0; -} -#endif - -#define DEV_NAME "sgalaxy" - -static struct isa_driver snd_sgalaxy_driver = { - .match = snd_sgalaxy_match, - .probe = snd_sgalaxy_probe, - .remove = __devexit_p(snd_sgalaxy_remove), -#ifdef CONFIG_PM - .suspend = snd_sgalaxy_suspend, - .resume = snd_sgalaxy_resume, -#endif - .driver = { - .name = DEV_NAME - }, -}; - -static int __init alsa_card_sgalaxy_init(void) -{ - return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS); -} - -static void __exit alsa_card_sgalaxy_exit(void) -{ - isa_unregister_driver(&snd_sgalaxy_driver); -} - -module_init(alsa_card_sgalaxy_init) -module_exit(alsa_card_sgalaxy_exit) -- cgit v1.2.3-59-g8ed1b From 71ba186c123630ddab17667ec9ecf7e2ef211295 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Thu, 12 Aug 2010 14:23:28 +0530 Subject: ath9k_htc: Fix disconnect issue in HT40 mode. Some APs advertise that they may be HT40 capable in the capabilites but the current operating channel configuration may be only HT20. This causes disconnection as ath9k_htc sets WLAN_RC_40_FLAG despite the AP operating in HT20 mode. Hence set this flag only if the current channel configuration is HT40 enabled. Cc: stable@kernel.org Signed-off-by: Vivek Natarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index ebed9d1691a5..7d09b4b17bbd 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -366,7 +366,8 @@ static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv, caps = WLAN_RC_HT_FLAG; if (sta->ht_cap.mcs.rx_mask[1]) caps |= WLAN_RC_DS_FLAG; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && + (conf_is_ht40(&priv->hw->conf))) caps |= WLAN_RC_40_FLAG; if (conf_is_ht40(&priv->hw->conf) && (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) -- cgit v1.2.3-59-g8ed1b From fe0dbcc9d2e941328b3269dab102b94ad697ade5 Mon Sep 17 00:00:00 2001 From: Yuri Kululin Date: Fri, 13 Aug 2010 13:46:12 +0400 Subject: wl1251: fix trigger scan timeout usage Use appropriate command (CMD_TRIGGER_SCAN_TO) instead of scan command (CMD_SCAN) to configure trigger scan timeout. This was broken in commit 3a98c30f3e8bb1f32b5bcb74a39647b3670de275. This fix address the bug reported here: https://bugzilla.kernel.org/show_bug.cgi?id=16554 Cc: stable@kernel.org Signed-off-by: Yuri Ershov Signed-off-by: Yuri Kululin Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1251_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index a37b30cef489..ce3722f4c3e3 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c @@ -484,7 +484,7 @@ int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) cmd->timeout = timeout; - ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); + ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, cmd, sizeof(*cmd)); if (ret < 0) { wl1251_error("cmd trigger scan to failed: %d", ret); goto out; -- cgit v1.2.3-59-g8ed1b From ca6cff1f80f30cc6313a943339361ad6f9e76548 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 13 Aug 2010 18:36:40 +0530 Subject: ath9k_htc: load proper firmware for device ID 7015 This patch handles the firmware loading properly for device ID 7015. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.h | 1 + drivers/net/wireless/ath/ath9k/eeprom_9287.c | 7 ++++++- drivers/net/wireless/ath/ath9k/hif_usb.c | 8 ++------ drivers/net/wireless/ath/ath9k/htc_drv_init.c | 1 + drivers/net/wireless/ath/ath9k/reg.h | 1 + 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 8750c558c221..7f48df1e2903 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -191,6 +191,7 @@ #define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1 #define AR9287_EEP_START_LOC 128 +#define AR9287_HTC_EEP_START_LOC 256 #define AR9287_NUM_2G_CAL_PIERS 3 #define AR9287_NUM_2G_CCK_TARGET_POWERS 3 #define AR9287_NUM_2G_20_TARGET_POWERS 3 diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 4a52cf03808b..dff2da777312 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -34,9 +34,14 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) struct ar9287_eeprom *eep = &ah->eeprom.map9287; struct ath_common *common = ath9k_hw_common(ah); u16 *eep_data; - int addr, eep_start_loc = AR9287_EEP_START_LOC; + int addr, eep_start_loc; eep_data = (u16 *)eep; + if (ah->hw_version.devid == 0x7015) + eep_start_loc = AR9287_HTC_EEP_START_LOC; + else + eep_start_loc = AR9287_EEP_START_LOC; + if (!ath9k_hw_use_flash(ah)) { ath_print(common, ATH_DBG_EEPROM, "Reading from EEPROM, not flash\n"); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 61c1bee3f26a..17e7a9a367e7 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -799,7 +799,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) } kfree(buf); - if (hif_dev->device_id == 0x7010) + if ((hif_dev->device_id == 0x7010) || (hif_dev->device_id == 0x7015)) firm_offset = AR7010_FIRMWARE_TEXT; else firm_offset = AR9271_FIRMWARE_TEXT; @@ -901,6 +901,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, switch(hif_dev->device_id) { case 0x7010: + case 0x7015: case 0x9018: if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) hif_dev->fw_name = FIRMWARE_AR7010_1_1; @@ -912,11 +913,6 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, break; } - if (!hif_dev->fw_name) { - dev_err(&udev->dev, "Can't determine firmware !\n"); - goto err_htc_hw_alloc; - } - ret = ath9k_hif_usb_dev_init(hif_dev); if (ret) { ret = -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 148b43317fdb..2d4279191d7a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -245,6 +245,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid) switch(devid) { case 0x7010: + case 0x7015: case 0x9018: priv->htc->credits = 45; break; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 633e3d949ec0..d01c4adab8d6 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -899,6 +899,7 @@ #define AR_DEVID_7010(_ah) \ (((_ah)->hw_version.devid == 0x7010) || \ + ((_ah)->hw_version.devid == 0x7015) || \ ((_ah)->hw_version.devid == 0x9018)) #define AR_RADIO_SREV_MAJOR 0xf0 -- cgit v1.2.3-59-g8ed1b From 6ccf15a1a76d2ff915cdef6ae4d12d0170087118 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 13 Aug 2010 11:27:28 -0400 Subject: ath5k: disable ASPM L0s for all cards Atheros PCIe wireless cards handled by ath5k do require L0s disabled. For distributions shipping with CONFIG_PCIEASPM (this will be enabled by default in the future in 2.6.36) this will also mean both L1 and L0s will be disabled when a pre 1.1 PCIe device is detected. We do know L1 works correctly even for all ath5k pre 1.1 PCIe devices though but cannot currently undue the effect of a blacklist, for details you can read pcie_aspm_sanity_check() and see how it adjusts the device link capability. It may be possible in the future to implement some PCI API to allow drivers to override blacklists for pre 1.1 PCIe but for now it is best to accept that both L0s and L1 will be disabled completely for distributions shipping with CONFIG_PCIEASPM rather than having this issue present. Motivation for adding this new API will be to help with power consumption for some of these devices. Example of issues you'd see: - On the Acer Aspire One (AOA150, Atheros Communications Inc. AR5001 Wireless Network Adapter [168c:001c] (rev 01)) doesn't work well with ASPM enabled, the card will eventually stall on heavy traffic with often 'unsupported jumbo' warnings appearing. Disabling ASPM L0s in ath5k fixes these problems. - On the same card you would see a storm of RXORN interrupts even though medium is idle. Credit for root causing and fixing the bug goes to Jussi Kivilinna. Cc: David Quan Cc: Matthew Garrett Cc: Tim Gardner Cc: Jussi Kivilinna Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: Maxim Levitsky Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 0d5de2574dd1..373dcfec689c 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -476,6 +477,26 @@ ath5k_pci_probe(struct pci_dev *pdev, int ret; u8 csz; + /* + * L0s needs to be disabled on all ath5k cards. + * + * For distributions shipping with CONFIG_PCIEASPM (this will be enabled + * by default in the future in 2.6.36) this will also mean both L1 and + * L0s will be disabled when a pre 1.1 PCIe device is detected. We do + * know L1 works correctly even for all ath5k pre 1.1 PCIe devices + * though but cannot currently undue the effect of a blacklist, for + * details you can read pcie_aspm_sanity_check() and see how it adjusts + * the device link capability. + * + * It may be possible in the future to implement some PCI API to allow + * drivers to override blacklists for pre 1.1 PCIe but for now it is + * best to accept that both L0s and L1 will be disabled completely for + * distributions shipping with CONFIG_PCIEASPM rather than having this + * issue present. Motivation for adding this new API will be to help + * with power consumption for some of these devices. + */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S); + ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "can't enable device\n"); -- cgit v1.2.3-59-g8ed1b From 1aa54bca6ee0d07ebcafb8ca8074b624d80724aa Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Wed, 28 Jul 2010 01:18:01 +0200 Subject: tracing: Sanitize value returned from write(trace_marker, "...", len) When userspace code writes non-new-line-terminated string to trace_marker file, write handler appends new-line and returns number of bytes written to trace buffer, so write(fd, "abc", 3) will return 4 That's unexpected and unfortunately it confuses glibc's fprintf function. Example: int main() { fprintf(stderr, "abc"); return 0; } $ gcc test.c -o test $ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer $ ./test 2>/sys/kernel/debug/tracing/trace_marker results in infinite loop: write(fd, "abc", 3) = 4 write(fd, "", 1) = 0 write(fd, "", 1) = 0 write(fd, "", 1) = 0 write(fd, "", 1) = 0 write(fd, "", 1) = 0 write(fd, "", 1) = 0 write(fd, "", 1) = 0 (...) ...and kernel trace buffer full of empty markers. Fix it by sanitizing write return value. Signed-off-by: Marcin Slusarz LKML-Reference: <20100727231801.GB2826@joi.lan> Cc: Frederic Weisbecker Cc: Ingo Molnar Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 086d36316805..88b42d14d32d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3498,6 +3498,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *fpos) { char *buf; + size_t written; if (tracing_disabled) return -EINVAL; @@ -3519,11 +3520,15 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, } else buf[cnt] = '\0'; - cnt = mark_printk("%s", buf); + written = mark_printk("%s", buf); kfree(buf); - *fpos += cnt; + *fpos += written; - return cnt; + /* don't tell userspace we wrote more - it might confuse them */ + if (written > cnt) + written = cnt; + + return written; } static int tracing_clock_show(struct seq_file *m, void *v) -- cgit v1.2.3-59-g8ed1b From 92298e668372f2f6c8a79fb272f13d65161a4876 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 13 Aug 2010 10:22:17 +1000 Subject: PCI: provide stub pci_domain_nr function for !CONFIG_PCI configs Allows the new PCI domain aware DRM code to compile on m68k. Reported-by: Geert Uytterhoeven Signed-off-by: Dave Airlie Signed-off-by: Jesse Barnes --- include/linux/pci.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index b1d17956a153..c8d95e369ff4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1214,6 +1214,9 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) { return NULL; } +static inline int pci_domain_nr(struct pci_bus *bus) +{ return 0; } + #define dev_is_pci(d) (false) #define dev_is_pf(d) (false) #define dev_num_vf(d) (0) -- cgit v1.2.3-59-g8ed1b From 2f174847b0fdd4eb9f482030a284db24aef7a97f Mon Sep 17 00:00:00 2001 From: eric miao Date: Thu, 12 Aug 2010 16:43:00 +0100 Subject: ARM: 6326/1: kgdb: fix GDB_MAX_REGS no longer used According to commit 22eeef4bb2a7fd225089c0044060ed1fbf091958 kgdb,arm: Individual register get/set for arm It's now replaced by DBG_MAX_REG_NUM. Cc: Jason Wessel Signed-off-by: Eric Miao Signed-off-by: Russell King --- arch/arm/kernel/kgdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index 778c2f7024ff..d6e8b4d2e60d 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) return; /* Initialize to zero */ - for (regno = 0; regno < GDB_MAX_REGS; regno++) + for (regno = 0; regno < DBG_MAX_REG_NUM; regno++) gdb_regs[regno] = 0; /* Otherwise, we have only some registers from switch_to() */ -- cgit v1.2.3-59-g8ed1b From 4f4e8f69895c8696a4bcc751817d4b186023ac44 Mon Sep 17 00:00:00 2001 From: Paul Zimmerman Date: Fri, 13 Aug 2010 12:42:07 -0700 Subject: ALSA: usb: USB3 SuperSpeed sound support This is V2 of the patch, after feedback from Clemens and Daniel. This patch adds SuperSpeed support to the USB drivers under sound/. It adds tests for USB_SPEED_SUPER to the appropriate places that check for the USB speed. This patch has been tested with our SS USB3 device emulating a set of Yamaha speakers and a Logitech microphone, but with the descriptors modified to add USB3 support. It has also been tested with the real speakers and microphone, to make sure that USB2 devices still work. Signed-off-by: Paul Zimmerman Cc: Clemens Ladisch Cc: Daniel Mack Cc: Greg Kroah-Hartman Signed-off-by: Takashi Iwai --- sound/usb/card.c | 31 +++++++++++++++++++++++-------- sound/usb/helper.c | 17 +++++++++++------ sound/usb/midi.c | 9 ++++++++- sound/usb/pcm.c | 4 ++-- sound/usb/proc.c | 2 +- sound/usb/urb.c | 2 +- 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 9feb00c831a0..498a2d8fa4bb 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -299,9 +299,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, *rchip = NULL; - if (snd_usb_get_speed(dev) != USB_SPEED_LOW && - snd_usb_get_speed(dev) != USB_SPEED_FULL && - snd_usb_get_speed(dev) != USB_SPEED_HIGH) { + switch (snd_usb_get_speed(dev)) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); return -ENXIO; } @@ -377,11 +381,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, if (len < sizeof(card->longname)) usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); - strlcat(card->longname, - snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : - snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : - ", high speed", - sizeof(card->longname)); + switch (snd_usb_get_speed(dev)) { + case USB_SPEED_LOW: + strlcat(card->longname, ", low speed", sizeof(card->longname)); + break; + case USB_SPEED_FULL: + strlcat(card->longname, ", full speed", sizeof(card->longname)); + break; + case USB_SPEED_HIGH: + strlcat(card->longname, ", high speed", sizeof(card->longname)); + break; + case USB_SPEED_SUPER: + strlcat(card->longname, ", super speed", sizeof(card->longname)); + break; + default: + break; + } snd_usb_audio_create_proc(chip); diff --git a/sound/usb/helper.c b/sound/usb/helper.c index d48d6f8f6ac9..f280c1903c25 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, struct usb_host_interface *alts) { - if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH && - get_endpoint(alts, 0)->bInterval >= 1 && - get_endpoint(alts, 0)->bInterval <= 4) - return get_endpoint(alts, 0)->bInterval - 1; - else - return 0; + switch (snd_usb_get_speed(chip->dev)) { + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + if (get_endpoint(alts, 0)->bInterval >= 1 && + get_endpoint(alts, 0)->bInterval <= 4) + return get_endpoint(alts, 0)->bInterval - 1; + break; + default: + break; + } + return 0; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index b9c2bc65f51a..156cd0716c42 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, if (!ep->ports[0].active) return; - count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; + switch (snd_usb_get_speed(ep->umidi->dev)) { + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + count = 1; + break; + default: + count = 2; + } count = snd_rawmidi_transmit(ep->ports[0].substream, urb->transfer_buffer, count); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 456829882f40..ebd09acd186e 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -467,7 +467,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs, return 0; } /* check whether the period time is >= the data packet interval */ - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) { ptime = 125 * (1 << fp->datainterval); if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); @@ -735,7 +735,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre } param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; - if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) + if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) /* full speed devices have fixed data packet interval */ ptmin = 1000; if (ptmin == 1000) diff --git a/sound/usb/proc.c b/sound/usb/proc.c index f5e3f356b95f..3c650ab3c91d 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s } snd_iprintf(buffer, "\n"); } - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) snd_iprintf(buffer, " Data packet interval: %d us\n", 125 * (1 << fp->datainterval)); // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); diff --git a/sound/usb/urb.c b/sound/usb/urb.c index de607d4411ac..8deeaad10f10 100644 --- a/sound/usb/urb.c +++ b/sound/usb/urb.c @@ -244,7 +244,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, else subs->curpacksize = maxsize; - if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) packs_per_ms = 8 >> subs->datainterval; else packs_per_ms = 1; -- cgit v1.2.3-59-g8ed1b From ce60659ad838a77d71aa817a6781659799970ae1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Jul 2010 13:19:39 -0700 Subject: iwlwifi: long monitor timer Change the name for monitor timer, also adding define for long monitor timer; long monitor timer can be used for the type of devices require longer time to determine the uCode is stuck on tx and needed reload. Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-1000.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-3945.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-5000.c | 14 +++++++------- drivers/net/wireless/iwlwifi/iwl-6000.c | 32 ++++++++++++++++---------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 3 ++- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index fec026212326..0b779a41a142 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -265,7 +265,7 @@ struct iwl_cfg iwl1000_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 128, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -297,7 +297,7 @@ struct iwl_cfg iwl1000_bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 128, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 6950a783913b..8ccfcd08218d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2731,7 +2731,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { .led_compensation = 64, .broken_powersave = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .tx_power_by_driver = true, }; @@ -2752,7 +2752,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { .led_compensation = 64, .broken_powersave = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .tx_power_by_driver = true, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d6da356608fa..d92b72909233 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2322,7 +2322,7 @@ struct iwl_cfg iwl4965_agn_cfg = { .led_compensation = 61, .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .temperature_kelvin = true, .max_event_log_size = 512, .tx_power_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index aacf3770f075..cd9f9fc53f8b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -510,7 +510,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -541,7 +541,7 @@ struct iwl_cfg iwl5100_bgn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -601,7 +601,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -632,7 +632,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -663,7 +663,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -693,7 +693,7 @@ struct iwl_cfg iwl5150_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index af4fd50f3405..b6468e962115 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -388,7 +388,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -424,7 +424,7 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -459,7 +459,7 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -496,7 +496,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -532,7 +532,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -606,7 +606,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -644,7 +644,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -680,7 +680,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -721,7 +721,7 @@ struct iwl_cfg iwl6000i_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -756,7 +756,7 @@ struct iwl_cfg iwl6000i_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -791,7 +791,7 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -828,7 +828,7 @@ struct iwl_cfg iwl6050_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1500, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -866,7 +866,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1500, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -902,7 +902,7 @@ struct iwl_cfg iwl6050_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1500, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -940,7 +940,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_MONITORING_PERIOD, + .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, .max_event_log_size = 1024, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f35bcad56e36..2e97cd2fa98a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1049,7 +1049,8 @@ struct iwl_event_log { #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) /* timer constants use to monitor and recover stuck tx queues in mSecs */ -#define IWL_MONITORING_PERIOD (1000) +#define IWL_DEF_MONITORING_PERIOD (1000) +#define IWL_LONG_MONITORING_PERIOD (5000) #define IWL_ONE_HUNDRED_MSECS (100) #define IWL_SIXTY_SECS (60000) -- cgit v1.2.3-59-g8ed1b From 3198c68cb4e1967f59244f0a0b9f46102d617373 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 23 Jul 2010 13:19:40 -0700 Subject: iwlwifi: use long monitor timer to avoid un-necessary reload For 5000 and 6000g2b series of devices, use long monitor timer to check stuck tx queues. .6000g2b series device, it is WiFi/BT combo device, there are some cases, tx queues are not move for a period of time because the WiFi/BT coex. .5000 series device, it is being reported firmware got reload more often than necessary, so extend the timer to avoid un-necessary reload. Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-5000.c | 10 +++++----- drivers/net/wireless/iwlwifi/iwl-6000.c | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cd9f9fc53f8b..0cbefa3d1e45 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -510,7 +510,7 @@ struct iwl_cfg iwl5300_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -541,7 +541,7 @@ struct iwl_cfg iwl5100_bgn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl5100_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -601,7 +601,7 @@ struct iwl_cfg iwl5100_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -632,7 +632,7 @@ struct iwl_cfg iwl5350_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b6468e962115..cee06b968de8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -496,7 +496,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -532,7 +532,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -570,7 +570,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -606,7 +606,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -644,7 +644,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, @@ -680,7 +680,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, -- cgit v1.2.3-59-g8ed1b From 84062dd3a6a045395a43de1d9adc9b8eb2d1426e Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 14 Aug 2010 23:22:16 +0200 Subject: kconfig: fix savedefconfig with choice marked optional savedefconfig failed to save the correct minimal config when it encountered a choice marked optional. Consider following minimal configuration: $cat Kconfig choice prompt "choice" optional config A bool "a" config B bool "b" endchoice $cat .config | grep -v ^# CONFIG_A=y $conf --savedefconfig=defconfig Kconfig would before this fix result in an empty file, because kconfig would assume that CONFIG_A=y is a default value. But because the choice is optional the default is that both A and B are =n. Fix so we handle optional choices correct. Signed-off-by: Sam Ravnborg Signed-off-by: Michal Marek --- scripts/kconfig/confdata.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index c39327e60ea4..515253fe46cf 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -497,7 +497,9 @@ int conf_write_defconfig(const char *filename) /* * If symbol is a choice value and equals to the * default for a choice - skip. - * But only if value is bool and equal to "y" . + * But only if value is bool and equal to "y" and + * choice is not "optional". + * (If choice is "optional" then all values can be "n") */ if (sym_is_choice_value(sym)) { struct symbol *cs; @@ -505,7 +507,7 @@ int conf_write_defconfig(const char *filename) cs = prop_get_symbol(sym_get_choice_prop(sym)); ds = sym_choice_default(cs); - if (sym == ds) { + if (!sym_is_optional(cs) && sym == ds) { if ((sym->type == S_BOOLEAN) && sym_get_tristate_value(sym) == yes) goto next_menu; -- cgit v1.2.3-59-g8ed1b From 3643f849d7da5c12da589beb03c12303fe79b841 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 14 Aug 2010 14:40:00 +0200 Subject: kconfig: fix segfault when detecting recursive dependency Following sample Kconfig generated a segfault: config FOO bool select PERF_EVENTS if HAVE_HW_BREAKPOINT config PERF_EVENTS bool config HAVE_HW_BREAKPOINT bool depends on PERF_EVENTS Fix by reverting back to a valid property if there was no property on the stack of symbols. The above pattern were seen in sh Kconfig. A fix for the Kconfig file has been sent to the sh folks. Signed-off-by: Sam Ravnborg Signed-off-by: Michal Marek --- scripts/kconfig/symbol.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index e95718fea355..943712ca6c0a 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -937,6 +937,8 @@ static void sym_check_print_recursive(struct symbol *last_sym) sym = stack->sym; next_sym = stack->next ? stack->next->sym : last_sym; prop = stack->prop; + if (prop == NULL) + prop = stack->sym->prop; /* for choice values find the menu entry (used below) */ if (sym_is_choice(sym) || sym_is_choice_value(sym)) { -- cgit v1.2.3-59-g8ed1b From bd365591dfb942d1447b8043e21e8ff112630db4 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Sat, 14 Aug 2010 23:56:21 +0100 Subject: ARM: 6328/1: Build with -fno-dwarf2-cfi-asm Commit d0679c7 restricted this workaround to powerpc only, but it turns out that ARM needs it as well. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=16310 . Reported-and-Tested-by: Robert Nelson Acked-by: Mikael Pettersson Signed-off-by: Michal Marek Signed-off-by: Russell King --- arch/arm/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 99b8200138d2..59c1ce858fc8 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -21,6 +21,9 @@ GZFLAGS :=-9 # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: KBUILD_CFLAGS +=$(call cc-option,-marm,) +# Never generate .eh_frame +KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) + # Do not use arch/arm/defconfig - it's always outdated. # Select a platform tht is kept up-to-date KBUILD_DEFCONFIG := versatile_defconfig -- cgit v1.2.3-59-g8ed1b From 2f09a4d5daaa36690d506fafda9c24f2be866f6b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 14 Aug 2010 22:38:09 -0700 Subject: xfrm: Use GFP_ATOMIC in xfrm_compile_policy As xfrm_compile_policy runs within a read_lock, we cannot use GFP_KERNEL for memory allocations. Reported-by: Luca Tettamanti Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ba59983aaffe..b14ed4b1f27c 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2504,7 +2504,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, if (p->dir > XFRM_POLICY_OUT) return NULL; - xp = xfrm_policy_alloc(net, GFP_KERNEL); + xp = xfrm_policy_alloc(net, GFP_ATOMIC); if (xp == NULL) { *dir = -ENOBUFS; return NULL; -- cgit v1.2.3-59-g8ed1b From f3d3f616e35db2ceeb11564eafd50759bb5bca8a Mon Sep 17 00:00:00 2001 From: Min Zhang Date: Sat, 14 Aug 2010 22:42:51 -0700 Subject: ipv6: remove sysctl jiffies conversion on gc_elasticity and min_adv_mss sysctl output ipv6 gc_elasticity and min_adv_mss as values divided by HZ. However, they are not in unit of jiffies, since ip6_rt_min_advmss refers to packet size and ip6_rt_fc_elasticity is used as scaler as in expire>>ip6_rt_gc_elasticity, so replace the jiffies conversion handler will regular handler for them. This has impact on scripts that are currently working assuming the divide by HZ, will yield different results with this patch in place. Signed-off-by: Min Zhang Signed-off-by: David S. Miller --- net/ipv6/route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8f2d0400cf8a..d126365ac046 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2580,7 +2580,7 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_jiffies, + .proc_handler = proc_dointvec, }, { .procname = "mtu_expires", @@ -2594,7 +2594,7 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_jiffies, + .proc_handler = proc_dointvec, }, { .procname = "gc_min_interval_ms", -- cgit v1.2.3-59-g8ed1b From f45755b8346f1a089ca7957dce5f4c3c6cb26e6f Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Fri, 13 Aug 2010 15:19:11 +0800 Subject: KVM: fix poison overwritten caused by using wrong xstate size fpu.state is allocated from task_xstate_cachep, the size of task_xstate_cachep is xstate_size. xstate_size is set from cpuid instruction, which is often smaller than sizeof(struct xsave_struct). kvm is using sizeof(struct xsave_struct) to fill in/out fpu.state.xsave, as what we allocated for fpu.state is xstate_size, kernel will write out of memory and caused poison/redzone/padding overwritten warnings. Signed-off-by: Xiaotian Feng Reviewed-by: Sheng Yang Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Suresh Siddha Cc: Brian Gerst Cc: Avi Kivity Cc: Robert Richter Cc: Sheng Yang Cc: Marcelo Tosatti Cc: Gleb Natapov Cc: Jan Kiszka Signed-off-by: Avi Kivity --- arch/x86/kernel/i387.c | 1 + arch/x86/kvm/x86.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index c4444bce8469..f855658d2784 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -40,6 +40,7 @@ static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu; unsigned int xstate_size; +EXPORT_SYMBOL_GPL(xstate_size); unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32); static struct i387_fxsave_struct fx_scratch __cpuinitdata; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 97aab036dabf..bb2347a69c07 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2387,7 +2387,7 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, if (cpu_has_xsave) memcpy(guest_xsave->region, &vcpu->arch.guest_fpu.state->xsave, - sizeof(struct xsave_struct)); + xstate_size); else { memcpy(guest_xsave->region, &vcpu->arch.guest_fpu.state->fxsave, @@ -2405,7 +2405,7 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, if (cpu_has_xsave) memcpy(&vcpu->arch.guest_fpu.state->xsave, - guest_xsave->region, sizeof(struct xsave_struct)); + guest_xsave->region, xstate_size); else { if (xstate_bv & ~XSTATE_FPSSE) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 3185bf8c23149f32d7e7363b84539ea50b26ecb1 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Fri, 13 Aug 2010 16:23:06 +0800 Subject: KVM: destroy workqueue on kvm_create_pit() failures kernel needs to destroy workqueue if kvm_create_pit() fails, otherwise after pit is freed, the workqueue is leaked. Signed-off-by: Xiaotian Feng Cc: Avi Kivity Cc: Marcelo Tosatti Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Gleb Natapov Cc: "Michael S. Tsirkin" Cc: Gregory Haskins Signed-off-by: Avi Kivity --- arch/x86/kvm/i8254.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 0fd6378981f4..f539c3c2a687 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -742,7 +742,7 @@ fail: kvm_unregister_irq_mask_notifier(kvm, 0, &pit->mask_notifier); kvm_unregister_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier); kvm_free_irq_source_id(kvm, pit->irq_source_id); - + destroy_workqueue(pit->wq); kfree(pit); return NULL; } -- cgit v1.2.3-59-g8ed1b From 21d93e2e29722d7832f61cc56d73fb953ee6578e Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Sun, 15 Aug 2010 10:47:23 +0100 Subject: ARM: 6329/1: wire up sys_accept4() on ARM sys_accept4() was added in kernel 2.6.28, but ARM was not updated to include it. The number and types of parameters is such that no ARM-specific processing is needed, so wiring up sys_accept4() just requires defining __NR_accept4 and adding a direct call in the syscall entry table. Tested with an EABI 2.6.35 kernel and Ulrich Drepper's original accept4() test program, modified to define __NR_accept4 for ARM. Using the updated unistd.h also eliminates a warning then building glibc (2.10.2 and newer) about accept4() being unimplemented. Signed-off-by: Mikael Pettersson Signed-off-by: Russell King --- arch/arm/include/asm/unistd.h | 1 + arch/arm/kernel/calls.S | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index dd2bf53000fe..d02cfb683487 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -392,6 +392,7 @@ #define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363) #define __NR_perf_event_open (__NR_SYSCALL_BASE+364) #define __NR_recvmmsg (__NR_SYSCALL_BASE+365) +#define __NR_accept4 (__NR_SYSCALL_BASE+366) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 37ae301cc47c..afeb71fa72cb 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -375,6 +375,7 @@ CALL(sys_rt_tgsigqueueinfo) CALL(sys_perf_event_open) /* 365 */ CALL(sys_recvmmsg) + CALL(sys_accept4) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted -- cgit v1.2.3-59-g8ed1b From 41e2e8fd34fff909a0e40129f6ac4233ecfa67a9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Aug 2010 23:33:46 +0100 Subject: ARM: Tighten check for allowable CPSR values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Arve Hjønnevåg Acked-by: Dima Zavin Signed-off-by: Russell King --- arch/arm/include/asm/ptrace.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index c974be8913a7..7ce15eb15f72 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -158,15 +158,24 @@ struct pt_regs { */ static inline int valid_user_regs(struct pt_regs *regs) { - if (user_mode(regs) && (regs->ARM_cpsr & PSR_I_BIT) == 0) { - regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT); - return 1; + unsigned long mode = regs->ARM_cpsr & MODE_MASK; + + /* + * Always clear the F (FIQ) and A (delayed abort) bits + */ + regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT); + + if ((regs->ARM_cpsr & PSR_I_BIT) == 0) { + if (mode == USR_MODE) + return 1; + if (elf_hwcap & HWCAP_26BIT && mode == USR26_MODE) + return 1; } /* * Force CPSR to something logical... */ - regs->ARM_cpsr &= PSR_f | PSR_s | (PSR_x & ~PSR_A_BIT) | PSR_T_BIT | MODE32_BIT; + regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT; if (!(elf_hwcap & HWCAP_26BIT)) regs->ARM_cpsr |= USR_MODE; -- cgit v1.2.3-59-g8ed1b From af4e36318edb848fcc0a8d5f75000ca00cdc7595 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 13 Aug 2010 12:42:24 +0900 Subject: nilfs2: fix list corruption after ifile creation failure If nilfs_attach_checkpoint() gets a memory allocation failure during creation of ifile, it will return without removing nilfs_sb_info struct from ns_supers list. When a concurrently mounted snapshot is unmounted or another new snapshot is mounted after that, this causes kernel oops as below: > BUG: unable to handle kernel NULL pointer dereference at (null) > IP: [] nilfs_find_sbinfo+0x74/0xa4 [nilfs2] > *pde = 00000000 > Oops: 0000 [#1] SMP > Call Trace: > [] ? nilfs_get_sb+0x165/0x532 [nilfs2] > [] ? ida_get_new_above+0x16d/0x187 > [] ? alloc_vfsmnt+0x7e/0x10a > [] ? kstrdup+0x2c/0x40 > [] ? vfs_kern_mount+0x96/0x14e > [] ? do_kern_mount+0x32/0xbd > [] ? do_mount+0x642/0x6a1 > [] ? do_page_fault+0x0/0x2d1 > [] ? copy_mount_options+0x80/0xe2 > [] ? strndup_user+0x48/0x67 > [] ? sys_mount+0x61/0x90 > [] ? sysenter_do_call+0x12/0x22 This fixes the problem. Signed-off-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Cc: stable@kernel.org --- fs/nilfs2/super.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1fa86b9df73b..bee60c04109a 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -400,9 +400,10 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) list_add(&sbi->s_list, &nilfs->ns_supers); up_write(&nilfs->ns_super_sem); + err = -ENOMEM; sbi->s_ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size); if (!sbi->s_ifile) - return -ENOMEM; + goto delist; down_read(&nilfs->ns_segctor_sem); err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, @@ -433,6 +434,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) nilfs_mdt_destroy(sbi->s_ifile); sbi->s_ifile = NULL; + delist: down_write(&nilfs->ns_super_sem); list_del_init(&sbi->s_list); up_write(&nilfs->ns_super_sem); -- cgit v1.2.3-59-g8ed1b From ea1a16f7168ac19d974ac51b47593b92280e7992 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 15 Aug 2010 20:16:11 +0900 Subject: nilfs2: fix false warning saying one of two super blocks is broken After applying commit b2ac86e1, the following message got appeared after unclean shutdown: > NILFS warning: broken superblock. using spare superblock. This turns out to be a false message due to the change which updates two super blocks alternately. The secondary super block now can be selected if it's newer than the primary one. This kills the false warning by suppressing it if another super block is not actually broken. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/the_nilfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 37de1f062d81..6af1c0073e9e 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -608,11 +608,11 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, return -EINVAL; } - if (swp) { + if (!valid[!swp]) printk(KERN_WARNING "NILFS warning: broken superblock. " "using spare superblock.\n"); + if (swp) nilfs_swap_super_block(nilfs); - } nilfs->ns_sbwcount = 0; nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime); -- cgit v1.2.3-59-g8ed1b From f14c4f141ad88290bb23d597a0a47833e7891fcd Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 27 Jul 2010 08:14:35 +0000 Subject: ARM: mach-shmobile: Runtime PM V3 This is the SH-Mobile ARM Runtime PM implementation V3. Only clocks are managed at this point. If Runtime PM is disabled then the clocks will be enabled before ->probe() and disabled after ->remove(). Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Makefile | 2 +- arch/arm/mach-shmobile/clock-sh7372.c | 2 +- arch/arm/mach-shmobile/pm_runtime.c | 169 ++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-shmobile/pm_runtime.c diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 5e16b4c69222..ae416fe7daf2 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -3,7 +3,7 @@ # # Common objects -obj-y := timer.o console.o clock.o +obj-y := timer.o console.o clock.o pm_runtime.o # CPU objects obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index fb4e9b1d788e..4a1d019f7bad 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -428,7 +428,7 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ - [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, CLK_ENABLE_ON_INIT), /* FSIA */ + [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSIA */ [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c new file mode 100644 index 000000000000..94912d3944d3 --- /dev/null +++ b/arch/arm/mach-shmobile/pm_runtime.c @@ -0,0 +1,169 @@ +/* + * arch/arm/mach-shmobile/pm_runtime.c + * + * Runtime PM support code for SuperH Mobile ARM + * + * Copyright (C) 2009-2010 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM_RUNTIME +#define BIT_ONCE 0 +#define BIT_ACTIVE 1 +#define BIT_CLK_ENABLED 2 + +struct pm_runtime_data { + unsigned long flags; + struct clk *clk; +}; + +static void __devres_release(struct device *dev, void *res) +{ + struct pm_runtime_data *prd = res; + + dev_dbg(dev, "__devres_release()\n"); + + if (test_bit(BIT_CLK_ENABLED, &prd->flags)) + clk_disable(prd->clk); + + if (test_bit(BIT_ACTIVE, &prd->flags)) + clk_put(prd->clk); +} + +static struct pm_runtime_data *__to_prd(struct device *dev) +{ + return devres_find(dev, __devres_release, NULL, NULL); +} + +static void platform_pm_runtime_init(struct device *dev, + struct pm_runtime_data *prd) +{ + if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) { + prd->clk = clk_get(dev, NULL); + if (!IS_ERR(prd->clk)) { + set_bit(BIT_ACTIVE, &prd->flags); + dev_info(dev, "clocks managed by runtime pm\n"); + } + } +} + +static void platform_pm_runtime_bug(struct device *dev, + struct pm_runtime_data *prd) +{ + if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) + dev_err(dev, "runtime pm suspend before resume\n"); +} + +int platform_pm_runtime_suspend(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_dbg(dev, "platform_pm_runtime_suspend()\n"); + + platform_pm_runtime_bug(dev, prd); + + if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { + clk_disable(prd->clk); + clear_bit(BIT_CLK_ENABLED, &prd->flags); + } + + return 0; +} + +int platform_pm_runtime_resume(struct device *dev) +{ + struct pm_runtime_data *prd = __to_prd(dev); + + dev_dbg(dev, "platform_pm_runtime_resume()\n"); + + platform_pm_runtime_init(dev, prd); + + if (prd && test_bit(BIT_ACTIVE, &prd->flags)) { + clk_enable(prd->clk); + set_bit(BIT_CLK_ENABLED, &prd->flags); + } + + return 0; +} + +int platform_pm_runtime_idle(struct device *dev) +{ + /* suspend synchronously to disable clocks immediately */ + return pm_runtime_suspend(dev); +} + +static int platform_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct pm_runtime_data *prd; + + dev_dbg(dev, "platform_bus_notify() %ld !\n", action); + + if (action == BUS_NOTIFY_BIND_DRIVER) { + prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL); + if (prd) + devres_add(dev, prd); + else + dev_err(dev, "unable to alloc memory for runtime pm\n"); + } + + return 0; +} + +#else /* CONFIG_PM_RUNTIME */ + +static int platform_bus_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct clk *clk; + + dev_dbg(dev, "platform_bus_notify() %ld !\n", action); + + switch (action) { + case BUS_NOTIFY_BIND_DRIVER: + clk = clk_get(dev, NULL); + if (!IS_ERR(clk)) { + clk_enable(clk); + clk_put(clk); + dev_info(dev, "runtime pm disabled, clock forced on\n"); + } + break; + case BUS_NOTIFY_UNBOUND_DRIVER: + clk = clk_get(dev, NULL); + if (!IS_ERR(clk)) { + clk_disable(clk); + clk_put(clk); + dev_info(dev, "runtime pm disabled, clock forced off\n"); + } + break; + } + + return 0; +} + +#endif /* CONFIG_PM_RUNTIME */ + +static struct notifier_block platform_bus_notifier = { + .notifier_call = platform_bus_notify +}; + +static int __init sh_pm_runtime_init(void) +{ + bus_register_notifier(&platform_bus_type, &platform_bus_notifier); + return 0; +} +core_initcall(sh_pm_runtime_init); -- cgit v1.2.3-59-g8ed1b From a4909b52682c1e2ac858754c8bc46f2501e67dee Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 26 Jul 2010 16:20:53 +0000 Subject: ARM: mach-shmobile: add clock definitions for CEU and CSI2 Two more clocks to be managed by the runtime PM. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 4a1d019f7bad..dcaac1b6691d 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -395,7 +395,7 @@ static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { enum { MSTP001, MSTP131, MSTP130, - MSTP129, MSTP128, + MSTP129, MSTP128, MSTP127, MSTP126, MSTP118, MSTP117, MSTP116, MSTP106, MSTP101, MSTP100, MSTP223, @@ -413,6 +413,8 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */ [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */ [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ + [MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU */ + [MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2 */ [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */ [MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ @@ -498,6 +500,8 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */ CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */ CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ + CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU */ + CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2 */ CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ -- cgit v1.2.3-59-g8ed1b From 2863e935a59b36d55522af8620112c64a56b4022 Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Sat, 14 Aug 2010 19:45:21 +0000 Subject: ARM: mach-shmobile: AP4EVB: use gpio-leds for leds. This allows control of the leds on the AP4EVB board by kernel events (triggers) like mmc0/mmc1. In userland, the leds won't be available anymore over /sys/class/gpio but via /sys/class/leds. Signed-off-by: Arnd Hannemann Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 52 +++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 23d472f9525e..98c1cf76c2b4 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -650,7 +651,44 @@ static struct platform_device hdmi_device = { }, }; +static struct gpio_led ap4evb_leds[] = { + { + .name = "led4", + .gpio = GPIO_PORT185, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "led2", + .gpio = GPIO_PORT186, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "led3", + .gpio = GPIO_PORT187, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "led1", + .gpio = GPIO_PORT188, + .default_state = LEDS_GPIO_DEFSTATE_ON, + } +}; + +static struct gpio_led_platform_data ap4evb_leds_pdata = { + .num_leds = ARRAY_SIZE(ap4evb_leds), + .leds = &ap4evb_leds, +}; + +static struct platform_device leds_device = { + .name = "leds-gpio", + .id = 0, + .dev = { + .platform_data = &ap4evb_leds_pdata, + }, +}; + static struct platform_device *ap4evb_devices[] __initdata = { + &leds_device, &nor_flash_device, &smc911x_device, &sdhi0_device, @@ -840,20 +878,6 @@ static void __init ap4evb_init(void) gpio_request(GPIO_FN_CS5A, NULL); gpio_request(GPIO_FN_IRQ6_39, NULL); - /* enable LED 1 - 4 */ - gpio_request(GPIO_PORT185, NULL); - gpio_request(GPIO_PORT186, NULL); - gpio_request(GPIO_PORT187, NULL); - gpio_request(GPIO_PORT188, NULL); - gpio_direction_output(GPIO_PORT185, 1); - gpio_direction_output(GPIO_PORT186, 1); - gpio_direction_output(GPIO_PORT187, 1); - gpio_direction_output(GPIO_PORT188, 1); - gpio_export(GPIO_PORT185, 0); - gpio_export(GPIO_PORT186, 0); - gpio_export(GPIO_PORT187, 0); - gpio_export(GPIO_PORT188, 0); - /* enable Debug switch (S6) */ gpio_request(GPIO_PORT32, NULL); gpio_request(GPIO_PORT33, NULL); -- cgit v1.2.3-59-g8ed1b From 8050fbf268c3bc09752ceece40aff5d3f4e3e182 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 16 Aug 2010 14:54:35 +0900 Subject: ARM: mach-shmobile: Fix up gpio-leds pdata definition. Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 98c1cf76c2b4..8afdb1dab029 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -676,7 +676,7 @@ static struct gpio_led ap4evb_leds[] = { static struct gpio_led_platform_data ap4evb_leds_pdata = { .num_leds = ARRAY_SIZE(ap4evb_leds), - .leds = &ap4evb_leds, + .leds = ap4evb_leds, }; static struct platform_device leds_device = { -- cgit v1.2.3-59-g8ed1b From a5ba6beb839cfa288960c92cd2668a2601c24dda Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Aug 2010 08:08:48 +0200 Subject: ALSA: riptide - Fix detection / load of firmware files The detection and loading of firmeware on riptide driver has been broken due to rewrite of some codes, checking the presense wrongly. This patch fixes the logic again. Reference: kernel bug 16596 https://bugzilla.kernel.org/show_bug.cgi?id=16596 Cc: Signed-off-by: Takashi Iwai --- sound/pci/riptide/riptide.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index f64fb7d988cb..ad5202efd7a9 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1224,15 +1224,14 @@ static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) firmware.firmware.ASIC, firmware.firmware.CODEC, firmware.firmware.AUXDSP, firmware.firmware.PROG); + if (!chip) + return 1; + for (i = 0; i < FIRMWARE_VERSIONS; i++) { if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) - break; - } - if (i >= FIRMWARE_VERSIONS) - return 0; /* no match */ + return 1; /* OK */ - if (!chip) - return 1; /* OK */ + } snd_printdd("Writing Firmware\n"); if (!chip->fw_entry) { -- cgit v1.2.3-59-g8ed1b From 77c0870ca515667b77750b397008d68a17fad9d8 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Mon, 16 Aug 2010 09:21:19 +0300 Subject: omap3: id: fix 3630 rev detection Wrong placement of break causes all revisions of 3630 to be detected as 3630 es1.2, we need to break main loop if we have an identified chip, default falls through as in the rest of the switches in this function. Cc: Paul Walmsley Cc: Sanjeev Premi Cc: Kevin Hilman Cc: Manjunath K Cc: Anand Gadiyar Cc: Felipe Balbi Signed-off-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/id.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index e8256a2ed8e7..9a879f959509 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -284,8 +284,8 @@ static void __init omap3_check_revision(void) default: omap_revision = OMAP3630_REV_ES1_2; omap_chip.oc |= CHIP_IS_OMAP3630ES1_2; - break; } + break; default: /* Unknown default to latest silicon rev as default*/ omap_revision = OMAP3630_REV_ES1_2; -- cgit v1.2.3-59-g8ed1b From 8098bb0d8c7fe4ace7d13274c85a149503eee114 Mon Sep 17 00:00:00 2001 From: "stanley.miao" Date: Mon, 16 Aug 2010 09:21:19 +0300 Subject: OMAP3: Fix a cpu type check problem cpu_is_omap3517() and cpu_is_omap3505() are the subgroups of cpu_is_omap34xx(), so we should check cpu_is_omap3517() and cpu_is_omap3505() first, then check cpu_is_omap34xx(). Otherwise, All AM35XX (Sitara) clocks do not get registered and device drivers (ti_hecc, etc...) that depend on those clocks are failing to get the clock and end up with non working device. Signed-off-by: Stanley.Miao Tested-by: Igor Grinberg Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock3xxx_data.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c index 138646deac89..dfdce2d82779 100644 --- a/arch/arm/mach-omap2/clock3xxx_data.c +++ b/arch/arm/mach-omap2/clock3xxx_data.c @@ -3417,7 +3417,13 @@ int __init omap3xxx_clk_init(void) struct omap_clk *c; u32 cpu_clkflg = CK_3XXX; - if (cpu_is_omap34xx()) { + if (cpu_is_omap3517()) { + cpu_mask = RATE_IN_3XXX | RATE_IN_3430ES2PLUS; + cpu_clkflg |= CK_3517; + } else if (cpu_is_omap3505()) { + cpu_mask = RATE_IN_3XXX | RATE_IN_3430ES2PLUS; + cpu_clkflg |= CK_3505; + } else if (cpu_is_omap34xx()) { cpu_mask = RATE_IN_3XXX; cpu_clkflg |= CK_343X; @@ -3432,12 +3438,6 @@ int __init omap3xxx_clk_init(void) cpu_mask |= RATE_IN_3430ES2PLUS; cpu_clkflg |= CK_3430ES2; } - } else if (cpu_is_omap3517()) { - cpu_mask = RATE_IN_3XXX | RATE_IN_3430ES2PLUS; - cpu_clkflg |= CK_3517; - } else if (cpu_is_omap3505()) { - cpu_mask = RATE_IN_3XXX | RATE_IN_3430ES2PLUS; - cpu_clkflg |= CK_3505; } if (omap3_has_192mhz_clk()) -- cgit v1.2.3-59-g8ed1b From daa3766e705c2605bd7f63b80c7742014ef9e04e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 15 Aug 2010 23:21:50 -0700 Subject: Revert "netlink: netlink_recvmsg() fix" This reverts commit 1235f504aaba2ebeabc863fdb3ceac764a317d47. It causes regressions worse than the problem it was trying to fix. Eric will try to solve the problem another way. Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 2cbf380377d5..8648a9922aab 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1406,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, struct netlink_sock *nlk = nlk_sk(sk); int noblock = flags&MSG_DONTWAIT; size_t copied; - struct sk_buff *skb; + struct sk_buff *skb, *frag __maybe_unused = NULL; int err; if (flags&MSG_OOB) @@ -1441,21 +1441,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, kfree_skb(skb); skb = compskb; } else { - /* - * Before setting frag_list to NULL, we must get a - * private copy of skb if shared (because of MSG_PEEK) - */ - if (skb_shared(skb)) { - struct sk_buff *nskb; - - nskb = pskb_copy(skb, GFP_KERNEL); - kfree_skb(skb); - skb = nskb; - err = -ENOMEM; - if (!skb) - goto out; - } - kfree_skb(skb_shinfo(skb)->frag_list); + frag = skb_shinfo(skb)->frag_list; skb_shinfo(skb)->frag_list = NULL; } } @@ -1492,6 +1478,10 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, if (flags & MSG_TRUNC) copied = skb->len; +#ifdef CONFIG_COMPAT_NETLINK_MESSAGES + skb_shinfo(skb)->frag_list = frag; +#endif + skb_free_datagram(sk, skb); if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) -- cgit v1.2.3-59-g8ed1b From a4192d32ae6788dc607e96fa85f9c9c8274e2212 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 16 Aug 2010 09:21:20 +0300 Subject: omap: Fix sev instruction usage for multi-omap Otherwise we get the following error with omap3_defconfig and CONFIG_SMP: Error: selected processor does not support `sev' Signed-off-by: Tony Lindgren Acked-by: Santosh Shilimkar --- arch/arm/mach-omap2/Makefile | 1 + arch/arm/mach-omap2/omap-smp.c | 3 +-- arch/arm/plat-omap/include/plat/smp.h | 7 ------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 63b2d8859c3c..88d3a1e920f5 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_LOCAL_TIMERS) += timer-mpu.o obj-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o obj-$(CONFIG_ARCH_OMAP4) += omap44xx-smc.o omap4-common.o +AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a AFLAGS_omap44xx-smc.o :=-Wa,-march=armv7-a # Functions loaded to SRAM diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index af3c20c8d3f9..9e9f70e18e3c 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -102,8 +102,7 @@ static void __init wakeup_secondary(void) * Send a 'sev' to wake the secondary core from WFE. * Drain the outstanding writes to memory */ - dsb(); - set_event(); + dsb_sev(); mb(); } diff --git a/arch/arm/plat-omap/include/plat/smp.h b/arch/arm/plat-omap/include/plat/smp.h index 6a3ff65c0303..5177a9c5a25a 100644 --- a/arch/arm/plat-omap/include/plat/smp.h +++ b/arch/arm/plat-omap/include/plat/smp.h @@ -19,13 +19,6 @@ #include -/* - * set_event() is used to wake up secondary core from wfe using sev. ROM - * code puts the second core into wfe(standby). - * - */ -#define set_event() __asm__ __volatile__ ("sev" : : : "memory") - /* Needed for secondary core boot */ extern void omap_secondary_startup(void); extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask); -- cgit v1.2.3-59-g8ed1b From c45bd374e560873f2fff392769b9576c4f3bad40 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 16 Aug 2010 09:21:20 +0300 Subject: omap: Use CONFIG_SMP for test_for_ipi and test_for_ltirq Otherwise we get the following error when enabling CONFIG_SMP for omap3_defconfig: arch/arm/kernel/entry-armv.S: Assembler messages: arch/arm/kernel/entry-armv.S:48: Error: bad instruction `test_for_ipi r0,r6,r5,lr' arch/arm/kernel/entry-armv.S:48: Error: bad instruction `test_for_ltirq r0,r6,r5,lr' arch/arm/kernel/entry-armv.S:48: Error: bad instruction `test_for_ipi r0,r6,r5,lr' arch/arm/kernel/entry-armv.S:48: Error: bad instruction `test_for_ltirq r0,r6,r5,lr' Signed-off-by: Tony Lindgren Acked-by: Santosh Shilimkar --- arch/arm/mach-omap2/include/mach/entry-macro.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S index 50fd74916643..06e64e1fc28a 100644 --- a/arch/arm/mach-omap2/include/mach/entry-macro.S +++ b/arch/arm/mach-omap2/include/mach/entry-macro.S @@ -177,7 +177,10 @@ omap_irq_base: .word 0 cmpne \irqnr, \tmp cmpcs \irqnr, \irqnr .endm +#endif +#endif /* MULTI_OMAP2 */ +#ifdef CONFIG_SMP /* We assume that irqstat (the raw value of the IRQ acknowledge * register) is preserved from the macro above. * If there is an IPI, we immediately signal end of interrupt @@ -205,8 +208,7 @@ omap_irq_base: .word 0 streq \irqstat, [\base, #GIC_CPU_EOI] cmp \tmp, #0 .endm -#endif -#endif /* MULTI_OMAP2 */ +#endif /* CONFIG_SMP */ .macro irq_prio_table .endm -- cgit v1.2.3-59-g8ed1b From c66dd2660de534973303e2dd4f7784763bc9e549 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 16 Aug 2010 09:21:20 +0300 Subject: omap: Fix omap_4430sdp_defconfig for make oldconfig Commit ffb63e3402849e1b70119ee0c9a81dc9da4dfa97 changed Kconfig to select support for omap2, 3 and 4 by default. However, CONFIG_SMP won't currently work properly on uniprocessor ARMs, or if support for earlier ARM cores is selected in. Fix this by updating omap_4430sdp_defconfig to not select omap2 or 3 at this point. Signed-off-by: Tony Lindgren Acked-by: Santosh Shilimkar --- arch/arm/configs/omap_4430sdp_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/omap_4430sdp_defconfig b/arch/arm/configs/omap_4430sdp_defconfig index 63e0c2d50f32..14c1e18c648f 100644 --- a/arch/arm/configs/omap_4430sdp_defconfig +++ b/arch/arm/configs/omap_4430sdp_defconfig @@ -13,6 +13,9 @@ CONFIG_MODULE_SRCVERSION_ALL=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_OMAP=y CONFIG_ARCH_OMAP4=y +# CONFIG_ARCH_OMAP2PLUS_TYPICAL is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP3 is not set # CONFIG_OMAP_MUX is not set CONFIG_OMAP_32K_TIMER=y CONFIG_OMAP_DM_TIMER=y -- cgit v1.2.3-59-g8ed1b From 58a5559e461a4ab945286dacef611d3c542c5fee Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Mon, 16 Aug 2010 09:21:19 +0300 Subject: OMAP3: PM: ensure IO wakeups are properly disabled Commit 5a5f561 (convert OMAP3 PRCM macros to the _SHIFT/_MASK suffixes) mistakenly removed the check for PER when disabling the IO chain. During idle, if the PER powerdomain transitions into a lower state and CORE does not, the IO pad wakeups are not being disabled in the idle path after they are enabled. This can happen with the lower C-states when using CPUidle for example. This patch ensures that the check for disabling IO wakeups also checks for PER transitions, matching the check done to enable IO wakeups. Found when debugging PM/CPUidle related problems reported by Ameya Palande . Problems were triggered particularily on boards with UART2 consoles (n900, Overo) since UART2 is in the PER powerdomain. Tested on l-o master (omap3_defonfig + CONFIG_CPU_IDLE=y) as well as with current PM branch. Boards tested: n900, Overo, omap3evm. Cc: Paul Walmsley Cc: Ameya Palande Tested-by: Jarkko Nikula Signed-off-by: Kevin Hilman [tony@atomide.com: updated description to clarify the transistion] Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pm34xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index fb4994ad622e..7b03426c72a3 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -480,7 +480,9 @@ void omap_sram_idle(void) } /* Disable IO-PAD and IO-CHAIN wakeup */ - if (omap3_has_io_wakeup() && core_next_state < PWRDM_POWER_ON) { + if (omap3_has_io_wakeup() && + (per_next_state < PWRDM_POWER_ON || + core_next_state < PWRDM_POWER_ON)) { prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN); omap3_disable_io_chain(); } -- cgit v1.2.3-59-g8ed1b From 8d9df9f0844ed87541453a3ef91bfc9f487053b7 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Mon, 16 Aug 2010 09:54:28 +0200 Subject: workqueue: free rescuer on destroy_workqueue wq->rescuer is not freed when wq is destroyed, leads a memory leak then. This patch also remove a redundant line. Signed-off-by: Xiaotian Feng Signed-off-by: Tejun Heo Cc: Oleg Nesterov --- kernel/workqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2994a0e3a61c..1001b6e3fcbd 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2782,7 +2782,6 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name, if (IS_ERR(rescuer->task)) goto err; - wq->rescuer = rescuer; rescuer->task->flags |= PF_THREAD_BOUND; wake_up_process(rescuer->task); } @@ -2848,6 +2847,7 @@ void destroy_workqueue(struct workqueue_struct *wq) if (wq->flags & WQ_RESCUER) { kthread_stop(wq->rescuer->task); free_mayday_mask(wq->mayday_mask); + kfree(wq->rescuer); } free_cwqs(wq); -- cgit v1.2.3-59-g8ed1b From c3e68fad88143fd1fe8fe640207fb19c0f087dbc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Aug 2010 10:15:57 +0200 Subject: ALSA: hda - Add quirk for Dell Vostro 1220 model=dell-vostro is needed for Dell Vostro 1220 with Coexnat 5067. Reference: Novell bnc#631066 https://bugzilla.novell.com/show_bug.cgi?id=631066 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 31b5d9eeba68..c424952a734e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3049,6 +3049,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), -- cgit v1.2.3-59-g8ed1b From ec53fe3d655befce6420a1b8485af9b1145a0c90 Mon Sep 17 00:00:00 2001 From: Eric Bénard Date: Fri, 30 Jul 2010 22:58:40 +0200 Subject: eukrea-baseboards: fix the merge in one file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last change I did made a big mess in function names and CONFIG names, this patch fixes this so that the baseboard support is really built when selected. Signed-off-by: Eric Bénard Signed-off-by: Sascha Hauer --- arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c | 2 +- arch/arm/mach-mx25/mach-cpuimx25.c | 4 ++-- arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c | 2 +- arch/arm/mach-mx3/mach-cpuimx35.c | 4 ++-- arch/arm/plat-mxc/include/mach/eukrea-baseboards.h | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c index 91931dcb0689..4aaadc753d3e 100644 --- a/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c +++ b/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c @@ -215,7 +215,7 @@ struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = { * Add platform devices present on this baseboard and init * them from CPU side as far as required to use them later on */ -void __init eukrea_mbimxsd_baseboard_init(void) +void __init eukrea_mbimxsd25_baseboard_init(void) { if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads, ARRAY_SIZE(eukrea_mbimxsd_pads))) diff --git a/arch/arm/mach-mx25/mach-cpuimx25.c b/arch/arm/mach-mx25/mach-cpuimx25.c index 56b2e26d23b4..b5efee23008f 100644 --- a/arch/arm/mach-mx25/mach-cpuimx25.c +++ b/arch/arm/mach-mx25/mach-cpuimx25.c @@ -147,8 +147,8 @@ static void __init eukrea_cpuimx25_init(void) if (!otg_mode_host) mxc_register_device(&otg_udc_device, &otg_device_pdata); -#ifdef CONFIG_MACH_EUKREA_MBIMXSD_BASEBOARD - eukrea_mbimxsd_baseboard_init(); +#ifdef CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD + eukrea_mbimxsd25_baseboard_init(); #endif } diff --git a/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c index 1dc5004df866..f8f15e3ac7a0 100644 --- a/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c +++ b/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c @@ -216,7 +216,7 @@ struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = { * Add platform devices present on this baseboard and init * them from CPU side as far as required to use them later on */ -void __init eukrea_mbimxsd_baseboard_init(void) +void __init eukrea_mbimxsd35_baseboard_init(void) { if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads, ARRAY_SIZE(eukrea_mbimxsd_pads))) diff --git a/arch/arm/mach-mx3/mach-cpuimx35.c b/arch/arm/mach-mx3/mach-cpuimx35.c index 63f970f340a2..e4268bbb8fbc 100644 --- a/arch/arm/mach-mx3/mach-cpuimx35.c +++ b/arch/arm/mach-mx3/mach-cpuimx35.c @@ -201,8 +201,8 @@ static void __init mxc_board_init(void) if (!otg_mode_host) mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata); -#ifdef CONFIG_MACH_EUKREA_MBIMXSD_BASEBOARD - eukrea_mbimxsd_baseboard_init(); +#ifdef CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD + eukrea_mbimxsd35_baseboard_init(); #endif } diff --git a/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h b/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h index 634e3f4c454d..656acb45d434 100644 --- a/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h +++ b/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h @@ -37,9 +37,9 @@ * mach-mx5/eukrea_mbimx51-baseboard.c for cpuimx51 */ -extern void eukrea_mbimx25_baseboard_init(void); +extern void eukrea_mbimxsd25_baseboard_init(void); extern void eukrea_mbimx27_baseboard_init(void); -extern void eukrea_mbimx35_baseboard_init(void); +extern void eukrea_mbimxsd35_baseboard_init(void); extern void eukrea_mbimx51_baseboard_init(void); #endif -- cgit v1.2.3-59-g8ed1b From e91846213241e3c46da8cbe992bceb1697de8d78 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Aug 2010 10:43:54 -0300 Subject: perf annotate tui: Fix exit and RIGHT keys handling As part of ongoing effort to reduce the coupling with libnewt, browsers are being changed to return the exit key. The annotate browser is not returning it as expected by builtin-annotate when annotating multiple symbols (when 'perf annotate' is called without specifying a symbol name). Fix it by returning the exit key and also adding the RIGHT key as a exit key so that going to the next symbol in the TUI can work again. Cc: Frederic Weisbecker Cc: Peter Zijlstra LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 55ff792459ac..a90273e63f4f 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -146,6 +146,7 @@ static int annotate_browser__run(struct annotate_browser *self, return -1; newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); + newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT); nd = self->curr_hot; if (nd) { @@ -178,7 +179,7 @@ static int annotate_browser__run(struct annotate_browser *self, } out: ui_browser__hide(&self->b); - return 0; + return es->u.key; } int hist_entry__tui_annotate(struct hist_entry *self) -- cgit v1.2.3-59-g8ed1b From 83e4491818040ae6b2d9fc60434616304a101d39 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 16 Aug 2010 16:01:28 +0200 Subject: USB HID: Add ID for eGalax Multitouch used in JooJoo tablet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JooJoo tablet (http://thejoojoo.com/) contains an "eGalax Inc. USB TouchController", and this patch hooks it up to the egalax-touch driver. Without the patch we don't get any cursor motion, since it comes through Z/RX rather than X/Y. (The egalax-touch driver does not yet generate a correct event sequence for the "serial" protocol used by this device, though -- see the note added to the code, which comes from research by Stéphane Chatty.) Cc: Jiri Kosina Cc: Stéphane Chatty Signed-off-by: Chris Ball Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-egalax.c | 9 +++++++++ drivers/hid/hid-ids.h | 1 + 3 files changed, 11 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e635199a0cd2..0c52899be964 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1299,6 +1299,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c index f44bdc084cb2..8ca7f65cf2f8 100644 --- a/drivers/hid/hid-egalax.c +++ b/drivers/hid/hid-egalax.c @@ -159,6 +159,13 @@ static int egalax_event(struct hid_device *hid, struct hid_field *field, { struct egalax_data *td = hid_get_drvdata(hid); + /* Note, eGalax has two product lines: the first is resistive and + * uses a standard parallel multitouch protocol (product ID == + * 48xx). The second is capacitive and uses an unusual "serial" + * protocol with a different message for each multitouch finger + * (product ID == 72xx). We do not yet generate a correct event + * sequence for the capacitive/serial protocol. + */ if (hid->claimed & HID_CLAIMED_INPUT) { struct input_dev *input = field->hidinput->input; @@ -246,6 +253,8 @@ static void egalax_remove(struct hid_device *hdev) static const struct hid_device_id egalax_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, { } }; MODULE_DEVICE_TABLE(hid, egalax_devices); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d3fc13ae094d..85c6d13c9ffa 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -188,6 +188,7 @@ #define USB_VENDOR_ID_DWAV 0x0eef #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 -- cgit v1.2.3-59-g8ed1b From 5629236b31239dbaa182cb7eb39aad4d62278f7c Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Tue, 3 Aug 2010 19:44:16 +0400 Subject: x86: intel_ips: do not use PCI resources before pci_enable_device() IRQ and resource[] may not have correct values until after PCI hotplug setup occurs at pci_enable_device() time. The semantic match that finds this problem is as follows: // @@ identifier x; identifier request ~= "pci_request.*|pci_resource.*"; @@ ( * x->irq | * x->resource | * request(x, ...) ) ... *pci_enable_device(x) // Signed-off-by: Kulikov Vasiliy Reviewed-by: Jesse Barnes Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_ips.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index afe82e50dfea..fad59b69a69c 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1432,6 +1432,12 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) spin_lock_init(&ips->turbo_status_lock); + ret = pci_enable_device(dev); + if (ret) { + dev_err(&dev->dev, "can't enable PCI device, aborting\n"); + goto error_free; + } + if (!pci_resource_start(dev, 0)) { dev_err(&dev->dev, "TBAR not assigned, aborting\n"); ret = -ENXIO; @@ -1444,11 +1450,6 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) goto error_free; } - ret = pci_enable_device(dev); - if (ret) { - dev_err(&dev->dev, "can't enable PCI device, aborting\n"); - goto error_free; - } ips->regmap = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); -- cgit v1.2.3-59-g8ed1b From 2e0ee69c214a0197e1b081ffec9c409ab2a5f094 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 5 Aug 2010 22:24:12 +0200 Subject: drivers/platform/x86: Adjust confusing if indentation The assignment of ret to -EIO appears to only make sense if the branch that it is aligned with is executed, so move it into that branch. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r disable braces4@ position p1,p2; statement S1,S2; @@ ( if (...) { ... } | if (...) S1@p1 S2@p2 ) @script:python@ p1 << r.p1; p2 << r.p2; @@ if (p1[0].column == p2[0].column): cocci.print_main("branch",p1) cocci.print_secs("after",p2) // Signed-off-by: Julia Lawall Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus_acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index e058c2ba2a15..ca05aefd03bf 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -938,10 +938,11 @@ static int set_brightness(int value) /* SPLV laptop */ if (hotk->methods->brightness_set) { if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set, - value, NULL)) + value, NULL)) { printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); ret = -EIO; + } goto out; } @@ -953,10 +954,11 @@ static int set_brightness(int value) hotk->methods->brightness_down, NULL, NULL); (value > 0) ? value-- : value++; - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { printk(KERN_WARNING "Asus ACPI: Error changing brightness\n"); ret = -EIO; + } } out: return ret; -- cgit v1.2.3-59-g8ed1b From 52d7ee558d3babb4918eed6769f593adc1b6616e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 8 Aug 2010 00:01:12 +0200 Subject: intel_ips: potential null dereference There is a potential NULL dereference of "limits." We can just return NULL earlier to avoid it. The caller already handles NULL returns. Signed-off-by: Dan Carpenter Reviewed-by: Jesse Barnes Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_ips.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index fad59b69a69c..9024480a8228 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1342,8 +1342,10 @@ static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips) limits = &ips_lv_limits; else if (strstr(boot_cpu_data.x86_model_id, "CPU U")) limits = &ips_ulv_limits; - else + else { dev_info(&ips->dev->dev, "No CPUID match found.\n"); + goto out; + } rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power); tdp = turbo_power & TURBO_TDP_MASK; -- cgit v1.2.3-59-g8ed1b From 122f26726b5e16174bf8a707df14be1d93c49d62 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:18 -0300 Subject: thinkpad-acpi: find ACPI video device by synthetic HID The Linux ACPI core locates the ACPI video devices for us and marks them with ACPI_VIDEO_HID. Use that information to locate the video device instead of a half-baked hunt for _BCL. This uncouples the detection of the number of backlight brightness levels on ThinkPads from the ACPI paths in vid_handle. With this change, the driver should be able to always detect whether the ThinkPad uses a 8-level or 16-level brightness scale even on newer models for which the vid_handle paths have not been updated yet. It will skip deactivated devices in the ACPI device tree, which is a change in behaviour. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 52 +++++++++--------------------------- 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 5d6119bed00c..9d6fc4c7c08e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6080,13 +6080,18 @@ static struct backlight_ops ibm_backlight_data = { /* --------------------------------------------------------------------- */ +/* + * Call _BCL method of video device. On some ThinkPads this will + * switch the firmware to the ACPI brightness control mode. + */ + static int __init tpacpi_query_bcl_levels(acpi_handle handle) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; int rc; - if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) { + if (ACPI_SUCCESS(acpi_evaluate_object(handle, "_BCL", NULL, &buffer))) { obj = (union acpi_object *)buffer.pointer; if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) { printk(TPACPI_ERR "Unknown _BCL data, " @@ -6103,55 +6108,22 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle) return rc; } -static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle, - u32 lvl, void *context, void **rv) -{ - char name[ACPI_PATH_SEGMENT_LENGTH]; - struct acpi_buffer buffer = { sizeof(name), &name }; - - if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) && - !strncmp("_BCL", name, sizeof(name) - 1)) { - BUG_ON(!rv || !*rv); - **(int **)rv = tpacpi_query_bcl_levels(handle); - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} /* * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map */ static unsigned int __init tpacpi_check_std_acpi_brightness_support(void) { - int status; + acpi_handle video_device; int bcl_levels = 0; - void *bcl_ptr = &bcl_levels; - if (!vid_handle) - TPACPI_ACPIHANDLE_INIT(vid); + tpacpi_acpi_handle_locate("video", ACPI_VIDEO_HID, &video_device); + if (video_device) + bcl_levels = tpacpi_query_bcl_levels(video_device); - if (!vid_handle) - return 0; - - /* - * Search for a _BCL method, and execute it. This is safe on all - * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista - * BIOS in ACPI backlight control mode. We do NOT have to care - * about calling the _BCL method in an enabled video device, any - * will do for our purposes. - */ + tp_features.bright_acpimode = (bcl_levels > 0); - status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3, - tpacpi_acpi_walk_find_bcl, NULL, NULL, - &bcl_ptr); - - if (ACPI_SUCCESS(status) && bcl_levels > 2) { - tp_features.bright_acpimode = 1; - return bcl_levels - 2; - } - - return 0; + return (bcl_levels > 2) ? (bcl_levels - 2) : 0; } /* -- cgit v1.2.3-59-g8ed1b From 217f09631a420295a9688e18aa4dbad1b385e56c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:19 -0300 Subject: thinkpad-acpi: untangle ACPI/vendor backlight selection acpi_video_backlight_support() already tells us if ACPI is handling backlight control through the generic ACPI handle. It is better to just trust it. While at it, adjust down a printk priority, and test earlier for brightness_enable=0. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett --- Documentation/laptops/thinkpad-acpi.txt | 4 ++++ drivers/platform/x86/thinkpad_acpi.c | 42 ++++++++++++++++----------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index f6f80257addb..1565eefd6fd5 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -1024,6 +1024,10 @@ ThinkPad-specific interface. The driver will disable its native backlight brightness control interface if it detects that the standard ACPI interface is available in the ThinkPad. +If you want to use the thinkpad-acpi backlight brightness control +instead of the generic ACPI video backlight brightness control for some +reason, you should use the acpi_backlight=vendor kernel parameter. + The brightness_enable module parameter can be used to control whether the LCD brightness control feature will be enabled when available. brightness_enable=0 forces it to be disabled. brightness_enable=1 diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9d6fc4c7c08e..b9430e887e95 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6216,28 +6216,6 @@ static int __init brightness_init(struct ibm_init_struct *iibm) if (tp_features.bright_unkfw) return 1; - if (tp_features.bright_acpimode) { - if (acpi_video_backlight_support()) { - if (brightness_enable > 1) { - printk(TPACPI_NOTICE - "Standard ACPI backlight interface " - "available, not loading native one.\n"); - return 1; - } else if (brightness_enable == 1) { - printk(TPACPI_NOTICE - "Backlight control force enabled, even if standard " - "ACPI backlight interface is available\n"); - } - } else { - if (brightness_enable > 1) { - printk(TPACPI_NOTICE - "Standard ACPI backlight interface not " - "available, thinkpad_acpi native " - "brightness control enabled\n"); - } - } - } - if (!brightness_enable) { dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, "brightness support disabled by " @@ -6245,6 +6223,26 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; } + if (acpi_video_backlight_support()) { + if (brightness_enable > 1) { + printk(TPACPI_INFO + "Standard ACPI backlight interface " + "available, not loading native one.\n"); + return 1; + } else if (brightness_enable == 1) { + printk(TPACPI_WARN + "Cannot enable backlight brightness support, " + "ACPI is already handling it. Refer to the " + "acpi_backlight kernel parameter\n"); + return 1; + } + } else if (tp_features.bright_acpimode && brightness_enable > 1) { + printk(TPACPI_NOTICE + "Standard ACPI backlight interface not " + "available, thinkpad_acpi native " + "brightness control enabled\n"); + } + /* * Check for module parameter bogosity, note that we * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be -- cgit v1.2.3-59-g8ed1b From 34a656d22f5539f613b93e7a1d14b4bd53592505 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:20 -0300 Subject: thinkpad-acpi: lock down size of hotkey keymap Use a safer coding style for the hotkey keymap. This does not fix any problems, as the current code is correct. But it might help avoid mistakes in the future. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b9430e887e95..b0b66fbd796c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -1911,6 +1911,17 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, TP_ACPI_HOTKEYSCAN_MUTE, TP_ACPI_HOTKEYSCAN_THINKPAD, + TP_ACPI_HOTKEYSCAN_UNK1, + TP_ACPI_HOTKEYSCAN_UNK2, + TP_ACPI_HOTKEYSCAN_UNK3, + TP_ACPI_HOTKEYSCAN_UNK4, + TP_ACPI_HOTKEYSCAN_UNK5, + TP_ACPI_HOTKEYSCAN_UNK6, + TP_ACPI_HOTKEYSCAN_UNK7, + TP_ACPI_HOTKEYSCAN_UNK8, + + /* Hotkey keymap size */ + TPACPI_HOTKEY_MAP_LEN }; enum { /* Keys/events available through NVRAM polling */ @@ -3113,7 +3124,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * If the above is too much to ask, don't change the keymap. * Ask the thinkpad-acpi maintainer to do it, instead. */ - static u16 ibm_keycode_map[] __initdata = { + static u16 ibm_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, @@ -3147,7 +3158,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, }; - static u16 lenovo_keycode_map[] __initdata = { + static u16 lenovo_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, @@ -3191,7 +3202,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, }; -#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map) #define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) @@ -3469,7 +3479,8 @@ static bool hotkey_notify_hotkey(const u32 hkey, *send_acpi_ev = true; *ignore_acpi_ev = false; - if (scancode > 0 && scancode < 0x21) { + /* HKEY event 0x1001 is scancode 0x00 */ + if (scancode > 0 && scancode <= TPACPI_HOTKEY_MAP_LEN) { scancode--; if (!(hotkey_source_mask & (1 << scancode))) { tpacpi_input_send_key_masked(scancode); -- cgit v1.2.3-59-g8ed1b From d1e14dca6a18aa40394316c872993ae3bc7e311a Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Mon, 9 Aug 2010 23:48:21 -0300 Subject: thinkpad-acpi: add support for model-specific keymaps Use the quirks engine to select model-specific keymaps, which makes it much easier to extend should we need it. Keycodes are based on the tables at http://www.thinkwiki.org/wiki/Default_meanings_of_special_keys. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 60 +++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b0b66fbd796c..9ebe4f7d044e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3093,6 +3093,8 @@ static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = { TPACPI_Q_IBM('1', 'D', TPACPI_HK_Q_INIMASK), /* X22, X23, X24 */ }; +typedef u16 tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN]; + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -3124,9 +3126,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) * If the above is too much to ask, don't change the keymap. * Ask the thinkpad-acpi maintainer to do it, instead. */ - static u16 ibm_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { + + enum keymap_index { + TPACPI_KEYMAP_IBM_GENERIC = 0, + TPACPI_KEYMAP_LENOVO_GENERIC, + }; + + static const tpacpi_keymap_t tpacpi_keymaps[] __initconst = { + /* Generic keymap for IBM ThinkPads */ + [TPACPI_KEYMAP_IBM_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ - KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, + KEY_FN_F1, KEY_BATTERY, KEY_COFFEE, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, @@ -3157,8 +3167,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - }; - static u16 lenovo_keycode_map[TPACPI_HOTKEY_MAP_LEN] __initdata = { + }, + + /* Generic keymap for Lenovo ThinkPads */ + [TPACPI_KEYMAP_LENOVO_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, @@ -3200,10 +3212,25 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + }, }; -#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) -#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) + static const struct tpacpi_quirk tpacpi_keymap_qtable[] __initconst = { + /* Generic maps (fallback) */ + { + .vendor = PCI_VENDOR_ID_IBM, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = TPACPI_KEYMAP_IBM_GENERIC, + }, + { + .vendor = PCI_VENDOR_ID_LENOVO, + .bios = TPACPI_MATCH_ANY, .ec = TPACPI_MATCH_ANY, + .quirks = TPACPI_KEYMAP_LENOVO_GENERIC, + }, + }; + +#define TPACPI_HOTKEY_MAP_SIZE sizeof(tpacpi_keymap_t) +#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(tpacpi_keymap_t[0]) int res, i; int status; @@ -3212,6 +3239,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) bool tabletsw_state = false; unsigned long quirks; + unsigned long keymap_id; vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, "initializing hotkey subdriver\n"); @@ -3352,7 +3380,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; /* Set up key map */ - hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); if (!hotkey_keycode_map) { @@ -3362,17 +3389,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) goto err_exit; } - if (tpacpi_is_lenovo()) { - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "using Lenovo default hot key map\n"); - memcpy(hotkey_keycode_map, &lenovo_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); - } else { - dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, - "using IBM default hot key map\n"); - memcpy(hotkey_keycode_map, &ibm_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); - } + keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable, + ARRAY_SIZE(tpacpi_keymap_qtable)); + BUG_ON(keymap_id >= ARRAY_SIZE(tpacpi_keymaps)); + dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, + "using keymap number %lu\n", keymap_id); + + memcpy(hotkey_keycode_map, &tpacpi_keymaps[keymap_id], + TPACPI_HOTKEY_MAP_SIZE); input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; -- cgit v1.2.3-59-g8ed1b From 2b75426282a8eb29d0a004ef0d289b0491c719be Mon Sep 17 00:00:00 2001 From: Jens Taprogge Date: Mon, 9 Aug 2010 23:48:22 -0300 Subject: thinkpad-acpi: Add KEY_CAMERA (Fn-F6) for Lenovo keyboards On the T410s and most likely other current models, Fn-F6 is labeled as Camera/Headphone key. Report key presses as KEY_CAMERA. Signed-off-by: Jens Taprogge Acked-by: Jerone Young Acked-by: Henrique de Moraes Holschuh Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9ebe4f7d044e..e35ed128bdef 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3173,7 +3173,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) [TPACPI_KEYMAP_LENOVO_GENERIC] = { /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, - KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, + KEY_WLAN, KEY_CAMERA, KEY_SWITCHVIDEOMODE, KEY_FN_F8, KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, /* Scan codes 0x0C to 0x1F: Other ACPI HKEY hot keys */ -- cgit v1.2.3-59-g8ed1b From c3f755e3842108c1cffe570fe9802239810352b6 Mon Sep 17 00:00:00 2001 From: Victor van den Elzen Date: Sun, 15 Aug 2010 01:19:33 +0200 Subject: platform/x86: move rfkill for Dell Mini 1012 to compal-laptop Like others in the Mini series, the Dell Mini 1012 does not support the smbios hook required by dell-laptop. Signed-off-by: Victor van den Elzen Cc: stable Signed-off-by: Matthew Garrett --- drivers/platform/x86/compal-laptop.c | 9 +++++++++ drivers/platform/x86/dell-laptop.c | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index d071ce056322..097083cac413 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -840,6 +840,14 @@ static struct dmi_system_id __initdata compal_dmi_table[] = { }, .callback = dmi_check_cb }, + { + .ident = "Dell Mini 1012", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), + }, + .callback = dmi_check_cb + }, { .ident = "Dell Inspiron 11z", .matches = { @@ -1092,5 +1100,6 @@ MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*"); +MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*"); MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*"); diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index b41ed5cab3e7..4413975912e0 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -121,6 +121,13 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), }, }, + { + .ident = "Dell Mini 1012", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), + }, + }, { .ident = "Dell Inspiron 11z", .matches = { -- cgit v1.2.3-59-g8ed1b From 5d9ac7fd32f600f9451ea58abdb07f7ed42e921d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 5 Aug 2010 13:58:22 -0400 Subject: cifs: clean up error handling in cifs_mknod Get rid of some nesting and add a label we can goto on error. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/dir.c | 149 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 578d88c5b46e..f17d50047f07 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -496,6 +496,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, struct cifsTconInfo *pTcon; char *full_path = NULL; struct inode *newinode = NULL; + int oplock = 0; + u16 fileHandle; + FILE_ALL_INFO *buf = NULL; + unsigned int bytes_written; + struct win_dev *pdev; if (!old_valid_dev(device_number)) return -EINVAL; @@ -506,9 +511,12 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, pTcon = cifs_sb->tcon; full_path = build_path_from_dentry(direntry); - if (full_path == NULL) + if (full_path == NULL) { rc = -ENOMEM; - else if (pTcon->unix_ext) { + goto mknod_out; + } + + if (pTcon->unix_ext) { struct cifs_unix_set_info_args args = { .mode = mode & ~current_umask(), .ctime = NO_CHANGE_64, @@ -527,87 +535,78 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc) + goto mknod_out; - if (!rc) { - rc = cifs_get_inode_info_unix(&newinode, full_path, + rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); - if (pTcon->nocase) - direntry->d_op = &cifs_ci_dentry_ops; - else - direntry->d_op = &cifs_dentry_ops; - if (rc == 0) - d_instantiate(direntry, newinode); - } - } else { - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { - int oplock = 0; - u16 fileHandle; - FILE_ALL_INFO *buf; + if (pTcon->nocase) + direntry->d_op = &cifs_ci_dentry_ops; + else + direntry->d_op = &cifs_dentry_ops; - cFYI(1, "sfu compat create special file"); + if (rc == 0) + d_instantiate(direntry, newinode); + goto mknod_out; + } - buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); - if (buf == NULL) { - kfree(full_path); - rc = -ENOMEM; - FreeXid(xid); - return rc; - } + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) + goto mknod_out; - rc = CIFSSMBOpen(xid, pTcon, full_path, - FILE_CREATE, /* fail if exists */ - GENERIC_WRITE /* BB would - WRITE_OWNER | WRITE_DAC be better? */, - /* Create a file and set the - file attribute to SYSTEM */ - CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, - &fileHandle, &oplock, buf, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); - - /* BB FIXME - add handling for backlevel servers - which need legacy open and check for all - calls to SMBOpen for fallback to SMBLeagcyOpen */ - if (!rc) { - /* BB Do not bother to decode buf since no - local inode yet to put timestamps in, - but we can reuse it safely */ - unsigned int bytes_written; - struct win_dev *pdev; - pdev = (struct win_dev *)buf; - if (S_ISCHR(mode)) { - memcpy(pdev->type, "IntxCHR", 8); - pdev->major = - cpu_to_le64(MAJOR(device_number)); - pdev->minor = - cpu_to_le64(MINOR(device_number)); - rc = CIFSSMBWrite(xid, pTcon, - fileHandle, - sizeof(struct win_dev), - 0, &bytes_written, (char *)pdev, - NULL, 0); - } else if (S_ISBLK(mode)) { - memcpy(pdev->type, "IntxBLK", 8); - pdev->major = - cpu_to_le64(MAJOR(device_number)); - pdev->minor = - cpu_to_le64(MINOR(device_number)); - rc = CIFSSMBWrite(xid, pTcon, - fileHandle, - sizeof(struct win_dev), - 0, &bytes_written, (char *)pdev, - NULL, 0); - } /* else if(S_ISFIFO */ - CIFSSMBClose(xid, pTcon, fileHandle); - d_drop(direntry); - } - kfree(buf); - /* add code here to set EAs */ - } + + cFYI(1, "sfu compat create special file"); + + buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); + if (buf == NULL) { + kfree(full_path); + rc = -ENOMEM; + FreeXid(xid); + return rc; } + /* FIXME: would WRITE_OWNER | WRITE_DAC be better? */ + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE, + GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, + &fileHandle, &oplock, buf, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc) + goto mknod_out; + + /* BB Do not bother to decode buf since no local inode yet to put + * timestamps in, but we can reuse it safely */ + + pdev = (struct win_dev *)buf; + if (S_ISCHR(mode)) { + memcpy(pdev->type, "IntxCHR", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } else if (S_ISBLK(mode)) { + memcpy(pdev->type, "IntxBLK", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } /* else if (S_ISFIFO) */ + CIFSSMBClose(xid, pTcon, fileHandle); + d_drop(direntry); + + /* FIXME: add code here to set EAs */ + +mknod_out: kfree(full_path); + kfree(buf); FreeXid(xid); return rc; } -- cgit v1.2.3-59-g8ed1b From 0a492896ac07336c98f37ad7fab4a6387b6ada78 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 15 Aug 2010 00:26:14 -0700 Subject: sparc: Really fix "console=" for serial consoles. If a video head and keyboard are hooked up, specifying "console=ttyS0" or similar to use a serial console will not work properly. The key issue is that we must register all serial console capable devices with register_console(), otherwise the command line specified device won't be found. The sun serial drivers would only register themselves as console devices if the OpenFirmware specified console device node matched. To fix this part we now unconditionally get the serial console register by setting serial_drv->cons always. Secondarily we must not add_preferred_console() using the firmware provided console setting if the user gaven an override on the kernel command line using "console=" The "primary framebuffer" matching logic was always triggering o n openfirmware device node match, make it not when a command line override was given. Reported-by: Frans Pop Tested-by: Frans Pop Signed-off-by: David S. Miller --- arch/sparc/include/asm/fb.h | 4 ++++ drivers/serial/suncore.c | 15 +++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/sparc/include/asm/fb.h b/arch/sparc/include/asm/fb.h index e834880be204..2173432ad7f7 100644 --- a/arch/sparc/include/asm/fb.h +++ b/arch/sparc/include/asm/fb.h @@ -1,5 +1,6 @@ #ifndef _SPARC_FB_H_ #define _SPARC_FB_H_ +#include #include #include #include @@ -18,6 +19,9 @@ static inline int fb_is_primary_device(struct fb_info *info) struct device *dev = info->device; struct device_node *node; + if (console_set_on_cmdline) + return 0; + node = dev->of_node; if (node && node == of_console_device) diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c index 544f2e25d0e5..6381a0282ee7 100644 --- a/drivers/serial/suncore.c +++ b/drivers/serial/suncore.c @@ -55,7 +55,12 @@ EXPORT_SYMBOL(sunserial_unregister_minors); int sunserial_console_match(struct console *con, struct device_node *dp, struct uart_driver *drv, int line, bool ignore_line) { - if (!con || of_console_device != dp) + if (!con) + return 0; + + drv->cons = con; + + if (of_console_device != dp) return 0; if (!ignore_line) { @@ -69,12 +74,10 @@ int sunserial_console_match(struct console *con, struct device_node *dp, return 0; } - con->index = line; - drv->cons = con; - - if (!console_set_on_cmdline) + if (!console_set_on_cmdline) { + con->index = line; add_preferred_console(con->name, line, NULL); - + } return 1; } EXPORT_SYMBOL(sunserial_console_match); -- cgit v1.2.3-59-g8ed1b From 232341ba7fa15115d40f6aa0f8dd14e96e3ad375 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 5 Aug 2010 13:58:38 -0400 Subject: cifs: consolidate error handling in several functions cifs has a lot of complicated functions that have to clean up things on error, but some of them don't have all of the cleanup code well-consolidated. Clean up and consolidate error handling in several functions. This is in preparation of later patches that will need to put references to the tcon link container. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/dir.c | 8 +++----- fs/cifs/file.c | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f17d50047f07..f9ed0751cc12 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -305,8 +305,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, full_path = build_path_from_dentry(direntry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto cifs_create_out; } if (oplockEnabled) @@ -365,9 +364,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (buf == NULL) { - kfree(full_path); - FreeXid(xid); - return -ENOMEM; + rc = -ENOMEM; + goto cifs_create_out; } /* diff --git a/fs/cifs/file.c b/fs/cifs/file.c index db11fdef0e92..de748c652d11 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -242,8 +242,7 @@ int cifs_open(struct inode *inode, struct file *file) full_path = build_path_from_dentry(file->f_path.dentry); if (full_path == NULL) { rc = -ENOMEM; - FreeXid(xid); - return rc; + goto out; } cFYI(1, "inode = 0x%p file flags are 0x%x for %s", -- cgit v1.2.3-59-g8ed1b From b9e0ba8114583b0462cfb18b4ca01fc82894c5c0 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 11 Aug 2010 20:56:03 +0400 Subject: booting-without-of: Remove nonexistent chapters from TOC, fix numbering Marvell and GPIO bindings live in their own files, so the TOC should not mention them. Also fix chapters numbering. Signed-off-by: Anton Vorontsov Signed-off-by: Grant Likely --- Documentation/powerpc/booting-without-of.txt | 31 ++-------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 568fa08e82e5..302db5da49b3 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -49,40 +49,13 @@ Table of Contents f) MDIO on GPIOs g) SPI busses - VII - Marvell Discovery mv64[345]6x System Controller chips - 1) The /system-controller node - 2) Child nodes of /system-controller - a) Marvell Discovery MDIO bus - b) Marvell Discovery ethernet controller - c) Marvell Discovery PHY nodes - d) Marvell Discovery SDMA nodes - e) Marvell Discovery BRG nodes - f) Marvell Discovery CUNIT nodes - g) Marvell Discovery MPSCROUTING nodes - h) Marvell Discovery MPSCINTR nodes - i) Marvell Discovery MPSC nodes - j) Marvell Discovery Watch Dog Timer nodes - k) Marvell Discovery I2C nodes - l) Marvell Discovery PIC (Programmable Interrupt Controller) nodes - m) Marvell Discovery MPP (Multipurpose Pins) multiplexing nodes - n) Marvell Discovery GPP (General Purpose Pins) nodes - o) Marvell Discovery PCI host bridge node - p) Marvell Discovery CPU Error nodes - q) Marvell Discovery SRAM Controller nodes - r) Marvell Discovery PCI Error Handler nodes - s) Marvell Discovery Memory Controller nodes - - VIII - Specifying interrupt information for devices + VII - Specifying interrupt information for devices 1) interrupts property 2) interrupt-parent property 3) OpenPIC Interrupt Controllers 4) ISA Interrupt Controllers - IX - Specifying GPIO information for devices - 1) gpios property - 2) gpio-controller nodes - - X - Specifying device power management information (sleep property) + VIII - Specifying device power management information (sleep property) Appendix A - Sample SOC node for MPC8540 -- cgit v1.2.3-59-g8ed1b From a8dcb878b628203f917c50b0268bba7fd146d9c0 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 16 Aug 2010 10:31:53 +0200 Subject: microblaze: Fix of/address: Merge all of the bus translation code Commit dbbdee94734bf6f1db7af42008a53655e77cab8f removed of_irq_pci_swizzle but didn't use pci_swizzle_interrupt_pin instead. Signed-off-by: Michal Simek Signed-off-by: Grant Likely --- arch/microblaze/kernel/prom_parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c index d33ba17601fa..99d9b61cccb5 100644 --- a/arch/microblaze/kernel/prom_parse.c +++ b/arch/microblaze/kernel/prom_parse.c @@ -73,7 +73,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) /* We can only get here if we hit a P2P bridge with no node, * let's do standard swizzling and try again */ - lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); + lspec = pci_swizzle_interrupt_pin(pdev, lspec); pdev = ppdev; } -- cgit v1.2.3-59-g8ed1b From 088ab302f23bfc8abfaada32506d02d64a637b23 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 16 Aug 2010 10:31:54 +0200 Subject: microblaze: Fix of: eliminate of_device->node and dev_archdata->{of,prom}_node Commit 58f9b0b02414062eaff46716bc04b47d7e79add5 should contain this fix too. Signed-off-by: Michal Simek Signed-off-by: Grant Likely --- arch/microblaze/pci/pci-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 23be25fec4d6..6ca8531a539e 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -1077,7 +1077,7 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus) struct dev_archdata *sd = &dev->dev.archdata; /* Setup OF node pointer in archdata */ - sd->of_node = pci_device_to_OF_node(dev); + dev->dev.of_node = pci_device_to_OF_node(dev); /* Fixup NUMA node as it may not be setup yet by the generic * code and is needed by the DMA init -- cgit v1.2.3-59-g8ed1b From b590cddfa6f40447158323b43a13cdae01d9a051 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 16 Aug 2010 15:58:29 -0500 Subject: kdb: fix compile error without CONFIG_KALLSYMS If CONFIG_KGDB_KDB is set and CONFIG_KALLSYMS is not set the kernel will fail to build with the error: kernel/built-in.o: In function `kallsyms_symbol_next': kernel/debug/kdb/kdb_support.c:237: undefined reference to `kdb_walk_kallsyms' kernel/built-in.o: In function `kallsyms_symbol_complete': kernel/debug/kdb/kdb_support.c:193: undefined reference to `kdb_walk_kallsyms' The kdb_walk_kallsyms needs a #ifdef proper header to match the C implementation. This patch also fixes the compiler warnings in kdb_support.c when compiling without CONFIG_KALLSYMS set. The compiler warnings are a result of the kallsyms_lookup() macro not initializing the two of the pass by reference variables. Signed-off-by: Jason Wessel Reported-by: Michal Simek --- kernel/debug/kdb/kdb_private.h | 7 +++++++ kernel/debug/kdb/kdb_support.c | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/debug/kdb/kdb_private.h b/kernel/debug/kdb/kdb_private.h index c438f545a321..be775f7e81e0 100644 --- a/kernel/debug/kdb/kdb_private.h +++ b/kernel/debug/kdb/kdb_private.h @@ -255,7 +255,14 @@ extern void kdb_ps1(const struct task_struct *p); extern void kdb_print_nameval(const char *name, unsigned long val); extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info); extern void kdb_meminfo_proc_show(void); +#ifdef CONFIG_KALLSYMS extern const char *kdb_walk_kallsyms(loff_t *pos); +#else /* ! CONFIG_KALLSYMS */ +static inline const char *kdb_walk_kallsyms(loff_t *pos) +{ + return NULL; +} +#endif /* ! CONFIG_KALLSYMS */ extern char *kdb_getstr(char *, size_t, char *); /* Defines for kdb_symbol_print */ diff --git a/kernel/debug/kdb/kdb_support.c b/kernel/debug/kdb/kdb_support.c index 45344d5c53dd..6b2485dcb050 100644 --- a/kernel/debug/kdb/kdb_support.c +++ b/kernel/debug/kdb/kdb_support.c @@ -82,8 +82,8 @@ static char *kdb_name_table[100]; /* arbitrary size */ int kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) { int ret = 0; - unsigned long symbolsize; - unsigned long offset; + unsigned long symbolsize = 0; + unsigned long offset = 0; #define knt1_size 128 /* must be >= kallsyms table size */ char *knt1 = NULL; -- cgit v1.2.3-59-g8ed1b From 8c8aefce934dc45de641fe78d48ff1b7722d826a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sat, 7 Aug 2010 11:00:59 -0700 Subject: kgdb: add missing __percpu markup in arch/x86/kernel/kgdb.c breakinfo->pev is a pointer to percpu pointer but was missing __percpu markup. Add it. Signed-off-by: Namhyung Kim Signed-off-by: Jason Wessel --- arch/x86/kernel/kgdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index ef10940e1af0..852b81967a37 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -194,7 +194,7 @@ static struct hw_breakpoint { unsigned long addr; int len; int type; - struct perf_event **pev; + struct perf_event * __percpu *pev; } breakinfo[HBP_NUM]; static unsigned long early_dr7; -- cgit v1.2.3-59-g8ed1b From 787ea1c5811b11124d28c8d85f483c4cd37f5c58 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Mon, 16 Aug 2010 15:58:30 -0500 Subject: arm,kgdb: fix GDB_MAX_REGS no longer used According to commit 22eeef4bb2a7fd225089c0044060ed1fbf091958 kgdb,arm: Individual register get/set for arm It's now replaced by DBG_MAX_REG_NUM. Signed-off-by: Eric Miao Signed-off-by: Jason Wessel --- arch/arm/kernel/kgdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index 778c2f7024ff..d6e8b4d2e60d 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) return; /* Initialize to zero */ - for (regno = 0; regno < GDB_MAX_REGS; regno++) + for (regno = 0; regno < DBG_MAX_REG_NUM; regno++) gdb_regs[regno] = 0; /* Otherwise, we have only some registers from switch_to() */ -- cgit v1.2.3-59-g8ed1b From fed891c89bfd8ef898c2289b34e748969bb12798 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 16 Aug 2010 15:58:30 -0500 Subject: vt: fix regression warnings from KMS merge Fix the following new sparse warnings in vt.c introduced by the commit b45cfba4e9005d64d419718e7ff7f7cab44c1994 (vt,console,kdb: implement atomic console enter/leave functions): drivers/char/vt.c:197:5: warning: symbol 'saved_fg_console' was not declared. Should it be static? drivers/char/vt.c:198:5: warning: symbol 'saved_last_console' was not declared. Should it be static? drivers/char/vt.c:199:5: warning: symbol 'saved_want_console' was not declared. Should it be static? drivers/char/vt.c:200:5: warning: symbol 'saved_vc_mode' was not declared. Should it be static? Signed-off-by: Jason Wessel Reviewed-by: Jesse Barnes CC: Andrew Morton --- drivers/char/vt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index c734f9b1263a..3af1a2229fec 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -194,10 +194,10 @@ static DECLARE_WORK(console_work, console_callback); int fg_console; int last_console; int want_console = -1; -int saved_fg_console; -int saved_last_console; -int saved_want_console; -int saved_vc_mode; +static int saved_fg_console; +static int saved_last_console; +static int saved_want_console; +static int saved_vc_mode; /* * For each existing display, we have a pointer to console currently visible -- cgit v1.2.3-59-g8ed1b From beed5336eba6a5a70c97e9f4bfff525915a25003 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Mon, 16 Aug 2010 15:58:31 -0500 Subject: vt,console,kdb: preserve console_blanked while in kdb Commit b45cfba4e9005d64d419718e7ff7f7cab44c1994 (vt,console,kdb: implement atomic console enter/leave functions) introduced the ability to atomically change the console mode with kernel mode setting but did not preserve the state of the console_blanked variable. The console_blanked variable must be restored when executing the con_debug_leave() or further kernel mode set changes (such as using chvt X) will fail to correctly set the state of console. Signed-off-by: Jason Wessel Reviewed-by: Jesse Barnes CC: Andrew Morton --- drivers/char/vt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 3af1a2229fec..50590c7f2c01 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -198,6 +198,7 @@ static int saved_fg_console; static int saved_last_console; static int saved_want_console; static int saved_vc_mode; +static int saved_console_blanked; /* * For each existing display, we have a pointer to console currently visible @@ -3449,6 +3450,7 @@ int con_debug_enter(struct vc_data *vc) saved_last_console = last_console; saved_want_console = want_console; saved_vc_mode = vc->vc_mode; + saved_console_blanked = console_blanked; vc->vc_mode = KD_TEXT; console_blanked = 0; if (vc->vc_sw->con_debug_enter) @@ -3492,6 +3494,7 @@ int con_debug_leave(void) fg_console = saved_fg_console; last_console = saved_last_console; want_console = saved_want_console; + console_blanked = saved_console_blanked; vc_cons[fg_console].d->vc_mode = saved_vc_mode; vc = vc_cons[fg_console].d; -- cgit v1.2.3-59-g8ed1b From 60652d07a028595df5c2582e915325d643a3800d Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 16 Aug 2010 12:20:59 +1000 Subject: ata: update for of_device to platform_device replacement Signed-off-by: Stephen Rothwell Signed-off-by: Grant Likely --- drivers/ata/sata_dwc_460ex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index ea24c1e51be2..2673a3d14806 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1588,7 +1588,7 @@ static const struct ata_port_info sata_dwc_port_info[] = { }, }; -static int sata_dwc_probe(struct of_device *ofdev, +static int sata_dwc_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct sata_dwc_device *hsdev; @@ -1702,7 +1702,7 @@ error_out: return err; } -static int sata_dwc_remove(struct of_device *ofdev) +static int sata_dwc_remove(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; struct ata_host *host = dev_get_drvdata(dev); -- cgit v1.2.3-59-g8ed1b From 8e8073a449b2e00641c095ad55bd56f43468daf9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 16 Aug 2010 15:04:29 -0700 Subject: sparc: Hook up new fanotify and prlimit64 syscalls. The only tricky bit is the compat version of fanotify_mark, which which on 32-bit the 64-bit mark argument is passed in as "high32", "low32". Signed-off-by: David S. Miller --- arch/sparc/include/asm/unistd.h | 5 ++++- arch/sparc/kernel/sys32.S | 9 +++++++++ arch/sparc/kernel/systbls_32.S | 3 ++- arch/sparc/kernel/systbls_64.S | 6 ++++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index d0b3b01ac9d4..03eb5a8f6f93 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -397,8 +397,11 @@ #define __NR_rt_tgsigqueueinfo 326 #define __NR_perf_event_open 327 #define __NR_recvmmsg 328 +#define __NR_fanotify_init 329 +#define __NR_fanotify_mark 330 +#define __NR_prlimit64 331 -#define NR_syscalls 329 +#define NR_syscalls 332 #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S index 46a76ba3fb4b..44e5faf1ad5f 100644 --- a/arch/sparc/kernel/sys32.S +++ b/arch/sparc/kernel/sys32.S @@ -330,6 +330,15 @@ do_sys_accept4: /* sys_accept4(int, struct sockaddr *, int *, int) */ nop nop + .globl sys32_fanotify_mark +sys32_fanotify_mark: + sethi %hi(sys_fanotify_mark), %g1 + sllx %o2, 32, %o2 + or %o2, %o3, %o2 + mov %o4, %o3 + jmpl %g1 + %lo(sys_fanotify_mark), %g0 + mov %o5, %o4 + .section __ex_table,"a" .align 4 .word 1b, __retl_efault, 2b, __retl_efault diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S index 801fc8e5a0e8..ec396e1916b9 100644 --- a/arch/sparc/kernel/systbls_32.S +++ b/arch/sparc/kernel/systbls_32.S @@ -82,5 +82,6 @@ sys_call_table: /*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate /*315*/ .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv -/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg +/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init +/*330*/ .long sys_fanotify_mark, sys_prlimit64 diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 9db058dd039e..8cfcaa549580 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S @@ -83,7 +83,8 @@ sys_call_table32: /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv - .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg + .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init +/*330*/ .word sys32_fanotify_mark, sys_prlimit64 #endif /* CONFIG_COMPAT */ @@ -158,4 +159,5 @@ sys_call_table: /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 /*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv - .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg + .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init +/*330*/ .word sys_fanotify_mark, sys_prlimit64 -- cgit v1.2.3-59-g8ed1b From 7cb4dc9fc95f89587f57f287b47e091d7806255e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 11 Aug 2010 11:28:02 +0200 Subject: AppArmor: fix task_setrlimit prototype After rlimits tree was merged we get the following errors: security/apparmor/lsm.c:663:2: warning: initialization from incompatible pointer type It is because AppArmor was merged in the meantime, but uses the old prototype. So fix it by adding struct task_struct as a first parameter of apparmor_task_setrlimit. NOTE that this is ONLY a compilation warning fix (and crashes caused by that). It needs proper handling in AppArmor depending on who is the 'task'. Signed-off-by: Jiri Slaby Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/lsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index d5666d3cc21b..f73e2c204218 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -607,8 +607,8 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, return error; } -static int apparmor_task_setrlimit(unsigned int resource, - struct rlimit *new_rlim) +static int apparmor_task_setrlimit(struct task_struct *task, + unsigned int resource, struct rlimit *new_rlim) { struct aa_profile *profile = aa_current_profile(); int error = 0; -- cgit v1.2.3-59-g8ed1b From 4ca2b7120cf8ee266e6c44429ccb541d63480c4a Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 8 Aug 2010 21:35:57 +0200 Subject: drm/nouveau: Don't try DDC on the dummy I2C channel. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index b1b22baf1428..a1473fff06ac 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -104,7 +104,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - struct nouveau_i2c_chan *i2c; + struct nouveau_i2c_chan *i2c = NULL; struct nouveau_encoder *nv_encoder; struct drm_mode_object *obj; int id; @@ -117,7 +117,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, if (!obj) continue; nv_encoder = nouveau_encoder(obj_to_encoder(obj)); - i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + + if (nv_encoder->dcb->i2c_index < 0xf) + i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) { *pnv_encoder = nv_encoder; -- cgit v1.2.3-59-g8ed1b From 56dfc58ea094e7a8607786f4762c65b09cd85738 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 10 Aug 2010 10:50:13 +1000 Subject: drm/nv50: fix minor thinko from nvc0 changes Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index 0bd407ca3d42..84614858728b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -163,7 +163,7 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) if (entry->chan) return -EEXIST; - if (dev_priv->card_type == NV_C0 && entry->read >= NV50_I2C_PORTS) { + if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) { NV_ERROR(dev, "unknown i2c port %d\n", entry->read); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 415e6186f17136075f7cc825ba3835d005773637 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 23 Jul 2010 09:06:52 +1000 Subject: drm/nouveau: fix race condition when under memory pressure When VRAM is running out it's possible that the client's push buffers get evicted to main memory. When they're validated back in, the GPU may be used for the copy back to VRAM, but the existing synchronisation code only deals with inter-channel sync, not sync between PFIFO and PGRAPH on the same channel. This leads to PFIFO fetching from command buffers that haven't quite been copied by PGRAPH yet. This patch marks push buffers as so, and forces any GPU-assisted buffer moves to be done on a different channel, which triggers the correct synchronisation to happen before we submit them. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bo.c | 15 +++++++++++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 1 + drivers/gpu/drm/nouveau/nouveau_gem.c | 36 +++++++++++++++++++++++++---------- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 84f85183d041..f6f44779d82f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -36,6 +36,21 @@ #include #include +int +nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan) +{ + struct nouveau_fence *prev_fence = nvbo->bo.sync_obj; + int ret; + + if (!prev_fence || nouveau_fence_channel(prev_fence) == chan) + return 0; + + spin_lock(&nvbo->bo.lock); + ret = ttm_bo_wait(&nvbo->bo, false, false, false); + spin_unlock(&nvbo->bo.lock); + return ret; +} + static void nouveau_bo_del_ttm(struct ttm_buffer_object *bo) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e424bf74d706..1e093a069b7b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1165,6 +1165,7 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); +extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *); /* nouveau_fence.c */ struct nouveau_fence; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 547f2c24c1e7..a915dcdd9a49 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -361,16 +361,11 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, list_for_each_entry(nvbo, list, entry) { struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; - struct nouveau_fence *prev_fence = nvbo->bo.sync_obj; - if (prev_fence && nouveau_fence_channel(prev_fence) != chan) { - spin_lock(&nvbo->bo.lock); - ret = ttm_bo_wait(&nvbo->bo, false, false, false); - spin_unlock(&nvbo->bo.lock); - if (unlikely(ret)) { - NV_ERROR(dev, "fail wait other chan\n"); - return ret; - } + ret = nouveau_bo_sync_gpu(nvbo, chan); + if (unlikely(ret)) { + NV_ERROR(dev, "fail pre-validate sync\n"); + return ret; } ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains, @@ -381,7 +376,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, return ret; } - nvbo->channel = chan; + nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan; ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, false, false, false); nvbo->channel = NULL; @@ -390,6 +385,12 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, return ret; } + ret = nouveau_bo_sync_gpu(nvbo, chan); + if (unlikely(ret)) { + NV_ERROR(dev, "fail post-validate sync\n"); + return ret; + } + if (nvbo->bo.offset == b->presumed.offset && ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || @@ -615,6 +616,21 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); + /* Mark push buffers as being used on PFIFO, the validation code + * will then make sure that if the pushbuf bo moves, that they + * happen on the kernel channel, which will in turn cause a sync + * to happen before we try and submit the push buffer. + */ + for (i = 0; i < req->nr_push; i++) { + if (push[i].bo_index >= req->nr_buffers) { + NV_ERROR(dev, "push %d buffer not in list\n", i); + ret = -EINVAL; + goto out; + } + + bo[push[i].bo_index].read_domains |= (1 << 31); + } + /* Validate buffer list */ ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, req->nr_buffers, &op, &do_reloc); -- cgit v1.2.3-59-g8ed1b From bd6aaea89318bd3aede9e219d6a003afd9978d5b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 12 Aug 2010 10:23:06 +1000 Subject: drm/nouveau: check for error when allocating/mapping dummy page Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 491767fe4fcf..6b9187d7f67d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -214,6 +214,7 @@ int nouveau_sgdma_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev->pdev; struct nouveau_gpuobj *gpuobj = NULL; uint32_t aper_size, obj_size; int i, ret; @@ -239,10 +240,19 @@ nouveau_sgdma_init(struct drm_device *dev) dev_priv->gart_info.sg_dummy_page = alloc_page(GFP_KERNEL|__GFP_DMA32); + if (!dev_priv->gart_info.sg_dummy_page) { + nouveau_gpuobj_del(dev, &gpuobj); + return -ENOMEM; + } + set_bit(PG_locked, &dev_priv->gart_info.sg_dummy_page->flags); dev_priv->gart_info.sg_dummy_bus = - pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0, + pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) { + nouveau_gpuobj_del(dev, &gpuobj); + return -EFAULT; + } if (dev_priv->card_type < NV_50) { /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and -- cgit v1.2.3-59-g8ed1b From 98720bf4e1ba5f1d0109f97a49a9028b91f25cbe Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Aug 2010 08:31:22 +1000 Subject: drm/nouveau: remove warning about unknown tmds table revisions This message is apparently confusing people, and is being blamed for some modesetting issues. Lets remove the message, and instead replace it with an unconditional printout of the table revision. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 0b69a9628c95..4a7bd7cafad6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5357,19 +5357,17 @@ static int parse_bit_tmds_tbl_entry(struct drm_device *dev, struct nvbios *bios, } tmdstableptr = ROM16(bios->data[bitentry->offset]); - - if (tmdstableptr == 0x0) { + if (!tmdstableptr) { NV_ERROR(dev, "Pointer to TMDS table invalid\n"); return -EINVAL; } + NV_INFO(dev, "TMDS table version %d.%d\n", + bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf); + /* nv50+ has v2.0, but we don't parse it atm */ - if (bios->data[tmdstableptr] != 0x11) { - NV_WARN(dev, - "TMDS table revision %d.%d not currently supported\n", - bios->data[tmdstableptr] >> 4, bios->data[tmdstableptr] & 0xf); + if (bios->data[tmdstableptr] != 0x11) return -ENOSYS; - } /* * These two scripts are odd: they don't seem to get run even when -- cgit v1.2.3-59-g8ed1b From 45a68a072ee3b7f8fbd84b946aac827cc61256b0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Aug 2010 08:37:55 +1000 Subject: drm/nouveau: punt some more log messages to debug level Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 4a7bd7cafad6..9e7fc1d0321c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -4587,7 +4587,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing output script 0\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -1) { @@ -4597,7 +4597,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing output script 1\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk == -2) { @@ -4610,7 +4610,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing output script 2\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk > 0) { @@ -4622,7 +4622,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } else if (pxclk < 0) { @@ -4634,7 +4634,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, return 1; } - NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script); + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); nouveau_bios_run_init_table(dev, script, dcbent); } -- cgit v1.2.3-59-g8ed1b From 46d4cae20038bcb2511cba0c86f0be2d11520369 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 13 Aug 2010 10:22:41 +1000 Subject: drm/nv50-nvc0: ramht_size is meant to be in bytes, not entries Fixes an infinite loop that can happen in RAMHT lookup. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_instmem.c | 2 +- drivers/gpu/drm/nouveau/nvc0_instmem.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 37c7b48ab24a..c95bf9b681dd 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -278,7 +278,7 @@ nv50_instmem_init(struct drm_device *dev) /*XXX: incorrect, but needed to make hash func "work" */ dev_priv->ramht_offset = 0x10000; dev_priv->ramht_bits = 9; - dev_priv->ramht_size = (1 << dev_priv->ramht_bits); + dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 3ab3cdc42173..854e0d72fc0d 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -221,7 +221,7 @@ nvc0_instmem_init(struct drm_device *dev) /*XXX: incorrect, but needed to make hash func "work" */ dev_priv->ramht_offset = 0x10000; dev_priv->ramht_bits = 9; - dev_priv->ramht_size = (1 << dev_priv->ramht_bits); + dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; return 0; } -- cgit v1.2.3-59-g8ed1b From 19bf5f7df918f86a1507389101b5eddcad983951 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 14 Aug 2010 18:45:58 +0200 Subject: drm/nouveau: Add TV-out quirk for an MSI nForce2 IGP. The blob also thinks there's a TV connected, so hardware bug... Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv17_tv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 44fefb0c7083..eefa5c856932 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -129,6 +129,14 @@ get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) return false; } + /* MSI nForce2 IGP */ + if (dev->pdev->device == 0x01f0 && + dev->pdev->subsystem_vendor == 0x1462 && + dev->pdev->subsystem_device == 0x5710) { + *pin_mask = 0xc; + return false; + } + return true; } -- cgit v1.2.3-59-g8ed1b From 20d66daf0aeae4abd2f498d0cedf3e506946f3c2 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 15 Aug 2010 14:32:49 +0200 Subject: drm/nouveau: Workaround missing GPIO tables on an Apple iMac G4 NV18. This should fix the reported TV-out load detection false positives (fdo bug 29455). Reported-by: Vlado Plaga Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 9e7fc1d0321c..e144f7a38d81 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -5807,6 +5807,22 @@ parse_dcb_gpio_table(struct nvbios *bios) gpio->line = tvdac_gpio[1] >> 4; gpio->invert = tvdac_gpio[0] & 2; } + } else { + /* + * No systematic way to store GPIO info on pre-v2.2 + * DCBs, try to match the PCI device IDs. + */ + + /* Apple iMac G4 NV18 */ + if (dev->pdev->device == 0x0189 && + dev->pdev->subsystem_vendor == 0x10de && + dev->pdev->subsystem_device == 0x0010) { + struct dcb_gpio_entry *gpio = new_gpio_entry(bios); + + gpio->tag = DCB_GPIO_TVDAC0; + gpio->line = 4; + } + } if (!gpio_table_ptr) -- cgit v1.2.3-59-g8ed1b From b515f3a2d8f8543aa189ac8d10195f923b64245b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 16 Aug 2010 08:18:16 +1000 Subject: drm/nvc0: fix thinko in instmem suspend/resume Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_instmem.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 854e0d72fc0d..6b451f864783 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c @@ -142,14 +142,16 @@ int nvc0_instmem_suspend(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 *buf; int i; dev_priv->susres.ramin_copy = vmalloc(65536); if (!dev_priv->susres.ramin_copy) return -ENOMEM; + buf = dev_priv->susres.ramin_copy; - for (i = 0x700000; i < 0x710000; i += 4) - dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i); + for (i = 0; i < 65536; i += 4) + buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); return 0; } @@ -157,14 +159,15 @@ void nvc0_instmem_resume(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 *buf = dev_priv->susres.ramin_copy; u64 chan; int i; chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; nv_wr32(dev, 0x001700, chan >> 16); - for (i = 0x700000; i < 0x710000; i += 4) - nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]); + for (i = 0; i < 65536; i += 4) + nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); vfree(dev_priv->susres.ramin_copy); dev_priv->susres.ramin_copy = NULL; -- cgit v1.2.3-59-g8ed1b From 625db6b7e34580b750a13fd36a211a4366f6c3e2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 17 Aug 2010 12:02:43 +1000 Subject: drm/nouveau: fix earlier mistake when fixing merge conflict Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e144f7a38d81..e4f33a4edea1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -2166,7 +2166,7 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb, uint32_t val = 0; if (off < pci_resource_len(dev->pdev, 1)) { - uint32_t __iomem *p = + uint8_t __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0); val = ioread32(p + (off & ~PAGE_MASK)); @@ -2182,7 +2182,7 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb, uint32_t off, uint32_t val) { if (off < pci_resource_len(dev->pdev, 1)) { - uint32_t __iomem *p = + uint8_t __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0); iowrite32(val, p + (off & ~PAGE_MASK)); -- cgit v1.2.3-59-g8ed1b From b9f0aee83335db1f3915f4e42a5e21b351740afd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 17 Aug 2010 14:46:00 +1000 Subject: drm: stop information leak of old kernel stack. non-critical issue, CVE-2010-2803 Userspace controls the amount of memory to be allocate, so it can get the ioctl to allocate more memory than the kernel uses, and get access to kernel stack. This can only be done for processes authenticated to the X server for DRI access, and if the user has DRI access. Fix is to just memset the data to 0 if the user doesn't copy into it in the first place. Reported-by: Kees Cook Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_drv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 90288ec7c284..3644c94c0a17 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -477,7 +477,9 @@ long drm_ioctl(struct file *filp, retcode = -EFAULT; goto err_i1; } - } + } else + memset(kdata, 0, _IOC_SIZE(cmd)); + if (ioctl->flags & DRM_UNLOCKED) retcode = func(dev, kdata, file_priv); else { -- cgit v1.2.3-59-g8ed1b From 1b2f1489633888d4a06028315dc19d65768a1c05 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 14 Aug 2010 20:20:34 +1000 Subject: drm: block userspace under allocating buffer and having drivers overwrite it (v2) With the current screwed but its ABI, ioctls for the drm, Linus pointed out that we could allow userspace to specify the allocation size, but we pass it to the driver which then uses it blindly to store a struct. Now if userspace specifies the allocation size as smaller than the driver needs, the driver can possibly overwrite memory. This patch restructures the driver ioctls so we store the structure size we are expecting, and make sure we allocate at least that size. The copy from/to userspace are still restricted to the size the user specifies, this allows ioctl structs to grow on both sides of the equation. Up until now we didn't really use the DRM_IOCTL defines in the kernel, so this cleans them up and adds them for nouveau. v2: fix nouveau pushbuf arg (thanks to Ben for pointing it out) Reported-by: Linus Torvalds Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_drv.c | 23 ++++++--- drivers/gpu/drm/i810/i810_dma.c | 30 ++++++------ drivers/gpu/drm/i830/i830_dma.c | 28 +++++------ drivers/gpu/drm/i915/i915_dma.c | 80 +++++++++++++++---------------- drivers/gpu/drm/mga/mga_state.c | 26 +++++----- drivers/gpu/drm/nouveau/nouveau_channel.c | 24 +++++----- drivers/gpu/drm/r128/r128_state.c | 35 +++++++------- drivers/gpu/drm/radeon/radeon_kms.c | 78 +++++++++++++++--------------- drivers/gpu/drm/radeon/radeon_state.c | 56 +++++++++++----------- drivers/gpu/drm/savage/savage_bci.c | 8 ++-- drivers/gpu/drm/sis/sis_mm.c | 12 ++--- drivers/gpu/drm/via/via_dma.c | 28 +++++------ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 34 ++++++------- include/drm/drmP.h | 6 ++- include/drm/i830_drm.h | 28 +++++------ include/drm/i915_drm.h | 1 + include/drm/mga_drm.h | 2 +- include/drm/nouveau_drm.h | 13 +++++ include/drm/radeon_drm.h | 4 +- include/drm/savage_drm.h | 8 ++-- 20 files changed, 275 insertions(+), 249 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 3644c94c0a17..84da748555bc 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -55,6 +55,9 @@ static int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv); +#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} + /** Ioctl table */ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), @@ -421,6 +424,7 @@ long drm_ioctl(struct file *filp, int retcode = -EINVAL; char stack_kdata[128]; char *kdata = NULL; + unsigned int usize, asize; dev = file_priv->minor->dev; atomic_inc(&dev->ioctl_count); @@ -436,11 +440,18 @@ long drm_ioctl(struct file *filp, ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) goto err_i1; if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && - (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { + u32 drv_size; ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; + drv_size = _IOC_SIZE(ioctl->cmd_drv); + usize = asize = _IOC_SIZE(cmd); + if (drv_size > asize) + asize = drv_size; + } else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { ioctl = &drm_ioctls[nr]; cmd = ioctl->cmd; + usize = asize = _IOC_SIZE(cmd); } else goto err_i1; @@ -460,10 +471,10 @@ long drm_ioctl(struct file *filp, retcode = -EACCES; } else { if (cmd & (IOC_IN | IOC_OUT)) { - if (_IOC_SIZE(cmd) <= sizeof(stack_kdata)) { + if (asize <= sizeof(stack_kdata)) { kdata = stack_kdata; } else { - kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + kdata = kmalloc(asize, GFP_KERNEL); if (!kdata) { retcode = -ENOMEM; goto err_i1; @@ -473,12 +484,12 @@ long drm_ioctl(struct file *filp, if (cmd & IOC_IN) { if (copy_from_user(kdata, (void __user *)arg, - _IOC_SIZE(cmd)) != 0) { + usize) != 0) { retcode = -EFAULT; goto err_i1; } } else - memset(kdata, 0, _IOC_SIZE(cmd)); + memset(kdata, 0, usize); if (ioctl->flags & DRM_UNLOCKED) retcode = func(dev, kdata, file_priv); @@ -490,7 +501,7 @@ long drm_ioctl(struct file *filp, if (cmd & IOC_OUT) { if (copy_to_user((void __user *)arg, kdata, - _IOC_SIZE(cmd)) != 0) + usize) != 0) retcode = -EFAULT; } } diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index 0e6c131313d9..61b4caf220fa 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -1255,21 +1255,21 @@ long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } struct drm_ioctl_desc i810_ioctls[] = { - DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED), }; int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c index 5168862c9227..671aa18415ac 100644 --- a/drivers/gpu/drm/i830/i830_dma.c +++ b/drivers/gpu/drm/i830/i830_dma.c @@ -1524,20 +1524,20 @@ long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } struct drm_ioctl_desc i830_ioctls[] = { - DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED), }; int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index f19ffe87af3c..a2d3509c393b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2360,46 +2360,46 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) } struct drm_ioctl_desc i915_ioctls[] = { - DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), - DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ), - DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), - DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_FLUSH, i915_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_FLIP, i915_flip_bufs, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_ALLOC, i915_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_FREE, i915_mem_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c index fff82045c427..9ce2827f8c00 100644 --- a/drivers/gpu/drm/mga/mga_state.c +++ b/drivers/gpu/drm/mga/mga_state.c @@ -1085,19 +1085,19 @@ file_priv) } struct drm_ioctl_desc mga_ioctls[] = { - DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH), - DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(MGA_FLUSH, mga_dma_flush, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_RESET, mga_dma_reset, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_SWAP, mga_dma_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_CLEAR, mga_dma_clear, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_VERTEX, mga_dma_vertex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_INDICES, mga_dma_indices, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_ILOAD, mga_dma_iload, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_BLIT, mga_dma_blit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_GETPARAM, mga_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_SET_FENCE, mga_set_fence, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH), + DRM_IOCTL_DEF_DRV(MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 90fdcda332be..0480f064f2c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -426,18 +426,18 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, ***********************************/ struct drm_ioctl_desc nouveau_ioctls[] = { - DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH), + DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH), }; int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index 077af1f2f9b4..a9e33ce65918 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -1639,30 +1639,29 @@ void r128_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) r128_do_cleanup_pageflip(dev); } } - void r128_driver_lastclose(struct drm_device *dev) { r128_do_cleanup_cce(dev); } struct drm_ioctl_desc r128_ioctls[] = { - DRM_IOCTL_DEF(DRM_R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_CCE_IDLE, r128_cce_idle, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_RESET, r128_engine_reset, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_FULLSCREEN, r128_fullscreen, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_SWAP, r128_cce_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_FLIP, r128_cce_flip, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_CLEAR, r128_cce_clear, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_VERTEX, r128_cce_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_INDICES, r128_cce_indices, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_BLIT, r128_cce_blit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_DEPTH, r128_cce_depth, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_STIPPLE, r128_cce_stipple, DRM_AUTH), - DRM_IOCTL_DEF(DRM_R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_R128_GETPARAM, r128_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_CCE_IDLE, r128_cce_idle, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_RESET, r128_engine_reset, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_FULLSCREEN, r128_fullscreen, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_SWAP, r128_cce_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_FLIP, r128_cce_flip, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_CLEAR, r128_cce_clear, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_VERTEX, r128_cce_vertex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_INDICES, r128_cce_indices, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_BLIT, r128_cce_blit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_DEPTH, r128_cce_depth, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_STIPPLE, r128_cce_stipple, DRM_AUTH), + DRM_IOCTL_DEF_DRV(R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(R128_GETPARAM, r128_getparam, DRM_AUTH), }; int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index b1c8ace5f080..27435db0aa48 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -323,45 +323,45 @@ KMS_INVALID_IOCTL(radeon_surface_free_kms) struct drm_ioctl_desc radeon_ioctls_kms[] = { - DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH), /* KMS */ - DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_CS, radeon_cs_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_INFO, radeon_info_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_SET_TILING, radeon_gem_set_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), }; int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms); diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index b3ba44c0a818..4ae5a3d1074e 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -3228,34 +3228,34 @@ void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) } struct drm_ioctl_desc radeon_ioctls[] = { - DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH) + DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH) }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index f576232846c3..6756c97899f1 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -1082,10 +1082,10 @@ void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv) } struct drm_ioctl_desc savage_ioctls[] = { - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH), }; int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls); diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c index 07d0f2979cac..7fe2b63412ce 100644 --- a/drivers/gpu/drm/sis/sis_mm.c +++ b/drivers/gpu/drm/sis/sis_mm.c @@ -320,12 +320,12 @@ void sis_reclaim_buffers_locked(struct drm_device *dev, } struct drm_ioctl_desc sis_ioctls[] = { - DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_drm_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_drm_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_FB_FREE, sis_drm_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_AGP_FREE, sis_drm_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), }; int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); diff --git a/drivers/gpu/drm/via/via_dma.c b/drivers/gpu/drm/via/via_dma.c index 68dda74a50ae..cc0ffa9abd00 100644 --- a/drivers/gpu/drm/via/via_dma.c +++ b/drivers/gpu/drm/via/via_dma.c @@ -722,20 +722,20 @@ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file * } struct drm_ioctl_desc via_ioctls[] = { - DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) + DRM_IOCTL_DEF_DRV(VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_FREEMEM, via_mem_free, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF_DRV(VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_DMA_INIT, via_dma_init, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_FLUSH, via_flush_ioctl, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), + DRM_IOCTL_DEF_DRV(VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) }; int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 9dd395b90216..72ec2e2b6e97 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -99,47 +99,47 @@ */ #define VMW_IOCTL_DEF(ioctl, func, flags) \ - [DRM_IOCTL_NR(ioctl) - DRM_COMMAND_BASE] = {ioctl, flags, func} + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = {DRM_##ioctl, flags, func, DRM_IOCTL_##ioctl} /** * Ioctl definitions. */ static struct drm_ioctl_desc vmw_ioctls[] = { - VMW_IOCTL_DEF(DRM_IOCTL_VMW_GET_PARAM, vmw_getparam_ioctl, + VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, + VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CURSOR_BYPASS, + VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, vmw_kms_cursor_bypass_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CONTROL_STREAM, vmw_overlay_ioctl, + VMW_IOCTL_DEF(VMW_CONTROL_STREAM, vmw_overlay_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, + VMW_IOCTL_DEF(VMW_CLAIM_STREAM, vmw_stream_claim_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_STREAM, vmw_stream_unref_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_STREAM, vmw_stream_unref_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_CONTEXT, vmw_context_define_ioctl, + VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_SURFACE, vmw_surface_define_ioctl, + VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, + VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_REF_SURFACE, vmw_surface_reference_ioctl, + VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_EXECBUF, vmw_execbuf_ioctl, + VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, + VMW_IOCTL_DEF(VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl, DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl, + VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_wait_ioctl, DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(DRM_IOCTL_VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, + VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED) }; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 2a512bc0d4ab..7809d230adee 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -305,14 +305,16 @@ struct drm_ioctl_desc { unsigned int cmd; int flags; drm_ioctl_t *func; + unsigned int cmd_drv; }; /** * Creates a driver or general drm_ioctl_desc array entry for the given * ioctl, for use by drm_ioctl(). */ -#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags} + +#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl} struct drm_magic_entry { struct list_head head; diff --git a/include/drm/i830_drm.h b/include/drm/i830_drm.h index 4b00d2dd4f68..61315c29b8f3 100644 --- a/include/drm/i830_drm.h +++ b/include/drm/i830_drm.h @@ -264,20 +264,20 @@ typedef struct _drm_i830_sarea { #define DRM_I830_GETPARAM 0x0c #define DRM_I830_SETPARAM 0x0d -#define DRM_IOCTL_I830_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_INIT, drm_i830_init_t) -#define DRM_IOCTL_I830_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_VERTEX, drm_i830_vertex_t) -#define DRM_IOCTL_I830_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_CLEAR, drm_i830_clear_t) -#define DRM_IOCTL_I830_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLUSH) -#define DRM_IOCTL_I830_GETAGE DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_GETAGE) -#define DRM_IOCTL_I830_GETBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETBUF, drm_i830_dma_t) -#define DRM_IOCTL_I830_SWAP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_SWAP) -#define DRM_IOCTL_I830_COPY DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_COPY, drm_i830_copy_t) -#define DRM_IOCTL_I830_DOCOPY DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_DOCOPY) -#define DRM_IOCTL_I830_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLIP) -#define DRM_IOCTL_I830_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_EMIT, drm_i830_irq_emit_t) -#define DRM_IOCTL_I830_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_WAIT, drm_i830_irq_wait_t) -#define DRM_IOCTL_I830_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETPARAM, drm_i830_getparam_t) -#define DRM_IOCTL_I830_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_SETPARAM, drm_i830_setparam_t) +#define DRM_IOCTL_I830_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I830_INIT, drm_i830_init_t) +#define DRM_IOCTL_I830_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_I830_VERTEX, drm_i830_vertex_t) +#define DRM_IOCTL_I830_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_I830_CLEAR, drm_i830_clear_t) +#define DRM_IOCTL_I830_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I830_FLUSH) +#define DRM_IOCTL_I830_GETAGE DRM_IO ( DRM_COMMAND_BASE + DRM_I830_GETAGE) +#define DRM_IOCTL_I830_GETBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_GETBUF, drm_i830_dma_t) +#define DRM_IOCTL_I830_SWAP DRM_IO ( DRM_COMMAND_BASE + DRM_I830_SWAP) +#define DRM_IOCTL_I830_COPY DRM_IOW( DRM_COMMAND_BASE + DRM_I830_COPY, drm_i830_copy_t) +#define DRM_IOCTL_I830_DOCOPY DRM_IO ( DRM_COMMAND_BASE + DRM_I830_DOCOPY) +#define DRM_IOCTL_I830_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I830_FLIP) +#define DRM_IOCTL_I830_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_IRQ_EMIT, drm_i830_irq_emit_t) +#define DRM_IOCTL_I830_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I830_IRQ_WAIT, drm_i830_irq_wait_t) +#define DRM_IOCTL_I830_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_GETPARAM, drm_i830_getparam_t) +#define DRM_IOCTL_I830_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I830_SETPARAM, drm_i830_setparam_t) typedef struct _drm_i830_clear { int clear_color; diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 7f0028e1010b..000357bf3ac8 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -206,6 +206,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) +#define DRM_IOCTL_I915_HWS_ADDR DRM_IOW(DRM_COMMAND_BASE + DRM_I915_HWS_ADDR, struct drm_i915_gem_init) #define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init) #define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer) #define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2) diff --git a/include/drm/mga_drm.h b/include/drm/mga_drm.h index 3ffbc4798afa..c16097f99be0 100644 --- a/include/drm/mga_drm.h +++ b/include/drm/mga_drm.h @@ -248,7 +248,7 @@ typedef struct _drm_mga_sarea { #define DRM_MGA_DMA_BOOTSTRAP 0x0c #define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) -#define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, struct drm_lock) #define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) #define DRM_IOCTL_MGA_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MGA_SWAP) #define DRM_IOCTL_MGA_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_CLEAR, drm_mga_clear_t) diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h index fe917dee723a..01a714119506 100644 --- a/include/drm/nouveau_drm.h +++ b/include/drm/nouveau_drm.h @@ -197,4 +197,17 @@ struct drm_nouveau_sarea { #define DRM_NOUVEAU_GEM_CPU_FINI 0x43 #define DRM_NOUVEAU_GEM_INFO 0x44 +#define DRM_IOCTL_NOUVEAU_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GETPARAM, struct drm_nouveau_getparam) +#define DRM_IOCTL_NOUVEAU_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_SETPARAM, struct drm_nouveau_setparam) +#define DRM_IOCTL_NOUVEAU_CHANNEL_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_CHANNEL_ALLOC, struct drm_nouveau_channel_alloc) +#define DRM_IOCTL_NOUVEAU_CHANNEL_FREE DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_CHANNEL_FREE, struct drm_nouveau_channel_free) +#define DRM_IOCTL_NOUVEAU_GROBJ_ALLOC DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GROBJ_ALLOC, struct drm_nouveau_grobj_alloc) +#define DRM_IOCTL_NOUVEAU_NOTIFIEROBJ_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, struct drm_nouveau_notifierobj_alloc) +#define DRM_IOCTL_NOUVEAU_GPUOBJ_FREE DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GPUOBJ_FREE, struct drm_nouveau_gpuobj_free) +#define DRM_IOCTL_NOUVEAU_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_NEW, struct drm_nouveau_gem_new) +#define DRM_IOCTL_NOUVEAU_GEM_PUSHBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_PUSHBUF, struct drm_nouveau_gem_pushbuf) +#define DRM_IOCTL_NOUVEAU_GEM_CPU_PREP DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_CPU_PREP, struct drm_nouveau_gem_cpu_prep) +#define DRM_IOCTL_NOUVEAU_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_CPU_FINI, struct drm_nouveau_gem_cpu_fini) +#define DRM_IOCTL_NOUVEAU_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_INFO, struct drm_nouveau_gem_info) + #endif /* __NOUVEAU_DRM_H__ */ diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 0acaf8f91437..10f8b53bdd40 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -547,8 +547,8 @@ typedef struct { #define DRM_IOCTL_RADEON_GEM_WAIT_IDLE DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_IDLE, struct drm_radeon_gem_wait_idle) #define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) #define DRM_IOCTL_RADEON_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INFO, struct drm_radeon_info) -#define DRM_IOCTL_RADEON_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_TILING, struct drm_radeon_gem_set_tiling) -#define DRM_IOCTL_RADEON_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling) +#define DRM_IOCTL_RADEON_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_TILING, struct drm_radeon_gem_set_tiling) +#define DRM_IOCTL_RADEON_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling) #define DRM_IOCTL_RADEON_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy) typedef struct drm_radeon_init { diff --git a/include/drm/savage_drm.h b/include/drm/savage_drm.h index 8a576ef01821..4863cf6bf96f 100644 --- a/include/drm/savage_drm.h +++ b/include/drm/savage_drm.h @@ -63,10 +63,10 @@ typedef struct _drm_savage_sarea { #define DRM_SAVAGE_BCI_EVENT_EMIT 0x02 #define DRM_SAVAGE_BCI_EVENT_WAIT 0x03 -#define DRM_IOCTL_SAVAGE_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t) -#define DRM_IOCTL_SAVAGE_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t) -#define DRM_IOCTL_SAVAGE_EVENT_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t) -#define DRM_IOCTL_SAVAGE_EVENT_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t) +#define DRM_IOCTL_SAVAGE_BCI_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t) +#define DRM_IOCTL_SAVAGE_BCI_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t) +#define DRM_IOCTL_SAVAGE_BCI_EVENT_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t) +#define DRM_IOCTL_SAVAGE_BCI_EVENT_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t) #define SAVAGE_DMA_PCI 1 #define SAVAGE_DMA_AGP 3 -- cgit v1.2.3-59-g8ed1b From f1ca09b2b5c9dd3988c61818a7d621b1400e4f0c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 16 Aug 2010 23:44:49 -0600 Subject: of: Fix missing includes This patch fixes missing includes from a number of .c files because the code (wrongfully) depended on prom.h including them. The include of linux/of_address.h was removed in microblaze prom.h in commit "of/address: Clean up function declarations" (sha1 id 22ae782f8), but not fixed in some callers. This patch fixes them up. Signed-off-by: Grant Likely Tested-by: Michal Simek --- arch/microblaze/pci/pci-common.c | 3 ++- arch/microblaze/pci/xilinx_pci.c | 1 + drivers/char/xilinx_hwicap/xilinx_hwicap.c | 1 + drivers/serial/of_serial.c | 3 +-- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index 6ca8531a539e..55ef532f32be 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -27,10 +27,11 @@ #include #include #include +#include +#include #include #include -#include #include #include diff --git a/arch/microblaze/pci/xilinx_pci.c b/arch/microblaze/pci/xilinx_pci.c index 7869a41b0f94..0687a42a5bd4 100644 --- a/arch/microblaze/pci/xilinx_pci.c +++ b/arch/microblaze/pci/xilinx_pci.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 0ed763cd2e77..b663d573aad9 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -94,6 +94,7 @@ #ifdef CONFIG_OF /* For open firmware. */ +#include #include #include #endif diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index 659a695bdad6..2af8fd113123 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c @@ -14,11 +14,10 @@ #include #include #include +#include #include #include -#include - struct of_serial_info { int type; int line; -- cgit v1.2.3-59-g8ed1b From 3d6e614952e3e4cf9e70e58893a740ffec220b24 Mon Sep 17 00:00:00 2001 From: "Hans J. Koch" Date: Thu, 12 Aug 2010 15:10:53 +0200 Subject: mx35: Fix boot ROM hang in internal boot mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a watchdog reset occurs after booting in internal boot mode, the i.MX35 won't boot anymore. The boot ROM code seems to assume that some clocks are turned on (they are after a power-on reset). This patch turns on the necessary clocks. Signed-off-by: Hans J. Koch Acked-by: Uwe Kleine-König Reported-by: John Ogness Signed-off-by: Sascha Hauer --- arch/arm/mach-mx3/clock-imx35.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index d3af0fdf8475..32adf8d5b1f8 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -485,10 +485,10 @@ static struct clk_lookup lookups[] = { int __init mx35_clocks_init() { - unsigned int ll = 0; + unsigned int cgr2 = 3 << 26, cgr3 = 0; #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - ll = (3 << 16); + cgr2 |= 3 << 16; #endif clkdev_add_table(lookups, ARRAY_SIZE(lookups)); @@ -499,8 +499,20 @@ int __init mx35_clocks_init() __raw_writel((3 << 18), CCM_BASE + CCM_CGR0); __raw_writel((3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 16), CCM_BASE + CCM_CGR1); - __raw_writel((3 << 26) | ll, CCM_BASE + CCM_CGR2); - __raw_writel(0, CCM_BASE + CCM_CGR3); + + /* + * Check if we came up in internal boot mode. If yes, we need some + * extra clocks turned on, otherwise the MX35 boot ROM code will + * hang after a watchdog reset. + */ + if (!(__raw_readl(CCM_BASE + CCM_RCSR) & (3 << 10))) { + /* Additionally turn on UART1, SCC, and IIM clocks */ + cgr2 |= 3 << 16 | 3 << 4; + cgr3 |= 3 << 2; + } + + __raw_writel(cgr2, CCM_BASE + CCM_CGR2); + __raw_writel(cgr3, CCM_BASE + CCM_CGR3); mxc_timer_init(&gpt_clk, MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT); -- cgit v1.2.3-59-g8ed1b From 625fdcaa6d2a3db6a922bbd833450424e906111c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Aug 2010 12:31:21 -0700 Subject: latencytop: Fix kconfig dependency warnings warning: (LATENCYTOP && HAVE_LATENCYTOP_SUPPORT) selects SCHED_DEBUG which has unmet direct dependencies (DEBUG_KERNEL && PROC_FS) warning: (LATENCYTOP && HAVE_LATENCYTOP_SUPPORT) selects SCHEDSTATS which has unmet direct dependencies (DEBUG_KERNEL && PROC_FS) Add depends on STACKTRACE_SUPPORT for 'select STACKTRACE'. Add depends on PROC_FS since that is where the output goes. Signed-off-by: Randy Dunlap Cc: Arjan van de Ven LKML-Reference: <20100812123121.a7c99cde.randy.dunlap@oracle.com> Signed-off-by: Ingo Molnar --- lib/Kconfig.debug | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 9e06b7f5ecf1..1b4afd2e6ca0 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -994,13 +994,16 @@ config FAULT_INJECTION_STACKTRACE_FILTER config LATENCYTOP bool "Latency measuring infrastructure" + depends on HAVE_LATENCYTOP_SUPPORT + depends on DEBUG_KERNEL + depends on STACKTRACE_SUPPORT + depends on PROC_FS select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE select KALLSYMS select KALLSYMS_ALL select STACKTRACE select SCHEDSTATS select SCHED_DEBUG - depends on HAVE_LATENCYTOP_SUPPORT help Enable this option if you want to use the LatencyTOP tool to find out which userspace is blocking on what kernel operations. -- cgit v1.2.3-59-g8ed1b From 9a6f17fd1cd84811962735ff47111f84a8f05073 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 22 Apr 2010 12:37:13 +0200 Subject: i.MX35: remove get_3_3_div helper function In the v2 reference manual there are no dividers combined of two dividers. Instead, all dividers are simple 6bit dividers. I assume the combined dividers only exist in preliminary hardware. Signed-off-by: Sascha Hauer --- arch/arm/mach-mx3/clock-imx35.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index 32adf8d5b1f8..d3a8d3f32160 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -176,16 +176,11 @@ static unsigned long get_rate_ipg(struct clk *clk) return get_rate_ahb(NULL) >> 1; } -static unsigned long get_3_3_div(unsigned long in) -{ - return (((in >> 3) & 0x7) + 1) * ((in & 0x7) + 1); -} - static unsigned long get_rate_uart(struct clk *clk) { unsigned long pdr3 = __raw_readl(CCM_BASE + CCM_PDR3); unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4); - unsigned long div = get_3_3_div(pdr4 >> 10); + unsigned long div = ((pdr4 >> 10) & 0x3f) + 1; if (pdr3 & (1 << 14)) return get_rate_arm() / div; @@ -216,7 +211,7 @@ static unsigned long get_rate_sdhc(struct clk *clk) break; } - return rate / get_3_3_div(div); + return rate / (div + 1); } static unsigned long get_rate_mshc(struct clk *clk) @@ -270,7 +265,7 @@ static unsigned long get_rate_csi(struct clk *clk) else rate = get_rate_ppll(); - return rate / get_3_3_div((pdr2 >> 16) & 0x3f); + return rate / (((pdr2 >> 16) & 0x3f) + 1); } static unsigned long get_rate_otg(struct clk *clk) @@ -283,22 +278,21 @@ static unsigned long get_rate_otg(struct clk *clk) else rate = get_rate_ppll(); - return rate / get_3_3_div((pdr4 >> 22) & 0x3f); + return rate / (((pdr4 >> 22) & 0x3f) + 1); } static unsigned long get_rate_ipg_per(struct clk *clk) { unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0); unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4); - unsigned long div1, div2; + unsigned long div; if (pdr0 & (1 << 26)) { - div1 = (pdr4 >> 19) & 0x7; - div2 = (pdr4 >> 16) & 0x7; - return get_rate_arm() / ((div1 + 1) * (div2 + 1)); + div = (pdr4 >> 16) & 0x3f; + return get_rate_arm() / (div + 1); } else { - div1 = (pdr0 >> 12) & 0x7; - return get_rate_ahb(NULL) / div1; + div = (pdr0 >> 12) & 0x7; + return get_rate_ahb(NULL) / div; } } -- cgit v1.2.3-59-g8ed1b From c96c1e394fa72bd995154af7143873945a3fa89d Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 16 Aug 2010 15:54:05 +0200 Subject: clock-imx35: fix divider if ahb is source for ipg_per According to the Datasheet: "i.MX35 (MCIMX35) Multimedia Applications Processor Reference Manual, Rev. 2" "Table 14-6. PDR0 Field Descriptions" the divider is CCM_PER_AHB[3:0] + 1. This patch adds the missing + 1. Signed-off-by: Marc Kleine-Budde Signed-off-by: Michael Grzeschik Signed-off-by: Sascha Hauer --- arch/arm/mach-mx3/clock-imx35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index d3a8d3f32160..e582ceb6e0c1 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -292,7 +292,7 @@ static unsigned long get_rate_ipg_per(struct clk *clk) return get_rate_arm() / (div + 1); } else { div = (pdr0 >> 12) & 0x7; - return get_rate_ahb(NULL) / div; + return get_rate_ahb(NULL) / (div + 1); } } -- cgit v1.2.3-59-g8ed1b From c56702de106b4fde301282f7ea60412276481442 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 16 Aug 2010 15:54:06 +0200 Subject: clock-imx35: correct arm and ahb clock calculation According to the Datasheet: "i.MX35 (MCIMX35) Multimedia Applications Processor Reference Manual, Rev. 2" "Figure 14-24. Clock Control And Gating" change the result of get_rate_ahb based on the frequency returned by get_rate_arm to calculate the proper rate. Signed-off-by: Marc Kleine-Budde Signed-off-by: Michael Grzeschik Signed-off-by: Sascha Hauer --- arch/arm/mach-mx3/clock-imx35.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index e582ceb6e0c1..1d311b77b40e 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -155,7 +155,7 @@ static unsigned long get_rate_arm(void) aad = &clk_consumer[(pdr0 >> 16) & 0xf]; if (aad->sel) - fref = fref * 2 / 3; + fref = fref * 3 / 4; return fref / aad->arm; } @@ -164,7 +164,7 @@ static unsigned long get_rate_ahb(struct clk *clk) { unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0); struct arm_ahb_div *aad; - unsigned long fref = get_rate_mpll(); + unsigned long fref = get_rate_arm(); aad = &clk_consumer[(pdr0 >> 16) & 0xf]; -- cgit v1.2.3-59-g8ed1b From c735c40587cea45f9d2f83339f374595073c1923 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Mon, 16 Aug 2010 15:54:07 +0200 Subject: clock-imx35: Calculate the base clock rate for the IPU unit The mx3fb driver needs the clock the IPU runs in order to calculate the divider for the LCD clock. This patch adds the clock rate calculation routine for the i.MX35 CPU. Signed-off-by: Juergen Beisert Signed-off-by: Michael Grzeschik Signed-off-by: Sascha Hauer --- arch/arm/mach-mx3/clock-imx35.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-mx3/clock-imx35.c index 1d311b77b40e..7a62e744a8b0 100644 --- a/arch/arm/mach-mx3/clock-imx35.c +++ b/arch/arm/mach-mx3/clock-imx35.c @@ -296,6 +296,33 @@ static unsigned long get_rate_ipg_per(struct clk *clk) } } +static unsigned long get_rate_hsp(struct clk *clk) +{ + unsigned long hsp_podf = (__raw_readl(CCM_BASE + CCM_PDR0) >> 20) & 0x03; + unsigned long fref = get_rate_mpll(); + + if (fref > 400 * 1000 * 1000) { + switch (hsp_podf) { + case 0: + return fref >> 2; + case 1: + return fref >> 3; + case 2: + return fref / 3; + } + } else { + switch (hsp_podf) { + case 0: + case 2: + return fref / 3; + case 1: + return fref / 6; + } + } + + return 0; +} + static int clk_cgr_enable(struct clk *clk) { u32 reg; @@ -353,7 +380,7 @@ DEFINE_CLOCK(i2c1_clk, 0, CCM_CGR1, 10, get_rate_ipg_per, NULL); DEFINE_CLOCK(i2c2_clk, 1, CCM_CGR1, 12, get_rate_ipg_per, NULL); DEFINE_CLOCK(i2c3_clk, 2, CCM_CGR1, 14, get_rate_ipg_per, NULL); DEFINE_CLOCK(iomuxc_clk, 0, CCM_CGR1, 16, NULL, NULL); -DEFINE_CLOCK(ipu_clk, 0, CCM_CGR1, 18, get_rate_ahb, NULL); +DEFINE_CLOCK(ipu_clk, 0, CCM_CGR1, 18, get_rate_hsp, NULL); DEFINE_CLOCK(kpp_clk, 0, CCM_CGR1, 20, get_rate_ipg, NULL); DEFINE_CLOCK(mlb_clk, 0, CCM_CGR1, 22, get_rate_ahb, NULL); DEFINE_CLOCK(mshc_clk, 0, CCM_CGR1, 24, get_rate_mshc, NULL); -- cgit v1.2.3-59-g8ed1b From c69aefabe004d24e6eedf83b6f253647f77dfc43 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 17 Aug 2010 10:39:22 +0200 Subject: ALSA: hda - Fix ALC680 base model capture - Fix capture mixer elements for ALC680 base model - Support auto change ADC for recording from MIC - Cancel capture source assigned in auto mode. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 176 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 32 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2cd1ae809e46..a4dd04524e43 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -19030,6 +19030,7 @@ static int patch_alc888(struct hda_codec *codec) /* * ALC680 support */ +#define ALC680_DIGIN_NID ALC880_DIGIN_NID #define ALC680_DIGOUT_NID ALC880_DIGOUT_NID #define alc680_modes alc260_modes @@ -19044,23 +19045,93 @@ static hda_nid_t alc680_adc_nids[3] = { 0x07, 0x08, 0x09 }; +/* + * Analog capture ADC cgange + */ +static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int pre_mic, pre_line; + + pre_mic = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); + pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]); + + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + + if (pre_mic || pre_line) { + if (pre_mic) + snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0, + format); + else + snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0, + format); + } else + snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format); + return 0; +} + +static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, 0x07); + snd_hda_codec_cleanup_stream(codec, 0x08); + snd_hda_codec_cleanup_stream(codec, 0x09); + return 0; +} + +static struct hda_pcm_stream alc680_pcm_analog_auto_capture = { + .substreams = 1, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ + .ops = { + .prepare = alc680_capture_pcm_prepare, + .cleanup = alc680_capture_pcm_cleanup + }, +}; + static struct snd_kcontrol_new alc680_base_mixer[] = { /* output mixer control */ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT), { } }; -static struct snd_kcontrol_new alc680_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), +static struct hda_bind_ctls alc680_bind_cap_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static struct hda_bind_ctls alc680_bind_cap_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT), + HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), + 0 + }, +}; + +static struct snd_kcontrol_new alc680_master_capture_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch), { } /* end */ }; @@ -19068,25 +19139,73 @@ static struct snd_kcontrol_new alc680_capture_mixer[] = { * generic initialization of ADC, input mixers and output mixers */ static struct hda_verb alc680_init_verbs[] = { - /* Unmute DAC0-1 and set vol = 0 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + { } }; +/* toggle speaker-output according to the hp-jack state */ +static void alc680_base_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + spec->autocfg.hp_pins[0] = 0x16; + spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x15; + spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18; + spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19; +} + +static void alc680_rec_autoswitch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int present; + hda_nid_t new_adc; + + present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); + + new_adc = present ? 0x8 : 0x7; + __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1); + snd_hda_codec_setup_stream(codec, new_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + +} + +static void alc680_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc_automute_amp(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc680_rec_autoswitch(codec); +} + +static void alc680_inithook(struct hda_codec *codec) +{ + alc_automute_amp(codec); + alc680_rec_autoswitch(codec); +} + /* create input playback/capture controls for the given pin */ static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid, const char *ctlname, int idx) @@ -19197,13 +19316,7 @@ static void alc680_auto_init_hp_out(struct hda_codec *codec) #define alc680_pcm_analog_capture alc880_pcm_analog_capture #define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture #define alc680_pcm_digital_playback alc880_pcm_digital_playback - -static struct hda_input_mux alc680_capture_source = { - .num_items = 1, - .items = { - { "Mic", 0x0 }, - }, -}; +#define alc680_pcm_digital_capture alc880_pcm_digital_capture /* * BIOS auto configuration @@ -19218,6 +19331,7 @@ static int alc680_parse_auto_config(struct hda_codec *codec) alc680_ignore); if (err < 0) return err; + if (!spec->autocfg.line_outs) { if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) { spec->multiout.max_channels = 2; @@ -19239,8 +19353,6 @@ static int alc680_parse_auto_config(struct hda_codec *codec) add_mixer(spec, spec->kctls.list); add_verb(spec, alc680_init_verbs); - spec->num_mux_defs = 1; - spec->input_mux = &alc680_capture_source; err = alc_auto_add_mic_boost(codec); if (err < 0) @@ -19279,17 +19391,17 @@ static struct snd_pci_quirk alc680_cfg_tbl[] = { static struct alc_config_preset alc680_presets[] = { [ALC680_BASE] = { .mixers = { alc680_base_mixer }, - .cap_mixer = alc680_capture_mixer, + .cap_mixer = alc680_master_capture_mixer, .init_verbs = { alc680_init_verbs }, .num_dacs = ARRAY_SIZE(alc680_dac_nids), .dac_nids = alc680_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc680_adc_nids), - .adc_nids = alc680_adc_nids, - .hp_nid = 0x04, .dig_out_nid = ALC680_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc680_modes), .channel_mode = alc680_modes, - .input_mux = &alc680_capture_source, + .unsol_event = alc680_unsol_event, + .setup = alc680_base_setup, + .init_hook = alc680_inithook, + }, }; @@ -19333,9 +19445,9 @@ static int patch_alc680(struct hda_codec *codec) setup_preset(codec, &alc680_presets[board_config]); spec->stream_analog_playback = &alc680_pcm_analog_playback; - spec->stream_analog_capture = &alc680_pcm_analog_capture; - spec->stream_analog_alt_capture = &alc680_pcm_analog_alt_capture; + spec->stream_analog_capture = &alc680_pcm_analog_auto_capture; spec->stream_digital_playback = &alc680_pcm_digital_playback; + spec->stream_digital_capture = &alc680_pcm_digital_capture; if (!spec->adc_nids) { spec->adc_nids = alc680_adc_nids; -- cgit v1.2.3-59-g8ed1b From 6b5d7a9f6f7ff0e096829c1d82f70d5a6066b889 Mon Sep 17 00:00:00 2001 From: Xiao Guangrong Date: Tue, 17 Aug 2010 15:02:12 +0800 Subject: KVM: PIT: free irq source id in handling error path Free irq source id if create pit workqueue fail Signed-off-by: Xiao Guangrong Signed-off-by: Avi Kivity --- arch/x86/kvm/i8254.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index f539c3c2a687..ddeb2314b522 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -697,6 +697,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags) pit->wq = create_singlethread_workqueue("kvm-pit-wq"); if (!pit->wq) { mutex_unlock(&pit->pit_state.lock); + kvm_free_irq_source_id(kvm, pit->irq_source_id); kfree(pit); return NULL; } -- cgit v1.2.3-59-g8ed1b From 3c955b407a084810f57260d61548cc92c14bc627 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 16 Aug 2010 11:58:58 +0100 Subject: fixes for using make 3.82 It doesn't like pattern and explicit rules to be on the same line, and it seems to be more picky when matching file (or really directory) names with different numbers of trailing slashes. Signed-off-by: Jan Beulich Acked-by: Sam Ravnborg Andrew Benton Cc: Signed-off-by: Michal Marek --- firmware/Makefile | 2 +- scripts/mkmakefile | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 020e629a615c..99955ed8b198 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -142,7 +142,7 @@ fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-) # Directories which we _might_ need to create, so we have a rule for them. -firmware-dirs := $(sort $(patsubst %,$(objtree)/$(obj)/%/,$(dir $(fw-external-y) $(fw-shipped-all)))) +firmware-dirs := $(sort $(addprefix $(objtree)/$(obj)/,$(dir $(fw-external-y) $(fw-shipped-all)))) quiet_cmd_mkdir = MKDIR $(patsubst $(objtree)/%,%,$@) cmd_mkdir = mkdir -p $@ diff --git a/scripts/mkmakefile b/scripts/mkmakefile index 67d59c7a18dc..5325423ceab4 100644 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -44,7 +44,9 @@ all: Makefile:; -\$(all) %/: all +\$(all): all @: +%/: all + @: EOF -- cgit v1.2.3-59-g8ed1b From 033a273f9836b592dd568abd0f655be469d66704 Mon Sep 17 00:00:00 2001 From: Bernd Petrovitsch Date: Tue, 17 Aug 2010 12:22:08 -0300 Subject: perf tools: Fix build on POSIX shells POSIX sh does not specify the brace expansion, so fix it by replacing the global $(shell ...) lines quite at the top creating the output directories with real rules. Cc: Ingo Molnar Cc: Kusanagi Kouichi Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <1282046280.5822.4.camel@thorin> Signed-off-by: Bernd Petrovitsch Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 41abb90df50d..dcb9700b88d2 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -157,10 +157,6 @@ all:: # # Define NO_DWARF if you do not want debug-info analysis feature at all. -$(shell sh -c 'mkdir -p $(OUTPUT)scripts/{perl,python}/Perf-Trace-Util/' 2> /dev/null) -$(shell sh -c 'mkdir -p $(OUTPUT)util/{ui/browsers,scripting-engines}/' 2> /dev/null) -$(shell sh -c 'mkdir $(OUTPUT)bench' 2> /dev/null) - $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) -include $(OUTPUT)PERF-VERSION-FILE @@ -186,8 +182,6 @@ ifeq ($(ARCH),x86_64) ARCH := x86 endif -$(shell sh -c 'mkdir -p $(OUTPUT)arch/$(ARCH)/util/' 2> /dev/null) - # CFLAGS and LDFLAGS are for the users to override from the command line. # @@ -268,6 +262,7 @@ export prefix bindir sharedir sysconfdir CC = $(CROSS_COMPILE)gcc AR = $(CROSS_COMPILE)ar RM = rm -f +MKDIR = mkdir TAR = tar FIND = find INSTALL = install @@ -838,6 +833,7 @@ ifndef V QUIET_CC = @echo ' ' CC $@; QUIET_AR = @echo ' ' AR $@; QUIET_LINK = @echo ' ' LINK $@; + QUIET_MKDIR = @echo ' ' MKDIR $@; QUIET_BUILT_IN = @echo ' ' BUILTIN $@; QUIET_GEN = @echo ' ' GEN $@; QUIET_SUBDIR0 = +@subdir= @@ -1012,6 +1008,14 @@ $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h +# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So +# we depend the various files onto their directories. +DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h +$(DIRECTORY_DEPS): $(sort $(dir $(DIRECTORY_DEPS))) +# In the second step, we make a rule to actually create these directories +$(sort $(dir $(DIRECTORY_DEPS))): + $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null + $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) -- cgit v1.2.3-59-g8ed1b From 23b90cfd7bcf8ae1c0711df1cae7dfec3c01aec8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 17 Aug 2010 09:15:24 -0700 Subject: x86/PCI: only define pci_domain_nr if PCI and PCI_DOMAINS are set Otherwise we'll duplicate definitions with the pci.h stubs. Reported-by: Randy Dunlap Acked-by: Randy Dunlap Signed-off-by: Jesse Barnes --- arch/x86/include/asm/pci.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 404a880ea325..d395540ff894 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -27,6 +27,9 @@ extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node); extern struct pci_bus *pci_scan_bus_with_sysdata(int busno); +#ifdef CONFIG_PCI + +#ifdef CONFIG_PCI_DOMAINS static inline int pci_domain_nr(struct pci_bus *bus) { struct pci_sysdata *sd = bus->sysdata; @@ -37,13 +40,12 @@ static inline int pci_proc_domain(struct pci_bus *bus) { return pci_domain_nr(bus); } - +#endif /* Can be used to override the logic in pci_scan_bus for skipping already-configured bus numbers - to be used for buggy BIOSes or architectures with incomplete PCI setup by the loader */ -#ifdef CONFIG_PCI extern unsigned int pcibios_assign_all_busses(void); extern int pci_legacy_init(void); # ifdef CONFIG_ACPI -- cgit v1.2.3-59-g8ed1b From c206a04fba2c3890bc95dc9c20ae2cf9740fae71 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 13 Aug 2010 18:47:33 -0400 Subject: ipw2100: don't sync status queue entries These are allocated with pci_alloc_consistent, so calling pci_dma_sync_single_for_cpu is incorrect usage of the API. Remove this misuse and consequently avoid the following backtrace: WARNING: at lib/dma-debug.c:902 check_sync+0xce/0x43a() Hardware name: 2373HU6 ipw2100 0000:02:02.0: DMA-API: device driver tries to sync DMA memory it has not allocated [device address=0x0000000034e88008] [size=8 bytes] Modules linked in: microcode ipw2100(+) snd_seq_device ppdev libipw nsc_ircc snd_pcm lib80211 video output irda parport_pc cfg80211 parport thinkpad_acpi e1000 iTCO_wdt crc_ccitt snd_timer iTCO_vendor_support snd i2c_i801 pcspkr rfkill soundcore joydev snd_page_alloc yenta_socket radeon ttm drm_kms_helper drm i2c_algo_bit i2c_core [last unloaded: scsi_wait_scan] Pid: 0, comm: swapper Tainted: G W 2.6.35-wl+ #8 Call Trace: [] warn_slowpath_common+0x6a/0x7f [] ? check_sync+0xce/0x43a [] warn_slowpath_fmt+0x2b/0x2f [] check_sync+0xce/0x43a [] ? print_lock_contention_bug+0x11/0xb2 [] debug_dma_sync_single_for_cpu+0x47/0x49 [] ? ehci_irq+0x31/0x331 [] ? ipw2100_irq_tasklet+0x24/0x5e9 [ipw2100] [] ? ipw2100_irq_tasklet+0x24/0x5e9 [ipw2100] [] pci_dma_sync_single_for_cpu.clone.1+0x42/0x4b [ipw2100] [] ipw2100_irq_tasklet+0x17c/0x5e9 [ipw2100] [] tasklet_action+0x78/0xcb [] __do_softirq+0xc4/0x183 [] do_softirq+0x3b/0x5f [] irq_exit+0x3a/0x6d [] do_IRQ+0x8b/0x9f [] common_interrupt+0x35/0x3c [] ? acpi_idle_enter_simple+0xfe/0x13c [] ? exit_itimers+0x2d/0x73 [] ? acpi_idle_enter_simple+0x100/0x13c [] cpuidle_idle_call+0x78/0xdc [] cpu_idle+0x9b/0xb7 [] rest_init+0xa6/0xab [] start_kernel+0x389/0x38e [] i386_start_kernel+0xc9/0xd0 Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 1189dbb6e2a6..996e9d7d7586 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -2723,14 +2723,6 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) packet = &priv->rx_buffers[i]; - /* Sync the DMA for the STATUS buffer so CPU is sure to get - * the correct values */ - pci_dma_sync_single_for_cpu(priv->pci_dev, - sq->nic + - sizeof(struct ipw2100_status) * i, - sizeof(struct ipw2100_status), - PCI_DMA_FROMDEVICE); - /* Sync the DMA for the RX buffer so CPU is sure to get * the correct values */ pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr, -- cgit v1.2.3-59-g8ed1b From 8b8ab9d5e352aae0dcae53c657b25ab61bb73f0f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 17 Aug 2010 11:24:01 +0200 Subject: iwlwifi: fix 3945 filter flags Applying the filter flags directly as done since commit 3474ad635db371b0d8d0ee40086f15d223d5b6a4 Author: Johannes Berg Date: Thu Apr 29 04:43:05 2010 -0700 iwlwifi: apply filter flags directly broke 3945 under some unknown circumstances, as reported by Alex. Since I want to keep the direct application of filter flags on iwlagn, duplicate the code into both 3945 and agn and remove committing the RXON that broke things from the 3945 version. Cc: stable@kernel.org [2.6.35] Reported-by: Alex Romosan Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 45 ++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-core.c | 45 ------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 3 -- drivers/net/wireless/iwlwifi/iwl3945-base.c | 51 ++++++++++++++++++++++++++++- 4 files changed, 94 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c1882fd8345d..10d7b9b7f064 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3667,6 +3667,49 @@ out_exit: IWL_DEBUG_MAC80211(priv, "leave\n"); } +static void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct iwl_priv *priv = hw->priv; + __le32 filter_or = 0, filter_nand = 0; + +#define CHK(test, flag) do { \ + if (*total_flags & (test)) \ + filter_or |= (flag); \ + else \ + filter_nand |= (flag); \ + } while (0) + + IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); + CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); + CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); + +#undef CHK + + mutex_lock(&priv->mutex); + + priv->staging_rxon.filter_flags &= ~filter_nand; + priv->staging_rxon.filter_flags |= filter_or; + + iwlcore_commit_rxon(priv); + + mutex_unlock(&priv->mutex); + + /* + * Receiving all multicast frames is always enabled by the + * default flags setup in iwl_connection_init_rx_config() + * since we currently do not support programming multicast + * filters into the device. + */ + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; +} + static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; @@ -3867,7 +3910,7 @@ static struct ieee80211_ops iwl_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .configure_filter = iwl_configure_filter, + .configure_filter = iwlagn_configure_filter, .set_key = iwl_mac_set_key, .update_tkip_key = iwl_mac_update_tkip_key, .conf_tx = iwl_mac_conf_tx, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2c03c6e20a72..07dbc2796448 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1328,51 +1328,6 @@ out: EXPORT_SYMBOL(iwl_apm_init); - -void iwl_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) -{ - struct iwl_priv *priv = hw->priv; - __le32 filter_or = 0, filter_nand = 0; - -#define CHK(test, flag) do { \ - if (*total_flags & (test)) \ - filter_or |= (flag); \ - else \ - filter_nand |= (flag); \ - } while (0) - - IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", - changed_flags, *total_flags); - - CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); - CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); - CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); - -#undef CHK - - mutex_lock(&priv->mutex); - - priv->staging_rxon.filter_flags &= ~filter_nand; - priv->staging_rxon.filter_flags |= filter_or; - - iwlcore_commit_rxon(priv); - - mutex_unlock(&priv->mutex); - - /* - * Receiving all multicast frames is always enabled by the - * default flags setup in iwl_connection_init_rx_config() - * since we currently do not support programming multicast - * filters into the device. - */ - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | - FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; -} -EXPORT_SYMBOL(iwl_configure_filter); - int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 4a71dfb10a15..5e6ee3da6bbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -372,9 +372,6 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, u32 decrypt_res, struct ieee80211_rx_status *stats); void iwl_irq_handle_error(struct iwl_priv *priv); -void iwl_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast); int iwl_set_hw_params(struct iwl_priv *priv); void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif); void iwl_bss_info_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 70c4b8fba0ee..59a308b02f95 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3391,6 +3391,55 @@ static int iwl3945_mac_sta_add(struct ieee80211_hw *hw, return 0; } + +static void iwl3945_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct iwl_priv *priv = hw->priv; + __le32 filter_or = 0, filter_nand = 0; + +#define CHK(test, flag) do { \ + if (*total_flags & (test)) \ + filter_or |= (flag); \ + else \ + filter_nand |= (flag); \ + } while (0) + + IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK); + CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK); + CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK); + +#undef CHK + + mutex_lock(&priv->mutex); + + priv->staging_rxon.filter_flags &= ~filter_nand; + priv->staging_rxon.filter_flags |= filter_or; + + /* + * Committing directly here breaks for some reason, + * but we'll eventually commit the filter flags + * change anyway. + */ + + mutex_unlock(&priv->mutex); + + /* + * Receiving all multicast frames is always enabled by the + * default flags setup in iwl_connection_init_rx_config() + * since we currently do not support programming multicast + * filters into the device. + */ + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | + FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; +} + + /***************************************************************************** * * sysfs attributes @@ -3796,7 +3845,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, .config = iwl_mac_config, - .configure_filter = iwl_configure_filter, + .configure_filter = iwl3945_configure_filter, .set_key = iwl3945_mac_set_key, .conf_tx = iwl_mac_conf_tx, .reset_tsf = iwl_mac_reset_tsf, -- cgit v1.2.3-59-g8ed1b From 7a50d06e242614f02004faed2972a8f2c9336d61 Mon Sep 17 00:00:00 2001 From: Graeme Smecher Date: Tue, 17 Aug 2010 10:13:44 -0700 Subject: of: fix missing headers for of_address_to_resource() in MTD and SysACE drivers The drivers for Xilinx' SystemACE and physically mapped MTDs were missing prototypes for of_address_to_resource(). This patch adds the necessary headers. Signed-off-by: Graeme Smecher Signed-off-by: Grant Likely --- drivers/block/xsysace.c | 1 + drivers/mtd/maps/physmap_of.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 2982b3ee9465..057413bb16e2 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -94,6 +94,7 @@ #include #include #if defined(CONFIG_OF) +#include #include #include #endif diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 00af55d7afba..fe63f6bd663c 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3-59-g8ed1b From 99c796df94afca5256860dd4760017f1dbb3480c Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 17 Aug 2010 22:13:22 +0100 Subject: VIDEO: amba clcd: don't disable an already disabled clock Fix the clock enable/disable tracking in the AMBA CLCD driver so that the driver doesn't try to disable an already disabled clock, thereby causing the clock (if shared) to become unbalanced. This resolves a problem with CLCD on LPC32xx ARM platforms. Reported-by: Kevin Wells Signed-off-by: Russell King --- drivers/video/amba-clcd.c | 10 ++++++++-- include/linux/amba/clcd.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index afe21e6eb544..1c2c68356ea7 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -80,7 +80,10 @@ static void clcdfb_disable(struct clcd_fb *fb) /* * Disable CLCD clock source. */ - clk_disable(fb->clk); + if (fb->clk_enabled) { + fb->clk_enabled = false; + clk_disable(fb->clk); + } } static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) @@ -88,7 +91,10 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) /* * Enable the CLCD clock source. */ - clk_enable(fb->clk); + if (!fb->clk_enabled) { + fb->clk_enabled = true; + clk_enable(fb->clk); + } /* * Bring up by first enabling.. diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h index ca16c3801a1e..be33b3affc8a 100644 --- a/include/linux/amba/clcd.h +++ b/include/linux/amba/clcd.h @@ -150,6 +150,7 @@ struct clcd_fb { u16 off_cntl; u32 clcd_cntl; u32 cmap[16]; + bool clk_enabled; }; static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs) -- cgit v1.2.3-59-g8ed1b From df486a25900f4dba9cdc3886c4ac871951c6aef3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 17 Aug 2010 17:42:45 -0400 Subject: NFS: Fix the selection of security flavours in Kconfig Randy Dunlap reports: ERROR: "svc_gss_principal" [fs/nfs/nfs.ko] undefined! because in fs/nfs/Kconfig, NFS_V4 selects RPCSEC_GSS_KRB5 and/or in fs/nfsd/Kconfig, NFSD_V4 selects RPCSEC_GSS_KRB5. RPCSEC_GSS_KRB5 does 5 selects, but none of these is enforced/followed by the fs/nfs[d]/Kconfig configs: select SUNRPC_GSS select CRYPTO select CRYPTO_MD5 select CRYPTO_DES select CRYPTO_CBC Reported-by: Randy Dunlap Cc: J. Bruce Fields Acked-by: Randy Dunlap Signed-off-by: Trond Myklebust --- fs/nfs/Kconfig | 1 - fs/nfsd/Kconfig | 1 - net/sunrpc/Kconfig | 9 +++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index cc1bb33b59b8..2ddc384ec042 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -63,7 +63,6 @@ config NFS_V3_ACL config NFS_V4 bool "NFS client support for NFS version 4" depends on NFS_FS - select RPCSEC_GSS_KRB5 help This option enables support for version 4 of the NFS protocol (RFC 3530) in the kernel's NFS client. diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 503b9da159a3..95932f523aef 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -69,7 +69,6 @@ config NFSD_V4 depends on NFSD && PROC_FS && EXPERIMENTAL select NFSD_V3 select FS_POSIX_ACL - select RPCSEC_GSS_KRB5 help This option enables support in your system's NFS server for version 4 of the NFS protocol (RFC 3530). diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index 443c161eb8bd..3376d7657185 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig @@ -18,10 +18,11 @@ config SUNRPC_XPRT_RDMA If unsure, say N. config RPCSEC_GSS_KRB5 - tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" - depends on SUNRPC && EXPERIMENTAL + tristate + depends on SUNRPC && CRYPTO + prompt "Secure RPC: Kerberos V mechanism" if !(NFS_V4 || NFSD_V4) + default y select SUNRPC_GSS - select CRYPTO select CRYPTO_MD5 select CRYPTO_DES select CRYPTO_CBC @@ -34,7 +35,7 @@ config RPCSEC_GSS_KRB5 available from http://linux-nfs.org/. In addition, user-space Kerberos support should be installed. - If unsure, say N. + If unsure, say Y. config RPCSEC_GSS_SPKM3 tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)" -- cgit v1.2.3-59-g8ed1b From 001389b9581c13fe5fc357a0f89234f85af4215d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Aug 2010 10:22:10 +0000 Subject: netfilter: {ip,ip6,arp}_tables: avoid lockdep false positive After commit 24b36f019 (netfilter: {ip,ip6,arp}_tables: dont block bottom half more than necessary), lockdep can raise a warning because we attempt to lock a spinlock with BH enabled, while the same lock is usually locked by another cpu in a softirq context. Disable again BH to avoid these lockdep warnings. Reported-by: Linus Torvalds Diagnosed-by: David S. Miller Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/netfilter/arp_tables.c | 2 ++ net/ipv4/netfilter/ip_tables.c | 2 ++ net/ipv6/netfilter/ip6_tables.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 6bccba31d132..51d6c3167975 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -735,6 +735,7 @@ static void get_counters(const struct xt_table_info *t, if (cpu == curcpu) continue; i = 0; + local_bh_disable(); xt_info_wrlock(cpu); xt_entry_foreach(iter, t->entries[cpu], t->size) { ADD_COUNTER(counters[i], iter->counters.bcnt, @@ -742,6 +743,7 @@ static void get_counters(const struct xt_table_info *t, ++i; } xt_info_wrunlock(cpu); + local_bh_enable(); } put_cpu(); } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index c439721b165a..97b64b22c412 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -909,6 +909,7 @@ get_counters(const struct xt_table_info *t, if (cpu == curcpu) continue; i = 0; + local_bh_disable(); xt_info_wrlock(cpu); xt_entry_foreach(iter, t->entries[cpu], t->size) { ADD_COUNTER(counters[i], iter->counters.bcnt, @@ -916,6 +917,7 @@ get_counters(const struct xt_table_info *t, ++i; /* macro does multi eval of i */ } xt_info_wrunlock(cpu); + local_bh_enable(); } put_cpu(); } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 5359ef4daac5..29a7bca29e3f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -922,6 +922,7 @@ get_counters(const struct xt_table_info *t, if (cpu == curcpu) continue; i = 0; + local_bh_disable(); xt_info_wrlock(cpu); xt_entry_foreach(iter, t->entries[cpu], t->size) { ADD_COUNTER(counters[i], iter->counters.bcnt, @@ -929,6 +930,7 @@ get_counters(const struct xt_table_info *t, ++i; } xt_info_wrunlock(cpu); + local_bh_enable(); } put_cpu(); } -- cgit v1.2.3-59-g8ed1b From 1c40be12f7d8ca1d387510d39787b12e512a7ce8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Aug 2010 20:04:22 +0000 Subject: net sched: fix some kernel memory leaks We leak at least 32bits of kernel memory to user land in tc dump, because we dont init all fields (capab ?) of the dumped structure. Use C99 initializers so that holes and non explicit fields are zeroed. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/act_gact.c | 21 ++++++++++++--------- net/sched/act_mirred.c | 15 ++++++++------- net/sched/act_nat.c | 22 +++++++++++----------- net/sched/act_simple.c | 11 ++++++----- net/sched/act_skbedit.c | 11 ++++++----- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 8406c6654990..c2ed90a4c0b4 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -152,21 +152,24 @@ static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { unsigned char *b = skb_tail_pointer(skb); - struct tc_gact opt; struct tcf_gact *gact = a->priv; + struct tc_gact opt = { + .index = gact->tcf_index, + .refcnt = gact->tcf_refcnt - ref, + .bindcnt = gact->tcf_bindcnt - bind, + .action = gact->tcf_action, + }; struct tcf_t t; - opt.index = gact->tcf_index; - opt.refcnt = gact->tcf_refcnt - ref; - opt.bindcnt = gact->tcf_bindcnt - bind; - opt.action = gact->tcf_action; NLA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); #ifdef CONFIG_GACT_PROB if (gact->tcfg_ptype) { - struct tc_gact_p p_opt; - p_opt.paction = gact->tcfg_paction; - p_opt.pval = gact->tcfg_pval; - p_opt.ptype = gact->tcfg_ptype; + struct tc_gact_p p_opt = { + .paction = gact->tcfg_paction, + .pval = gact->tcfg_pval, + .ptype = gact->tcfg_ptype, + }; + NLA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); } #endif diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 11f195af2da0..0c311be92827 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -219,15 +219,16 @@ static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, i { unsigned char *b = skb_tail_pointer(skb); struct tcf_mirred *m = a->priv; - struct tc_mirred opt; + struct tc_mirred opt = { + .index = m->tcf_index, + .action = m->tcf_action, + .refcnt = m->tcf_refcnt - ref, + .bindcnt = m->tcf_bindcnt - bind, + .eaction = m->tcfm_eaction, + .ifindex = m->tcfm_ifindex, + }; struct tcf_t t; - opt.index = m->tcf_index; - opt.action = m->tcf_action; - opt.refcnt = m->tcf_refcnt - ref; - opt.bindcnt = m->tcf_bindcnt - bind; - opt.eaction = m->tcfm_eaction; - opt.ifindex = m->tcfm_ifindex; NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 509a2d53a99d..186eb837e600 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -272,19 +272,19 @@ static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_nat *p = a->priv; - struct tc_nat opt; + struct tc_nat opt = { + .old_addr = p->old_addr, + .new_addr = p->new_addr, + .mask = p->mask, + .flags = p->flags, + + .index = p->tcf_index, + .action = p->tcf_action, + .refcnt = p->tcf_refcnt - ref, + .bindcnt = p->tcf_bindcnt - bind, + }; struct tcf_t t; - opt.old_addr = p->old_addr; - opt.new_addr = p->new_addr; - opt.mask = p->mask; - opt.flags = p->flags; - - opt.index = p->tcf_index; - opt.action = p->tcf_action; - opt.refcnt = p->tcf_refcnt - ref; - opt.bindcnt = p->tcf_bindcnt - bind; - NLA_PUT(skb, TCA_NAT_PARMS, sizeof(opt), &opt); t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 4a1d640b0cf1..97e84f3ee775 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -164,13 +164,14 @@ static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_defact *d = a->priv; - struct tc_defact opt; + struct tc_defact opt = { + .index = d->tcf_index, + .refcnt = d->tcf_refcnt - ref, + .bindcnt = d->tcf_bindcnt - bind, + .action = d->tcf_action, + }; struct tcf_t t; - opt.index = d->tcf_index; - opt.refcnt = d->tcf_refcnt - ref; - opt.bindcnt = d->tcf_bindcnt - bind; - opt.action = d->tcf_action; NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); NLA_PUT_STRING(skb, TCA_DEF_DATA, d->tcfd_defdata); t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index e9607fe55b58..66cbf4eb8855 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -159,13 +159,14 @@ static inline int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, { unsigned char *b = skb_tail_pointer(skb); struct tcf_skbedit *d = a->priv; - struct tc_skbedit opt; + struct tc_skbedit opt = { + .index = d->tcf_index, + .refcnt = d->tcf_refcnt - ref, + .bindcnt = d->tcf_bindcnt - bind, + .action = d->tcf_action, + }; struct tcf_t t; - opt.index = d->tcf_index; - opt.refcnt = d->tcf_refcnt - ref; - opt.bindcnt = d->tcf_bindcnt - bind; - opt.action = d->tcf_action; NLA_PUT(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt); if (d->flags & SKBEDIT_F_PRIORITY) NLA_PUT(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority), -- cgit v1.2.3-59-g8ed1b From ef201bebe5afc91a2b99b45dacc8c6dd88ca9e58 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 17:09:53 -0700 Subject: sparc64: Fix rwsem constant bug leading to hangs. As noticed by Linus, it is critical that some of the rwsem constants be signed. Yet, hex constants are unsigned unless explicitly casted or negated. The most critical one is RWSEM_WAITING_BIAS. This bug was exacerbated by commit 424acaaeb3a3932d64a9b4bd59df6cf72c22d8f3 ("rwsem: wake queued readers when writer blocks on active read lock") Signed-off-by: David S. Miller --- arch/sparc/include/asm/rwsem-const.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/include/asm/rwsem-const.h b/arch/sparc/include/asm/rwsem-const.h index a303c9d64d84..e4c61a18bb28 100644 --- a/arch/sparc/include/asm/rwsem-const.h +++ b/arch/sparc/include/asm/rwsem-const.h @@ -5,7 +5,7 @@ #define RWSEM_UNLOCKED_VALUE 0x00000000 #define RWSEM_ACTIVE_BIAS 0x00000001 #define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS 0xffff0000 +#define RWSEM_WAITING_BIAS (-0x00010000) #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) -- cgit v1.2.3-59-g8ed1b From 86fa04b8742ac681d470786f55e2403ada0075b2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 17:12:04 -0700 Subject: sparc64: Fix atomic64_t routine return values. Should return 'long' instead of 'int'. Thanks to Dimitris Michailidis and Tony Luck. Signed-off-by: David S. Miller --- arch/sparc/include/asm/atomic_64.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 2050ca02c423..f0c74227c737 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -25,9 +25,9 @@ extern void atomic_sub(int, atomic_t *); extern void atomic64_sub(int, atomic64_t *); extern int atomic_add_ret(int, atomic_t *); -extern int atomic64_add_ret(int, atomic64_t *); +extern long atomic64_add_ret(int, atomic64_t *); extern int atomic_sub_ret(int, atomic_t *); -extern int atomic64_sub_ret(int, atomic64_t *); +extern long atomic64_sub_ret(int, atomic64_t *); #define atomic_dec_return(v) atomic_sub_ret(1, v) #define atomic64_dec_return(v) atomic64_sub_ret(1, v) @@ -91,7 +91,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) -static inline int atomic64_add_unless(atomic64_t *v, long a, long u) +static inline long atomic64_add_unless(atomic64_t *v, long a, long u) { long c, old; c = atomic64_read(v); -- cgit v1.2.3-59-g8ed1b From e5093aec2e6b60c3df2420057ffab9ed4a6d2792 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Wed, 11 Aug 2010 02:02:10 +0000 Subject: net: Fix a memmove bug in dev_gro_receive() >Xin Xiaohui wrote: > I looked into the code dev_gro_receive(), found the code here: > if the frags[0] is pulled to 0, then the page will be released, > and memmove() frags left. > Is that right? I'm not sure if memmove do right or not, but > frags[0].size is never set after memove at least. what I think > a simple way is not to do anything if we found frags[0].size == 0. > The patch is as followed. ... This version of the patch fixes the bug directly in memmove. Reported-by: "Xin, Xiaohui" Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 1ae654391442..3721fbb9a83c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3143,7 +3143,7 @@ pull: put_page(skb_shinfo(skb)->frags[0].page); memmove(skb_shinfo(skb)->frags, skb_shinfo(skb)->frags + 1, - --skb_shinfo(skb)->nr_frags); + --skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); } } -- cgit v1.2.3-59-g8ed1b From d7627467b7a8dd6944885290a03a07ceb28c10eb Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 17 Aug 2010 23:52:56 +0100 Subject: Make do_execve() take a const filename pointer Make do_execve() take a const filename pointer so that kernel_execve() compiles correctly on ARM: arch/arm/kernel/sys_arm.c:88: warning: passing argument 1 of 'do_execve' discards qualifiers from pointer target type This also requires the argv and envp arguments to be consted twice, once for the pointer array and once for the strings the array points to. This is because do_execve() passes a pointer to the filename (now const) to copy_strings_kernel(). A simpler alternative would be to cast the filename pointer in do_execve() when it's passed to copy_strings_kernel(). do_execve() may not change any of the strings it is passed as part of the argv or envp lists as they are some of them in .rodata, so marking these strings as const should be fine. Further kernel_execve() and sys_execve() need to be changed to match. This has been test built on x86_64, frv, arm and mips. Signed-off-by: David Howells Tested-by: Ralf Baechle Acked-by: Russell King Signed-off-by: Linus Torvalds --- arch/alpha/kernel/process.c | 5 +++-- arch/arm/kernel/sys_arm.c | 14 +++++++++----- arch/avr32/kernel/process.c | 5 +++-- arch/avr32/kernel/sys_avr32.c | 4 +++- arch/blackfin/kernel/process.c | 4 +++- arch/cris/arch-v10/kernel/process.c | 4 +++- arch/cris/arch-v32/kernel/process.c | 6 ++++-- arch/frv/kernel/process.c | 5 +++-- arch/h8300/kernel/process.c | 5 ++++- arch/h8300/kernel/sys_h8300.c | 4 +++- arch/ia64/kernel/process.c | 4 +++- arch/m32r/kernel/process.c | 4 ++-- arch/m32r/kernel/sys_m32r.c | 4 +++- arch/m68k/kernel/process.c | 4 +++- arch/m68k/kernel/sys_m68k.c | 4 +++- arch/m68knommu/kernel/process.c | 4 +++- arch/m68knommu/kernel/sys_m68k.c | 4 +++- arch/microblaze/kernel/sys_microblaze.c | 10 +++++++--- arch/mips/kernel/syscall.c | 10 +++++++--- arch/mn10300/kernel/process.c | 4 ++-- arch/parisc/hpux/fs.c | 6 ++++-- arch/parisc/kernel/process.c | 15 ++++++++++----- arch/powerpc/kernel/process.c | 5 +++-- arch/s390/kernel/process.c | 5 +++-- arch/score/kernel/sys_score.c | 10 +++++++--- arch/sh/kernel/process_32.c | 7 ++++--- arch/sh/kernel/process_64.c | 4 ++-- arch/sh/kernel/sys_sh32.c | 4 +++- arch/sh/kernel/sys_sh64.c | 4 +++- arch/sparc/kernel/process_32.c | 6 ++++-- arch/sparc/kernel/process_64.c | 4 ++-- arch/sparc/kernel/sys_sparc_32.c | 4 +++- arch/sparc/kernel/sys_sparc_64.c | 4 +++- arch/tile/kernel/process.c | 5 +++-- arch/um/kernel/exec.c | 5 +++-- arch/um/kernel/syscall.c | 4 +++- arch/x86/include/asm/syscalls.h | 5 +++-- arch/x86/kernel/process.c | 5 +++-- arch/x86/kernel/sys_i386_32.c | 4 +++- arch/xtensa/kernel/process.c | 5 +++-- fs/binfmt_misc.c | 2 +- fs/binfmt_script.c | 3 ++- fs/exec.c | 21 +++++++++++---------- include/linux/binfmts.h | 7 ++++--- include/linux/sched.h | 4 +++- include/linux/syscalls.h | 2 +- init/do_mounts_initrd.c | 7 ++++--- init/main.c | 6 +++--- kernel/kmod.c | 4 +++- security/commoncap.c | 2 +- 50 files changed, 179 insertions(+), 98 deletions(-) diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 88e608aebc8c..842dba308eab 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -387,8 +387,9 @@ EXPORT_SYMBOL(dump_elf_task_fp); * sys_execve() executes a new program. */ asmlinkage int -do_sys_execve(const char __user *ufilename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs) +do_sys_execve(const char __user *ufilename, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { int error; char *filename; diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 5b7c541a4c63..62e7c61d0342 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -62,8 +62,9 @@ asmlinkage int sys_vfork(struct pt_regs *regs) /* sys_execve() executes a new program. * This is called indirectly via a small wrapper */ -asmlinkage int sys_execve(const char __user *filenamei, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs) +asmlinkage int sys_execve(const char __user *filenamei, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { int error; char * filename; @@ -78,14 +79,17 @@ out: return error; } -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { struct pt_regs regs; int ret; memset(®s, 0, sizeof(struct pt_regs)); - ret = do_execve(filename, (char __user * __user *)argv, - (char __user * __user *)envp, ®s); + ret = do_execve(filename, + (const char __user *const __user *)argv, + (const char __user *const __user *)envp, ®s); if (ret < 0) goto out; diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index e5daddff397d..9c46aaad11ce 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c @@ -384,8 +384,9 @@ asmlinkage int sys_vfork(struct pt_regs *regs) } asmlinkage int sys_execve(const char __user *ufilename, - char __user *__user *uargv, - char __user *__user *uenvp, struct pt_regs *regs) + const char __user *const __user *uargv, + const char __user *const __user *uenvp, + struct pt_regs *regs) { int error; char *filename; diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c index 459349b5ed5a..62635a09ae3e 100644 --- a/arch/avr32/kernel/sys_avr32.c +++ b/arch/avr32/kernel/sys_avr32.c @@ -7,7 +7,9 @@ */ #include -int kernel_execve(const char *file, char **argv, char **envp) +int kernel_execve(const char *file, + const char *const *argv, + const char *const *envp) { register long scno asm("r8") = __NR_execve; register long sc1 asm("r12") = (long)file; diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index a566f61c002a..01f98cb964d2 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -209,7 +209,9 @@ copy_thread(unsigned long clone_flags, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char __user *name, char __user * __user *argv, char __user * __user *envp) +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) { int error; char *filename; diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 93f0f64b1326..9a57db6907f5 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -204,7 +204,9 @@ asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *fname, char **argv, char **envp, +asmlinkage int sys_execve(const char *fname, + const char *const *argv, + const char *const *envp, long r13, long mof, long srp, struct pt_regs *regs) { diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index 2661a9529d70..562f84718906 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -218,8 +218,10 @@ sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, /* sys_execve() executes a new program. */ asmlinkage int -sys_execve(const char *fname, char **argv, char **envp, long r13, long mof, long srp, - struct pt_regs *regs) +sys_execve(const char *fname, + const char *const *argv, + const char *const *envp, long r13, long mof, long srp, + struct pt_regs *regs) { int error; char *filename; diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index 428931cf2f0c..2b63b0191f52 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -250,8 +250,9 @@ int copy_thread(unsigned long clone_flags, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp) +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) { int error; char * filename; diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index 8b7b78d77d5c..97478138e361 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -212,7 +212,10 @@ int copy_thread(unsigned long clone_flags, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *name, char **argv, char **envp,int dummy,...) +asmlinkage int sys_execve(const char *name, + const char *const *argv, + const char *const *envp, + int dummy, ...) { int error; char * filename; diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c index f9b3f44da69f..dc1ac0243b78 100644 --- a/arch/h8300/kernel/sys_h8300.c +++ b/arch/h8300/kernel/sys_h8300.c @@ -51,7 +51,9 @@ asmlinkage void syscall_print(void *dummy,...) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long res __asm__("er0"); register char *const *_c __asm__("er3") = envp; diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index a879c03b7f1c..16f1c7b04c69 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -633,7 +633,9 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) } long -sys_execve (const char __user *filename, char __user * __user *argv, char __user * __user *envp, +sys_execve (const char __user *filename, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { char *fname; diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index 8665a4d868ec..422bea9f1dbc 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -289,8 +289,8 @@ asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, * sys_execve() executes a new program. */ asmlinkage int sys_execve(const char __user *ufilename, - char __user * __user *uargv, - char __user * __user *uenvp, + const char __user *const __user *uargv, + const char __user *const __user *uenvp, unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, struct pt_regs regs) { diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index 0a00f467edfa..d841fb6cc703 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c @@ -93,7 +93,9 @@ asmlinkage int sys_cachectl(char *addr, int nbytes, int op) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __scno __asm__ ("r7") = __NR_execve; register long __arg3 __asm__ ("r2") = (long)(envp); diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 221d0b71ce39..18732ab23292 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -315,7 +315,9 @@ EXPORT_SYMBOL(dump_fpu); /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char __user *name, char __user * __user *argv, char __user * __user *envp) +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) { int error; char * filename; diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 77896692eb0a..2f431ece7b5f 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -459,7 +459,9 @@ asmlinkage int sys_getpagesize(void) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __res asm ("%d0") = __NR_execve; register long __a asm ("%d1") = (long)(filename); diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index 6350f68cd026..4d090d3c0897 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c @@ -350,7 +350,9 @@ void dump(struct pt_regs *fp) /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(const char *name, char **argv, char **envp) +asmlinkage int sys_execve(const char *name, + const char *const *argv, + const char *const *envp) { int error; char * filename; diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c index d65e9c4c930c..68488ae47f0a 100644 --- a/arch/m68knommu/kernel/sys_m68k.c +++ b/arch/m68knommu/kernel/sys_m68k.c @@ -44,7 +44,9 @@ asmlinkage int sys_getpagesize(void) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __res asm ("%d0") = __NR_execve; register long __a asm ("%d1") = (long)(filename); diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c index 6abab6ebedbe..2250fe9d269b 100644 --- a/arch/microblaze/kernel/sys_microblaze.c +++ b/arch/microblaze/kernel/sys_microblaze.c @@ -47,8 +47,10 @@ asmlinkage long microblaze_clone(int flags, unsigned long stack, struct pt_regs return do_fork(flags, stack, regs, 0, NULL, NULL); } -asmlinkage long microblaze_execve(const char __user *filenamei, char __user *__user *argv, - char __user *__user *envp, struct pt_regs *regs) +asmlinkage long microblaze_execve(const char __user *filenamei, + const char __user *const __user *argv, + const char __user *const __user *envp, + struct pt_regs *regs) { int error; char *filename; @@ -77,7 +79,9 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register const char *__a __asm__("r5") = filename; register const void *__b __asm__("r6") = argv; diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index bddce0bca195..1dc6edff45e0 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -258,8 +258,10 @@ asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs) error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user *__user *) (long)regs.regs[5], - (char __user *__user *) (long)regs.regs[6], ®s); + error = do_execve(filename, + (const char __user *const __user *) (long)regs.regs[5], + (const char __user *const __user *) (long)regs.regs[6], + ®s); putname(filename); out: @@ -436,7 +438,9 @@ asmlinkage void bad_stack(void) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register unsigned long __a0 asm("$4") = (unsigned long) filename; register unsigned long __a1 asm("$5") = (unsigned long) argv; diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index 762eb325b949..f48373e2bc1c 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -269,8 +269,8 @@ asmlinkage long sys_vfork(void) } asmlinkage long sys_execve(const char __user *name, - char __user * __user *argv, - char __user * __user *envp) + const char __user *const __user *argv, + const char __user *const __user *envp) { char *filename; int error; diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 1444875a7611..0dc8543acb4f 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c @@ -41,8 +41,10 @@ int hpux_execve(struct pt_regs *regs) if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user * __user *) regs->gr[25], - (char __user * __user *) regs->gr[24], regs); + error = do_execve(filename, + (const char __user *const __user *) regs->gr[25], + (const char __user *const __user *) regs->gr[24], + regs); putname(filename); diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 76332dadc6e9..4b4b9181a1a0 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -348,17 +348,22 @@ asmlinkage int sys_execve(struct pt_regs *regs) error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char __user * __user *) regs->gr[25], - (char __user * __user *) regs->gr[24], regs); + error = do_execve(filename, + (const char __user *const __user *) regs->gr[25], + (const char __user *const __user *) regs->gr[24], + regs); putname(filename); out: return error; } -extern int __execve(const char *filename, char *const argv[], - char *const envp[], struct task_struct *task); -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +extern int __execve(const char *filename, + const char *const argv[], + const char *const envp[], struct task_struct *task); +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { return __execve(filename, argv, envp, current); } diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index feacfb789686..91356ffda2ca 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1034,8 +1034,9 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, flush_fp_to_thread(current); flush_altivec_to_thread(current); flush_spe_to_thread(current); - error = do_execve(filename, (char __user * __user *) a1, - (char __user * __user *) a2, regs); + error = do_execve(filename, + (const char __user *const __user *) a1, + (const char __user *const __user *) a2, regs); putname(filename); out: return error; diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 7eafaf2662b9..d3a2d1c6438e 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -267,8 +267,9 @@ asmlinkage void execve_tail(void) /* * sys_execve() executes a new program. */ -SYSCALL_DEFINE3(execve, const char __user *, name, char __user * __user *, argv, - char __user * __user *, envp) +SYSCALL_DEFINE3(execve, const char __user *, name, + const char __user *const __user *, argv, + const char __user *const __user *, envp) { struct pt_regs *regs = task_pt_regs(current); char *filename; diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c index 651096ff8db4..e478bf9a7e91 100644 --- a/arch/score/kernel/sys_score.c +++ b/arch/score/kernel/sys_score.c @@ -99,8 +99,10 @@ score_execve(struct pt_regs *regs) if (IS_ERR(filename)) return error; - error = do_execve(filename, (char __user *__user*)regs->regs[5], - (char __user *__user *) regs->regs[6], regs); + error = do_execve(filename, + (const char __user *const __user *)regs->regs[5], + (const char __user *const __user *)regs->regs[6], + regs); putname(filename); return error; @@ -110,7 +112,9 @@ score_execve(struct pt_regs *regs) * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register unsigned long __r4 asm("r4") = (unsigned long) filename; register unsigned long __r5 asm("r5") = (unsigned long) argv; diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 052981972ae6..762a13984bbd 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -296,9 +296,10 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, /* * sys_execve() executes a new program. */ -asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv, - char __user * __user *uenvp, unsigned long r7, - struct pt_regs __regs) +asmlinkage int sys_execve(const char __user *ufilename, + const char __user *const __user *uargv, + const char __user *const __user *uenvp, + unsigned long r7, struct pt_regs __regs) { struct pt_regs *regs = RELOC_HIDE(&__regs, 0); int error; diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 68d128d651b3..210c1cabcb7f 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -497,8 +497,8 @@ asmlinkage int sys_execve(const char *ufilename, char **uargv, goto out; error = do_execve(filename, - (char __user * __user *)uargv, - (char __user * __user *)uenvp, + (const char __user *const __user *)uargv, + (const char __user *const __user *)uenvp, pregs); putname(filename); out: diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c index eb68bfdd86e6..f56b6fe5c5d0 100644 --- a/arch/sh/kernel/sys_sh32.c +++ b/arch/sh/kernel/sys_sh32.c @@ -71,7 +71,9 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register long __sc0 __asm__ ("r3") = __NR_execve; register long __sc4 __asm__ ("r4") = (long) filename; diff --git a/arch/sh/kernel/sys_sh64.c b/arch/sh/kernel/sys_sh64.c index 287235768bc5..c5a38c4bf410 100644 --- a/arch/sh/kernel/sys_sh64.c +++ b/arch/sh/kernel/sys_sh64.c @@ -33,7 +33,9 @@ * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve); register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename; diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 40e29fc8a4d6..17529298c50a 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -633,8 +633,10 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if(IS_ERR(filename)) goto out; error = do_execve(filename, - (char __user * __user *)regs->u_regs[base + UREG_I1], - (char __user * __user *)regs->u_regs[base + UREG_I2], + (const char __user *const __user *) + regs->u_regs[base + UREG_I1], + (const char __user *const __user *) + regs->u_regs[base + UREG_I2], regs); putname(filename); out: diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index dbe81a368b45..485f54748384 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -739,9 +739,9 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if (IS_ERR(filename)) goto out; error = do_execve(filename, - (char __user * __user *) + (const char __user *const __user *) regs->u_regs[base + UREG_I1], - (char __user * __user *) + (const char __user *const __user *) regs->u_regs[base + UREG_I2], regs); putname(filename); if (!error) { diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index ee995b7dae7e..50794137d710 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -282,7 +282,9 @@ out: * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { long __res; register long __g1 __asm__ ("g1") = __NR_execve; diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 3d435c42e6db..f836f4e93afe 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -758,7 +758,9 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { long __res; register long __g1 __asm__ ("g1") = __NR_execve; diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index ed590ad0acdc..985cc28c74c5 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -543,8 +543,9 @@ long _sys_vfork(struct pt_regs *regs) /* * sys_execve() executes a new program. */ -long _sys_execve(char __user *path, char __user *__user *argv, - char __user *__user *envp, struct pt_regs *regs) +long _sys_execve(const char __user *path, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { long error; char *filename; diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 59b20d93b6d4..cd145eda3579 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -44,8 +44,9 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) PT_REGS_SP(regs) = esp; } -static long execve1(const char *file, char __user * __user *argv, - char __user *__user *env) +static long execve1(const char *file, + const char __user *const __user *argv, + const char __user *const __user *env) { long error; diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 7427c0b1930c..5ddb246626db 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -51,7 +51,9 @@ long old_mmap(unsigned long addr, unsigned long len, return err; } -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { mm_segment_t fs; int ret; diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index feb2ff9bfc2d..f1d8b441fc77 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -23,8 +23,9 @@ long sys_iopl(unsigned int, struct pt_regs *); /* kernel/process.c */ int sys_fork(struct pt_regs *); int sys_vfork(struct pt_regs *); -long sys_execve(const char __user *, char __user * __user *, - char __user * __user *, struct pt_regs *); +long sys_execve(const char __user *, + const char __user *const __user *, + const char __user *const __user *, struct pt_regs *); long sys_clone(unsigned long, unsigned long, void __user *, void __user *, struct pt_regs *); diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 64ecaf0af9af..57d1868a86aa 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -301,8 +301,9 @@ EXPORT_SYMBOL(kernel_thread); /* * sys_execve() executes a new program. */ -long sys_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs) +long sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs) { long error; char *filename; diff --git a/arch/x86/kernel/sys_i386_32.c b/arch/x86/kernel/sys_i386_32.c index 196552bb412c..d5e06624e34a 100644 --- a/arch/x86/kernel/sys_i386_32.c +++ b/arch/x86/kernel/sys_i386_32.c @@ -28,7 +28,9 @@ * Do a system call from kernel instead of calling sys_execve so we * end up with proper pt_regs. */ -int kernel_execve(const char *filename, char *const argv[], char *const envp[]) +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) { long __res; asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index 7c2f38f68ebb..e3558b9a58ba 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -318,8 +318,9 @@ long xtensa_clone(unsigned long clone_flags, unsigned long newsp, */ asmlinkage -long xtensa_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp, +long xtensa_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp, long a3, long a4, long a5, struct pt_regs *regs) { diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 9e60fd201716..a7528b913936 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -108,7 +108,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) Node *fmt; struct file * interp_file = NULL; char iname[BINPRM_BUF_SIZE]; - char *iname_addr = iname; + const char *iname_addr = iname; int retval; int fd_binary = -1; diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index aca9d55afb22..396a9884591f 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -16,7 +16,8 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) { - char *cp, *i_name, *i_arg; + const char *i_arg, *i_name; + char *cp; struct file *file; char interp[BINPRM_BUF_SIZE]; int retval; diff --git a/fs/exec.c b/fs/exec.c index 7761837e4500..05c7d6b84df7 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -361,13 +361,13 @@ err: /* * count() counts the number of strings in array ARGV. */ -static int count(char __user * __user * argv, int max) +static int count(const char __user * const __user * argv, int max) { int i = 0; if (argv != NULL) { for (;;) { - char __user * p; + const char __user * p; if (get_user(p, argv)) return -EFAULT; @@ -387,7 +387,7 @@ static int count(char __user * __user * argv, int max) * processes's memory to the new process's stack. The call to get_user_pages() * ensures the destination page is created and not swapped out. */ -static int copy_strings(int argc, char __user * __user * argv, +static int copy_strings(int argc, const char __user *const __user *argv, struct linux_binprm *bprm) { struct page *kmapped_page = NULL; @@ -396,7 +396,7 @@ static int copy_strings(int argc, char __user * __user * argv, int ret; while (argc-- > 0) { - char __user *str; + const char __user *str; int len; unsigned long pos; @@ -470,12 +470,13 @@ out: /* * Like copy_strings, but get argv and its values from kernel memory. */ -int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm) +int copy_strings_kernel(int argc, const char *const *argv, + struct linux_binprm *bprm) { int r; mm_segment_t oldfs = get_fs(); set_fs(KERNEL_DS); - r = copy_strings(argc, (char __user * __user *)argv, bprm); + r = copy_strings(argc, (const char __user *const __user *)argv, bprm); set_fs(oldfs); return r; } @@ -997,7 +998,7 @@ EXPORT_SYMBOL(flush_old_exec); void setup_new_exec(struct linux_binprm * bprm) { int i, ch; - char * name; + const char *name; char tcomm[sizeof(current->comm)]; arch_pick_mmap_layout(current->mm); @@ -1316,9 +1317,9 @@ EXPORT_SYMBOL(search_binary_handler); /* * sys_execve() executes a new program. */ -int do_execve(char * filename, - char __user *__user *argv, - char __user *__user *envp, +int do_execve(const char * filename, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs * regs) { struct linux_binprm *bprm; diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index c809e286d213..a065612fc928 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -50,8 +50,8 @@ struct linux_binprm{ int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */ unsigned int per_clear; /* bits to clear in current->personality */ int argc, envc; - char * filename; /* Name of binary as seen by procps */ - char * interp; /* Name of the binary really executed. Most + const char * filename; /* Name of binary as seen by procps */ + const char * interp; /* Name of the binary really executed. Most of the time same as filename, but could be different for binfmt_{misc,script} */ unsigned interp_flags; @@ -126,7 +126,8 @@ extern int setup_arg_pages(struct linux_binprm * bprm, unsigned long stack_top, int executable_stack); extern int bprm_mm_init(struct linux_binprm *bprm); -extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm); +extern int copy_strings_kernel(int argc, const char *const *argv, + struct linux_binprm *bprm); extern int prepare_bprm_creds(struct linux_binprm *bprm); extern void install_exec_creds(struct linux_binprm *bprm); extern void do_coredump(long signr, int exit_code, struct pt_regs *regs); diff --git a/include/linux/sched.h b/include/linux/sched.h index ce160d68f5e7..1e2a6db2d7dd 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2109,7 +2109,9 @@ extern void daemonize(const char *, ...); extern int allow_signal(int); extern int disallow_signal(int); -extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *); +extern int do_execve(const char *, + const char __user * const __user *, + const char __user * const __user *, struct pt_regs *); extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *); struct task_struct *fork_idle(int); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 6e5d19788634..e6319d18a55d 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -820,7 +820,7 @@ asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, u64 mask, int fd, const char __user *pathname); -int kernel_execve(const char *filename, char *const argv[], char *const envp[]); +int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]); asmlinkage long sys_perf_event_open( diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 2b108538d0d9..3098a38f3ae1 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -24,10 +24,11 @@ static int __init no_initrd(char *str) __setup("noinitrd", no_initrd); -static int __init do_linuxrc(void * shell) +static int __init do_linuxrc(void *_shell) { - static char *argv[] = { "linuxrc", NULL, }; - extern char * envp_init[]; + static const char *argv[] = { "linuxrc", NULL, }; + extern const char *envp_init[]; + const char *shell = _shell; sys_close(old_fd);sys_close(root_fd); sys_setsid(); diff --git a/init/main.c b/init/main.c index 22d61cb06f98..94ab488039aa 100644 --- a/init/main.c +++ b/init/main.c @@ -197,8 +197,8 @@ static int __init set_reset_devices(char *str) __setup("reset_devices", set_reset_devices); -static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; -char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; +static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; +const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; static const char *panic_later, *panic_param; extern const struct obs_kernel_param __setup_start[], __setup_end[]; @@ -809,7 +809,7 @@ static void __init do_pre_smp_initcalls(void) do_one_initcall(*fn); } -static void run_init_process(char *init_filename) +static void run_init_process(const char *init_filename) { argv_init[0] = init_filename; kernel_execve(init_filename, argv_init, envp_init); diff --git a/kernel/kmod.c b/kernel/kmod.c index 6e9b19667a8d..9cd0591c96a2 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -153,7 +153,9 @@ static int ____call_usermodehelper(void *data) goto fail; } - retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); + retval = kernel_execve(sub_info->path, + (const char *const *)sub_info->argv, + (const char *const *)sub_info->envp); /* Exec failed? */ fail: diff --git a/security/commoncap.c b/security/commoncap.c index 4e015996dd4d..9d172e6e330c 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -40,7 +40,7 @@ * * Warn if that happens, once per boot. */ -static void warn_setuid_and_fcaps_mixed(char *fname) +static void warn_setuid_and_fcaps_mixed(const char *fname) { static int warned; if (!warned) { -- cgit v1.2.3-59-g8ed1b From f362b73244fb16ea4ae127ced1467dd8adaa7733 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Tue, 17 Aug 2010 23:56:55 +0100 Subject: Fix unprotected access to task credentials in waitid() Using a program like the following: #include #include #include #include int main() { id_t id; siginfo_t infop; pid_t res; id = fork(); if (id == 0) { sleep(1); exit(0); } kill(id, SIGSTOP); alarm(1); waitid(P_PID, id, &infop, WCONTINUED); return 0; } to call waitid() on a stopped process results in access to the child task's credentials without the RCU read lock being held - which may be replaced in the meantime - eliciting the following warning: =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- kernel/exit.c:1460 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 1 2 locks held by waitid02/22252: #0: (tasklist_lock){.?.?..}, at: [] do_wait+0xc5/0x310 #1: (&(&sighand->siglock)->rlock){-.-...}, at: [] wait_consider_task+0x19a/0xbe0 stack backtrace: Pid: 22252, comm: waitid02 Not tainted 2.6.35-323cd+ #3 Call Trace: [] lockdep_rcu_dereference+0xa4/0xc0 [] wait_consider_task+0xaf1/0xbe0 [] do_wait+0xf5/0x310 [] sys_waitid+0x86/0x1f0 [] ? child_wait_callback+0x0/0x70 [] system_call_fastpath+0x16/0x1b This is fixed by holding the RCU read lock in wait_task_continued() to ensure that the task's current credentials aren't destroyed between us reading the cred pointer and us reading the UID from those credentials. Furthermore, protect wait_task_stopped() in the same way. We don't need to keep holding the RCU read lock once we've read the UID from the credentials as holding the RCU read lock doesn't stop the target task from changing its creds under us - so the credentials may be outdated immediately after we've read the pointer, lock or no lock. Signed-off-by: Daniel J Blueman Signed-off-by: David Howells Acked-by: Paul E. McKenney Acked-by: Oleg Nesterov Signed-off-by: Linus Torvalds --- kernel/exit.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/exit.c b/kernel/exit.c index 671ed56e0a49..03120229db28 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1386,8 +1386,7 @@ static int wait_task_stopped(struct wait_opts *wo, if (!unlikely(wo->wo_flags & WNOWAIT)) *p_code = 0; - /* don't need the RCU readlock here as we're holding a spinlock */ - uid = __task_cred(p)->uid; + uid = task_uid(p); unlock_sig: spin_unlock_irq(&p->sighand->siglock); if (!exit_code) @@ -1460,7 +1459,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) } if (!unlikely(wo->wo_flags & WNOWAIT)) p->signal->flags &= ~SIGNAL_STOP_CONTINUED; - uid = __task_cred(p)->uid; + uid = task_uid(p); spin_unlock_irq(&p->sighand->siglock); pid = task_pid_vnr(p); -- cgit v1.2.3-59-g8ed1b From a7c8962bfbc730a9acc0a635bad0f9628b6e816a Mon Sep 17 00:00:00 2001 From: David Miller Date: Mon, 16 Aug 2010 21:20:07 -0700 Subject: arcmsr_hba: Missing slab.h include Signed-off-by: David S. Miller Signed-off-by: Linus Torvalds --- drivers/scsi/arcmsr/arcmsr_hba.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 95a895dd4f13..c8dc392edd57 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 602586a83b719df0fbd94196a1359ed35aeb2df3 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 17 Aug 2010 15:23:56 -0700 Subject: shmem: put_super must percpu_counter_destroy list_add() corruption messages reported from shmem_fill_super()'s recently introduced percpu_counter_init(): shmem_put_super() needs to remember to percpu_counter_destroy(). And also check error from percpu_counter_init(). Reported-bisected-and-tested-by: Tetsuo Handa Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds --- mm/shmem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index dfaa0f4e9789..080b09a57a8f 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2325,7 +2325,10 @@ static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs) static void shmem_put_super(struct super_block *sb) { - kfree(sb->s_fs_info); + struct shmem_sb_info *sbinfo = SHMEM_SB(sb); + + percpu_counter_destroy(&sbinfo->used_blocks); + kfree(sbinfo); sb->s_fs_info = NULL; } @@ -2367,7 +2370,8 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) #endif spin_lock_init(&sbinfo->stat_lock); - percpu_counter_init(&sbinfo->used_blocks, 0); + if (percpu_counter_init(&sbinfo->used_blocks, 0)) + goto failed; sbinfo->free_inodes = sbinfo->max_inodes; sb->s_maxbytes = SHMEM_MAX_BYTES; -- cgit v1.2.3-59-g8ed1b From 3a3a5ddb7a0f43c3dd0f98673f3d930a456725f8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 16 Aug 2010 18:09:31 +1000 Subject: Update recovery_offset even when external metadata is used. The update of ->recovery_offset in sync_sbs is appropriate even then external metadata is in use. However sync_sbs is only called when native metadata is used. So move that update in to the top of md_update_sb (which is the only caller of sync_sbs) before the test on ->external. This moves the update out of ->write_lock protection, but those fields only need ->reconfig_mutex protection which they still have. Also move the test on ->persistent up to where ->external is set as for metadata update purposes they are the same. Clear MD_CHANGE_DEVS and MD_CHANGE_CLEAN as they can only be confusing if ->external is set or ->persistent isn't. Finally move the update of ->utime down as it is only relevent (like the ->events update) for native metadata. Signed-off-by: NeilBrown Reported-by: "Kwolek, Adam" --- drivers/md/md.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 11567c7999a2..c148b6302154 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2136,16 +2136,6 @@ static void sync_sbs(mddev_t * mddev, int nospares) * with the rest of the array) */ mdk_rdev_t *rdev; - - /* First make sure individual recovery_offsets are correct */ - list_for_each_entry(rdev, &mddev->disks, same_set) { - if (rdev->raid_disk >= 0 && - mddev->delta_disks >= 0 && - !test_bit(In_sync, &rdev->flags) && - mddev->curr_resync_completed > rdev->recovery_offset) - rdev->recovery_offset = mddev->curr_resync_completed; - - } list_for_each_entry(rdev, &mddev->disks, same_set) { if (rdev->sb_events == mddev->events || (nospares && @@ -2167,12 +2157,27 @@ static void md_update_sb(mddev_t * mddev, int force_change) int sync_req; int nospares = 0; - mddev->utime = get_seconds(); - if (mddev->external) - return; repeat: + /* First make sure individual recovery_offsets are correct */ + list_for_each_entry(rdev, &mddev->disks, same_set) { + if (rdev->raid_disk >= 0 && + mddev->delta_disks >= 0 && + !test_bit(In_sync, &rdev->flags) && + mddev->curr_resync_completed > rdev->recovery_offset) + rdev->recovery_offset = mddev->curr_resync_completed; + + } + if (mddev->external || !mddev->persistent) { + clear_bit(MD_CHANGE_DEVS, &mddev->flags); + clear_bit(MD_CHANGE_CLEAN, &mddev->flags); + wake_up(&mddev->sb_wait); + return; + } + spin_lock_irq(&mddev->write_lock); + mddev->utime = get_seconds(); + set_bit(MD_CHANGE_PENDING, &mddev->flags); if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags)) force_change = 1; @@ -2221,19 +2226,6 @@ repeat: MD_BUG(); mddev->events --; } - - /* - * do not write anything to disk if using - * nonpersistent superblocks - */ - if (!mddev->persistent) { - if (!mddev->external) - clear_bit(MD_CHANGE_PENDING, &mddev->flags); - - spin_unlock_irq(&mddev->write_lock); - wake_up(&mddev->sb_wait); - return; - } sync_sbs(mddev, nospares); spin_unlock_irq(&mddev->write_lock); -- cgit v1.2.3-59-g8ed1b From e6ffbcb6cd0ac471223df24ae77eb486c1ee68cc Mon Sep 17 00:00:00 2001 From: Adrian Drzewiecki Date: Wed, 18 Aug 2010 11:49:02 +1000 Subject: md: Notify sysfs when RAID1/5/10 disk is In_sync. When RAID1 is done syncing disks, it'll update the state of synced rdevs to In_sync. But it neglected to notify sysfs that the attribute changed. So any programs that are waiting for an rdev's state to change will not be woken. (raid5/raid10 added by neilb) Signed-off-by: Adrian Drzewiecki Signed-off-by: NeilBrown --- drivers/md/raid1.c | 1 + drivers/md/raid10.c | 1 + drivers/md/raid5.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 73cc74ffc26b..0e1abf1bb38e 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1135,6 +1135,7 @@ static int raid1_spare_active(mddev_t *mddev) spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded--; spin_unlock_irqrestore(&conf->device_lock, flags); + sysfs_notify_dirent(rdev->sysfs_state); } } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a88aeb5198c7..76d1fc9c65ba 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1130,6 +1130,7 @@ static int raid10_spare_active(mddev_t *mddev) spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded--; spin_unlock_irqrestore(&conf->device_lock, flags); + sysfs_notify_dirent(tmp->rdev->sysfs_state); } } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 866d4b5a144c..7865dd090bde 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5341,6 +5341,7 @@ static int raid5_spare_active(mddev_t *mddev) spin_lock_irqsave(&conf->device_lock, flags); mddev->degraded--; spin_unlock_irqrestore(&conf->device_lock, flags); + sysfs_notify_dirent(tmp->rdev->sysfs_state); } } print_raid5_conf(conf); -- cgit v1.2.3-59-g8ed1b From 6b9656205469269c050963c71fca1998b247a560 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 18 Aug 2010 11:56:59 +1000 Subject: md: provide appropriate return value for spare_active functions. md_check_recovery expects ->spare_active to return 'true' if any spares were activated, but none of them do, so the consequent change in 'degraded' is not notified through sysfs. So count the number of spares activated, subtract it from 'degraded' just once, and return it. Reported-by: Adrian Drzewiecki Signed-off-by: NeilBrown --- drivers/md/raid1.c | 12 +++++++----- drivers/md/raid10.c | 12 +++++++----- drivers/md/raid5.c | 12 +++++++----- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 0e1abf1bb38e..64d96526a9cc 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1120,6 +1120,8 @@ static int raid1_spare_active(mddev_t *mddev) { int i; conf_t *conf = mddev->private; + int count = 0; + unsigned long flags; /* * Find all failed disks within the RAID1 configuration @@ -1131,16 +1133,16 @@ static int raid1_spare_active(mddev_t *mddev) if (rdev && !test_bit(Faulty, &rdev->flags) && !test_and_set_bit(In_sync, &rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded--; - spin_unlock_irqrestore(&conf->device_lock, flags); + count++; sysfs_notify_dirent(rdev->sysfs_state); } } + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded -= count; + spin_unlock_irqrestore(&conf->device_lock, flags); print_conf(conf); - return 0; + return count; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 76d1fc9c65ba..a2f8a7153dce 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1116,6 +1116,8 @@ static int raid10_spare_active(mddev_t *mddev) int i; conf_t *conf = mddev->private; mirror_info_t *tmp; + int count = 0; + unsigned long flags; /* * Find all non-in_sync disks within the RAID10 configuration @@ -1126,16 +1128,16 @@ static int raid10_spare_active(mddev_t *mddev) if (tmp->rdev && !test_bit(Faulty, &tmp->rdev->flags) && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded--; - spin_unlock_irqrestore(&conf->device_lock, flags); + count++; sysfs_notify_dirent(tmp->rdev->sysfs_state); } } + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded -= count; + spin_unlock_irqrestore(&conf->device_lock, flags); print_conf(conf); - return 0; + return count; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 7865dd090bde..69b0a169e43d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5330,6 +5330,8 @@ static int raid5_spare_active(mddev_t *mddev) int i; raid5_conf_t *conf = mddev->private; struct disk_info *tmp; + int count = 0; + unsigned long flags; for (i = 0; i < conf->raid_disks; i++) { tmp = conf->disks + i; @@ -5337,15 +5339,15 @@ static int raid5_spare_active(mddev_t *mddev) && tmp->rdev->recovery_offset == MaxSector && !test_bit(Faulty, &tmp->rdev->flags) && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded--; - spin_unlock_irqrestore(&conf->device_lock, flags); + count++; sysfs_notify_dirent(tmp->rdev->sysfs_state); } } + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded -= count; + spin_unlock_irqrestore(&conf->device_lock, flags); print_raid5_conf(conf); - return 0; + return count; } static int raid5_remove_disk(mddev_t *mddev, int number) -- cgit v1.2.3-59-g8ed1b From dc6ae5e471425762122bb93310dd46101ccd840d Mon Sep 17 00:00:00 2001 From: Jate Sujjavanich Date: Mon, 7 Jun 2010 11:39:30 -0400 Subject: m68knommu: arch/m68k/include/asm/ide.h fix for nommu The arch/m68k/include/asm/ide.h produces errors when the IDE driver is compiled for my 523x uClinux system under kernel. The header makes some redefines of operators not defined in the arch/m68k/include/asm/io_no.h header. There are no separate mmio and iospace defines. Signed-off-by: Jate Sujjavanich Acked-by: Geert Uytterhoeven Signed-off-by: Greg Ungerer --- arch/m68k/include/asm/ide.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/m68k/include/asm/ide.h b/arch/m68k/include/asm/ide.h index 3958726664ba..492fee8a1ab2 100644 --- a/arch/m68k/include/asm/ide.h +++ b/arch/m68k/include/asm/ide.h @@ -1,6 +1,4 @@ /* - * linux/include/asm-m68k/ide.h - * * Copyright (C) 1994-1996 Linus Torvalds & authors */ @@ -34,6 +32,8 @@ #include #include +#ifdef CONFIG_MMU + /* * Get rid of defs from io.h - ide has its private and conflicting versions * Since so far no single m68k platform uses ISA/PCI I/O space for IDE, we @@ -53,5 +53,14 @@ #define __ide_mm_outsw(port, addr, n) raw_outsw((u16 *)port, addr, n) #define __ide_mm_outsl(port, addr, n) raw_outsl((u32 *)port, addr, n) +#else + +#define __ide_mm_insw(port, addr, n) io_insw((unsigned int)port, addr, n) +#define __ide_mm_insl(port, addr, n) io_insl((unsigned int)port, addr, n) +#define __ide_mm_outsw(port, addr, n) io_outsw((unsigned int)port, addr, n) +#define __ide_mm_outsl(port, addr, n) io_outsl((unsigned int)port, addr, n) + +#endif /* CONFIG_MMU */ + #endif /* __KERNEL__ */ #endif /* _M68K_IDE_H */ -- cgit v1.2.3-59-g8ed1b From c7484cf467df44c0d478b0412dc01e71fbec7923 Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Wed, 14 Jul 2010 22:01:13 +0400 Subject: m68knommu: formatting of pointers in printk() arch/m68knommu/kernel/process.c: formatting of pointers in printk() Use %p instead of %08x in printk(). Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Ungerer --- arch/m68knommu/kernel/process.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c index 6350f68cd026..3fb9e45df888 100644 --- a/arch/m68knommu/kernel/process.c +++ b/arch/m68knommu/kernel/process.c @@ -316,14 +316,14 @@ void dump(struct pt_regs *fp) fp->d0, fp->d1, fp->d2, fp->d3); printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", fp->d4, fp->d5, fp->a0, fp->a1); - printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", - (unsigned int) rdusp(), (unsigned int) fp); + printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %p\n", + (unsigned int) rdusp(), fp); printk(KERN_EMERG "\nCODE:"); tp = ((unsigned char *) fp->pc) - 0x20; for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%p: ", tp + i); printk("%08x ", (int) *sp++); } printk(KERN_EMERG "\n"); @@ -332,7 +332,7 @@ void dump(struct pt_regs *fp) tp = ((unsigned char *) fp) - 0x40; for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%p: ", tp + i); printk("%08x ", (int) *sp++); } printk(KERN_EMERG "\n"); @@ -341,7 +341,7 @@ void dump(struct pt_regs *fp) tp = (unsigned char *) (rdusp() - 0x10); for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { if ((i % 0x10) == 0) - printk(KERN_EMERG "%08x: ", (int) (tp + i)); + printk(KERN_EMERG "%p: ", tp + i); printk("%08x ", (int) *sp++); } printk(KERN_EMERG "\n"); -- cgit v1.2.3-59-g8ed1b From 5e1c53356d79591b10cdea12e3d5ebace8e7b6fa Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 28 Jul 2010 13:32:46 +1000 Subject: m68knommu: include sched.h in ColdFire/SPI driver Using the coldfire qspi driver, I get the following error: drivers/spi/coldfire_qspi.c: In function 'mcfqspi_irq_handler': drivers/spi/coldfire_qspi.c:166: error: 'TASK_NORMAL' undeclared (first use in this function) drivers/spi/coldfire_qspi.c:166: error: (Each undeclared identifier is reported only once It is solved by adding the following include to coldfire_sqpi.c: #include Fix suggested by Jate Sujjavanich Signed-off-by: Greg Ungerer --- drivers/spi/coldfire_qspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c index 59be3efe0636..052b3c7fa6a0 100644 --- a/drivers/spi/coldfire_qspi.c +++ b/drivers/spi/coldfire_qspi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From b10f997bb0f4e5b34d447f498fb85834a40d3acb Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 21:44:13 -0700 Subject: sparc64: Really fix atomic64_t interface types. Linus noticed that some of the interface arguments didn't get "int" --> "long" conversion, as needed. Signed-off-by: David S. Miller --- arch/sparc/include/asm/atomic_64.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index f0c74227c737..bdb2ff880bdd 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -20,14 +20,14 @@ #define atomic64_set(v, i) (((v)->counter) = i) extern void atomic_add(int, atomic_t *); -extern void atomic64_add(int, atomic64_t *); +extern void atomic64_add(long, atomic64_t *); extern void atomic_sub(int, atomic_t *); -extern void atomic64_sub(int, atomic64_t *); +extern void atomic64_sub(long, atomic64_t *); extern int atomic_add_ret(int, atomic_t *); -extern long atomic64_add_ret(int, atomic64_t *); +extern long atomic64_add_ret(long, atomic64_t *); extern int atomic_sub_ret(int, atomic_t *); -extern long atomic64_sub_ret(int, atomic64_t *); +extern long atomic64_sub_ret(long, atomic64_t *); #define atomic_dec_return(v) atomic_sub_ret(1, v) #define atomic64_dec_return(v) atomic64_sub_ret(1, v) -- cgit v1.2.3-59-g8ed1b From 5c79a5ae23e72fa12f1c7c528f62bf3ea35da0dc Mon Sep 17 00:00:00 2001 From: Ernst Schwab Date: Mon, 16 Aug 2010 15:10:11 +0200 Subject: spi.h: missing kernel-doc notation, please fix Added comments in kernel-doc notation for previously added struct fields. Signed-off-by: Ernst Schwab Acked-by: Randy Dunlap Signed-off-by: Grant Likely --- include/linux/spi/spi.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index ae0a5286f558..92e52a1e6af3 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -213,6 +213,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @dma_alignment: SPI controller constraint on DMA buffers alignment. * @mode_bits: flags understood by this controller driver * @flags: other constraints relevant to this driver + * @bus_lock_spinlock: spinlock for SPI bus locking + * @bus_lock_mutex: mutex for SPI bus locking + * @bus_lock_flag: indicates that the SPI bus is locked for exclusive use * @setup: updates the device mode and clocking records used by a * device's SPI controller; protocol code may call this. This * must fail if an unrecognized or unsupported mode is requested. -- cgit v1.2.3-59-g8ed1b From f4ae2faa40199b97b12f508234640bc565d166f8 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 11 Aug 2010 14:07:01 +0300 Subject: fix reiserfs_evict_inode end_writeback second call reiserfs_evict_inode calls end_writeback two times hitting kernel BUG at fs/inode.c:298 becase inode->i_state is I_CLEAR already. Signed-off-by: Sergey Senozhatsky Signed-off-by: Al Viro --- fs/reiserfs/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index ae35413dcbe1..caa758377d66 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -83,6 +83,7 @@ void reiserfs_evict_inode(struct inode *inode) dquot_drop(inode); inode->i_blocks = 0; reiserfs_write_unlock_once(inode->i_sb, depth); + return; no_delete: end_writeback(inode); -- cgit v1.2.3-59-g8ed1b From b845ff8f3ea2988ad5041315e2d35298e85cbc2f Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 17 Aug 2010 17:08:35 +0300 Subject: cramfs: only unlock new inodes Commit 77b8a75f5bb introduced a warning at fs/inode.c:692 unlock_new_inode(), caused by unlock_new_inode() being called on existing inodes as well. This patch changes setup_inode() to only call unlock_new_inode() for I_NEW inodes. Signed-off-by: Alexander Shishkin Signed-off-by: Al Viro --- fs/cramfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index a53b130b366c..1e7a33028d33 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -80,7 +80,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, } } else { inode = iget_locked(sb, CRAMINO(cramfs_inode)); - if (inode) { + if (inode && (inode->i_state & I_NEW)) { setup_inode(inode, cramfs_inode); unlock_new_inode(inode); } -- cgit v1.2.3-59-g8ed1b From dad5eb6daa7eeb63d4fc9d982892c59faa07e797 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 17 Aug 2010 12:42:13 +0200 Subject: vfs: update ctime when changing the file's permission by setfacl generic_acl_set didn't update the ctime of the file when its permission was changed. Steps to reproduce: # touch aaa # stat -c %Z aaa 1275289822 # setfacl -m 'u::x,g::x,o::x' aaa # stat -c %Z aaa 1275289822 <- unchanged But, according to the spec of the ctime, vfs must update it. Port of ext3 patch by Miao Xie . CC: Al Viro Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/generic_acl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/generic_acl.c b/fs/generic_acl.c index 99800e564157..6bc9e3a5a693 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c @@ -94,6 +94,7 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value, if (error < 0) goto failed; inode->i_mode = mode; + inode->i_ctime = CURRENT_TIME; if (error == 0) { posix_acl_release(acl); acl = NULL; -- cgit v1.2.3-59-g8ed1b From 87e99511ea54510ffb60b98001d108794d5037f8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 11 Aug 2010 17:05:45 +0200 Subject: kill BH_Ordered flag Instead of abusing a buffer_head flag just add a variant of sync_dirty_buffer which allows passing the exact type of write flag required. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/buffer.c | 17 ++++++++-------- fs/jbd/commit.c | 49 +++++++++++++++++++++++---------------------- fs/jbd2/commit.c | 39 ++++++++++++++---------------------- fs/nilfs2/super.c | 28 +++++++++++++------------- include/linux/buffer_head.h | 3 +-- 5 files changed, 63 insertions(+), 73 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 50efa339e051..6c8ad977f3d4 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2911,13 +2911,6 @@ int submit_bh(int rw, struct buffer_head * bh) BUG_ON(buffer_delay(bh)); BUG_ON(buffer_unwritten(bh)); - /* - * Mask in barrier bit for a write (could be either a WRITE or a - * WRITE_SYNC - */ - if (buffer_ordered(bh) && (rw & WRITE)) - rw |= WRITE_BARRIER; - /* * Only clear out a write error when rewriting */ @@ -3021,7 +3014,7 @@ EXPORT_SYMBOL(ll_rw_block); * and then start new I/O and then wait upon it. The caller must have a ref on * the buffer_head. */ -int sync_dirty_buffer(struct buffer_head *bh) +int __sync_dirty_buffer(struct buffer_head *bh, int rw) { int ret = 0; @@ -3030,7 +3023,7 @@ int sync_dirty_buffer(struct buffer_head *bh) if (test_clear_buffer_dirty(bh)) { get_bh(bh); bh->b_end_io = end_buffer_write_sync; - ret = submit_bh(WRITE_SYNC, bh); + ret = submit_bh(rw, bh); wait_on_buffer(bh); if (buffer_eopnotsupp(bh)) { clear_buffer_eopnotsupp(bh); @@ -3043,6 +3036,12 @@ int sync_dirty_buffer(struct buffer_head *bh) } return ret; } +EXPORT_SYMBOL(__sync_dirty_buffer); + +int sync_dirty_buffer(struct buffer_head *bh) +{ + return __sync_dirty_buffer(bh, WRITE_SYNC); +} EXPORT_SYMBOL(sync_dirty_buffer); /* diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 28a9ddaa0c49..95d8c11c929e 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -119,7 +119,6 @@ static int journal_write_commit_record(journal_t *journal, struct buffer_head *bh; journal_header_t *header; int ret; - int barrier_done = 0; if (is_journal_aborted(journal)) return 0; @@ -137,34 +136,36 @@ static int journal_write_commit_record(journal_t *journal, JBUFFER_TRACE(descriptor, "write commit block"); set_buffer_dirty(bh); + if (journal->j_flags & JFS_BARRIER) { - set_buffer_ordered(bh); - barrier_done = 1; - } - ret = sync_dirty_buffer(bh); - if (barrier_done) - clear_buffer_ordered(bh); - /* is it possible for another commit to fail at roughly - * the same time as this one? If so, we don't want to - * trust the barrier flag in the super, but instead want - * to remember if we sent a barrier request - */ - if (ret == -EOPNOTSUPP && barrier_done) { - char b[BDEVNAME_SIZE]; + ret = __sync_dirty_buffer(bh, WRITE_SYNC | WRITE_BARRIER); - printk(KERN_WARNING - "JBD: barrier-based sync failed on %s - " - "disabling barriers\n", - bdevname(journal->j_dev, b)); - spin_lock(&journal->j_state_lock); - journal->j_flags &= ~JFS_BARRIER; - spin_unlock(&journal->j_state_lock); + /* + * Is it possible for another commit to fail at roughly + * the same time as this one? If so, we don't want to + * trust the barrier flag in the super, but instead want + * to remember if we sent a barrier request + */ + if (ret == -EOPNOTSUPP) { + char b[BDEVNAME_SIZE]; - /* And try again, without the barrier */ - set_buffer_uptodate(bh); - set_buffer_dirty(bh); + printk(KERN_WARNING + "JBD: barrier-based sync failed on %s - " + "disabling barriers\n", + bdevname(journal->j_dev, b)); + spin_lock(&journal->j_state_lock); + journal->j_flags &= ~JFS_BARRIER; + spin_unlock(&journal->j_state_lock); + + /* And try again, without the barrier */ + set_buffer_uptodate(bh); + set_buffer_dirty(bh); + ret = sync_dirty_buffer(bh); + } + } else { ret = sync_dirty_buffer(bh); } + put_bh(bh); /* One for getblk() */ journal_put_journal_head(descriptor); diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index f52e5e8049f1..7c068c189d80 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -101,7 +101,6 @@ static int journal_submit_commit_record(journal_t *journal, struct commit_header *tmp; struct buffer_head *bh; int ret; - int barrier_done = 0; struct timespec now = current_kernel_time(); if (is_journal_aborted(journal)) @@ -136,30 +135,22 @@ static int journal_submit_commit_record(journal_t *journal, if (journal->j_flags & JBD2_BARRIER && !JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { - set_buffer_ordered(bh); - barrier_done = 1; - } - ret = submit_bh(WRITE_SYNC_PLUG, bh); - if (barrier_done) - clear_buffer_ordered(bh); - - /* is it possible for another commit to fail at roughly - * the same time as this one? If so, we don't want to - * trust the barrier flag in the super, but instead want - * to remember if we sent a barrier request - */ - if (ret == -EOPNOTSUPP && barrier_done) { - printk(KERN_WARNING - "JBD2: Disabling barriers on %s, " - "not supported by device\n", journal->j_devname); - write_lock(&journal->j_state_lock); - journal->j_flags &= ~JBD2_BARRIER; - write_unlock(&journal->j_state_lock); + ret = submit_bh(WRITE_SYNC_PLUG | WRITE_BARRIER, bh); + if (ret == -EOPNOTSUPP) { + printk(KERN_WARNING + "JBD2: Disabling barriers on %s, " + "not supported by device\n", journal->j_devname); + write_lock(&journal->j_state_lock); + journal->j_flags &= ~JBD2_BARRIER; + write_unlock(&journal->j_state_lock); - /* And try again, without the barrier */ - lock_buffer(bh); - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); + /* And try again, without the barrier */ + lock_buffer(bh); + set_buffer_uptodate(bh); + clear_buffer_dirty(bh); + ret = submit_bh(WRITE_SYNC_PLUG, bh); + } + } else { ret = submit_bh(WRITE_SYNC_PLUG, bh); } *cbh = bh; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1fa86b9df73b..68345430fb48 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -175,24 +175,24 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag) { struct the_nilfs *nilfs = sbi->s_nilfs; int err; - int barrier_done = 0; - if (nilfs_test_opt(sbi, BARRIER)) { - set_buffer_ordered(nilfs->ns_sbh[0]); - barrier_done = 1; - } retry: set_buffer_dirty(nilfs->ns_sbh[0]); - err = sync_dirty_buffer(nilfs->ns_sbh[0]); - if (err == -EOPNOTSUPP && barrier_done) { - nilfs_warning(sbi->s_super, __func__, - "barrier-based sync failed. " - "disabling barriers\n"); - nilfs_clear_opt(sbi, BARRIER); - barrier_done = 0; - clear_buffer_ordered(nilfs->ns_sbh[0]); - goto retry; + + if (nilfs_test_opt(sbi, BARRIER)) { + err = __sync_dirty_buffer(nilfs->ns_sbh[0], + WRITE_SYNC | WRITE_BARRIER); + if (err == -EOPNOTSUPP) { + nilfs_warning(sbi->s_super, __func__, + "barrier-based sync failed. " + "disabling barriers\n"); + nilfs_clear_opt(sbi, BARRIER); + goto retry; + } + } else { + err = sync_dirty_buffer(nilfs->ns_sbh[0]); } + if (unlikely(err)) { printk(KERN_ERR "NILFS: unable to write superblock (err=%d)\n", err); diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 43e649a72529..72c1cf83eb85 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -32,7 +32,6 @@ enum bh_state_bits { BH_Delay, /* Buffer is not yet allocated on disk */ BH_Boundary, /* Block is followed by a discontiguity */ BH_Write_EIO, /* I/O error on write */ - BH_Ordered, /* ordered write */ BH_Eopnotsupp, /* operation not supported (barrier) */ BH_Unwritten, /* Buffer is allocated on disk but not written */ BH_Quiet, /* Buffer Error Prinks to be quiet */ @@ -125,7 +124,6 @@ BUFFER_FNS(Async_Write, async_write) BUFFER_FNS(Delay, delay) BUFFER_FNS(Boundary, boundary) BUFFER_FNS(Write_EIO, write_io_error) -BUFFER_FNS(Ordered, ordered) BUFFER_FNS(Eopnotsupp, eopnotsupp) BUFFER_FNS(Unwritten, unwritten) @@ -183,6 +181,7 @@ void unlock_buffer(struct buffer_head *bh); void __lock_buffer(struct buffer_head *bh); void ll_rw_block(int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); +int __sync_dirty_buffer(struct buffer_head *bh, int rw); int submit_bh(int, struct buffer_head *); void write_boundary_block(struct block_device *bdev, sector_t bblock, unsigned blocksize); -- cgit v1.2.3-59-g8ed1b From 9cb569d601e0b93e01c20a22872270ec663b75f6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 11 Aug 2010 17:06:24 +0200 Subject: remove SWRITE* I/O types These flags aren't real I/O types, but tell ll_rw_block to always lock the buffer instead of giving up on a failed trylock. Instead add a new write_dirty_buffer helper that implements this semantic and use it from the existing SWRITE* callers. Note that the ll_rw_block code had a bug where it didn't promote WRITE_SYNC_PLUG properly, which this patch fixes. In the ufs code clean up the helper that used to call ll_rw_block to mirror sync_dirty_buffer, which is the function it implements for compound buffers. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/buffer.c | 52 +++++++++++++++++++++++++-------------------- fs/fat/misc.c | 4 +++- fs/jbd/checkpoint.c | 4 +++- fs/jbd/journal.c | 2 +- fs/jbd/revoke.c | 2 +- fs/jbd2/checkpoint.c | 4 +++- fs/jbd2/journal.c | 2 +- fs/jbd2/revoke.c | 2 +- fs/reiserfs/journal.c | 2 +- fs/ufs/balloc.c | 24 +++++++-------------- fs/ufs/ialloc.c | 18 ++++++---------- fs/ufs/truncate.c | 18 ++++++---------- fs/ufs/util.c | 20 +++++++---------- fs/ufs/util.h | 3 +-- include/linux/buffer_head.h | 1 + include/linux/fs.h | 9 -------- 16 files changed, 73 insertions(+), 94 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 6c8ad977f3d4..3e7dca279d1c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -770,11 +770,12 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) spin_unlock(lock); /* * Ensure any pending I/O completes so that - * ll_rw_block() actually writes the current - * contents - it is a noop if I/O is still in - * flight on potentially older contents. + * write_dirty_buffer() actually writes the + * current contents - it is a noop if I/O is + * still in flight on potentially older + * contents. */ - ll_rw_block(SWRITE_SYNC_PLUG, 1, &bh); + write_dirty_buffer(bh, WRITE_SYNC_PLUG); /* * Kick off IO for the previous mapping. Note @@ -2949,22 +2950,21 @@ EXPORT_SYMBOL(submit_bh); /** * ll_rw_block: low-level access to block devices (DEPRECATED) - * @rw: whether to %READ or %WRITE or %SWRITE or maybe %READA (readahead) + * @rw: whether to %READ or %WRITE or maybe %READA (readahead) * @nr: number of &struct buffer_heads in the array * @bhs: array of pointers to &struct buffer_head * * ll_rw_block() takes an array of pointers to &struct buffer_heads, and * requests an I/O operation on them, either a %READ or a %WRITE. The third - * %SWRITE is like %WRITE only we make sure that the *current* data in buffers - * are sent to disk. The fourth %READA option is described in the documentation - * for generic_make_request() which ll_rw_block() calls. + * %READA option is described in the documentation for generic_make_request() + * which ll_rw_block() calls. * * This function drops any buffer that it cannot get a lock on (with the - * BH_Lock state bit) unless SWRITE is required, any buffer that appears to be - * clean when doing a write request, and any buffer that appears to be - * up-to-date when doing read request. Further it marks as clean buffers that - * are processed for writing (the buffer cache won't assume that they are - * actually clean until the buffer gets unlocked). + * BH_Lock state bit), any buffer that appears to be clean when doing a write + * request, and any buffer that appears to be up-to-date when doing read + * request. Further it marks as clean buffers that are processed for + * writing (the buffer cache won't assume that they are actually clean + * until the buffer gets unlocked). * * ll_rw_block sets b_end_io to simple completion handler that marks * the buffer up-to-date (if approriate), unlocks the buffer and wakes @@ -2980,20 +2980,13 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) for (i = 0; i < nr; i++) { struct buffer_head *bh = bhs[i]; - if (rw == SWRITE || rw == SWRITE_SYNC || rw == SWRITE_SYNC_PLUG) - lock_buffer(bh); - else if (!trylock_buffer(bh)) + if (!trylock_buffer(bh)) continue; - - if (rw == WRITE || rw == SWRITE || rw == SWRITE_SYNC || - rw == SWRITE_SYNC_PLUG) { + if (rw == WRITE) { if (test_clear_buffer_dirty(bh)) { bh->b_end_io = end_buffer_write_sync; get_bh(bh); - if (rw == SWRITE_SYNC) - submit_bh(WRITE_SYNC, bh); - else - submit_bh(WRITE, bh); + submit_bh(WRITE, bh); continue; } } else { @@ -3009,6 +3002,19 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) } EXPORT_SYMBOL(ll_rw_block); +void write_dirty_buffer(struct buffer_head *bh, int rw) +{ + lock_buffer(bh); + if (!test_clear_buffer_dirty(bh)) { + unlock_buffer(bh); + return; + } + bh->b_end_io = end_buffer_write_sync; + get_bh(bh); + submit_bh(rw, bh); +} +EXPORT_SYMBOL(write_dirty_buffer); + /* * For a data-integrity writeout, we need to wait upon any in-progress I/O * and then start new I/O and then wait upon it. The caller must have a ref on diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 1fa23f6ffba5..1736f2356388 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -250,7 +250,9 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) { int i, err = 0; - ll_rw_block(SWRITE, nr_bhs, bhs); + for (i = 0; i < nr_bhs; i++) + write_dirty_buffer(bhs[i], WRITE); + for (i = 0; i < nr_bhs; i++) { wait_on_buffer(bhs[i]); if (buffer_eopnotsupp(bhs[i])) { diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index b0435dd0654d..05a38b9c4c0e 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c @@ -254,7 +254,9 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) { int i; - ll_rw_block(SWRITE, *batch_count, bhs); + for (i = 0; i < *batch_count; i++) + write_dirty_buffer(bhs[i], WRITE); + for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = bhs[i]; clear_buffer_jwrite(bh); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index f19ce94693d8..2c4b1f109da9 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1024,7 +1024,7 @@ void journal_update_superblock(journal_t *journal, int wait) if (wait) sync_dirty_buffer(bh); else - ll_rw_block(SWRITE, 1, &bh); + write_dirty_buffer(bh, WRITE); out: /* If we have just flushed the log (by marking s_start==0), then diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index ad717328343a..d29018307e2e 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c @@ -617,7 +617,7 @@ static void flush_descriptor(journal_t *journal, set_buffer_jwrite(bh); BUFFER_TRACE(bh, "write"); set_buffer_dirty(bh); - ll_rw_block((write_op == WRITE) ? SWRITE : SWRITE_SYNC_PLUG, 1, &bh); + write_dirty_buffer(bh, write_op); } #endif diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 1c23a0f4e8a3..5247e7ffdcb4 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -255,7 +255,9 @@ __flush_batch(journal_t *journal, int *batch_count) { int i; - ll_rw_block(SWRITE, *batch_count, journal->j_chkpt_bhs); + for (i = 0; i < *batch_count; i++) + write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE); + for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = journal->j_chkpt_bhs[i]; clear_buffer_jwrite(bh); diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index ad5866aaf0f9..0e8014ea6b94 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1124,7 +1124,7 @@ void jbd2_journal_update_superblock(journal_t *journal, int wait) set_buffer_uptodate(bh); } } else - ll_rw_block(SWRITE, 1, &bh); + write_dirty_buffer(bh, WRITE); out: /* If we have just flushed the log (by marking s_start==0), then diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index a360b06af2e3..9ad321fd63fd 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -625,7 +625,7 @@ static void flush_descriptor(journal_t *journal, set_buffer_jwrite(bh); BUFFER_TRACE(bh, "write"); set_buffer_dirty(bh); - ll_rw_block((write_op == WRITE) ? SWRITE : SWRITE_SYNC_PLUG, 1, &bh); + write_dirty_buffer(bh, write_op); } #endif diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 1ec952b1f036..812e2c05aa29 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2311,7 +2311,7 @@ static int journal_read_transaction(struct super_block *sb, /* flush out the real blocks */ for (i = 0; i < get_desc_trans_len(desc); i++) { set_buffer_dirty(real_blocks[i]); - ll_rw_block(SWRITE, 1, real_blocks + i); + write_dirty_buffer(real_blocks[i], WRITE); } for (i = 0; i < get_desc_trans_len(desc); i++) { wait_on_buffer(real_blocks[i]); diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 048484fb10d2..46f7a807bbc1 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -114,10 +114,8 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; unlock_super (sb); @@ -207,10 +205,8 @@ do_more: ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); if (overflow) { fragment += count; @@ -558,10 +554,8 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment, ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment); @@ -680,10 +674,8 @@ cg_found: succed: ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; result += cgno * uspi->s_fpg; diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 428017e018fe..2eabf04af3de 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -113,10 +113,8 @@ void ufs_free_inode (struct inode * inode) ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; unlock_super (sb); @@ -156,10 +154,8 @@ static void ufs2_init_inodes_chunk(struct super_block *sb, fs32_add(sb, &ucg->cg_u.cg_u2.cg_initediblk, uspi->s_inopb); ubh_mark_buffer_dirty(UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer(UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); UFSD("EXIT\n"); } @@ -290,10 +286,8 @@ cg_found: } ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); - if (sb->s_flags & MS_SYNCHRONOUS) { - ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); - ubh_wait_on_buffer (UCPI_UBH(ucpi)); - } + if (sb->s_flags & MS_SYNCHRONOUS) + ubh_sync_block(UCPI_UBH(ucpi)); sb->s_dirt = 1; inode->i_ino = cg * uspi->s_ipg + bit; diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 34d5cb135320..a58f9155fc9a 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -243,10 +243,8 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) ubh_bforget(ind_ubh); ind_ubh = NULL; } - if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) { - ubh_ll_rw_block(SWRITE, ind_ubh); - ubh_wait_on_buffer (ind_ubh); - } + if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) + ubh_sync_block(ind_ubh); ubh_brelse (ind_ubh); UFSD("EXIT: ino %lu\n", inode->i_ino); @@ -307,10 +305,8 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) ubh_bforget(dind_bh); dind_bh = NULL; } - if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) { - ubh_ll_rw_block(SWRITE, dind_bh); - ubh_wait_on_buffer (dind_bh); - } + if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) + ubh_sync_block(dind_bh); ubh_brelse (dind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); @@ -367,10 +363,8 @@ static int ufs_trunc_tindirect(struct inode *inode) ubh_bforget(tind_bh); tind_bh = NULL; } - if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) { - ubh_ll_rw_block(SWRITE, tind_bh); - ubh_wait_on_buffer (tind_bh); - } + if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) + ubh_sync_block(tind_bh); ubh_brelse (tind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); diff --git a/fs/ufs/util.c b/fs/ufs/util.c index 85a7fc9e4a4e..d2c36d53fe66 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -113,21 +113,17 @@ void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag) } } -void ubh_ll_rw_block(int rw, struct ufs_buffer_head *ubh) +void ubh_sync_block(struct ufs_buffer_head *ubh) { - if (!ubh) - return; + if (ubh) { + unsigned i; - ll_rw_block(rw, ubh->count, ubh->bh); -} + for (i = 0; i < ubh->count; i++) + write_dirty_buffer(ubh->bh[i], WRITE); -void ubh_wait_on_buffer (struct ufs_buffer_head * ubh) -{ - unsigned i; - if (!ubh) - return; - for ( i = 0; i < ubh->count; i++ ) - wait_on_buffer (ubh->bh[i]); + for (i = 0; i < ubh->count; i++) + wait_on_buffer(ubh->bh[i]); + } } void ubh_bforget (struct ufs_buffer_head * ubh) diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 0466036912f1..9f8775ce381c 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -269,8 +269,7 @@ extern void ubh_brelse (struct ufs_buffer_head *); extern void ubh_brelse_uspi (struct ufs_sb_private_info *); extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *); extern void ubh_mark_buffer_uptodate (struct ufs_buffer_head *, int); -extern void ubh_ll_rw_block(int, struct ufs_buffer_head *); -extern void ubh_wait_on_buffer (struct ufs_buffer_head *); +extern void ubh_sync_block(struct ufs_buffer_head *); extern void ubh_bforget (struct ufs_buffer_head *); extern int ubh_buffer_dirty (struct ufs_buffer_head *); #define ubh_ubhcpymem(mem,ubh,size) _ubh_ubhcpymem_(uspi,mem,ubh,size) diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 72c1cf83eb85..ec94c12f21da 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -182,6 +182,7 @@ void __lock_buffer(struct buffer_head *bh); void ll_rw_block(int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); int __sync_dirty_buffer(struct buffer_head *bh, int rw); +void write_dirty_buffer(struct buffer_head *bh, int rw); int submit_bh(int, struct buffer_head *); void write_boundary_block(struct block_device *bdev, sector_t bblock, unsigned blocksize); diff --git a/include/linux/fs.h b/include/linux/fs.h index 9a96b4d83fc1..29f7c975304c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -125,9 +125,6 @@ struct inodes_stat_t { * block layer could (in theory) choose to ignore this * request if it runs into resource problems. * WRITE A normal async write. Device will be plugged. - * SWRITE Like WRITE, but a special case for ll_rw_block() that - * tells it to lock the buffer first. Normally a buffer - * must be locked before doing IO. * WRITE_SYNC_PLUG Synchronous write. Identical to WRITE, but passes down * the hint that someone will be waiting on this IO * shortly. The device must still be unplugged explicitly, @@ -138,9 +135,6 @@ struct inodes_stat_t { * immediately after submission. The write equivalent * of READ_SYNC. * WRITE_ODIRECT_PLUG Special case write for O_DIRECT only. - * SWRITE_SYNC - * SWRITE_SYNC_PLUG Like WRITE_SYNC/WRITE_SYNC_PLUG, but locks the buffer. - * See SWRITE. * WRITE_BARRIER Like WRITE_SYNC, but tells the block layer that all * previously submitted writes must be safely on storage * before this one is started. Also guarantees that when @@ -155,7 +149,6 @@ struct inodes_stat_t { #define READ 0 #define WRITE RW_MASK #define READA RWA_MASK -#define SWRITE (WRITE | READA) #define READ_SYNC (READ | REQ_SYNC | REQ_UNPLUG) #define READ_META (READ | REQ_META) @@ -165,8 +158,6 @@ struct inodes_stat_t { #define WRITE_META (WRITE | REQ_META) #define WRITE_BARRIER (WRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG | \ REQ_HARDBARRIER) -#define SWRITE_SYNC_PLUG (SWRITE | REQ_SYNC | REQ_NOIDLE) -#define SWRITE_SYNC (SWRITE | REQ_SYNC | REQ_NOIDLE | REQ_UNPLUG) /* * These aren't really reads or writes, they pass down information about -- cgit v1.2.3-59-g8ed1b From 9b3bb86acabe0c05923cea1ed3b0bee9439fef4b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 17 Aug 2010 22:49:26 -0700 Subject: sparc64: Make rwsems 64-bit. Basically tip-off the powerpc code, use a 64-bit type and atomic64_t interfaces for the implementation. This gets us off of the by-hand asm code I wrote, which frankly I think probably ruins I-cache hit rates. The idea was the keep the call chains less deep, but anything taking the rw-semaphores probably is also calling other stuff and therefore already has allocated a stack-frame. So no real stack frame savings ever. Ben H. has posted patches to make powerpc use 64-bit too and with some abstractions we can probably use a shared header file somewhere. With suggestions from Sam Ravnborg. Signed-off-by: David S. Miller --- arch/sparc/include/asm/rwsem-const.h | 12 --- arch/sparc/include/asm/rwsem.h | 120 ++++++++++++++++++++++---- arch/sparc/lib/Makefile | 2 +- arch/sparc/lib/rwsem_64.S | 163 ----------------------------------- 4 files changed, 104 insertions(+), 193 deletions(-) delete mode 100644 arch/sparc/include/asm/rwsem-const.h delete mode 100644 arch/sparc/lib/rwsem_64.S diff --git a/arch/sparc/include/asm/rwsem-const.h b/arch/sparc/include/asm/rwsem-const.h deleted file mode 100644 index e4c61a18bb28..000000000000 --- a/arch/sparc/include/asm/rwsem-const.h +++ /dev/null @@ -1,12 +0,0 @@ -/* rwsem-const.h: RW semaphore counter constants. */ -#ifndef _SPARC64_RWSEM_CONST_H -#define _SPARC64_RWSEM_CONST_H - -#define RWSEM_UNLOCKED_VALUE 0x00000000 -#define RWSEM_ACTIVE_BIAS 0x00000001 -#define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS (-0x00010000) -#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS -#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) - -#endif /* _SPARC64_RWSEM_CONST_H */ diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h index 6e5621006f85..a2b4302869bc 100644 --- a/arch/sparc/include/asm/rwsem.h +++ b/arch/sparc/include/asm/rwsem.h @@ -15,16 +15,21 @@ #include #include -#include struct rwsem_waiter; struct rw_semaphore { - signed int count; - spinlock_t wait_lock; - struct list_head wait_list; + signed long count; +#define RWSEM_UNLOCKED_VALUE 0x00000000L +#define RWSEM_ACTIVE_BIAS 0x00000001L +#define RWSEM_ACTIVE_MASK 0xffffffffL +#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + spinlock_t wait_lock; + struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; + struct lockdep_map dep_map; #endif }; @@ -41,6 +46,11 @@ struct rw_semaphore { #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) +extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); +extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); + extern void __init_rwsem(struct rw_semaphore *sem, const char *name, struct lock_class_key *key); @@ -51,27 +61,103 @@ do { \ __init_rwsem((sem), #sem, &__key); \ } while (0) -extern void __down_read(struct rw_semaphore *sem); -extern int __down_read_trylock(struct rw_semaphore *sem); -extern void __down_write(struct rw_semaphore *sem); -extern int __down_write_trylock(struct rw_semaphore *sem); -extern void __up_read(struct rw_semaphore *sem); -extern void __up_write(struct rw_semaphore *sem); -extern void __downgrade_write(struct rw_semaphore *sem); +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + if (unlikely(atomic64_inc_return((atomic64_t *)(&sem->count)) <= 0L)) + rwsem_down_read_failed(sem); +} + +static inline int __down_read_trylock(struct rw_semaphore *sem) +{ + long tmp; + + while ((tmp = sem->count) >= 0L) { + if (tmp == cmpxchg(&sem->count, tmp, + tmp + RWSEM_ACTIVE_READ_BIAS)) { + return 1; + } + } + return 0; +} +/* + * lock for writing + */ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { - __down_write(sem); + long tmp; + + tmp = atomic64_add_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic64_t *)(&sem->count)); + if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) + rwsem_down_write_failed(sem); } -static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +static inline void __down_write(struct rw_semaphore *sem) { - return atomic_add_return(delta, (atomic_t *)(&sem->count)); + __down_write_nested(sem, 0); +} + +static inline int __down_write_trylock(struct rw_semaphore *sem) +{ + long tmp; + + tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, + RWSEM_ACTIVE_WRITE_BIAS); + return tmp == RWSEM_UNLOCKED_VALUE; } -static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + long tmp; + + tmp = atomic64_dec_return((atomic64_t *)(&sem->count)); + if (unlikely(tmp < -1L && (tmp & RWSEM_ACTIVE_MASK) == 0L)) + rwsem_wake(sem); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + if (unlikely(atomic64_sub_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic64_t *)(&sem->count)) < 0L)) + rwsem_wake(sem); +} + +/* + * implement atomic add functionality + */ +static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) +{ + atomic64_add(delta, (atomic64_t *)(&sem->count)); +} + +/* + * downgrade write lock to read lock + */ +static inline void __downgrade_write(struct rw_semaphore *sem) +{ + long tmp; + + tmp = atomic64_add_return(-RWSEM_WAITING_BIAS, (atomic64_t *)(&sem->count)); + if (tmp < 0L) + rwsem_downgrade_wake(sem); +} + +/* + * implement exchange and add functionality + */ +static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) { - atomic_add(delta, (atomic_t *)(&sem->count)); + return atomic64_add_return(delta, (atomic64_t *)(&sem->count)); } static inline int rwsem_is_locked(struct rw_semaphore *sem) diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index c4b5e03af115..846d1c4374ea 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -15,7 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o lib-$(CONFIG_SPARC32) += copy_user.o locks.o lib-y += atomic_$(BITS).o lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o -lib-y += rwsem_$(BITS).o +lib-$(CONFIG_SPARC32) += rwsem_32.o lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o diff --git a/arch/sparc/lib/rwsem_64.S b/arch/sparc/lib/rwsem_64.S deleted file mode 100644 index 91a7d29a79d5..000000000000 --- a/arch/sparc/lib/rwsem_64.S +++ /dev/null @@ -1,163 +0,0 @@ -/* rwsem.S: RW semaphore assembler. - * - * Written by David S. Miller (davem@redhat.com), 2001. - * Derived from asm-i386/rwsem.h - */ - -#include - - .section .sched.text, "ax" - - .globl __down_read -__down_read: -1: lduw [%o0], %g1 - add %g1, 1, %g7 - cas [%o0], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, 1b - add %g7, 1, %g7 - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: - retl - nop -3: - save %sp, -192, %sp - call rwsem_down_read_failed - mov %i0, %o0 - ret - restore - .size __down_read, .-__down_read - - .globl __down_read_trylock -__down_read_trylock: -1: lduw [%o0], %g1 - add %g1, 1, %g7 - cmp %g7, 0 - bl,pn %icc, 2f - mov 0, %o1 - cas [%o0], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, 1b - mov 1, %o1 -2: retl - mov %o1, %o0 - .size __down_read_trylock, .-__down_read_trylock - - .globl __down_write -__down_write: - sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 - or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 -1: - lduw [%o0], %g3 - add %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - cmp %g7, 0 - bne,pn %icc, 3f - nop -2: retl - nop -3: - save %sp, -192, %sp - call rwsem_down_write_failed - mov %i0, %o0 - ret - restore - .size __down_write, .-__down_write - - .globl __down_write_trylock -__down_write_trylock: - sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 - or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 -1: - lduw [%o0], %g3 - cmp %g3, 0 - bne,pn %icc, 2f - mov 0, %o1 - add %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - mov 1, %o1 -2: retl - mov %o1, %o0 - .size __down_write_trylock, .-__down_write_trylock - - .globl __up_read -__up_read: -1: - lduw [%o0], %g1 - sub %g1, 1, %g7 - cas [%o0], %g1, %g7 - cmp %g1, %g7 - bne,pn %icc, 1b - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: retl - nop -3: sethi %hi(RWSEM_ACTIVE_MASK), %g1 - sub %g7, 1, %g7 - or %g1, %lo(RWSEM_ACTIVE_MASK), %g1 - andcc %g7, %g1, %g0 - bne,pn %icc, 2b - nop - save %sp, -192, %sp - call rwsem_wake - mov %i0, %o0 - ret - restore - .size __up_read, .-__up_read - - .globl __up_write -__up_write: - sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 - or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 -1: - lduw [%o0], %g3 - sub %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - sub %g7, %g1, %g7 - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: - retl - nop -3: - save %sp, -192, %sp - call rwsem_wake - mov %i0, %o0 - ret - restore - .size __up_write, .-__up_write - - .globl __downgrade_write -__downgrade_write: - sethi %hi(RWSEM_WAITING_BIAS), %g1 - or %g1, %lo(RWSEM_WAITING_BIAS), %g1 -1: - lduw [%o0], %g3 - sub %g3, %g1, %g7 - cas [%o0], %g3, %g7 - cmp %g3, %g7 - bne,pn %icc, 1b - sub %g7, %g1, %g7 - cmp %g7, 0 - bl,pn %icc, 3f - nop -2: - retl - nop -3: - save %sp, -192, %sp - call rwsem_downgrade_wake - mov %i0, %o0 - ret - restore - .size __downgrade_write, .-__downgrade_write -- cgit v1.2.3-59-g8ed1b From 2c7d46ec192e4f2b350f67a0e185b9bce646cd6b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 18 Aug 2010 16:16:05 +1000 Subject: md raid-1/10 Fix bio_rw bit manipulations again commit 7b6d91daee5cac6402186ff224c3af39d79f4a0e changed the behaviour of a few variables in raid1 and raid10 from flags to bit-sets, but left them as type 'bool' so they did not work. Change them (back) to unsigned long. (historical note: see 1ef04fefe2241087d9db7e9615c3f11b516e36cf) Signed-off-by: NeilBrown Reported-by: Jiri Slaby and many others --- drivers/md/raid1.c | 8 ++++---- drivers/md/raid10.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 64d96526a9cc..ad83a4dcadc3 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -787,8 +787,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) struct bio_list bl; struct page **behind_pages = NULL; const int rw = bio_data_dir(bio); - const bool do_sync = (bio->bi_rw & REQ_SYNC); - bool do_barriers; + const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); + unsigned long do_barriers; mdk_rdev_t *blocked_rdev; /* @@ -1643,7 +1643,7 @@ static void raid1d(mddev_t *mddev) * We already have a nr_pending reference on these rdevs. */ int i; - const bool do_sync = (r1_bio->master_bio->bi_rw & REQ_SYNC); + const unsigned long do_sync = (r1_bio->master_bio->bi_rw & REQ_SYNC); clear_bit(R1BIO_BarrierRetry, &r1_bio->state); clear_bit(R1BIO_Barrier, &r1_bio->state); for (i=0; i < conf->raid_disks; i++) @@ -1699,7 +1699,7 @@ static void raid1d(mddev_t *mddev) (unsigned long long)r1_bio->sector); raid_end_bio_io(r1_bio); } else { - const bool do_sync = r1_bio->master_bio->bi_rw & REQ_SYNC; + const unsigned long do_sync = r1_bio->master_bio->bi_rw & REQ_SYNC; r1_bio->bios[r1_bio->read_disk] = mddev->ro ? IO_BLOCKED : NULL; r1_bio->read_disk = disk; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a2f8a7153dce..84718383124d 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -799,7 +799,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) int i; int chunk_sects = conf->chunk_mask + 1; const int rw = bio_data_dir(bio); - const bool do_sync = (bio->bi_rw & REQ_SYNC); + const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); struct bio_list bl; unsigned long flags; mdk_rdev_t *blocked_rdev; @@ -1737,7 +1737,7 @@ static void raid10d(mddev_t *mddev) raid_end_bio_io(r10_bio); bio_put(bio); } else { - const bool do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC); + const unsigned long do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC); bio_put(bio); rdev = conf->mirrors[mirror].rdev; if (printk_ratelimit()) -- cgit v1.2.3-59-g8ed1b From 3572b33efb044f76c224197408a812cda7d54fe4 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 16 Aug 2010 10:40:49 +0000 Subject: ARM: mach-shmobile: Clock framework comment fix Update clock framework header comment for SH-Mobile ARM. Signed-off-by: Magnus Damm Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c index b7c705a213a2..6b7c7c42bc8f 100644 --- a/arch/arm/mach-shmobile/clock.c +++ b/arch/arm/mach-shmobile/clock.c @@ -1,8 +1,10 @@ /* - * SH-Mobile Timer + * SH-Mobile Clock Framework * * Copyright (C) 2010 Magnus Damm * + * Used together with arch/arm/common/clkdev.c and drivers/sh/clk.c. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. -- cgit v1.2.3-59-g8ed1b From 4e1774f3a5de0885be2e59a8e8ef0e99c5f79e7a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 17 Aug 2010 22:53:58 +0000 Subject: ARM: mach-shmobile: do not enable the PLLC2 clock on init AP4EVB has to reparent PLLC2 to provide a precise HDMI clock, this is only possible, if PLLC2 hasn't been enabled yet. Since no other driver currently uses PLLC2 we can safely remove the CLK_ENABLE_ON_INIT flag. This fixes the "Cannot set PLLC2 parent: -16, 1 users" error message, when trying to use HDMI on AP4EVB. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/clock-sh7372.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index dcaac1b6691d..759468992ad2 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -286,7 +286,6 @@ static struct clk_ops pllc2_clk_ops = { struct clk pllc2_clk = { .ops = &pllc2_clk_ops, - .flags = CLK_ENABLE_ON_INIT, .parent = &extal1_div2_clk, .freq_table = pllc2_freq_table, .parent_table = pllc2_parent, -- cgit v1.2.3-59-g8ed1b From 9f6f11b65ea2da8fab4d6902595d770e89e64d93 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 18 Aug 2010 03:37:19 +0000 Subject: ARM: mach-shmobile: ap4evb: modify FSI2 ID Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 8afdb1dab029..1b95f122ecf5 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -559,7 +559,7 @@ static struct resource fsi_resources[] = { static struct platform_device fsi_device = { .name = "sh_fsi2", - .id = 0, + .id = -1, .num_resources = ARRAY_SIZE(fsi_resources), .resource = fsi_resources, .dev = { -- cgit v1.2.3-59-g8ed1b From 351af0725e5222e35741011d1ea62215c1ed06db Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Fri, 6 Aug 2010 13:39:08 +0800 Subject: perf, x86: Fix Intel-nhm PMU programming errata workaround Fix the Errata AAK100/AAP53/BD53 workaround, the officialy documented workaround we implemented in: 11164cd: perf, x86: Add Nehelem PMU programming errata workaround doesn't actually work fully and causes a stuck PMU state under load and non-functioning perf profiling. A functional workaround was found by trial & error. Affects all Nehalem-class Intel PMUs. Signed-off-by: Zhang Yanmin Signed-off-by: Peter Zijlstra LKML-Reference: <1281073148.2125.63.camel@ymzhang.sh.intel.com> Cc: Arjan van de Ven Cc: "H. Peter Anvin" Cc: # .35.x Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 81 ++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 214ac860ebe0..d8d86d014008 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -491,33 +491,78 @@ static void intel_pmu_enable_all(int added) * Intel Errata AAP53 (model 30) * Intel Errata BD53 (model 44) * - * These chips need to be 'reset' when adding counters by programming - * the magic three (non counting) events 0x4300D2, 0x4300B1 and 0x4300B5 - * either in sequence on the same PMC or on different PMCs. + * The official story: + * These chips need to be 'reset' when adding counters by programming the + * magic three (non-counting) events 0x4300B5, 0x4300D2, and 0x4300B1 either + * in sequence on the same PMC or on different PMCs. + * + * In practise it appears some of these events do in fact count, and + * we need to programm all 4 events. */ -static void intel_pmu_nhm_enable_all(int added) +static void intel_pmu_nhm_workaround(void) { - if (added) { - struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); - int i; + struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); + static const unsigned long nhm_magic[4] = { + 0x4300B5, + 0x4300D2, + 0x4300B1, + 0x4300B1 + }; + struct perf_event *event; + int i; + + /* + * The Errata requires below steps: + * 1) Clear MSR_IA32_PEBS_ENABLE and MSR_CORE_PERF_GLOBAL_CTRL; + * 2) Configure 4 PERFEVTSELx with the magic events and clear + * the corresponding PMCx; + * 3) set bit0~bit3 of MSR_CORE_PERF_GLOBAL_CTRL; + * 4) Clear MSR_CORE_PERF_GLOBAL_CTRL; + * 5) Clear 4 pairs of ERFEVTSELx and PMCx; + */ + + /* + * The real steps we choose are a little different from above. + * A) To reduce MSR operations, we don't run step 1) as they + * are already cleared before this function is called; + * B) Call x86_perf_event_update to save PMCx before configuring + * PERFEVTSELx with magic number; + * C) With step 5), we do clear only when the PERFEVTSELx is + * not used currently. + * D) Call x86_perf_event_set_period to restore PMCx; + */ - wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 0, 0x4300D2); - wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 1, 0x4300B1); - wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 2, 0x4300B5); + /* We always operate 4 pairs of PERF Counters */ + for (i = 0; i < 4; i++) { + event = cpuc->events[i]; + if (event) + x86_perf_event_update(event); + } - wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x3); - wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0); + for (i = 0; i < 4; i++) { + wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + i, nhm_magic[i]); + wrmsrl(MSR_ARCH_PERFMON_PERFCTR0 + i, 0x0); + } - for (i = 0; i < 3; i++) { - struct perf_event *event = cpuc->events[i]; + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0xf); + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0); - if (!event) - continue; + for (i = 0; i < 4; i++) { + event = cpuc->events[i]; + if (event) { + x86_perf_event_set_period(event); __x86_pmu_enable_event(&event->hw, - ARCH_PERFMON_EVENTSEL_ENABLE); - } + ARCH_PERFMON_EVENTSEL_ENABLE); + } else + wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + i, 0x0); } +} + +static void intel_pmu_nhm_enable_all(int added) +{ + if (added) + intel_pmu_nhm_workaround(); intel_pmu_enable_all(added); } -- cgit v1.2.3-59-g8ed1b From 850a496f969719b494cc972ab1d0e088737358d7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Aug 2010 06:18:57 -0400 Subject: hostfs: dumb (and usually harmless) tpyo - strncpy instead of strlcpy ... not harmless in this case - we have a string in the end of buffer already. Signed-off-by: Al Viro --- fs/hostfs/hostfs_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index dd1e55535a4e..77c4f6ee6c40 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -104,7 +104,7 @@ static char *__dentry_name(struct dentry *dentry, char *name) __putname(name); return NULL; } - strncpy(name, root, PATH_MAX); + strlcpy(name, root, PATH_MAX); if (len > p - name) { __putname(name); return NULL; -- cgit v1.2.3-59-g8ed1b From 3b6036d148bad5bb7928b021a49bb9e395361084 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Aug 2010 06:21:10 -0400 Subject: hostfs ->follow_link() braino we want the assignment to err done inside the if () to be visible after it, so (re)declaring err inside if () body is wrong. Signed-off-by: Al Viro --- fs/hostfs/hostfs_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 77c4f6ee6c40..f7dc9b5f9ef8 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -876,7 +876,7 @@ static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd) char *path = dentry_name(dentry); int err = -ENOMEM; if (path) { - int err = hostfs_do_readlink(path, link, PATH_MAX); + err = hostfs_do_readlink(path, link, PATH_MAX); if (err == PATH_MAX) err = -E2BIG; __putname(path); -- cgit v1.2.3-59-g8ed1b From 3a48ee8a4ad26c3a538b6fc11a86a8f80c3dce18 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 16 Aug 2010 19:05:23 +0200 Subject: mbcache: Limit the maximum number of cache entries Limit the maximum number of mb_cache entries depending on the number of hash buckets: if the only limit to the number of cache entries is the available memory the hash chains can grow very long, taking a long time to search. At least partially solves https://bugzilla.lustre.org/show_bug.cgi?id=22771. Signed-off-by: Andreas Gruenbacher Signed-off-by: Al Viro --- fs/mbcache.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/fs/mbcache.c b/fs/mbcache.c index cf4e6cdfd15b..93444747237b 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -80,6 +80,7 @@ struct mb_cache { struct list_head c_cache_list; const char *c_name; atomic_t c_entry_count; + int c_max_entries; int c_bucket_bits; struct kmem_cache *c_entry_cache; struct list_head *c_block_hash; @@ -243,6 +244,12 @@ mb_cache_create(const char *name, int bucket_bits) if (!cache->c_entry_cache) goto fail2; + /* + * Set an upper limit on the number of cache entries so that the hash + * chains won't grow too long. + */ + cache->c_max_entries = bucket_count << 4; + spin_lock(&mb_cache_spinlock); list_add(&cache->c_cache_list, &mb_cache_list); spin_unlock(&mb_cache_spinlock); @@ -333,7 +340,6 @@ mb_cache_destroy(struct mb_cache *cache) kfree(cache); } - /* * mb_cache_entry_alloc() * @@ -345,17 +351,29 @@ mb_cache_destroy(struct mb_cache *cache) struct mb_cache_entry * mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) { - struct mb_cache_entry *ce; - - ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); - if (ce) { + struct mb_cache_entry *ce = NULL; + + if (atomic_read(&cache->c_entry_count) >= cache->c_max_entries) { + spin_lock(&mb_cache_spinlock); + if (!list_empty(&mb_cache_lru_list)) { + ce = list_entry(mb_cache_lru_list.next, + struct mb_cache_entry, e_lru_list); + list_del_init(&ce->e_lru_list); + __mb_cache_entry_unhash(ce); + } + spin_unlock(&mb_cache_spinlock); + } + if (!ce) { + ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags); + if (!ce) + return NULL; atomic_inc(&cache->c_entry_count); INIT_LIST_HEAD(&ce->e_lru_list); INIT_LIST_HEAD(&ce->e_block_list); ce->e_cache = cache; - ce->e_used = 1 + MB_CACHE_WRITER; ce->e_queued = 0; } + ce->e_used = 1 + MB_CACHE_WRITER; return ce; } -- cgit v1.2.3-59-g8ed1b From 93b352fce679945845664b56b0c3afbd655a7a12 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 16 Aug 2010 16:09:09 +0800 Subject: pxa3xx: fix ns2cycle equation Test on a PXA310 platform with Samsung K9F2G08X0B NAND flash, with tCH=5 and clk is 156MHz, ns2cycle(5, 156000000) returns -1. ns2cycle returns negtive value will break NDTR0_tXX macros. After checking the commit log, I found the problem is introduced by commit 5b0d4d7c8a67c5ba3d35e6ceb0c5530cc6846db7 "[MTD] [NAND] pxa3xx: convert from ns to clock ticks more accurately" To get num of clock cycles, we use below equation: num of clock cycles = time (ns) / one clock cycle (ns) + 1 We need to add 1 cycle here because integer division will truncate the result. It is possible the developers set the Min values in SPEC for timing settings. Thus the truncate may cause problem, and it is safe to add an extra cycle here. The various fields in NDTR{01} are in units of clock ticks minus one, thus we should subtract 1 cycle then. Thus the correct equation should be: num of clock cycles = time (ns) / one clock cycle (ns) + 1 - 1 = time (ns) / one clock cycle (ns) Signed-off-by: Axel Lin Signed-off-by: Lei Wen Acked-by: Eric Miao Signed-off-by: David Woodhouse Cc: stable@kernel.org --- drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index e02fa4f0e3c9..4d89f3780207 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -363,7 +363,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { #define tAR_NDTR1(r) (((r) >> 0) & 0xf) /* convert nano-seconds to nand flash controller clock cycles */ -#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1) +#define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) /* convert nand flash controller clock cycles to nano-seconds */ #define cycle2ns(c, clk) ((((c) + 1) * 1000000 + clk / 500) / (clk / 1000)) -- cgit v1.2.3-59-g8ed1b From 2e2e88ea8c3bd9e1bd6e42faf047a4ac3fbb3b2f Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:30 +1000 Subject: fs: fix do_lookup false negative fs: fix do_lookup false negative In do_lookup, if we initially find no dentry, we take the directory i_mutex and re-check the lookup. If we find a dentry there, then we revalidate it if needed. However if that revalidate asks for the dentry to be invalidated, we return -ENOENT from do_lookup. What should happen instead is an attempt to allocate and lookup a new dentry. This is probably not noticed because it is rare. It is only reached if a concurrent create races in first (in which case, the dentry probably won't be invalidated anyway), or if the racy __d_lookup has failed due to a false-negative (which is very rare). Fix this by removing code and have it use the normal reval path. Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- fs/namei.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 17ea76bf2fbe..c2742b7dec59 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -709,6 +709,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, dentry = __d_lookup(nd->path.dentry, name); if (!dentry) goto need_lookup; +found: if (dentry->d_op && dentry->d_op->d_revalidate) goto need_revalidate; done: @@ -766,14 +767,7 @@ out_unlock: * we waited on the semaphore. Need to revalidate. */ mutex_unlock(&dir->i_mutex); - if (dentry->d_op && dentry->d_op->d_revalidate) { - dentry = do_revalidate(dentry, nd); - if (!dentry) - dentry = ERR_PTR(-ENOENT); - } - if (IS_ERR(dentry)) - goto fail; - goto done; + goto found; need_revalidate: dentry = do_revalidate(dentry, nd); -- cgit v1.2.3-59-g8ed1b From baa0389073eb7beb9d36f6d13df97e16c1bfa626 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:31 +1000 Subject: fs: dentry allocation consolidation fs: dentry allocation consolidation There are 2 duplicate copies of code in dentry allocation in path lookup. Consolidate them into a single function. Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- fs/namei.c | 70 +++++++++++++++++++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index c2742b7dec59..b815a4d2e1d6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -685,6 +685,35 @@ static __always_inline void follow_dotdot(struct nameidata *nd) follow_mount(&nd->path); } +/* + * Allocate a dentry with name and parent, and perform a parent + * directory ->lookup on it. Returns the new dentry, or ERR_PTR + * on error. parent->d_inode->i_mutex must be held. d_lookup must + * have verified that no child exists while under i_mutex. + */ +static struct dentry *d_alloc_and_lookup(struct dentry *parent, + struct qstr *name, struct nameidata *nd) +{ + struct inode *inode = parent->d_inode; + struct dentry *dentry; + struct dentry *old; + + /* Don't create child dentry for a dead directory. */ + if (unlikely(IS_DEADDIR(inode))) + return ERR_PTR(-ENOENT); + + dentry = d_alloc(parent, name); + if (unlikely(!dentry)) + return ERR_PTR(-ENOMEM); + + old = inode->i_op->lookup(inode, dentry, nd); + if (unlikely(old)) { + dput(dentry); + dentry = old; + } + return dentry; +} + /* * It's more convoluted than I'd like it to be, but... it's still fairly * small and for now I'd prefer to have fast path as straight as possible. @@ -738,30 +767,13 @@ need_lookup: * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup */ dentry = d_lookup(parent, name); - if (!dentry) { - struct dentry *new; - - /* Don't create child dentry for a dead directory. */ - dentry = ERR_PTR(-ENOENT); - if (IS_DEADDIR(dir)) - goto out_unlock; - - new = d_alloc(parent, name); - dentry = ERR_PTR(-ENOMEM); - if (new) { - dentry = dir->i_op->lookup(dir, new, nd); - if (dentry) - dput(new); - else - dentry = new; - } -out_unlock: + if (likely(!dentry)) { + dentry = d_alloc_and_lookup(parent, name, nd); mutex_unlock(&dir->i_mutex); if (IS_ERR(dentry)) goto fail; goto done; } - /* * Uhhuh! Nasty case: the cache was re-populated while * we waited on the semaphore. Need to revalidate. @@ -1135,24 +1147,8 @@ static struct dentry *__lookup_hash(struct qstr *name, if (dentry && dentry->d_op && dentry->d_op->d_revalidate) dentry = do_revalidate(dentry, nd); - if (!dentry) { - struct dentry *new; - - /* Don't create child dentry for a dead directory. */ - dentry = ERR_PTR(-ENOENT); - if (IS_DEADDIR(inode)) - goto out; - - new = d_alloc(base, name); - dentry = ERR_PTR(-ENOMEM); - if (!new) - goto out; - dentry = inode->i_op->lookup(inode, new, nd); - if (!dentry) - dentry = new; - else - dput(new); - } + if (!dentry) + dentry = d_alloc_and_lookup(base, name, nd); out: return dentry; } -- cgit v1.2.3-59-g8ed1b From 44672e4fbd40e2dda8bbce7d0f71d24dbfc7e00e Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:32 +1000 Subject: apparmor: use task path helpers apparmor: use task path helpers Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- security/apparmor/path.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 96bab9469d48..19358dc14605 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -62,19 +62,14 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, int deleted, connected; int error = 0; - /* Get the root we want to resolve too */ + /* Get the root we want to resolve too, released below */ if (flags & PATH_CHROOT_REL) { /* resolve paths relative to chroot */ - read_lock(¤t->fs->lock); - root = current->fs->root; - /* released below */ - path_get(&root); - read_unlock(¤t->fs->lock); + get_fs_root(current->fs, &root); } else { /* resolve paths relative to namespace */ root.mnt = current->nsproxy->mnt_ns->root; root.dentry = root.mnt->mnt_root; - /* released below */ path_get(&root); } -- cgit v1.2.3-59-g8ed1b From 2a4419b5b2a77f3f4537c14f7ad7df95770655dd Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:33 +1000 Subject: fs: fs_struct rwlock to spinlock fs: fs_struct rwlock to spinlock struct fs_struct.lock is an rwlock with the read-side used to protect root and pwd members while taking references to them. Taking a reference to a path typically requires just 2 atomic ops, so the critical section is very small. Parallel read-side operations would have cacheline contention on the lock, the dentry, and the vfsmount cachelines, so the rwlock is unlikely to ever give a real parallelism increase. Replace it with a spinlock to avoid one or two atomic operations in typical path lookup fastpath. Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- drivers/staging/pohmelfs/path_entry.c | 8 ++++---- fs/exec.c | 4 ++-- fs/fs_struct.c | 32 ++++++++++++++++---------------- include/linux/fs_struct.h | 14 +++++++------- kernel/fork.c | 10 +++++----- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/staging/pohmelfs/path_entry.c b/drivers/staging/pohmelfs/path_entry.c index cdc4dd50d638..8ec83d2dffb7 100644 --- a/drivers/staging/pohmelfs/path_entry.c +++ b/drivers/staging/pohmelfs/path_entry.c @@ -44,9 +44,9 @@ int pohmelfs_construct_path_string(struct pohmelfs_inode *pi, void *data, int le return -ENOENT; } - read_lock(¤t->fs->lock); + spin_lock(¤t->fs->lock); path.mnt = mntget(current->fs->root.mnt); - read_unlock(¤t->fs->lock); + spin_unlock(¤t->fs->lock); path.dentry = d; @@ -91,9 +91,9 @@ int pohmelfs_path_length(struct pohmelfs_inode *pi) return -ENOENT; } - read_lock(¤t->fs->lock); + spin_lock(¤t->fs->lock); root = dget(current->fs->root.dentry); - read_unlock(¤t->fs->lock); + spin_unlock(¤t->fs->lock); spin_lock(&dcache_lock); diff --git a/fs/exec.c b/fs/exec.c index 7761837e4500..5adab2c93eca 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1117,7 +1117,7 @@ int check_unsafe_exec(struct linux_binprm *bprm) bprm->unsafe = tracehook_unsafe_exec(p); n_fs = 1; - write_lock(&p->fs->lock); + spin_lock(&p->fs->lock); rcu_read_lock(); for (t = next_thread(p); t != p; t = next_thread(t)) { if (t->fs == p->fs) @@ -1134,7 +1134,7 @@ int check_unsafe_exec(struct linux_binprm *bprm) res = 1; } } - write_unlock(&p->fs->lock); + spin_unlock(&p->fs->lock); return res; } diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 1ee40eb9a2c0..ed45a9cf5f3d 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -13,11 +13,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path) { struct path old_root; - write_lock(&fs->lock); + spin_lock(&fs->lock); old_root = fs->root; fs->root = *path; path_get(path); - write_unlock(&fs->lock); + spin_unlock(&fs->lock); if (old_root.dentry) path_put(&old_root); } @@ -30,11 +30,11 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) { struct path old_pwd; - write_lock(&fs->lock); + spin_lock(&fs->lock); old_pwd = fs->pwd; fs->pwd = *path; path_get(path); - write_unlock(&fs->lock); + spin_unlock(&fs->lock); if (old_pwd.dentry) path_put(&old_pwd); @@ -51,7 +51,7 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) task_lock(p); fs = p->fs; if (fs) { - write_lock(&fs->lock); + spin_lock(&fs->lock); if (fs->root.dentry == old_root->dentry && fs->root.mnt == old_root->mnt) { path_get(new_root); @@ -64,7 +64,7 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) fs->pwd = *new_root; count++; } - write_unlock(&fs->lock); + spin_unlock(&fs->lock); } task_unlock(p); } while_each_thread(g, p); @@ -87,10 +87,10 @@ void exit_fs(struct task_struct *tsk) if (fs) { int kill; task_lock(tsk); - write_lock(&fs->lock); + spin_lock(&fs->lock); tsk->fs = NULL; kill = !--fs->users; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); task_unlock(tsk); if (kill) free_fs_struct(fs); @@ -104,7 +104,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) if (fs) { fs->users = 1; fs->in_exec = 0; - rwlock_init(&fs->lock); + spin_lock_init(&fs->lock); fs->umask = old->umask; get_fs_root_and_pwd(old, &fs->root, &fs->pwd); } @@ -121,10 +121,10 @@ int unshare_fs_struct(void) return -ENOMEM; task_lock(current); - write_lock(&fs->lock); + spin_lock(&fs->lock); kill = !--fs->users; current->fs = new_fs; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); task_unlock(current); if (kill) @@ -143,7 +143,7 @@ EXPORT_SYMBOL(current_umask); /* to be mentioned only in INIT_TASK */ struct fs_struct init_fs = { .users = 1, - .lock = __RW_LOCK_UNLOCKED(init_fs.lock), + .lock = __SPIN_LOCK_UNLOCKED(init_fs.lock), .umask = 0022, }; @@ -156,14 +156,14 @@ void daemonize_fs_struct(void) task_lock(current); - write_lock(&init_fs.lock); + spin_lock(&init_fs.lock); init_fs.users++; - write_unlock(&init_fs.lock); + spin_unlock(&init_fs.lock); - write_lock(&fs->lock); + spin_lock(&fs->lock); current->fs = &init_fs; kill = !--fs->users; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); task_unlock(current); if (kill) diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index eca3d5202138..a42b5bf02f8b 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -5,7 +5,7 @@ struct fs_struct { int users; - rwlock_t lock; + spinlock_t lock; int umask; int in_exec; struct path root, pwd; @@ -23,29 +23,29 @@ extern int unshare_fs_struct(void); static inline void get_fs_root(struct fs_struct *fs, struct path *root) { - read_lock(&fs->lock); + spin_lock(&fs->lock); *root = fs->root; path_get(root); - read_unlock(&fs->lock); + spin_unlock(&fs->lock); } static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd) { - read_lock(&fs->lock); + spin_lock(&fs->lock); *pwd = fs->pwd; path_get(pwd); - read_unlock(&fs->lock); + spin_unlock(&fs->lock); } static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root, struct path *pwd) { - read_lock(&fs->lock); + spin_lock(&fs->lock); *root = fs->root; path_get(root); *pwd = fs->pwd; path_get(pwd); - read_unlock(&fs->lock); + spin_unlock(&fs->lock); } #endif /* _LINUX_FS_STRUCT_H */ diff --git a/kernel/fork.c b/kernel/fork.c index 98b450876f93..856eac3ec52e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -752,13 +752,13 @@ static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) struct fs_struct *fs = current->fs; if (clone_flags & CLONE_FS) { /* tsk->fs is already what we want */ - write_lock(&fs->lock); + spin_lock(&fs->lock); if (fs->in_exec) { - write_unlock(&fs->lock); + spin_unlock(&fs->lock); return -EAGAIN; } fs->users++; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); return 0; } tsk->fs = copy_fs_struct(fs); @@ -1676,13 +1676,13 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) if (new_fs) { fs = current->fs; - write_lock(&fs->lock); + spin_lock(&fs->lock); current->fs = new_fs; if (--fs->users) new_fs = NULL; else new_fs = fs; - write_unlock(&fs->lock); + spin_unlock(&fs->lock); } if (new_mm) { -- cgit v1.2.3-59-g8ed1b From b04f784e5d19ed58892833dae845738972cea260 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:34 +1000 Subject: fs: remove extra lookup in __lookup_hash fs: remove extra lookup in __lookup_hash Optimize lookup for create operations, where no dentry should often be common-case. In cases where it is not, such as unlink, the added overhead is much smaller than the removed. Also, move comments about __d_lookup racyness to the __d_lookup call site. d_lookup is intuitive; __d_lookup is what needs commenting. So in that same vein, add kerneldoc comments to __d_lookup and clean up some of the comments: - We are interested in how the RCU lookup works here, particularly with renames. Make that explicit, and point to the document where it is explained in more detail. - RCU is pretty standard now, and macros make implementations pretty mindless. If we want to know about RCU barrier details, we look in RCU code. - Delete some boring legacy comments because we don't care much about how the code used to work, more about the interesting parts of how it works now. So comments about lazy LRU may be interesting, but would better be done in the LRU or refcount management code. Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- fs/dcache.c | 60 +++++++++++++++++++++++++++++++++++------------------------- fs/namei.c | 32 ++++++++++++++++---------------- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 4d13bf50b7b1..d56a40b5a577 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1332,31 +1332,13 @@ EXPORT_SYMBOL(d_add_ci); * d_lookup - search for a dentry * @parent: parent dentry * @name: qstr of name we wish to find + * Returns: dentry, or NULL * - * Searches the children of the parent dentry for the name in question. If - * the dentry is found its reference count is incremented and the dentry - * is returned. The caller must use dput to free the entry when it has - * finished using it. %NULL is returned on failure. - * - * __d_lookup is dcache_lock free. The hash list is protected using RCU. - * Memory barriers are used while updating and doing lockless traversal. - * To avoid races with d_move while rename is happening, d_lock is used. - * - * Overflows in memcmp(), while d_move, are avoided by keeping the length - * and name pointer in one structure pointed by d_qstr. - * - * rcu_read_lock() and rcu_read_unlock() are used to disable preemption while - * lookup is going on. - * - * The dentry unused LRU is not updated even if lookup finds the required dentry - * in there. It is updated in places such as prune_dcache, shrink_dcache_sb, - * select_parent and __dget_locked. This laziness saves lookup from dcache_lock - * acquisition. - * - * d_lookup() is protected against the concurrent renames in some unrelated - * directory using the seqlockt_t rename_lock. + * d_lookup searches the children of the parent dentry for the name in + * question. If the dentry is found its reference count is incremented and the + * dentry is returned. The caller must use dput to free the entry when it has + * finished using it. %NULL is returned if the dentry does not exist. */ - struct dentry * d_lookup(struct dentry * parent, struct qstr * name) { struct dentry * dentry = NULL; @@ -1372,6 +1354,21 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name) } EXPORT_SYMBOL(d_lookup); +/* + * __d_lookup - search for a dentry (racy) + * @parent: parent dentry + * @name: qstr of name we wish to find + * Returns: dentry, or NULL + * + * __d_lookup is like d_lookup, however it may (rarely) return a + * false-negative result due to unrelated rename activity. + * + * __d_lookup is slightly faster by avoiding rename_lock read seqlock, + * however it must be used carefully, eg. with a following d_lookup in + * the case of failure. + * + * __d_lookup callers must be commented. + */ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) { unsigned int len = name->len; @@ -1382,6 +1379,19 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) struct hlist_node *node; struct dentry *dentry; + /* + * The hash list is protected using RCU. + * + * Take d_lock when comparing a candidate dentry, to avoid races + * with d_move(). + * + * It is possible that concurrent renames can mess up our list + * walk here and result in missing our dentry, resulting in the + * false-negative result. d_lookup() protects against concurrent + * renames using rename_lock seqlock. + * + * See Documentation/vfs/dcache-locking.txt for more details. + */ rcu_read_lock(); hlist_for_each_entry_rcu(dentry, node, head, d_hash) { @@ -1396,8 +1406,8 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) /* * Recheck the dentry after taking the lock - d_move may have - * changed things. Don't bother checking the hash because we're - * about to compare the whole name anyway. + * changed things. Don't bother checking the hash because + * we're about to compare the whole name anyway. */ if (dentry->d_parent != parent) goto next; diff --git a/fs/namei.c b/fs/namei.c index b815a4d2e1d6..11de7c39ff76 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -735,6 +735,11 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, return err; } + /* + * Rename seqlock is not required here because in the off chance + * of a false negative due to a concurrent rename, we're going to + * do the non-racy lookup, below. + */ dentry = __d_lookup(nd->path.dentry, name); if (!dentry) goto need_lookup; @@ -754,17 +759,13 @@ need_lookup: mutex_lock(&dir->i_mutex); /* * First re-do the cached lookup just in case it was created - * while we waited for the directory semaphore.. - * - * FIXME! This could use version numbering or similar to - * avoid unnecessary cache lookups. - * - * The "dcache_lock" is purely to protect the RCU list walker - * from concurrent renames at this point (we mustn't get false - * negatives from the RCU list walk here, unlike the optimistic - * fast walk). + * while we waited for the directory semaphore, or the first + * lookup failed due to an unrelated rename. * - * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup + * This could use version numbering or similar to avoid unnecessary + * cache lookups, but then we'd have to do the first lookup in the + * non-racy way. However in the common case here, everything should + * be hot in cache, so would it be a big win? */ dentry = d_lookup(parent, name); if (likely(!dentry)) { @@ -1136,13 +1137,12 @@ static struct dentry *__lookup_hash(struct qstr *name, goto out; } - dentry = __d_lookup(base, name); - - /* lockess __d_lookup may fail due to concurrent d_move() - * in some unrelated directory, so try with d_lookup + /* + * Don't bother with __d_lookup: callers are for creat as + * well as unlink, so a lot of the time it would cost + * a double lookup. */ - if (!dentry) - dentry = d_lookup(base, name); + dentry = d_lookup(base, name); if (dentry && dentry->d_op && dentry->d_op->d_revalidate) dentry = do_revalidate(dentry, nd); -- cgit v1.2.3-59-g8ed1b From ee2ffa0dfdd2db19705f2ba1c6a4c0bfe8122dd8 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:35 +1000 Subject: fs: cleanup files_lock locking fs: cleanup files_lock locking Lock tty_files with a new spinlock, tty_files_lock; provide helpers to manipulate the per-sb files list; unexport the files_lock spinlock. Cc: linux-kernel@vger.kernel.org Cc: Christoph Hellwig Cc: Alan Cox Acked-by: Andi Kleen Acked-by: Greg Kroah-Hartman Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- drivers/char/pty.c | 6 +++++- drivers/char/tty_io.c | 26 ++++++++++++++++++-------- fs/file_table.c | 42 ++++++++++++++++++------------------------ fs/open.c | 4 ++-- include/linux/fs.h | 7 ++----- include/linux/tty.h | 1 + security/selinux/hooks.c | 4 ++-- 7 files changed, 48 insertions(+), 42 deletions(-) diff --git a/drivers/char/pty.c b/drivers/char/pty.c index ad46eae1f9bb..2c64faa8efa4 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -676,7 +676,11 @@ static int ptmx_open(struct inode *inode, struct file *filp) set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ filp->private_data = tty; - file_move(filp, &tty->tty_files); + + file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ + spin_lock(&tty_files_lock); + list_add(&filp->f_u.fu_list, &tty->tty_files); + spin_unlock(&tty_files_lock); retval = devpts_pty_new(inode, tty->link); if (retval) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0350c42375a2..cd5b829634ea 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -136,6 +136,9 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ DEFINE_MUTEX(tty_mutex); EXPORT_SYMBOL(tty_mutex); +/* Spinlock to protect the tty->tty_files list */ +DEFINE_SPINLOCK(tty_files_lock); + static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); ssize_t redirected_tty_write(struct file *, const char __user *, @@ -235,11 +238,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) struct list_head *p; int count = 0; - file_list_lock(); + spin_lock(&tty_files_lock); list_for_each(p, &tty->tty_files) { count++; } - file_list_unlock(); + spin_unlock(&tty_files_lock); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) @@ -519,7 +522,7 @@ void __tty_hangup(struct tty_struct *tty) workqueue with the lock held */ check_tty_count(tty, "tty_hangup"); - file_list_lock(); + spin_lock(&tty_files_lock); /* This breaks for file handles being sent over AF_UNIX sockets ? */ list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { if (filp->f_op->write == redirected_tty_write) @@ -530,7 +533,7 @@ void __tty_hangup(struct tty_struct *tty) __tty_fasync(-1, filp, 0); /* can't block */ filp->f_op = &hung_up_tty_fops; } - file_list_unlock(); + spin_unlock(&tty_files_lock); tty_ldisc_hangup(tty); @@ -1424,9 +1427,9 @@ static void release_one_tty(struct work_struct *work) tty_driver_kref_put(driver); module_put(driver->owner); - file_list_lock(); + spin_lock(&tty_files_lock); list_del_init(&tty->tty_files); - file_list_unlock(); + spin_unlock(&tty_files_lock); put_pid(tty->pgrp); put_pid(tty->session); @@ -1671,7 +1674,10 @@ int tty_release(struct inode *inode, struct file *filp) * - do_tty_hangup no longer sees this file descriptor as * something that needs to be handled for hangups. */ - file_kill(filp); + spin_lock(&tty_files_lock); + BUG_ON(list_empty(&filp->f_u.fu_list)); + list_del_init(&filp->f_u.fu_list); + spin_unlock(&tty_files_lock); filp->private_data = NULL; /* @@ -1840,7 +1846,11 @@ got_driver: } filp->private_data = tty; - file_move(filp, &tty->tty_files); + BUG_ON(list_empty(&filp->f_u.fu_list)); + file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ + spin_lock(&tty_files_lock); + list_add(&filp->f_u.fu_list, &tty->tty_files); + spin_unlock(&tty_files_lock); check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) diff --git a/fs/file_table.c b/fs/file_table.c index edecd36fed9b..6f0e62ecfddd 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -32,8 +32,7 @@ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -/* public. Not pretty! */ -__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); /* SLAB cache for file structures */ static struct kmem_cache *filp_cachep __read_mostly; @@ -249,7 +248,7 @@ static void __fput(struct file *file) cdev_put(inode->i_cdev); fops_put(file->f_op); put_pid(file->f_owner.pid); - file_kill(file); + file_sb_list_del(file); if (file->f_mode & FMODE_WRITE) drop_file_write_access(file); file->f_path.dentry = NULL; @@ -328,31 +327,29 @@ struct file *fget_light(unsigned int fd, int *fput_needed) return file; } - void put_filp(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { security_file_free(file); - file_kill(file); + file_sb_list_del(file); file_free(file); } } -void file_move(struct file *file, struct list_head *list) +void file_sb_list_add(struct file *file, struct super_block *sb) { - if (!list) - return; - file_list_lock(); - list_move(&file->f_u.fu_list, list); - file_list_unlock(); + spin_lock(&files_lock); + BUG_ON(!list_empty(&file->f_u.fu_list)); + list_add(&file->f_u.fu_list, &sb->s_files); + spin_unlock(&files_lock); } -void file_kill(struct file *file) +void file_sb_list_del(struct file *file) { if (!list_empty(&file->f_u.fu_list)) { - file_list_lock(); + spin_lock(&files_lock); list_del_init(&file->f_u.fu_list); - file_list_unlock(); + spin_unlock(&files_lock); } } @@ -361,7 +358,7 @@ int fs_may_remount_ro(struct super_block *sb) struct file *file; /* Check that no files are currently opened for writing. */ - file_list_lock(); + spin_lock(&files_lock); list_for_each_entry(file, &sb->s_files, f_u.fu_list) { struct inode *inode = file->f_path.dentry->d_inode; @@ -373,10 +370,10 @@ int fs_may_remount_ro(struct super_block *sb) if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) goto too_bad; } - file_list_unlock(); + spin_unlock(&files_lock); return 1; /* Tis' cool bro. */ too_bad: - file_list_unlock(); + spin_unlock(&files_lock); return 0; } @@ -392,7 +389,7 @@ void mark_files_ro(struct super_block *sb) struct file *f; retry: - file_list_lock(); + spin_lock(&files_lock); list_for_each_entry(f, &sb->s_files, f_u.fu_list) { struct vfsmount *mnt; if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) @@ -408,16 +405,13 @@ retry: continue; file_release_write(f); mnt = mntget(f->f_path.mnt); - file_list_unlock(); - /* - * This can sleep, so we can't hold - * the file_list_lock() spinlock. - */ + /* This can sleep, so we can't hold the spinlock. */ + spin_unlock(&files_lock); mnt_drop_write(mnt); mntput(mnt); goto retry; } - file_list_unlock(); + spin_unlock(&files_lock); } void __init files_init(unsigned long mempages) diff --git a/fs/open.c b/fs/open.c index 630715f9f73d..d74e1983e8dc 100644 --- a/fs/open.c +++ b/fs/open.c @@ -675,7 +675,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, f->f_path.mnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); - file_move(f, &inode->i_sb->s_files); + file_sb_list_add(f, inode->i_sb); error = security_dentry_open(f, cred); if (error) @@ -721,7 +721,7 @@ cleanup_all: mnt_drop_write(mnt); } } - file_kill(f); + file_sb_list_del(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: diff --git a/include/linux/fs.h b/include/linux/fs.h index 29f7c975304c..5a9a9e5a3705 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -944,9 +944,6 @@ struct file { unsigned long f_mnt_write_state; #endif }; -extern spinlock_t files_lock; -#define file_list_lock() spin_lock(&files_lock); -#define file_list_unlock() spin_unlock(&files_lock); #define get_file(x) atomic_long_inc(&(x)->f_count) #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) @@ -2188,8 +2185,8 @@ static inline void insert_inode_hash(struct inode *inode) { __insert_inode_hash(inode, inode->i_ino); } -extern void file_move(struct file *f, struct list_head *list); -extern void file_kill(struct file *f); +extern void file_sb_list_add(struct file *f, struct super_block *sb); +extern void file_sb_list_del(struct file *f); #ifdef CONFIG_BLOCK extern void submit_bio(int, struct bio *); extern int bdev_read_only(struct block_device *); diff --git a/include/linux/tty.h b/include/linux/tty.h index 1437da3ddc62..f6b371a2514e 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -470,6 +470,7 @@ extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); extern struct mutex tty_mutex; +extern spinlock_t tty_files_lock; extern void tty_write_unlock(struct tty_struct *tty); extern int tty_write_lock(struct tty_struct *tty, int ndelay); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 42043f96e54f..bd7da0f0ccf3 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2170,7 +2170,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, tty = get_current_tty(); if (tty) { - file_list_lock(); + spin_lock(&tty_files_lock); if (!list_empty(&tty->tty_files)) { struct inode *inode; @@ -2186,7 +2186,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, drop_tty = 1; } } - file_list_unlock(); + spin_unlock(&tty_files_lock); tty_kref_put(tty); } /* Reset controlling tty. */ -- cgit v1.2.3-59-g8ed1b From d996b62a8df1d935b01319bf8defb95b5709f7b8 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:36 +1000 Subject: tty: fix fu_list abuse tty: fix fu_list abuse tty code abuses fu_list, which causes a bug in remount,ro handling. If a tty device node is opened on a filesystem, then the last link to the inode removed, the filesystem will be allowed to be remounted readonly. This is because fs_may_remount_ro does not find the 0 link tty inode on the file sb list (because the tty code incorrectly removed it to use for its own purpose). This can result in a filesystem with errors after it is marked "clean". Taking idea from Christoph's initial patch, allocate a tty private struct at file->private_data and put our required list fields in there, linking file and tty. This makes tty nodes behave the same way as other device nodes and avoid meddling with the vfs, and avoids this bug. The error handling is not trivial in the tty code, so for this bugfix, I take the simple approach of using __GFP_NOFAIL and don't worry about memory errors. This is not a problem because our allocator doesn't fail small allocs as a rule anyway. So proper error handling is left as an exercise for tty hackers. [ Arguably filesystem's device inode would ideally be divorced from the driver's pseudo inode when it is opened, but in practice it's not clear whether that will ever be worth implementing. ] Cc: linux-kernel@vger.kernel.org Cc: Christoph Hellwig Cc: Alan Cox Cc: Greg Kroah-Hartman Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- drivers/char/pty.c | 6 +--- drivers/char/tty_io.c | 84 +++++++++++++++++++++++++++++++----------------- fs/internal.h | 2 ++ include/linux/fs.h | 2 -- include/linux/tty.h | 8 +++++ security/selinux/hooks.c | 5 ++- 6 files changed, 69 insertions(+), 38 deletions(-) diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 2c64faa8efa4..c350d01716bd 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -675,12 +675,8 @@ static int ptmx_open(struct inode *inode, struct file *filp) } set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - filp->private_data = tty; - file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ - spin_lock(&tty_files_lock); - list_add(&filp->f_u.fu_list, &tty->tty_files); - spin_unlock(&tty_files_lock); + tty_add_file(tty, filp); retval = devpts_pty_new(inode, tty->link); if (retval) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index cd5b829634ea..949067a0bd47 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -188,6 +188,41 @@ void free_tty_struct(struct tty_struct *tty) kfree(tty); } +static inline struct tty_struct *file_tty(struct file *file) +{ + return ((struct tty_file_private *)file->private_data)->tty; +} + +/* Associate a new file with the tty structure */ +void tty_add_file(struct tty_struct *tty, struct file *file) +{ + struct tty_file_private *priv; + + /* XXX: must implement proper error handling in callers */ + priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL); + + priv->tty = tty; + priv->file = file; + file->private_data = priv; + + spin_lock(&tty_files_lock); + list_add(&priv->list, &tty->tty_files); + spin_unlock(&tty_files_lock); +} + +/* Delete file from its tty */ +void tty_del_file(struct file *file) +{ + struct tty_file_private *priv = file->private_data; + + spin_lock(&tty_files_lock); + list_del(&priv->list); + spin_unlock(&tty_files_lock); + file->private_data = NULL; + kfree(priv); +} + + #define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) /** @@ -500,6 +535,7 @@ void __tty_hangup(struct tty_struct *tty) struct file *cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; + struct tty_file_private *priv; int closecount = 0, n; unsigned long flags; int refs = 0; @@ -509,7 +545,7 @@ void __tty_hangup(struct tty_struct *tty) spin_lock(&redirect_lock); - if (redirect && redirect->private_data == tty) { + if (redirect && file_tty(redirect) == tty) { f = redirect; redirect = NULL; } @@ -524,7 +560,8 @@ void __tty_hangup(struct tty_struct *tty) spin_lock(&tty_files_lock); /* This breaks for file handles being sent over AF_UNIX sockets ? */ - list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { + list_for_each_entry(priv, &tty->tty_files, list) { + filp = priv->file; if (filp->f_op->write == redirected_tty_write) cons_filp = filp; if (filp->f_op->write != tty_write) @@ -892,12 +929,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int i; - struct tty_struct *tty; - struct inode *inode; + struct inode *inode = file->f_path.dentry->d_inode; + struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; - tty = file->private_data; - inode = file->f_path.dentry->d_inode; if (tty_paranoia_check(tty, inode, "tty_read")) return -EIO; if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) @@ -1068,12 +1103,11 @@ void tty_write_message(struct tty_struct *tty, char *msg) static ssize_t tty_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct tty_struct *tty; struct inode *inode = file->f_path.dentry->d_inode; + struct tty_struct *tty = file_tty(file); + struct tty_ldisc *ld; ssize_t ret; - struct tty_ldisc *ld; - tty = file->private_data; if (tty_paranoia_check(tty, inode, "tty_write")) return -EIO; if (!tty || !tty->ops->write || @@ -1510,13 +1544,13 @@ static void release_tty(struct tty_struct *tty, int idx) int tty_release(struct inode *inode, struct file *filp) { - struct tty_struct *tty, *o_tty; + struct tty_struct *tty = file_tty(filp); + struct tty_struct *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int devpts; int idx; char buf[64]; - tty = filp->private_data; if (tty_paranoia_check(tty, inode, "tty_release_dev")) return 0; @@ -1674,11 +1708,7 @@ int tty_release(struct inode *inode, struct file *filp) * - do_tty_hangup no longer sees this file descriptor as * something that needs to be handled for hangups. */ - spin_lock(&tty_files_lock); - BUG_ON(list_empty(&filp->f_u.fu_list)); - list_del_init(&filp->f_u.fu_list); - spin_unlock(&tty_files_lock); - filp->private_data = NULL; + tty_del_file(filp); /* * Perform some housekeeping before deciding whether to return. @@ -1845,12 +1875,8 @@ got_driver: return PTR_ERR(tty); } - filp->private_data = tty; - BUG_ON(list_empty(&filp->f_u.fu_list)); - file_sb_list_del(filp); /* __dentry_open has put it on the sb list */ - spin_lock(&tty_files_lock); - list_add(&filp->f_u.fu_list, &tty->tty_files); - spin_unlock(&tty_files_lock); + tty_add_file(tty, filp); + check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -1926,11 +1952,10 @@ got_driver: static unsigned int tty_poll(struct file *filp, poll_table *wait) { - struct tty_struct *tty; + struct tty_struct *tty = file_tty(filp); struct tty_ldisc *ld; int ret = 0; - tty = filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll")) return 0; @@ -1943,11 +1968,10 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) static int __tty_fasync(int fd, struct file *filp, int on) { - struct tty_struct *tty; + struct tty_struct *tty = file_tty(filp); unsigned long flags; int retval = 0; - tty = filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync")) goto out; @@ -2501,13 +2525,13 @@ EXPORT_SYMBOL(tty_pair_get_pty); */ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct tty_struct *tty, *real_tty; + struct tty_struct *tty = file_tty(file); + struct tty_struct *real_tty; void __user *p = (void __user *)arg; int retval; struct tty_ldisc *ld; struct inode *inode = file->f_dentry->d_inode; - tty = file->private_data; if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; @@ -2629,7 +2653,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct inode *inode = file->f_dentry->d_inode; - struct tty_struct *tty = file->private_data; + struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; int retval = -ENOIOCTLCMD; @@ -2721,7 +2745,7 @@ void __do_SAK(struct tty_struct *tty) if (!filp) continue; if (filp->f_op->read == tty_read && - filp->private_data == tty) { + file_tty(filp) == tty) { printk(KERN_NOTICE "SAK: killed process %d" " (%s): fd#%d opened to the tty\n", task_pid_nr(p), p->comm, i); diff --git a/fs/internal.h b/fs/internal.h index 6b706bc60a66..6a5c13a80660 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -80,6 +80,8 @@ extern void chroot_fs_refs(struct path *, struct path *); /* * file_table.c */ +extern void file_sb_list_add(struct file *f, struct super_block *sb); +extern void file_sb_list_del(struct file *f); extern void mark_files_ro(struct super_block *); extern struct file *get_empty_filp(void); diff --git a/include/linux/fs.h b/include/linux/fs.h index 5a9a9e5a3705..5e65add0f163 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2185,8 +2185,6 @@ static inline void insert_inode_hash(struct inode *inode) { __insert_inode_hash(inode, inode->i_ino); } -extern void file_sb_list_add(struct file *f, struct super_block *sb); -extern void file_sb_list_del(struct file *f); #ifdef CONFIG_BLOCK extern void submit_bio(int, struct bio *); extern int bdev_read_only(struct block_device *); diff --git a/include/linux/tty.h b/include/linux/tty.h index f6b371a2514e..67d64e6efe7a 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -329,6 +329,13 @@ struct tty_struct { struct tty_port *port; }; +/* Each of a tty's open files has private_data pointing to tty_file_private */ +struct tty_file_private { + struct tty_struct *tty; + struct file *file; + struct list_head list; +}; + /* tty magic number */ #define TTY_MAGIC 0x5401 @@ -458,6 +465,7 @@ extern void proc_clear_tty(struct task_struct *p); extern struct tty_struct *get_current_tty(void); extern void tty_default_fops(struct file_operations *fops); extern struct tty_struct *alloc_tty_struct(void); +extern void tty_add_file(struct tty_struct *tty, struct file *file); extern void free_tty_struct(struct tty_struct *tty); extern void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index bd7da0f0ccf3..4796ddd4e721 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2172,6 +2172,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, if (tty) { spin_lock(&tty_files_lock); if (!list_empty(&tty->tty_files)) { + struct tty_file_private *file_priv; struct inode *inode; /* Revalidate access to controlling tty. @@ -2179,7 +2180,9 @@ static inline void flush_unauthorized_files(const struct cred *cred, than using file_has_perm, as this particular open file may belong to another process and we are only interested in the inode-based check here. */ - file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list); + file_priv = list_first_entry(&tty->tty_files, + struct tty_file_private, list); + file = file_priv->file; inode = file->f_path.dentry->d_inode; if (inode_has_perm(cred, inode, FILE__READ | FILE__WRITE, NULL)) { -- cgit v1.2.3-59-g8ed1b From 2dc91abe03d8ce6dd7f9251faffafca5f6b9e85d Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:37 +1000 Subject: lglock: introduce special lglock and brlock spin locks lglock: introduce special lglock and brlock spin locks This patch introduces "local-global" locks (lglocks). These can be used to: - Provide fast exclusive access to per-CPU data, with exclusive access to another CPU's data allowed but possibly subject to contention, and to provide very slow exclusive access to all per-CPU data. - Or to provide very fast and scalable read serialisation, and to provide very slow exclusive serialisation of data (not necessarily per-CPU data). Brlocks are also implemented as a short-hand notation for the latter use case. Thanks to Paul for local/global naming convention. Cc: linux-kernel@vger.kernel.org Cc: Al Viro Cc: "Paul E. McKenney" Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- include/linux/lglock.h | 172 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 include/linux/lglock.h diff --git a/include/linux/lglock.h b/include/linux/lglock.h new file mode 100644 index 000000000000..b288cb713b90 --- /dev/null +++ b/include/linux/lglock.h @@ -0,0 +1,172 @@ +/* + * Specialised local-global spinlock. Can only be declared as global variables + * to avoid overhead and keep things simple (and we don't want to start using + * these inside dynamically allocated structures). + * + * "local/global locks" (lglocks) can be used to: + * + * - Provide fast exclusive access to per-CPU data, with exclusive access to + * another CPU's data allowed but possibly subject to contention, and to + * provide very slow exclusive access to all per-CPU data. + * - Or to provide very fast and scalable read serialisation, and to provide + * very slow exclusive serialisation of data (not necessarily per-CPU data). + * + * Brlocks are also implemented as a short-hand notation for the latter use + * case. + * + * Copyright 2009, 2010, Nick Piggin, Novell Inc. + */ +#ifndef __LINUX_LGLOCK_H +#define __LINUX_LGLOCK_H + +#include +#include +#include + +/* can make br locks by using local lock for read side, global lock for write */ +#define br_lock_init(name) name##_lock_init() +#define br_read_lock(name) name##_local_lock() +#define br_read_unlock(name) name##_local_unlock() +#define br_write_lock(name) name##_global_lock_online() +#define br_write_unlock(name) name##_global_unlock_online() + +#define DECLARE_BRLOCK(name) DECLARE_LGLOCK(name) +#define DEFINE_BRLOCK(name) DEFINE_LGLOCK(name) + + +#define lg_lock_init(name) name##_lock_init() +#define lg_local_lock(name) name##_local_lock() +#define lg_local_unlock(name) name##_local_unlock() +#define lg_local_lock_cpu(name, cpu) name##_local_lock_cpu(cpu) +#define lg_local_unlock_cpu(name, cpu) name##_local_unlock_cpu(cpu) +#define lg_global_lock(name) name##_global_lock() +#define lg_global_unlock(name) name##_global_unlock() +#define lg_global_lock_online(name) name##_global_lock_online() +#define lg_global_unlock_online(name) name##_global_unlock_online() + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define LOCKDEP_INIT_MAP lockdep_init_map + +#define DEFINE_LGLOCK_LOCKDEP(name) \ + struct lock_class_key name##_lock_key; \ + struct lockdep_map name##_lock_dep_map; \ + EXPORT_SYMBOL(name##_lock_dep_map) + +#else +#define LOCKDEP_INIT_MAP(a, b, c, d) + +#define DEFINE_LGLOCK_LOCKDEP(name) +#endif + + +#define DECLARE_LGLOCK(name) \ + extern void name##_lock_init(void); \ + extern void name##_local_lock(void); \ + extern void name##_local_unlock(void); \ + extern void name##_local_lock_cpu(int cpu); \ + extern void name##_local_unlock_cpu(int cpu); \ + extern void name##_global_lock(void); \ + extern void name##_global_unlock(void); \ + extern void name##_global_lock_online(void); \ + extern void name##_global_unlock_online(void); \ + +#define DEFINE_LGLOCK(name) \ + \ + DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \ + DEFINE_LGLOCK_LOCKDEP(name); \ + \ + void name##_lock_init(void) { \ + int i; \ + LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \ + for_each_possible_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + *lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \ + } \ + } \ + EXPORT_SYMBOL(name##_lock_init); \ + \ + void name##_local_lock(void) { \ + arch_spinlock_t *lock; \ + preempt_disable(); \ + rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \ + lock = &__get_cpu_var(name##_lock); \ + arch_spin_lock(lock); \ + } \ + EXPORT_SYMBOL(name##_local_lock); \ + \ + void name##_local_unlock(void) { \ + arch_spinlock_t *lock; \ + rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \ + lock = &__get_cpu_var(name##_lock); \ + arch_spin_unlock(lock); \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_local_unlock); \ + \ + void name##_local_lock_cpu(int cpu) { \ + arch_spinlock_t *lock; \ + preempt_disable(); \ + rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \ + lock = &per_cpu(name##_lock, cpu); \ + arch_spin_lock(lock); \ + } \ + EXPORT_SYMBOL(name##_local_lock_cpu); \ + \ + void name##_local_unlock_cpu(int cpu) { \ + arch_spinlock_t *lock; \ + rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \ + lock = &per_cpu(name##_lock, cpu); \ + arch_spin_unlock(lock); \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_local_unlock_cpu); \ + \ + void name##_global_lock_online(void) { \ + int i; \ + preempt_disable(); \ + rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_lock(lock); \ + } \ + } \ + EXPORT_SYMBOL(name##_global_lock_online); \ + \ + void name##_global_unlock_online(void) { \ + int i; \ + rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_unlock(lock); \ + } \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_global_unlock_online); \ + \ + void name##_global_lock(void) { \ + int i; \ + preempt_disable(); \ + rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_lock(lock); \ + } \ + } \ + EXPORT_SYMBOL(name##_global_lock); \ + \ + void name##_global_unlock(void) { \ + int i; \ + rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \ + for_each_online_cpu(i) { \ + arch_spinlock_t *lock; \ + lock = &per_cpu(name##_lock, i); \ + arch_spin_unlock(lock); \ + } \ + preempt_enable(); \ + } \ + EXPORT_SYMBOL(name##_global_unlock); +#endif -- cgit v1.2.3-59-g8ed1b From 6416ccb7899960868f5016751fb81bf25213d24f Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:38 +1000 Subject: fs: scale files_lock fs: scale files_lock Improve scalability of files_lock by adding per-cpu, per-sb files lists, protected with an lglock. The lglock provides fast access to the per-cpu lists to add and remove files. It also provides a snapshot of all the per-cpu lists (although this is very slow). One difficulty with this approach is that a file can be removed from the list by another CPU. We must track which per-cpu list the file is on with a new variale in the file struct (packed into a hole on 64-bit archs). Scalability could suffer if files are frequently removed from different cpu's list. However loads with frequent removal of files imply short interval between adding and removing the files, and the scheduler attempts to avoid moving processes too far away. Also, even in the case of cross-CPU removal, the hardware has much more opportunity to parallelise cacheline transfers with N cachelines than with 1. A worst-case test of 1 CPU allocating files subsequently being freed by N CPUs degenerates to contending on a single lock, which is no worse than before. When more than one CPU are allocating files, even if they are always freed by different CPUs, there will be more parallelism than the single-lock case. Testing results: On a 2 socket, 8 core opteron, I measure the number of times the lock is taken to remove the file, the number of times it is removed by the same CPU that added it, and the number of times it is removed by the same node that added it. Booting: locks= 25049 cpu-hits= 23174 (92.5%) node-hits= 23945 (95.6%) kbuild -j16 locks=2281913 cpu-hits=2208126 (96.8%) node-hits=2252674 (98.7%) dbench 64 locks=4306582 cpu-hits=4287247 (99.6%) node-hits=4299527 (99.8%) So a file is removed from the same CPU it was added by over 90% of the time. It remains within the same node 95% of the time. Tim Chen ran some numbers for a 64 thread Nehalem system performing a compile. throughput 2.6.34-rc2 24.5 +patch 24.9 us sys idle IO wait (in %) 2.6.34-rc2 51.25 28.25 17.25 3.25 +patch 53.75 18.5 19 8.75 So significantly less CPU time spent in kernel code, higher idle time and slightly higher throughput. Single threaded performance difference was within the noise of microbenchmarks. That is not to say penalty does not exist, the code is larger and more memory accesses required so it will be slightly slower. Cc: linux-kernel@vger.kernel.org Cc: Tim Chen Cc: Andi Kleen Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- fs/file_table.c | 108 ++++++++++++++++++++++++++++++++++++++++++++--------- fs/super.c | 18 +++++++++ include/linux/fs.h | 7 ++++ 3 files changed, 115 insertions(+), 18 deletions(-) diff --git a/fs/file_table.c b/fs/file_table.c index 6f0e62ecfddd..a04bdd81c11c 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include #include #include @@ -32,7 +34,8 @@ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); +DECLARE_LGLOCK(files_lglock); +DEFINE_LGLOCK(files_lglock); /* SLAB cache for file structures */ static struct kmem_cache *filp_cachep __read_mostly; @@ -336,30 +339,98 @@ void put_filp(struct file *file) } } +static inline int file_list_cpu(struct file *file) +{ +#ifdef CONFIG_SMP + return file->f_sb_list_cpu; +#else + return smp_processor_id(); +#endif +} + +/* helper for file_sb_list_add to reduce ifdefs */ +static inline void __file_sb_list_add(struct file *file, struct super_block *sb) +{ + struct list_head *list; +#ifdef CONFIG_SMP + int cpu; + cpu = smp_processor_id(); + file->f_sb_list_cpu = cpu; + list = per_cpu_ptr(sb->s_files, cpu); +#else + list = &sb->s_files; +#endif + list_add(&file->f_u.fu_list, list); +} + +/** + * file_sb_list_add - add a file to the sb's file list + * @file: file to add + * @sb: sb to add it to + * + * Use this function to associate a file with the superblock of the inode it + * refers to. + */ void file_sb_list_add(struct file *file, struct super_block *sb) { - spin_lock(&files_lock); - BUG_ON(!list_empty(&file->f_u.fu_list)); - list_add(&file->f_u.fu_list, &sb->s_files); - spin_unlock(&files_lock); + lg_local_lock(files_lglock); + __file_sb_list_add(file, sb); + lg_local_unlock(files_lglock); } +/** + * file_sb_list_del - remove a file from the sb's file list + * @file: file to remove + * @sb: sb to remove it from + * + * Use this function to remove a file from its superblock. + */ void file_sb_list_del(struct file *file) { if (!list_empty(&file->f_u.fu_list)) { - spin_lock(&files_lock); + lg_local_lock_cpu(files_lglock, file_list_cpu(file)); list_del_init(&file->f_u.fu_list); - spin_unlock(&files_lock); + lg_local_unlock_cpu(files_lglock, file_list_cpu(file)); } } +#ifdef CONFIG_SMP + +/* + * These macros iterate all files on all CPUs for a given superblock. + * files_lglock must be held globally. + */ +#define do_file_list_for_each_entry(__sb, __file) \ +{ \ + int i; \ + for_each_possible_cpu(i) { \ + struct list_head *list; \ + list = per_cpu_ptr((__sb)->s_files, i); \ + list_for_each_entry((__file), list, f_u.fu_list) + +#define while_file_list_for_each_entry \ + } \ +} + +#else + +#define do_file_list_for_each_entry(__sb, __file) \ +{ \ + struct list_head *list; \ + list = &(sb)->s_files; \ + list_for_each_entry((__file), list, f_u.fu_list) + +#define while_file_list_for_each_entry \ +} + +#endif + int fs_may_remount_ro(struct super_block *sb) { struct file *file; - /* Check that no files are currently opened for writing. */ - spin_lock(&files_lock); - list_for_each_entry(file, &sb->s_files, f_u.fu_list) { + lg_global_lock(files_lglock); + do_file_list_for_each_entry(sb, file) { struct inode *inode = file->f_path.dentry->d_inode; /* File with pending delete? */ @@ -369,11 +440,11 @@ int fs_may_remount_ro(struct super_block *sb) /* Writeable file? */ if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) goto too_bad; - } - spin_unlock(&files_lock); + } while_file_list_for_each_entry; + lg_global_unlock(files_lglock); return 1; /* Tis' cool bro. */ too_bad: - spin_unlock(&files_lock); + lg_global_unlock(files_lglock); return 0; } @@ -389,8 +460,8 @@ void mark_files_ro(struct super_block *sb) struct file *f; retry: - spin_lock(&files_lock); - list_for_each_entry(f, &sb->s_files, f_u.fu_list) { + lg_global_lock(files_lglock); + do_file_list_for_each_entry(sb, f) { struct vfsmount *mnt; if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) continue; @@ -406,12 +477,12 @@ retry: file_release_write(f); mnt = mntget(f->f_path.mnt); /* This can sleep, so we can't hold the spinlock. */ - spin_unlock(&files_lock); + lg_global_unlock(files_lglock); mnt_drop_write(mnt); mntput(mnt); goto retry; - } - spin_unlock(&files_lock); + } while_file_list_for_each_entry; + lg_global_unlock(files_lglock); } void __init files_init(unsigned long mempages) @@ -431,5 +502,6 @@ void __init files_init(unsigned long mempages) if (files_stat.max_files < NR_FILE) files_stat.max_files = NR_FILE; files_defer_init(); + lg_lock_init(files_lglock); percpu_counter_init(&nr_files, 0); } diff --git a/fs/super.c b/fs/super.c index 9674ab2c8718..8819e3a7ff20 100644 --- a/fs/super.c +++ b/fs/super.c @@ -54,7 +54,22 @@ static struct super_block *alloc_super(struct file_system_type *type) s = NULL; goto out; } +#ifdef CONFIG_SMP + s->s_files = alloc_percpu(struct list_head); + if (!s->s_files) { + security_sb_free(s); + kfree(s); + s = NULL; + goto out; + } else { + int i; + + for_each_possible_cpu(i) + INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i)); + } +#else INIT_LIST_HEAD(&s->s_files); +#endif INIT_LIST_HEAD(&s->s_instances); INIT_HLIST_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); @@ -108,6 +123,9 @@ out: */ static inline void destroy_super(struct super_block *s) { +#ifdef CONFIG_SMP + free_percpu(s->s_files); +#endif security_sb_free(s); kfree(s->s_subtype); kfree(s->s_options); diff --git a/include/linux/fs.h b/include/linux/fs.h index 5e65add0f163..76041b614758 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -920,6 +920,9 @@ struct file { #define f_vfsmnt f_path.mnt const struct file_operations *f_op; spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */ +#ifdef CONFIG_SMP + int f_sb_list_cpu; +#endif atomic_long_t f_count; unsigned int f_flags; fmode_t f_mode; @@ -1334,7 +1337,11 @@ struct super_block { struct list_head s_inodes; /* all inodes */ struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */ +#ifdef CONFIG_SMP + struct list_head __percpu *s_files; +#else struct list_head s_files; +#endif /* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */ struct list_head s_dentry_lru; /* unused dentry lru */ int s_nr_dentry_unused; /* # of dentry on lru */ -- cgit v1.2.3-59-g8ed1b From 99b7db7b8ffd6bb755eb0a175596421a0b581cb2 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Wed, 18 Aug 2010 04:37:39 +1000 Subject: fs: brlock vfsmount_lock fs: brlock vfsmount_lock Use a brlock for the vfsmount lock. It must be taken for write whenever modifying the mount hash or associated fields, and may be taken for read when performing mount hash lookups. A new lock is added for the mnt-id allocator, so it doesn't need to take the heavy vfsmount write-lock. The number of atomics should remain the same for fastpath rlock cases, though code would be slightly slower due to per-cpu access. Scalability is not not be much improved in common cases yet, due to other locks (ie. dcache_lock) getting in the way. However path lookups crossing mountpoints should be one case where scalability is improved (currently requiring the global lock). The slowpath is slower due to use of brlock. On a 64 core, 64 socket, 32 node Altix system (high latency to remote nodes), a simple umount microbenchmark (mount --bind mnt mnt2 ; umount mnt2 loop 1000 times), before this patch it took 6.8s, afterwards took 7.1s, about 5% slower. Cc: Al Viro Signed-off-by: Nick Piggin Signed-off-by: Al Viro --- fs/dcache.c | 11 ++-- fs/internal.h | 5 +- fs/namei.c | 7 ++- fs/namespace.c | 177 ++++++++++++++++++++++++++++++++++++--------------------- fs/pnode.c | 11 +++- 5 files changed, 134 insertions(+), 77 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index d56a40b5a577..83293be48149 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1935,7 +1935,7 @@ static int prepend_path(const struct path *path, struct path *root, bool slash = false; int error = 0; - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); while (dentry != root->dentry || vfsmnt != root->mnt) { struct dentry * parent; @@ -1964,7 +1964,7 @@ out: if (!error && !slash) error = prepend(buffer, buflen, "/", 1); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return error; global_root: @@ -2302,11 +2302,12 @@ int path_is_under(struct path *path1, struct path *path2) struct vfsmount *mnt = path1->mnt; struct dentry *dentry = path1->dentry; int res; - spin_lock(&vfsmount_lock); + + br_read_lock(vfsmount_lock); if (mnt != path2->mnt) { for (;;) { if (mnt->mnt_parent == mnt) { - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return 0; } if (mnt->mnt_parent == path2->mnt) @@ -2316,7 +2317,7 @@ int path_is_under(struct path *path1, struct path *path2) dentry = mnt->mnt_mountpoint; } res = is_subdir(dentry, path2->dentry); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return res; } EXPORT_SYMBOL(path_is_under); diff --git a/fs/internal.h b/fs/internal.h index 6a5c13a80660..a6910e91cee8 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -9,6 +9,8 @@ * 2 of the License, or (at your option) any later version. */ +#include + struct super_block; struct linux_binprm; struct path; @@ -70,7 +72,8 @@ extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); extern void __init mnt_init(void); -extern spinlock_t vfsmount_lock; +DECLARE_BRLOCK(vfsmount_lock); + /* * fs_struct.c diff --git a/fs/namei.c b/fs/namei.c index 11de7c39ff76..24896e833565 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -595,15 +595,16 @@ int follow_up(struct path *path) { struct vfsmount *parent; struct dentry *mountpoint; - spin_lock(&vfsmount_lock); + + br_read_lock(vfsmount_lock); parent = path->mnt->mnt_parent; if (parent == path->mnt) { - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return 0; } mntget(parent); mountpoint = dget(path->mnt->mnt_mountpoint); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); dput(path->dentry); path->dentry = mountpoint; mntput(path->mnt); diff --git a/fs/namespace.c b/fs/namespace.c index 2e10cb19c5b0..de402eb6eafb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -38,12 +40,10 @@ #define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) #define HASH_SIZE (1UL << HASH_SHIFT) -/* spinlock for vfsmount related operations, inplace of dcache_lock */ -__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); - static int event; static DEFINE_IDA(mnt_id_ida); static DEFINE_IDA(mnt_group_ida); +static DEFINE_SPINLOCK(mnt_id_lock); static int mnt_id_start = 0; static int mnt_group_start = 1; @@ -55,6 +55,16 @@ static struct rw_semaphore namespace_sem; struct kobject *fs_kobj; EXPORT_SYMBOL_GPL(fs_kobj); +/* + * vfsmount lock may be taken for read to prevent changes to the + * vfsmount hash, ie. during mountpoint lookups or walking back + * up the tree. + * + * It should be taken for write in all cases where the vfsmount + * tree or hash is modified or when a vfsmount structure is modified. + */ +DEFINE_BRLOCK(vfsmount_lock); + static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); @@ -65,18 +75,21 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) -/* allocation is serialized by namespace_sem */ +/* + * allocation is serialized by namespace_sem, but we need the spinlock to + * serialize with freeing. + */ static int mnt_alloc_id(struct vfsmount *mnt) { int res; retry: ida_pre_get(&mnt_id_ida, GFP_KERNEL); - spin_lock(&vfsmount_lock); + spin_lock(&mnt_id_lock); res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id); if (!res) mnt_id_start = mnt->mnt_id + 1; - spin_unlock(&vfsmount_lock); + spin_unlock(&mnt_id_lock); if (res == -EAGAIN) goto retry; @@ -86,11 +99,11 @@ retry: static void mnt_free_id(struct vfsmount *mnt) { int id = mnt->mnt_id; - spin_lock(&vfsmount_lock); + spin_lock(&mnt_id_lock); ida_remove(&mnt_id_ida, id); if (mnt_id_start > id) mnt_id_start = id; - spin_unlock(&vfsmount_lock); + spin_unlock(&mnt_id_lock); } /* @@ -348,7 +361,7 @@ static int mnt_make_readonly(struct vfsmount *mnt) { int ret = 0; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt->mnt_flags |= MNT_WRITE_HOLD; /* * After storing MNT_WRITE_HOLD, we'll read the counters. This store @@ -382,15 +395,15 @@ static int mnt_make_readonly(struct vfsmount *mnt) */ smp_wmb(); mnt->mnt_flags &= ~MNT_WRITE_HOLD; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); return ret; } static void __mnt_unmake_readonly(struct vfsmount *mnt) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt->mnt_flags &= ~MNT_READONLY; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) @@ -414,6 +427,7 @@ void free_vfsmnt(struct vfsmount *mnt) /* * find the first or last mount at @dentry on vfsmount @mnt depending on * @dir. If @dir is set return the first mount else return the last mount. + * vfsmount_lock must be held for read or write. */ struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, int dir) @@ -443,10 +457,11 @@ struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, struct vfsmount *lookup_mnt(struct path *path) { struct vfsmount *child_mnt; - spin_lock(&vfsmount_lock); + + br_read_lock(vfsmount_lock); if ((child_mnt = __lookup_mnt(path->mnt, path->dentry, 1))) mntget(child_mnt); - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return child_mnt; } @@ -455,6 +470,9 @@ static inline int check_mnt(struct vfsmount *mnt) return mnt->mnt_ns == current->nsproxy->mnt_ns; } +/* + * vfsmount lock must be held for write + */ static void touch_mnt_namespace(struct mnt_namespace *ns) { if (ns) { @@ -463,6 +481,9 @@ static void touch_mnt_namespace(struct mnt_namespace *ns) } } +/* + * vfsmount lock must be held for write + */ static void __touch_mnt_namespace(struct mnt_namespace *ns) { if (ns && ns->event != event) { @@ -471,6 +492,9 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) } } +/* + * vfsmount lock must be held for write + */ static void detach_mnt(struct vfsmount *mnt, struct path *old_path) { old_path->dentry = mnt->mnt_mountpoint; @@ -482,6 +506,9 @@ static void detach_mnt(struct vfsmount *mnt, struct path *old_path) old_path->dentry->d_mounted--; } +/* + * vfsmount lock must be held for write + */ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, struct vfsmount *child_mnt) { @@ -490,6 +517,9 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, dentry->d_mounted++; } +/* + * vfsmount lock must be held for write + */ static void attach_mnt(struct vfsmount *mnt, struct path *path) { mnt_set_mountpoint(path->mnt, path->dentry, mnt); @@ -499,7 +529,7 @@ static void attach_mnt(struct vfsmount *mnt, struct path *path) } /* - * the caller must hold vfsmount_lock + * vfsmount lock must be held for write */ static void commit_tree(struct vfsmount *mnt) { @@ -623,39 +653,43 @@ static inline void __mntput(struct vfsmount *mnt) void mntput_no_expire(struct vfsmount *mnt) { repeat: - if (atomic_dec_and_lock(&mnt->mnt_count, &vfsmount_lock)) { - if (likely(!mnt->mnt_pinned)) { - spin_unlock(&vfsmount_lock); - __mntput(mnt); - return; - } - atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count); - mnt->mnt_pinned = 0; - spin_unlock(&vfsmount_lock); - acct_auto_close_mnt(mnt); - goto repeat; + if (atomic_add_unless(&mnt->mnt_count, -1, 1)) + return; + br_write_lock(vfsmount_lock); + if (!atomic_dec_and_test(&mnt->mnt_count)) { + br_write_unlock(vfsmount_lock); + return; + } + if (likely(!mnt->mnt_pinned)) { + br_write_unlock(vfsmount_lock); + __mntput(mnt); + return; } + atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count); + mnt->mnt_pinned = 0; + br_write_unlock(vfsmount_lock); + acct_auto_close_mnt(mnt); + goto repeat; } - EXPORT_SYMBOL(mntput_no_expire); void mnt_pin(struct vfsmount *mnt) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt->mnt_pinned++; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } EXPORT_SYMBOL(mnt_pin); void mnt_unpin(struct vfsmount *mnt) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); if (mnt->mnt_pinned) { atomic_inc(&mnt->mnt_count); mnt->mnt_pinned--; } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } EXPORT_SYMBOL(mnt_unpin); @@ -746,12 +780,12 @@ int mnt_had_events(struct proc_mounts *p) struct mnt_namespace *ns = p->ns; int res = 0; - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); if (p->event != ns->event) { p->event = ns->event; res = 1; } - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); return res; } @@ -952,12 +986,12 @@ int may_umount_tree(struct vfsmount *mnt) int minimum_refs = 0; struct vfsmount *p; - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); for (p = mnt; p; p = next_mnt(p, mnt)) { actual_refs += atomic_read(&p->mnt_count); minimum_refs += 2; } - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); if (actual_refs > minimum_refs) return 0; @@ -984,10 +1018,10 @@ int may_umount(struct vfsmount *mnt) { int ret = 1; down_read(&namespace_sem); - spin_lock(&vfsmount_lock); + br_read_lock(vfsmount_lock); if (propagate_mount_busy(mnt, 2)) ret = 0; - spin_unlock(&vfsmount_lock); + br_read_unlock(vfsmount_lock); up_read(&namespace_sem); return ret; } @@ -1003,13 +1037,14 @@ void release_mounts(struct list_head *head) if (mnt->mnt_parent != mnt) { struct dentry *dentry; struct vfsmount *m; - spin_lock(&vfsmount_lock); + + br_write_lock(vfsmount_lock); dentry = mnt->mnt_mountpoint; m = mnt->mnt_parent; mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; m->mnt_ghosts--; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); dput(dentry); mntput(m); } @@ -1017,6 +1052,10 @@ void release_mounts(struct list_head *head) } } +/* + * vfsmount lock must be held for write + * namespace_sem must be held for write + */ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) { struct vfsmount *p; @@ -1107,7 +1146,7 @@ static int do_umount(struct vfsmount *mnt, int flags) } down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); event++; if (!(flags & MNT_DETACH)) @@ -1119,7 +1158,7 @@ static int do_umount(struct vfsmount *mnt, int flags) umount_tree(mnt, 1, &umount_list); retval = 0; } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); return retval; @@ -1231,19 +1270,19 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, q = clone_mnt(p, p->mnt_root, flag); if (!q) goto Enomem; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); list_add_tail(&q->mnt_list, &res->mnt_list); attach_mnt(q, &path); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } } return res; Enomem: if (res) { LIST_HEAD(umount_list); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); umount_tree(res, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); release_mounts(&umount_list); } return NULL; @@ -1262,9 +1301,9 @@ void drop_collected_mounts(struct vfsmount *mnt) { LIST_HEAD(umount_list); down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); umount_tree(mnt, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); } @@ -1392,7 +1431,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, if (err) goto out_cleanup_ids; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); if (IS_MNT_SHARED(dest_mnt)) { for (p = source_mnt; p; p = next_mnt(p, source_mnt)) @@ -1411,7 +1450,8 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, list_del_init(&child->mnt_hash); commit_tree(child); } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); + return 0; out_cleanup_ids: @@ -1466,10 +1506,10 @@ static int do_change_type(struct path *path, int flag) goto out_unlock; } - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) change_mnt_propagation(m, type); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); out_unlock: up_write(&namespace_sem); @@ -1513,9 +1553,10 @@ static int do_loopback(struct path *path, char *old_name, err = graft_tree(mnt, path); if (err) { LIST_HEAD(umount_list); - spin_lock(&vfsmount_lock); + + br_write_lock(vfsmount_lock); umount_tree(mnt, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); release_mounts(&umount_list); } @@ -1568,16 +1609,16 @@ static int do_remount(struct path *path, int flags, int mnt_flags, else err = do_remount_sb(sb, flags, data, 0); if (!err) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); mnt_flags |= path->mnt->mnt_flags & MNT_PROPAGATION_MASK; path->mnt->mnt_flags = mnt_flags; - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } up_write(&sb->s_umount); if (!err) { - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); touch_mnt_namespace(path->mnt->mnt_ns); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); } return err; } @@ -1754,7 +1795,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) return; down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); /* extract from the expiration list every vfsmount that matches the * following criteria: @@ -1773,7 +1814,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) touch_mnt_namespace(mnt->mnt_ns); umount_tree(mnt, 1, &umounts); } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umounts); @@ -1830,6 +1871,8 @@ resume: /* * process a list of expirable mountpoints with the intent of discarding any * submounts of a specific parent mountpoint + * + * vfsmount_lock must be held for write */ static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) { @@ -2048,9 +2091,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, kfree(new_ns); return ERR_PTR(-ENOMEM); } - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); list_add_tail(&new_ns->list, &new_ns->root->mnt_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); /* * Second pass: switch the tsk->fs->* elements and mark new vfsmounts @@ -2244,7 +2287,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, goto out2; /* not attached */ /* make sure we can reach put_old from new_root */ tmp = old.mnt; - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); if (tmp != new.mnt) { for (;;) { if (tmp->mnt_parent == tmp) @@ -2264,7 +2307,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, /* mount new_root on / */ attach_mnt(new.mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); chroot_fs_refs(&root, &new); error = 0; path_put(&root_parent); @@ -2279,7 +2322,7 @@ out1: out0: return error; out3: - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); goto out2; } @@ -2326,6 +2369,8 @@ void __init mnt_init(void) for (u = 0; u < HASH_SIZE; u++) INIT_LIST_HEAD(&mount_hashtable[u]); + br_lock_init(vfsmount_lock); + err = sysfs_init(); if (err) printk(KERN_WARNING "%s: sysfs_init error: %d\n", @@ -2344,9 +2389,9 @@ void put_mnt_ns(struct mnt_namespace *ns) if (!atomic_dec_and_test(&ns->count)) return; down_write(&namespace_sem); - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); umount_tree(ns->root, 0, &umount_list); - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); kfree(ns); diff --git a/fs/pnode.c b/fs/pnode.c index 5cc564a83149..8066b8dd748f 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -126,6 +126,9 @@ static int do_make_slave(struct vfsmount *mnt) return 0; } +/* + * vfsmount lock must be held for write + */ void change_mnt_propagation(struct vfsmount *mnt, int type) { if (type == MS_SHARED) { @@ -270,12 +273,12 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, prev_src_mnt = child; } out: - spin_lock(&vfsmount_lock); + br_write_lock(vfsmount_lock); while (!list_empty(&tmp_list)) { child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); umount_tree(child, 0, &umount_list); } - spin_unlock(&vfsmount_lock); + br_write_unlock(vfsmount_lock); release_mounts(&umount_list); return ret; } @@ -296,6 +299,8 @@ static inline int do_refcount_check(struct vfsmount *mnt, int count) * other mounts its parent propagates to. * Check if any of these mounts that **do not have submounts** * have more references than 'refcnt'. If so return busy. + * + * vfsmount lock must be held for read or write */ int propagate_mount_busy(struct vfsmount *mnt, int refcnt) { @@ -353,6 +358,8 @@ static void __propagate_umount(struct vfsmount *mnt) * collect all mounts that receive propagation from the mount in @list, * and return these additional mounts in the same list. * @list: the list of mounts to be unmounted. + * + * vfsmount lock must be held for write */ int propagate_umount(struct list_head *list) { -- cgit v1.2.3-59-g8ed1b From 56385a12d9bb9e173751f74b6c430742018cafc0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 18 Aug 2010 14:08:17 +0200 Subject: ALSA: emu10k1 - delay the PCM interrupts (add pcm_irq_delay parameter) With some hardware combinations, the PCM interrupts are acknowledged before the period boundary from the emu10k1 chip. The midlevel PCM code gets confused and the playback stream is interrupted. It seems that the interrupt processing shift by 2 samples is enough to fix this issue. This default value does not harm other, non-affected hardware. More information: Kernel bugzilla bug#16300 [A copmile warning fixed by tiwai] Signed-off-by: Jaroslav Kysela Cc: Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 1 + sound/core/pcm_native.c | 4 ++++ sound/pci/emu10k1/emu10k1.c | 4 ++++ sound/pci/emu10k1/emupcm.c | 30 ++++++++++++++++++++++++++---- sound/pci/emu10k1/memory.c | 4 +++- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 6a664c3f7c1e..7dc97d12253c 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1707,6 +1707,7 @@ struct snd_emu10k1 { unsigned int card_type; /* EMU10K1_CARD_* */ unsigned int ecard_ctrl; /* ecard control bits */ unsigned long dma_mask; /* PCI DMA mask */ + unsigned int delay_pcm_irq; /* in samples */ int max_cache_pages; /* max memory size / PAGE_SIZE */ struct snd_dma_buffer silent_page; /* silent page */ struct snd_dma_buffer ptb_pages; /* page table pages */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a3b2a6479246..134fc6c2e08d 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -978,6 +978,10 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) { if (substream->runtime->trigger_master != substream) return 0; + /* some drivers might use hw_ptr to recover from the pause - + update the hw_ptr now */ + if (push) + snd_pcm_update_hw_ptr(substream); /* The jiffies check in snd_pcm_update_hw_ptr*() is done by * a delta betwen the current jiffies, this gives a large enough * delta, effectively to skip the check once. diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4203782d7cb7..aff8387c45cf 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -52,6 +52,7 @@ static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; static int enable_ir[SNDRV_CARDS]; static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ +static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); @@ -73,6 +74,8 @@ module_param_array(enable_ir, bool, NULL, 0444); MODULE_PARM_DESC(enable_ir, "Enable IR."); module_param_array(subsystem, uint, NULL, 0444); MODULE_PARM_DESC(subsystem, "Force card subsystem model."); +module_param_array(delay_pcm_irq, uint, NULL, 0444); +MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0)."); /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ @@ -127,6 +130,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, &emu)) < 0) goto error; card->private_data = emu; + emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) goto error; if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 55b83ef73c63..622bace148e3 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -332,7 +332,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, evoice->epcm->ccca_start_addr = start_addr + ccis; if (extra) { start_addr += ccis; - end_addr += ccis; + end_addr += ccis + emu->delay_pcm_irq; } if (stereo && !extra) { snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); @@ -360,7 +360,9 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, /* Assumption that PT is already 0 so no harm overwriting */ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); - snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); + snd_emu10k1_ptr_write(emu, PSST, voice, + (start_addr + (extra ? emu->delay_pcm_irq : 0)) | + (send_amount[2] << 24)); if (emu->card_capabilities->emu_model) pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ else @@ -732,6 +734,23 @@ static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_ snd_emu10k1_ptr_write(emu, IP, voice, 0); } +static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) +{ + unsigned int ptr, period_pos; + + /* try to sychronize the current position for the interrupt + source voice */ + period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt; + period_pos %= runtime->period_size; + ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number); + ptr &= ~0x00ffffff; + ptr |= epcm->ccca_start_addr + period_pos; + snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr); +} + static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -753,6 +772,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, /* follow thru */ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) + snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime); mix = &emu->pcm_mixer[substream->number]; snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); @@ -869,8 +890,9 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * #endif /* printk(KERN_DEBUG - "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", - ptr, runtime->buffer_size, runtime->period_size); + "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n", + (long)ptr, (long)runtime->buffer_size, + (long)runtime->period_size); */ return ptr; } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index ffb1ddb8dc28..957a311514c8 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -310,8 +310,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (snd_BUG_ON(!hdr)) return NULL; + idx = runtime->period_size >= runtime->buffer_size ? + (emu->delay_pcm_irq * 2) : 0; mutex_lock(&hdr->block_mutex); - blk = search_empty(emu, runtime->dma_bytes); + blk = search_empty(emu, runtime->dma_bytes + idx); if (blk == NULL) { mutex_unlock(&hdr->block_mutex); return NULL; -- cgit v1.2.3-59-g8ed1b From bd76af0f87f7a1815b311bde269a3f18305b3169 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 18 Aug 2010 14:16:54 +0200 Subject: ALSA: pcm midlevel code - add time check for double interrupt acknowledge The current code in pcm_lib.c do all checks using only the position in the ring buffer. Unfortunately, where the interrupts gets delayed or merged into one, we need another timing source to check when the buffer size boundary overlaps to avoid the wrong updating of the ring buffer pointers. This code uses jiffies to check the right time window without any performance impact. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 + sound/core/pcm_lib.c | 14 +++++++++----- sound/core/pcm_native.c | 2 ++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 85f1c6bf8566..dfd9b76b1853 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -278,6 +278,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ + unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ /* -- HW params -- */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e23e0e7ab26f..a1707cca9c66 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* delta = "expected next hw_ptr" for in_interrupt != 0 */ delta = runtime->hw_ptr_interrupt + runtime->period_size; if (delta > new_hw_ptr) { - hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) - hw_base = 0; - new_hw_ptr = hw_base + pos; - goto __delta; + /* check for double acknowledged interrupts */ + hdelta = jiffies - runtime->hw_ptr_jiffies; + if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + goto __delta; + } } } /* new_hw_ptr might be lower than old_hw_ptr in case when */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 134fc6c2e08d..e2e73895db12 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); runtime->hw_ptr_jiffies = jiffies; + runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / + runtime->rate; runtime->status->state = state; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) -- cgit v1.2.3-59-g8ed1b From 0a377cff9428af2da2b293d11e07bc4dbf064ee5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 18 Aug 2010 09:25:42 -0400 Subject: NFS: Fix an Oops in the NFSv4 atomic open code Adam Lackorzynski reports: with 2.6.35.2 I'm getting this reproducible Oops: [ 110.825396] BUG: unable to handle kernel NULL pointer dereference at (null) [ 110.828638] IP: [] encode_attrs+0x1a/0x2a4 [ 110.828638] PGD be89f067 PUD bf18f067 PMD 0 [ 110.828638] Oops: 0000 [#1] SMP [ 110.828638] last sysfs file: /sys/class/net/lo/operstate [ 110.828638] CPU 2 [ 110.828638] Modules linked in: rtc_cmos rtc_core rtc_lib amd64_edac_mod i2c_amd756 edac_core i2c_core dm_mirror dm_region_hash dm_log dm_snapshot sg sr_mod usb_storage ohci_hcd mptspi tg3 mptscsih mptbase usbcore nls_base [last unloaded: scsi_wait_scan] [ 110.828638] [ 110.828638] Pid: 11264, comm: setchecksum Not tainted 2.6.35.2 #1 [ 110.828638] RIP: 0010:[] [] encode_attrs+0x1a/0x2a4 [ 110.828638] RSP: 0000:ffff88003bf5b878 EFLAGS: 00010296 [ 110.828638] RAX: ffff8800bddb48a8 RBX: ffff88003bf5bb18 RCX: 0000000000000000 [ 110.828638] RDX: ffff8800be258800 RSI: 0000000000000000 RDI: ffff88003bf5b9f8 [ 110.828638] RBP: 0000000000000000 R08: ffff8800bddb48a8 R09: 0000000000000004 [ 110.828638] R10: 0000000000000003 R11: ffff8800be779000 R12: ffff8800be258800 [ 110.828638] R13: ffff88003bf5b9f8 R14: ffff88003bf5bb20 R15: ffff8800be258800 [ 110.828638] FS: 0000000000000000(0000) GS:ffff880041e00000(0063) knlGS:00000000556bd6b0 [ 110.828638] CS: 0010 DS: 002b ES: 002b CR0: 000000008005003b [ 110.828638] CR2: 0000000000000000 CR3: 00000000be8ef000 CR4: 00000000000006e0 [ 110.828638] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 110.828638] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 110.828638] Process setchecksum (pid: 11264, threadinfo ffff88003bf5a000, task ffff88003f232210) [ 110.828638] Stack: [ 110.828638] 0000000000000000 ffff8800bfbcf920 0000000000000000 0000000000000ffe [ 110.828638] <0> 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 110.828638] <0> 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 110.828638] Call Trace: [ 110.828638] [] ? nfs4_xdr_enc_setattr+0x90/0xb4 [ 110.828638] [] ? call_transmit+0x1c3/0x24a [ 110.828638] [] ? __rpc_execute+0x78/0x22a [ 110.828638] [] ? rpc_run_task+0x21/0x2b [ 110.828638] [] ? rpc_call_sync+0x3d/0x5d [ 110.828638] [] ? _nfs4_do_setattr+0x11b/0x147 [ 110.828638] [] ? nfs_init_locked+0x0/0x32 [ 110.828638] [] ? ifind+0x4e/0x90 [ 110.828638] [] ? nfs4_do_setattr+0x4b/0x6e [ 110.828638] [] ? nfs4_do_open+0x291/0x3a6 [ 110.828638] [] ? nfs4_open_revalidate+0x63/0x14a [ 110.828638] [] ? nfs_open_revalidate+0xd7/0x161 [ 110.828638] [] ? do_lookup+0x1a4/0x201 [ 110.828638] [] ? link_path_walk+0x6a/0x9d5 [ 110.828638] [] ? do_last+0x17b/0x58e [ 110.828638] [] ? do_filp_open+0x1bd/0x56e [ 110.828638] [] ? _atomic_dec_and_lock+0x30/0x48 [ 110.828638] [] ? dput+0x37/0x152 [ 110.828638] [] ? alloc_fd+0x69/0x10a [ 110.828638] [] ? do_sys_open+0x56/0x100 [ 110.828638] [] ? ia32_sysret+0x0/0x5 [ 110.828638] Code: 83 f1 01 e8 f5 ca ff ff 48 83 c4 50 5b 5d 41 5c c3 41 57 41 56 41 55 49 89 fd 41 54 49 89 d4 55 48 89 f5 53 48 81 ec 18 01 00 00 <8b> 06 89 c2 83 e2 08 83 fa 01 19 db 83 e3 f8 83 c3 18 a8 01 8d [ 110.828638] RIP [] encode_attrs+0x1a/0x2a4 [ 110.828638] RSP [ 110.828638] CR2: 0000000000000000 [ 112.840396] ---[ end trace 95282e83fd77358f ]--- We need to ensure that the O_EXCL flag is turned off if the user doesn't set O_CREAT. Cc: stable@kernel.org Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 2 +- fs/nfs/nfs4proc.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index bd91b2778315..e257172d438c 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1110,7 +1110,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) goto no_open_dput; /* We can't create new files, or truncate existing ones here */ - openflags &= ~(O_CREAT|O_TRUNC); + openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); /* * Note: we're not holding inode->i_mutex and so may be racing with diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6b44bbfb7d8a..089da5b5d20a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2036,7 +2036,8 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct rpc_cred *cred; struct nfs4_state *state; struct dentry *res; - fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); + int open_flags = nd->intent.open.flags; + fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); if (nd->flags & LOOKUP_CREATE) { attr.ia_mode = nd->intent.open.create_mode; @@ -2044,8 +2045,9 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) if (!IS_POSIXACL(dir)) attr.ia_mode &= ~current_umask(); } else { + open_flags &= ~O_EXCL; attr.ia_valid = 0; - BUG_ON(nd->intent.open.flags & O_CREAT); + BUG_ON(open_flags & O_CREAT); } cred = rpc_lookup_cred(); @@ -2054,7 +2056,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) parent = dentry->d_parent; /* Protect against concurrent sillydeletes */ nfs_block_sillyrename(parent); - state = nfs4_do_open(dir, &path, fmode, nd->intent.open.flags, &attr, cred); + state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred); put_rpccred(cred); if (IS_ERR(state)) { if (PTR_ERR(state) == -ENOENT) { -- cgit v1.2.3-59-g8ed1b From 1cb0c924fa2d616e5e3b5bc62d97191aac9ff442 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 18 Aug 2010 21:11:11 +0900 Subject: nilfs2: wait for discard to finish nilfs_discard_segment() doesn't wait for completion of discard requests. This specifies BLKDEV_IFL_WAIT flag when calling blkdev_issue_discard() in order to fix the sync failure. Reported-by: Christoph Hellwig Signed-off-by: Ryusuke Konishi Cc: Christoph Hellwig --- fs/nilfs2/the_nilfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 6af1c0073e9e..4317f177ea7c 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -775,6 +775,7 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, start * sects_per_block, nblocks * sects_per_block, GFP_NOFS, + BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER); if (ret < 0) return ret; @@ -785,7 +786,8 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, ret = blkdev_issue_discard(nilfs->ns_bdev, start * sects_per_block, nblocks * sects_per_block, - GFP_NOFS, BLKDEV_IFL_BARRIER); + GFP_NOFS, + BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER); return ret; } -- cgit v1.2.3-59-g8ed1b From 07a7795ca2e6e66d00b184efb46bd0e23d90d3fe Mon Sep 17 00:00:00 2001 From: Hans Rosenfeld Date: Wed, 18 Aug 2010 16:19:50 +0200 Subject: x86, cpu: Fix regression in AMD errata checking code A bug in the family-model-stepping matching code caused the presence of errata to go undetected when OSVW was not used. This causes hangs on some K8 systems because the E400 workaround is not enabled. Signed-off-by: Hans Rosenfeld LKML-Reference: <1282141190-930137-1-git-send-email-hans.rosenfeld@amd.com> Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/amd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 60a57b13082d..ba5f62f45f01 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -669,7 +669,7 @@ bool cpu_has_amd_erratum(const int *erratum) } /* OSVW unavailable or ID unknown, match family-model-stepping range */ - ms = (cpu->x86_model << 8) | cpu->x86_mask; + ms = (cpu->x86_model << 4) | cpu->x86_mask; while ((range = *erratum++)) if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) && (ms >= AMD_MODEL_RANGE_START(range)) && -- cgit v1.2.3-59-g8ed1b From fd89a137924e0710078c3ae855e7cec1c43cb845 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Mon, 16 Aug 2010 14:38:33 +0200 Subject: x86-32: Separate 1:1 pagetables from swapper_pg_dir This patch fixes machine crashes which occur when heavily exercising the CPU hotplug codepaths on a 32-bit kernel. These crashes are caused by AMD Erratum 383 and result in a fatal machine check exception. Here's the scenario: 1. On 32-bit, the swapper_pg_dir page table is used as the initial page table for booting a secondary CPU. 2. To make this work, swapper_pg_dir needs a direct mapping of physical memory in it (the low mappings). By adding those low, large page (2M) mappings (PAE kernel), we create the necessary conditions for Erratum 383 to occur. 3. Other CPUs which do not participate in the off- and onlining game may use swapper_pg_dir while the low mappings are present (when leave_mm is called). For all steps below, the CPU referred to is a CPU that is using swapper_pg_dir, and not the CPU which is being onlined. 4. The presence of the low mappings in swapper_pg_dir can result in TLB entries for addresses below __PAGE_OFFSET to be established speculatively. These TLB entries are marked global and large. 5. When the CPU with such TLB entry switches to another page table, this TLB entry remains because it is global. 6. The process then generates an access to an address covered by the above TLB entry but there is a permission mismatch - the TLB entry covers a large global page not accessible to userspace. 7. Due to this permission mismatch a new 4kb, user TLB entry gets established. Further, Erratum 383 provides for a small window of time where both TLB entries are present. This results in an uncorrectable machine check exception signalling a TLB multimatch which panics the machine. There are two ways to fix this issue: 1. Always do a global TLB flush when a new cr3 is loaded and the old page table was swapper_pg_dir. I consider this a hack hard to understand and with performance implications 2. Do not use swapper_pg_dir to boot secondary CPUs like 64-bit does. This patch implements solution 2. It introduces a trampoline_pg_dir which has the same layout as swapper_pg_dir with low_mappings. This page table is used as the initial page table of the booting CPU. Later in the bringup process, it switches to swapper_pg_dir and does a global TLB flush. This fixes the crashes in our test cases. -v2: switch to swapper_pg_dir right after entering start_secondary() so that we are able to access percpu data which might not be mapped in the trampoline page table. Signed-off-by: Joerg Roedel LKML-Reference: <20100816123833.GB28147@aftab> Signed-off-by: Borislav Petkov Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/pgtable_32.h | 1 + arch/x86/include/asm/trampoline.h | 3 +++ arch/x86/kernel/head_32.S | 8 +++++++- arch/x86/kernel/setup.c | 2 ++ arch/x86/kernel/smpboot.c | 32 +++++++++++++------------------- arch/x86/kernel/trampoline.c | 18 ++++++++++++++++++ 6 files changed, 44 insertions(+), 20 deletions(-) diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h index 2984a25ff383..f686f49e8b7b 100644 --- a/arch/x86/include/asm/pgtable_32.h +++ b/arch/x86/include/asm/pgtable_32.h @@ -26,6 +26,7 @@ struct mm_struct; struct vm_area_struct; extern pgd_t swapper_pg_dir[1024]; +extern pgd_t trampoline_pg_dir[1024]; static inline void pgtable_cache_init(void) { } static inline void check_pgt_cache(void) { } diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h index cb507bb05d79..8f78fdf3f178 100644 --- a/arch/x86/include/asm/trampoline.h +++ b/arch/x86/include/asm/trampoline.h @@ -13,14 +13,17 @@ extern unsigned char *trampoline_base; extern unsigned long init_rsp; extern unsigned long initial_code; +extern unsigned long initial_page_table; extern unsigned long initial_gs; #define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE) extern unsigned long setup_trampoline(void); +extern void __init setup_trampoline_page_table(void); extern void __init reserve_trampoline_memory(void); #else static inline void reserve_trampoline_memory(void) {}; +extern void __init setup_trampoline_page_table(void) {}; #endif /* CONFIG_X86_TRAMPOLINE */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index ff4c453e13f3..fa8c1b8e09fb 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -334,7 +334,7 @@ ENTRY(startup_32_smp) /* * Enable paging */ - movl $pa(swapper_pg_dir),%eax + movl pa(initial_page_table), %eax movl %eax,%cr3 /* set the page table pointer.. */ movl %cr0,%eax orl $X86_CR0_PG,%eax @@ -614,6 +614,8 @@ ignore_int: .align 4 ENTRY(initial_code) .long i386_start_kernel +ENTRY(initial_page_table) + .long pa(swapper_pg_dir) /* * BSS section @@ -629,6 +631,10 @@ ENTRY(swapper_pg_dir) #endif swapper_pg_fixmap: .fill 1024,4,0 +#ifdef CONFIG_X86_TRAMPOLINE +ENTRY(trampoline_pg_dir) + .fill 1024,4,0 +#endif ENTRY(empty_zero_page) .fill 4096,1,0 diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b008e7883207..c3a4fbb2b996 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1014,6 +1014,8 @@ void __init setup_arch(char **cmdline_p) paging_init(); x86_init.paging.pagetable_setup_done(swapper_pg_dir); + setup_trampoline_page_table(); + tboot_probe(); #ifdef CONFIG_X86_64 diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index a5e928b0cb5f..abf4a86ffc54 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -73,7 +73,6 @@ #ifdef CONFIG_X86_32 u8 apicid_2_node[MAX_APICID]; -static int low_mappings; #endif /* State of each CPU */ @@ -281,6 +280,18 @@ notrace static void __cpuinit start_secondary(void *unused) * fragile that we want to limit the things done here to the * most necessary things. */ + +#ifdef CONFIG_X86_32 + /* + * Switch away from the trampoline page-table + * + * Do this before cpu_init() because it needs to access per-cpu + * data which may not be mapped in the trampoline page-table. + */ + load_cr3(swapper_pg_dir); + __flush_tlb_all(); +#endif + vmi_bringup(); cpu_init(); preempt_disable(); @@ -299,12 +310,6 @@ notrace static void __cpuinit start_secondary(void *unused) legacy_pic->chip->unmask(0); } -#ifdef CONFIG_X86_32 - while (low_mappings) - cpu_relax(); - __flush_tlb_all(); -#endif - /* This must be done before setting cpu_online_mask */ set_cpu_sibling_map(raw_smp_processor_id()); wmb(); @@ -750,6 +755,7 @@ do_rest: #ifdef CONFIG_X86_32 /* Stack for startup_32 can be just as for start_secondary onwards */ irq_ctx_init(cpu); + initial_page_table = __pa(&trampoline_pg_dir); #else clear_tsk_thread_flag(c_idle.idle, TIF_FORK); initial_gs = per_cpu_offset(cpu); @@ -897,20 +903,8 @@ int __cpuinit native_cpu_up(unsigned int cpu) per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; -#ifdef CONFIG_X86_32 - /* init low mem mapping */ - clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, - min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); - flush_tlb_all(); - low_mappings = 1; - err = do_boot_cpu(apicid, cpu); - zap_low_mappings(false); - low_mappings = 0; -#else - err = do_boot_cpu(apicid, cpu); -#endif if (err) { pr_debug("do_boot_cpu failed %d\n", err); return -EIO; diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c index c652ef62742d..a874495b3673 100644 --- a/arch/x86/kernel/trampoline.c +++ b/arch/x86/kernel/trampoline.c @@ -1,6 +1,7 @@ #include #include +#include #include #if defined(CONFIG_X86_64) && defined(CONFIG_ACPI_SLEEP) @@ -37,3 +38,20 @@ unsigned long __trampinit setup_trampoline(void) memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE); return virt_to_phys(trampoline_base); } + +void __init setup_trampoline_page_table(void) +{ +#ifdef CONFIG_X86_32 + /* Copy kernel address range */ + clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min_t(unsigned long, KERNEL_PGD_PTRS, + KERNEL_PGD_BOUNDARY)); + + /* Initialize low mappings */ + clone_pgd_range(trampoline_pg_dir, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min_t(unsigned long, KERNEL_PGD_PTRS, + KERNEL_PGD_BOUNDARY)); +#endif +} -- cgit v1.2.3-59-g8ed1b From ecafda60e88031bcc4271c446f984ee883d69ea8 Mon Sep 17 00:00:00 2001 From: Kusanagi Kouichi Date: Wed, 18 Aug 2010 13:32:37 -0300 Subject: perf tools: Fix build error on read only source. Parts of the build process were generating files outside the specified O= directory, causing the build to fail on systems where the sources are in a read only file system. Fix it by using $(OUTPUT) on these locations. Also check that $(OUTPUT) actually exists, just like the top level kernel Makefile does. Otherwise the failure message emitted is completely misleading. Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Paul Mackerras LKML-Reference: <20100817140841.0859362C03A@msa106.auone-net.jp> Signed-off-by: Kusanagi Kouichi Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 14 ++++++++++---- tools/perf/feature-tests.mak | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index dcb9700b88d2..4f1fa77c1feb 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -5,6 +5,12 @@ endif # The default target of this Makefile is... all:: +ifneq ($(OUTPUT),) +# check that the output directory actually exists +OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) +$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) +endif + # Define V=1 to have a more verbose compile. # Define V=2 to have an even more verbose compile. # @@ -931,15 +937,15 @@ $(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh - $(QUIET_GEN)$(RM) $@ $@+ && \ + $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - $@.sh >$@+ && \ - chmod +x $@+ && \ - mv $@+ $(OUTPUT)$@ + $@.sh > $(OUTPUT)$@+ && \ + chmod +x $(OUTPUT)$@+ && \ + mv $(OUTPUT)$@+ $(OUTPUT)$@ configure: configure.ac $(QUIET_GEN)$(RM) $@ $<+ && \ diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak index ddb68e601f0e..7a7b60859053 100644 --- a/tools/perf/feature-tests.mak +++ b/tools/perf/feature-tests.mak @@ -113,7 +113,7 @@ endef # try-cc # Usage: option = $(call try-cc, source-to-build, cc-options) try-cc = $(shell sh -c \ - 'TMP="$(TMPOUT).$$$$"; \ + 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ echo "$(1)" | \ $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ rm -f "$$TMP"') -- cgit v1.2.3-59-g8ed1b From 81ca03a0e2ea0207b2df80e0edcf4c775c07a505 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 18 Aug 2010 09:25:38 -0700 Subject: mmc: build fix: mmc_pm_notify is only available with CONFIG_PM=y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a build breakage introduced by commit 4c2ef25fe0b8 ("mmc: fix all hangs related to mmc/sd card insert/removal during suspend/resume") Cc: David Brownell Cc: Alan Stern Cc: linux-mmc@vger.kernel.org Cc: Andrew Morton Signed-off-by: Uwe Kleine-König Acked-by: Kukjin Kim Acked-by: Maxim Levitsky Acked-by: Randy Dunlap Signed-off-by: Linus Torvalds --- drivers/mmc/core/host.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 0efe631e50ca..d80cfdc8edd2 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -86,7 +86,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable); +#ifdef CONFIG_PM host->pm_notify.notifier_call = mmc_pm_notify; +#endif /* * By default, hosts do not support SGIO or large requests. -- cgit v1.2.3-59-g8ed1b From 145e5aa269d54e4ea53fdb5e597007bd287fbe49 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 18 Aug 2010 10:17:44 -0700 Subject: [IA64] Fix build error: conflicting types for ‘sys_execve’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arch/ia64/kernel/process.c:636: error: conflicting types for ‘sys_execve’ commit d7627467b7a8dd6944885290a03a07ceb28c10eb Make do_execve() take a const filename pointer Missed the declaration of sys_execve in the ia64 asm/unistd.h (perhaps because there is no reason for it to be there ... it might be a left over from the COMPAT code?). Just delete the conflicting version. Signed-off-by: Tony Luck --- arch/ia64/include/asm/unistd.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 87f1bd1efc82..954d398a54b4 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -356,8 +356,6 @@ asmlinkage unsigned long sys_mmap2( int fd, long pgoff); struct pt_regs; struct sigaction; -long sys_execve(const char __user *filename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs); asmlinkage long sys_ia64_pipe(void); asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, -- cgit v1.2.3-59-g8ed1b From fc87a40677bbe0937e2ff0642c7e83c9a4813f3d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 18 Aug 2010 13:13:39 -0400 Subject: cifs: fix NULL pointer dereference in cifs_find_smb_ses cifs_find_smb_ses assumes that the vol->password field is a valid pointer, but that's only the case if a password was passed in via the options string. It's possible that one won't be if there is no mount helper on the box. Reported-by: diabel Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 95c2ea67edfb..446e2486d5f0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1673,7 +1673,8 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) MAX_USERNAME_SIZE)) continue; if (strlen(vol->username) != 0 && - strncmp(ses->password, vol->password, + strncmp(ses->password, + vol->password ? vol->password : "", MAX_PASSWORD_SIZE)) continue; } -- cgit v1.2.3-59-g8ed1b From d15ca3203754359cfe5d18910722d3089b204cc4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 18 Aug 2010 18:55:33 +0100 Subject: Fix the declaration of sys_execve() in asm-generic/syscalls.h Fix the declaration of sys_execve() in asm-generic/syscalls.h to have various consts applied to its pointers. Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- include/asm-generic/syscalls.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/asm-generic/syscalls.h b/include/asm-generic/syscalls.h index df84e3b04555..d89dec864d42 100644 --- a/include/asm-generic/syscalls.h +++ b/include/asm-generic/syscalls.h @@ -23,8 +23,10 @@ asmlinkage long sys_vfork(struct pt_regs *regs); #endif #ifndef sys_execve -asmlinkage long sys_execve(char __user *filename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs); +asmlinkage long sys_execve(const char __user *filename, + const char __user *const __user *argv, + const char __user *const __user *envp, + struct pt_regs *regs); #endif #ifndef sys_mmap2 -- cgit v1.2.3-59-g8ed1b From 8848a91068c018bc91f597038a0f41462a0f88a4 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 18 Aug 2010 11:42:23 -0700 Subject: x86-32: Fix dummy trampoline-related inline stubs Fix dummy inline stubs for trampoline-related functions when no trampolines exist (until we get rid of the no-trampoline case entirely.) Signed-off-by: H. Peter Anvin Cc: Joerg Roedel Cc: Borislav Petkov LKML-Reference: <4C6C294D.3030404@zytor.com> --- arch/x86/include/asm/trampoline.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h index 8f78fdf3f178..4dde797c0578 100644 --- a/arch/x86/include/asm/trampoline.h +++ b/arch/x86/include/asm/trampoline.h @@ -22,8 +22,8 @@ extern unsigned long setup_trampoline(void); extern void __init setup_trampoline_page_table(void); extern void __init reserve_trampoline_memory(void); #else -static inline void reserve_trampoline_memory(void) {}; -extern void __init setup_trampoline_page_table(void) {}; +static inline void setup_trampoline_page_table(void) {} +static inline void reserve_trampoline_memory(void) {} #endif /* CONFIG_X86_TRAMPOLINE */ #endif /* __ASSEMBLY__ */ -- cgit v1.2.3-59-g8ed1b From 37c6c9b0e941fbb7f37a93d36abaf5fcafea87a8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Aug 2010 10:04:43 -0700 Subject: drm/i915: add panel reset workaround Ironlake requires that we clear the reset panel bit during power sequences and restore it afterwards. Uncondtionally add code to do that since it should be harmless on SNB+. Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_dp.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c6629bd9430f..d1b4ece4df00 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -765,6 +765,12 @@ static void ironlake_edp_panel_on (struct drm_device *dev) return; pp = I915_READ(PCH_PP_CONTROL); + + /* ILK workaround: disable reset around power sequence */ + pp &= ~PANEL_POWER_RESET; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); @@ -773,7 +779,9 @@ static void ironlake_edp_panel_on (struct drm_device *dev) I915_READ(PCH_PP_STATUS)); pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD); + pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); } static void ironlake_edp_panel_off (struct drm_device *dev) @@ -782,6 +790,12 @@ static void ironlake_edp_panel_off (struct drm_device *dev) u32 pp; pp = I915_READ(PCH_PP_CONTROL); + + /* ILK workaround: disable reset around power sequence */ + pp &= ~PANEL_POWER_RESET; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + pp &= ~POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); @@ -790,8 +804,9 @@ static void ironlake_edp_panel_off (struct drm_device *dev) I915_READ(PCH_PP_STATUS)); /* Make sure VDD is enabled so DP AUX will work */ - pp |= EDP_FORCE_VDD; + pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); } static void ironlake_edp_backlight_on (struct drm_device *dev) -- cgit v1.2.3-59-g8ed1b From 7643a7fa16edf180d593f705f4fa5930c40e8d2d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Aug 2010 10:06:44 -0700 Subject: drm/i915: eDP mode set sequence corrections We should disable the panel first when shutting down an eDP link. And when turning one on, the panel needs to be enabled before link training or eDP I/O won't be enabled. Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_dp.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d1b4ece4df00..8061a48804a3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -840,20 +840,19 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { - if (dp_reg & DP_PORT_EN) { - intel_dp_link_down(intel_dp); - if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { - ironlake_edp_backlight_off(dev); - ironlake_edp_panel_off(dev); - } + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { + ironlake_edp_backlight_off(dev); + ironlake_edp_panel_off(dev); } + if (dp_reg & DP_PORT_EN) + intel_dp_link_down(intel_dp); } else { if (!(dp_reg & DP_PORT_EN)) { - intel_dp_link_train(intel_dp); - if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) { + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_panel_on(dev); + intel_dp_link_train(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) ironlake_edp_backlight_on(dev); - } } } intel_dp->dpms_mode = mode; -- cgit v1.2.3-59-g8ed1b From 9cce37f4855a30cc7c364edf18522282782f7ddc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 13 Aug 2010 15:11:26 -0700 Subject: drm/i915: fix VGA plane disable for Ironlake+ We need to use I/O port instructions to access VGA registers on Ironlake+, and it doesn't hurt on other platforms, so switch the VGA plane disable function over to using them. Move it to init time as well while we're at it, no need to repeatedly disable the VGA plane with every mode set and DPMS event. Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_display.c | 55 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 149c18b7c375..fbe42f0a315d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "drmP.h" #include "intel_drv.h" #include "i915_drm.h" @@ -1621,29 +1622,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -/* Disable the VGA plane that we never use */ -static void i915_disable_vga (struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u8 sr1; - u32 vga_reg; - - if (HAS_PCH_SPLIT(dev)) - vga_reg = CPU_VGACNTRL; - else - vga_reg = VGACNTRL; - - if (I915_READ(vga_reg) & VGA_DISP_DISABLE) - return; - - I915_WRITE8(VGA_SR_INDEX, 1); - sr1 = I915_READ8(VGA_SR_DATA); - I915_WRITE8(VGA_SR_DATA, sr1 | (1 << 5)); - udelay(100); - - I915_WRITE(vga_reg, VGA_DISP_DISABLE); -} - static void ironlake_disable_pll_edp (struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2156,8 +2134,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); - i915_disable_vga(dev); - /* disable cpu pipe, disable after all planes disabled */ temp = I915_READ(pipeconf_reg); if ((temp & PIPEACONF_ENABLE) != 0) { @@ -2391,9 +2367,6 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); - /* Disable the VGA plane that we never use */ - i915_disable_vga(dev); - /* Disable display plane */ temp = I915_READ(dspcntr_reg); if ((temp & DISPLAY_PLANE_ENABLE) != 0) { @@ -6002,6 +5975,29 @@ static void intel_init_quirks(struct drm_device *dev) } } +/* Disable the VGA plane that we never use */ +static void i915_disable_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u8 sr1; + u32 vga_reg; + + if (HAS_PCH_SPLIT(dev)) + vga_reg = CPU_VGACNTRL; + else + vga_reg = VGACNTRL; + + vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); + outb(1, VGA_SR_INDEX); + sr1 = inb(VGA_SR_DATA); + outb(sr1 | 1<<5, VGA_SR_DATA); + vga_put(dev->pdev, VGA_RSRC_LEGACY_IO); + udelay(300); + + I915_WRITE(vga_reg, VGA_DISP_DISABLE); + POSTING_READ(vga_reg); +} + void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -6050,6 +6046,9 @@ void intel_modeset_init(struct drm_device *dev) intel_init_clock_gating(dev); + /* Just disable it once at startup */ + i915_disable_vga(dev); + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); intel_init_emon(dev); -- cgit v1.2.3-59-g8ed1b From d240f20f545fa4ed78ce48d1eb62ab529f2b1467 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 13 Aug 2010 15:43:26 -0700 Subject: drm/i915: make sure eDP PLL is enabled at the right time We need to make sure the eDP PLL is enabled before the pipes or planes, so do it as part of the DP prepare mode set function. Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_display.c | 39 ++--------------------- drivers/gpu/drm/i915/intel_dp.c | 60 ++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fbe42f0a315d..14c45b1e8778 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1622,32 +1622,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void ironlake_disable_pll_edp (struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; - - DRM_DEBUG_KMS("\n"); - dpa_ctl = I915_READ(DP_A); - dpa_ctl &= ~DP_PLL_ENABLE; - I915_WRITE(DP_A, dpa_ctl); -} - -static void ironlake_enable_pll_edp (struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; - - dpa_ctl = I915_READ(DP_A); - dpa_ctl |= DP_PLL_ENABLE; - I915_WRITE(DP_A, dpa_ctl); - POSTING_READ(DP_A); - udelay(200); -} - - static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock) { struct drm_device *dev = crtc->dev; @@ -1940,10 +1914,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) } } - if (HAS_eDP) { - /* enable eDP PLL */ - ironlake_enable_pll_edp(crtc); - } else { + if (!HAS_eDP) { /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ temp = I915_READ(fdi_rx_reg); @@ -2242,10 +2213,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); I915_READ(pch_dpll_reg); - if (HAS_eDP) { - ironlake_disable_pll_edp(crtc); - } - /* Switch from PCDclk to Rawclk */ temp = I915_READ(fdi_rx_reg); temp &= ~FDI_SEL_PCDCLK; @@ -3930,9 +3897,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll_reg = pch_dpll_reg; } - if (is_edp) { - ironlake_disable_pll_edp(crtc); - } else if ((dpll & DPLL_VCO_ENABLE)) { + if (!is_edp) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); I915_READ(dpll_reg); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8061a48804a3..caaaa8f9db3e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -831,6 +831,60 @@ static void ironlake_edp_backlight_off (struct drm_device *dev) I915_WRITE(PCH_PP_CONTROL, pp); } +static void ironlake_edp_pll_on(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + DRM_DEBUG_KMS("\n"); + dpa_ctl = I915_READ(DP_A); + dpa_ctl &= ~DP_PLL_ENABLE; + I915_WRITE(DP_A, dpa_ctl); +} + +static void ironlake_edp_pll_off(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + dpa_ctl = I915_READ(DP_A); + dpa_ctl |= DP_PLL_ENABLE; + I915_WRITE(DP_A, dpa_ctl); + udelay(200); +} + +static void intel_dp_prepare(struct drm_encoder *encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dp_reg = I915_READ(intel_dp->output_reg); + + if (IS_eDP(intel_dp)) { + ironlake_edp_backlight_off(dev); + ironlake_edp_panel_on(dev); + ironlake_edp_pll_on(encoder); + } + if (dp_reg & DP_PORT_EN) + intel_dp_link_down(intel_dp); +} + +static void intel_dp_commit(struct drm_encoder *encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dp_reg = I915_READ(intel_dp->output_reg); + + if (!(dp_reg & DP_PORT_EN)) { + intel_dp_link_train(intel_dp); + } + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) + ironlake_edp_backlight_on(dev); +} + static void intel_dp_dpms(struct drm_encoder *encoder, int mode) { @@ -846,6 +900,8 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) } if (dp_reg & DP_PORT_EN) intel_dp_link_down(intel_dp); + if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) + ironlake_edp_pll_off(encoder); } else { if (!(dp_reg & DP_PORT_EN)) { if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) @@ -1427,9 +1483,9 @@ intel_dp_destroy (struct drm_connector *connector) static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { .dpms = intel_dp_dpms, .mode_fixup = intel_dp_mode_fixup, - .prepare = intel_encoder_prepare, + .prepare = intel_dp_prepare, .mode_set = intel_dp_mode_set, - .commit = intel_encoder_commit, + .commit = intel_dp_commit, }; static const struct drm_connector_funcs intel_dp_connector_funcs = { -- cgit v1.2.3-59-g8ed1b From 5db5584441c2dceb75696fb31a44ac7b9b925359 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 11 Aug 2010 19:11:19 -0700 Subject: drivers/net/wireless: Restore upper case words in wiphy_ messages Commit c96c31e499b70964cfc88744046c998bb710e4b8 "(drivers/net/wireless: Use wiphy_)" inadvertently changed some upper case words to lower case. Restore the original case. Signed-off-by: Joe Perches Signed-off-by: John W. Linville --- drivers/net/wireless/adm8211.c | 8 +++--- drivers/net/wireless/at76c50x-usb.c | 22 ++++++++--------- drivers/net/wireless/ath/ar9170/main.c | 4 +-- drivers/net/wireless/mac80211_hwsim.c | 2 +- drivers/net/wireless/mwl8k.c | 34 +++++++++++++------------- drivers/net/wireless/p54/eeprom.c | 6 ++--- drivers/net/wireless/p54/fwio.c | 2 +- drivers/net/wireless/p54/led.c | 4 +-- drivers/net/wireless/p54/p54pci.c | 2 +- drivers/net/wireless/p54/txrx.c | 2 +- drivers/net/wireless/rtl818x/rtl8180_dev.c | 6 ++--- drivers/net/wireless/rtl818x/rtl8187_dev.c | 4 +-- drivers/net/wireless/rtl818x/rtl8187_rtl8225.c | 4 +-- 13 files changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index a105087af963..f9aa1bc0a947 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -732,7 +732,7 @@ static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan) /* Nothing to do for ADMtek BBP */ } else if (priv->bbp_type != ADM8211_TYPE_ADMTEK) - wiphy_debug(dev->wiphy, "unsupported bbp type %d\n", + wiphy_debug(dev->wiphy, "unsupported BBP type %d\n", priv->bbp_type); ADM8211_RESTORE(); @@ -1032,7 +1032,7 @@ static int adm8211_hw_init_bbp(struct ieee80211_hw *dev) break; } } else - wiphy_debug(dev->wiphy, "unsupported bbp %d\n", priv->bbp_type); + wiphy_debug(dev->wiphy, "unsupported BBP %d\n", priv->bbp_type); ADM8211_CSR_WRITE(SYNRF, 0); @@ -1525,7 +1525,7 @@ static int adm8211_start(struct ieee80211_hw *dev) retval = request_irq(priv->pdev->irq, adm8211_interrupt, IRQF_SHARED, "adm8211", dev); if (retval) { - wiphy_err(dev->wiphy, "failed to register irq handler\n"); + wiphy_err(dev->wiphy, "failed to register IRQ handler\n"); goto fail; } @@ -1902,7 +1902,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_eeprom; } - wiphy_info(dev->wiphy, "hwaddr %pm, rev 0x%02x\n", + wiphy_info(dev->wiphy, "hwaddr %pM, Rev 0x%02x\n", dev->wiphy->perm_addr, pdev->revision); return 0; diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index d5140a87f073..1128fa8c9ed5 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -655,7 +655,7 @@ static int at76_get_hw_config(struct at76_priv *priv) exit: kfree(hwcfg); if (ret < 0) - wiphy_err(priv->hw->wiphy, "cannot get hw config (error %d)\n", + wiphy_err(priv->hw->wiphy, "cannot get HW Config (error %d)\n", ret); return ret; @@ -960,7 +960,7 @@ static void at76_dump_mib_mac_addr(struct at76_priv *priv) sizeof(struct mib_mac_addr)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac_addr) failed: %d\n", ret); + "at76_get_mib (MAC_ADDR) failed: %d\n", ret); goto exit; } @@ -989,7 +989,7 @@ static void at76_dump_mib_mac_wep(struct at76_priv *priv) sizeof(struct mib_mac_wep)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac_wep) failed: %d\n", ret); + "at76_get_mib (MAC_WEP) failed: %d\n", ret); goto exit; } @@ -1026,7 +1026,7 @@ static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) sizeof(struct mib_mac_mgmt)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac_mgmt) failed: %d\n", ret); + "at76_get_mib (MAC_MGMT) failed: %d\n", ret); goto exit; } @@ -1062,7 +1062,7 @@ static void at76_dump_mib_mac(struct at76_priv *priv) ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mac) failed: %d\n", ret); + "at76_get_mib (MAC) failed: %d\n", ret); goto exit; } @@ -1099,7 +1099,7 @@ static void at76_dump_mib_phy(struct at76_priv *priv) ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (phy) failed: %d\n", ret); + "at76_get_mib (PHY) failed: %d\n", ret); goto exit; } @@ -1132,7 +1132,7 @@ static void at76_dump_mib_local(struct at76_priv *priv) ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (local) failed: %d\n", ret); + "at76_get_mib (LOCAL) failed: %d\n", ret); goto exit; } @@ -1158,7 +1158,7 @@ static void at76_dump_mib_mdomain(struct at76_priv *priv) sizeof(struct mib_mdomain)); if (ret < 0) { wiphy_err(priv->hw->wiphy, - "at76_get_mib (mdomain) failed: %d\n", ret); + "at76_get_mib (MDOMAIN) failed: %d\n", ret); goto exit; } @@ -1229,7 +1229,7 @@ static int at76_submit_rx_urb(struct at76_priv *priv) struct sk_buff *skb = priv->rx_skb; if (!priv->rx_urb) { - wiphy_err(priv->hw->wiphy, "%s: priv->rx_urb is null\n", + wiphy_err(priv->hw->wiphy, "%s: priv->rx_urb is NULL\n", __func__); return -EFAULT; } @@ -1792,7 +1792,7 @@ static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) wiphy_err(priv->hw->wiphy, "error in tx submit urb: %d\n", ret); if (ret == -EINVAL) wiphy_err(priv->hw->wiphy, - "-einval: tx urb %p hcpriv %p complete %p\n", + "-EINVAL: tx urb %p hcpriv %p complete %p\n", priv->tx_urb, priv->tx_urb->hcpriv, priv->tx_urb->complete); } @@ -2310,7 +2310,7 @@ static int at76_init_new_device(struct at76_priv *priv, priv->mac80211_registered = 1; - wiphy_info(priv->hw->wiphy, "usb %s, mac %pm, firmware %d.%d.%d-%d\n", + wiphy_info(priv->hw->wiphy, "USB %s, MAC %pM, firmware %d.%d.%d-%d\n", dev_name(&interface->dev), priv->mac_addr, priv->fw_version.major, priv->fw_version.minor, priv->fw_version.patch, priv->fw_version.build); diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index c67b05f3bcbd..debfb0fbc7c5 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -245,7 +245,7 @@ static void __ar9170_dump_txstats(struct ar9170 *ar) { int i; - wiphy_debug(ar->hw->wiphy, "qos queue stats\n"); + wiphy_debug(ar->hw->wiphy, "QoS queue stats\n"); for (i = 0; i < __AR9170_NUM_TXQ; i++) wiphy_debug(ar->hw->wiphy, @@ -387,7 +387,7 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar, if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) { #ifdef AR9170_QUEUE_DEBUG wiphy_debug(ar->hw->wiphy, - "skip frame => da %pm != %pm\n", + "skip frame => DA %pM != %pM\n", mac, ieee80211_get_DA(hdr)); ar9170_print_txheader(ar, skb); #endif /* AR9170_QUEUE_DEBUG */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 01ad7f77383a..86fa8abdd66f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -486,7 +486,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct ieee80211_rx_status rx_status; if (data->idle) { - wiphy_debug(hw->wiphy, "trying to tx when idle - reject\n"); + wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); return false; } diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d761ed2d8af4..f152a25be59f 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -910,14 +910,14 @@ static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index) rxq->rxd = pci_alloc_consistent(priv->pdev, size, &rxq->rxd_dma); if (rxq->rxd == NULL) { - wiphy_err(hw->wiphy, "failed to alloc rx descriptors\n"); + wiphy_err(hw->wiphy, "failed to alloc RX descriptors\n"); return -ENOMEM; } memset(rxq->rxd, 0, size); rxq->buf = kmalloc(MWL8K_RX_DESCS * sizeof(*rxq->buf), GFP_KERNEL); if (rxq->buf == NULL) { - wiphy_err(hw->wiphy, "failed to alloc rx skbuff list\n"); + wiphy_err(hw->wiphy, "failed to alloc RX skbuff list\n"); pci_free_consistent(priv->pdev, size, rxq->rxd, rxq->rxd_dma); return -ENOMEM; } @@ -1145,14 +1145,14 @@ static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) txq->txd = pci_alloc_consistent(priv->pdev, size, &txq->txd_dma); if (txq->txd == NULL) { - wiphy_err(hw->wiphy, "failed to alloc tx descriptors\n"); + wiphy_err(hw->wiphy, "failed to alloc TX descriptors\n"); return -ENOMEM; } memset(txq->txd, 0, size); txq->skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->skb), GFP_KERNEL); if (txq->skb == NULL) { - wiphy_err(hw->wiphy, "failed to alloc tx skbuff list\n"); + wiphy_err(hw->wiphy, "failed to alloc TX skbuff list\n"); pci_free_consistent(priv->pdev, size, txq->txd, txq->txd_dma); return -ENOMEM; } @@ -1573,7 +1573,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) PCI_DMA_BIDIRECTIONAL); if (!timeout) { - wiphy_err(hw->wiphy, "command %s timeout after %u ms\n", + wiphy_err(hw->wiphy, "Command %s timeout after %u ms\n", mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), MWL8K_CMD_TIMEOUT_MS); rc = -ETIMEDOUT; @@ -1584,11 +1584,11 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) rc = cmd->result ? -EINVAL : 0; if (rc) - wiphy_err(hw->wiphy, "command %s error 0x%x\n", + wiphy_err(hw->wiphy, "Command %s error 0x%x\n", mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), le16_to_cpu(cmd->result)); else if (ms > 2000) - wiphy_notice(hw->wiphy, "command %s took %d ms\n", + wiphy_notice(hw->wiphy, "Command %s took %d ms\n", mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), ms); @@ -3210,7 +3210,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { - wiphy_err(hw->wiphy, "failed to register irq handler\n"); + wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); return -EIO; } @@ -3926,7 +3926,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, priv->sram = pci_iomap(pdev, 0, 0x10000); if (priv->sram == NULL) { - wiphy_err(hw->wiphy, "cannot map device sram\n"); + wiphy_err(hw->wiphy, "Cannot map device SRAM\n"); goto err_iounmap; } @@ -3938,7 +3938,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, if (priv->regs == NULL) { priv->regs = pci_iomap(pdev, 2, 0x10000); if (priv->regs == NULL) { - wiphy_err(hw->wiphy, "cannot map device registers\n"); + wiphy_err(hw->wiphy, "Cannot map device registers\n"); goto err_iounmap; } } @@ -3950,14 +3950,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Ask userland hotplug daemon for the device firmware */ rc = mwl8k_request_firmware(priv); if (rc) { - wiphy_err(hw->wiphy, "firmware files not found\n"); + wiphy_err(hw->wiphy, "Firmware files not found\n"); goto err_stop_firmware; } /* Load firmware into hardware */ rc = mwl8k_load_firmware(hw); if (rc) { - wiphy_err(hw->wiphy, "cannot start firmware\n"); + wiphy_err(hw->wiphy, "Cannot start firmware\n"); goto err_stop_firmware; } @@ -4047,7 +4047,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { - wiphy_err(hw->wiphy, "failed to register irq handler\n"); + wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); goto err_free_queues; } @@ -4067,7 +4067,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = mwl8k_cmd_get_hw_spec_sta(hw); } if (rc) { - wiphy_err(hw->wiphy, "cannot initialise firmware\n"); + wiphy_err(hw->wiphy, "Cannot initialise firmware\n"); goto err_free_irq; } @@ -4081,14 +4081,14 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, /* Turn radio off */ rc = mwl8k_cmd_radio_disable(hw); if (rc) { - wiphy_err(hw->wiphy, "cannot disable\n"); + wiphy_err(hw->wiphy, "Cannot disable\n"); goto err_free_irq; } /* Clear MAC address */ rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); if (rc) { - wiphy_err(hw->wiphy, "cannot clear mac address\n"); + wiphy_err(hw->wiphy, "Cannot clear MAC address\n"); goto err_free_irq; } @@ -4098,7 +4098,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, rc = ieee80211_register_hw(hw); if (rc) { - wiphy_err(hw->wiphy, "cannot register device\n"); + wiphy_err(hw->wiphy, "Cannot register device\n"); goto err_free_queues; } diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index d687cb7f2a59..78347041ec40 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -167,7 +167,7 @@ static int p54_generate_band(struct ieee80211_hw *dev, } if (j == 0) { - wiphy_err(dev->wiphy, "disabling totally damaged %d GHz band\n", + wiphy_err(dev->wiphy, "Disabling totally damaged %d GHz band\n", (band == IEEE80211_BAND_2GHZ) ? 2 : 5); ret = -ENODATA; @@ -695,12 +695,12 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) u8 perm_addr[ETH_ALEN]; wiphy_warn(dev->wiphy, - "invalid hwaddr! using randomly generated mac addr\n"); + "Invalid hwaddr! Using randomly generated MAC addr\n"); random_ether_addr(perm_addr); SET_IEEE80211_PERM_ADDR(dev, perm_addr); } - wiphy_info(dev->wiphy, "hwaddr %pm, mac:isl38%02x rf:%s\n", + wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n", dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 47006bca4852..15b20c29a604 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -125,7 +125,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (fw_version) wiphy_info(priv->hw->wiphy, - "fw rev %s - softmac protocol %x.%x\n", + "FW rev %s - Softmac protocol %x.%x\n", fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); if (priv->fw_var < 0x500) diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c index ea91f5cce6b3..3837e1eec5f4 100644 --- a/drivers/net/wireless/p54/led.c +++ b/drivers/net/wireless/p54/led.c @@ -58,7 +58,7 @@ static void p54_update_leds(struct work_struct *work) err = p54_set_leds(priv); if (err && net_ratelimit()) wiphy_err(priv->hw->wiphy, - "failed to update leds (%d).\n", err); + "failed to update LEDs (%d).\n", err); if (rerun) ieee80211_queue_delayed_work(priv->hw, &priv->led_work, @@ -103,7 +103,7 @@ static int p54_register_led(struct p54_common *priv, err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev); if (err) wiphy_err(priv->hw->wiphy, - "failed to register %s led.\n", name); + "Failed to register %s LED.\n", name); else led->registered = 1; diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 822f8dc26e9c..1eacba4daa5b 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -466,7 +466,7 @@ static int p54p_open(struct ieee80211_hw *dev) P54P_READ(dev_int); if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { - wiphy_err(dev->wiphy, "cannot boot firmware!\n"); + wiphy_err(dev->wiphy, "Cannot boot firmware!\n"); p54p_stop(dev); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 427b46f558ed..173aec3d6e7e 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -540,7 +540,7 @@ static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) case P54_TRAP_BEACON_TX: break; case P54_TRAP_RADAR: - wiphy_info(priv->hw->wiphy, "radar (freq:%d mhz)\n", freq); + wiphy_info(priv->hw->wiphy, "radar (freq:%d MHz)\n", freq); break; case P54_TRAP_NO_BEACON: if (priv->vif) diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c index b50c39aaec05..30107ce78dfb 100644 --- a/drivers/net/wireless/rtl818x/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -445,7 +445,7 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) &priv->rx_ring_dma); if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { - wiphy_err(dev->wiphy, "cannot allocate rx ring\n"); + wiphy_err(dev->wiphy, "Cannot allocate RX ring\n"); return -ENOMEM; } @@ -502,7 +502,7 @@ static int rtl8180_init_tx_ring(struct ieee80211_hw *dev, ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); if (!ring || (unsigned long)ring & 0xFF) { - wiphy_err(dev->wiphy, "cannot allocate tx ring (prio = %d)\n", + wiphy_err(dev->wiphy, "Cannot allocate TX ring (prio = %d)\n", prio); return -ENOMEM; } @@ -568,7 +568,7 @@ static int rtl8180_start(struct ieee80211_hw *dev) ret = request_irq(priv->pdev->irq, rtl8180_interrupt, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) { - wiphy_err(dev->wiphy, "failed to register irq handler\n"); + wiphy_err(dev->wiphy, "failed to register IRQ handler\n"); goto err_free_rings; } diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 5738a55c1b06..98e0351c1dd6 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -573,7 +573,7 @@ static int rtl8187_cmd_reset(struct ieee80211_hw *dev) } while (--i); if (!i) { - wiphy_err(dev->wiphy, "reset timeout!\n"); + wiphy_err(dev->wiphy, "Reset timeout!\n"); return -ETIMEDOUT; } @@ -1526,7 +1526,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, mutex_init(&priv->conf_mutex); skb_queue_head_init(&priv->b_tx_status.queue); - wiphy_info(dev->wiphy, "hwaddr %pm, %s v%d + %s, rfkill mask %d\n", + wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n", mac_addr, chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask); diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index fd96f9112322..97eebdcf7eb9 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -366,7 +366,7 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) rtl8225_write(dev, 0x02, 0x044d); msleep(100); if (!(rtl8225_read(dev, 6) & (1 << 7))) - wiphy_warn(dev->wiphy, "rf calibration failed! %x\n", + wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n", rtl8225_read(dev, 6)); } @@ -735,7 +735,7 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) rtl8225_write(dev, 0x02, 0x044D); msleep(100); if (!(rtl8225_read(dev, 6) & (1 << 7))) - wiphy_warn(dev->wiphy, "rf calibration failed! %x\n", + wiphy_warn(dev->wiphy, "RF Calibration Failed! %x\n", rtl8225_read(dev, 6)); } -- cgit v1.2.3-59-g8ed1b From 6a017e043a8c5e4f1e7c1152bc6477da8066f5f6 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 18 Aug 2010 12:53:28 -0700 Subject: iwlwifi: use long monitor timer for 5300 series For 5000 series of devices, use long monitor timer to check stuck tx queues. This modification apply to all the 5000 series including 5300 and others. Cc: stable@kernel.org [2.6.35] Reported-by: drago01 Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 0cbefa3d1e45..48bdcd8d2e94 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -663,7 +663,7 @@ struct iwl_cfg iwl5150_agn_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, @@ -693,7 +693,7 @@ struct iwl_cfg iwl5150_abg_cfg = { .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, - .monitor_recover_period = IWL_DEF_MONITORING_PERIOD, + .monitor_recover_period = IWL_LONG_MONITORING_PERIOD, .max_event_log_size = 512, .ucode_tracing = true, .sensitivity_calib_by_driver = true, -- cgit v1.2.3-59-g8ed1b From 6ec274750c99448c3412bbc10c97ce0c993f8a4e Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 18 Aug 2010 08:03:37 +0000 Subject: sparc64: simple microoptimizations for atomic functions Simple microoptimizations for sparc64 atomic functions: Save one instruction by using a delay slot. Use %g1 instead of %g7, because %g1 is written earlier. Signed-off-by: Mikulas Patocka Signed-off-by: David S. Miller --- arch/sparc/lib/atomic_64.S | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 0268210ca168..703c9c3935b7 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -52,10 +52,9 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ cas [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %icc, 2f - add %g7, %o0, %g7 - sra %g7, 0, %o0 + add %g1, %o0, %g1 retl - nop + sra %g1, 0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic_add_ret, .-atomic_add_ret @@ -68,10 +67,9 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ cas [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %icc, 2f - sub %g7, %o0, %g7 - sra %g7, 0, %o0 + sub %g1, %o0, %g1 retl - nop + sra %g1, 0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic_sub_ret, .-atomic_sub_ret @@ -114,10 +112,9 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ casx [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %xcc, 2f - add %g7, %o0, %g7 - mov %g7, %o0 - retl nop + retl + add %g1, %o0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic64_add_ret, .-atomic64_add_ret @@ -130,9 +127,8 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ casx [%o1], %g1, %g7 cmp %g1, %g7 bne,pn %xcc, 2f - sub %g7, %o0, %g7 - mov %g7, %o0 - retl nop + retl + sub %g1, %o0, %o0 2: BACKOFF_SPIN(%o2, %o3, 1b) .size atomic64_sub_ret, .-atomic64_sub_ret -- cgit v1.2.3-59-g8ed1b From 0f58189d4a3ca96d7959501ecb203177efdbc5bd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 18 Aug 2010 22:53:26 -0700 Subject: sparc64: Make lock backoff really a NOP on UP builds. As noticed by Mikulas Patocka, the backoff macros don't completely nop out for UP builds, we still get a branch always and a delay slot nop. Fix this by making the branch to the backoff spin loop selective, then we can nop out the spin loop completely. Signed-off-by: David S. Miller --- arch/sparc/include/asm/backoff.h | 11 ++++++++--- arch/sparc/lib/atomic_64.S | 16 ++++++++-------- arch/sparc/lib/bitops.S | 12 ++++++------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/arch/sparc/include/asm/backoff.h b/arch/sparc/include/asm/backoff.h index fa1fdf67e350..db3af0d30fb1 100644 --- a/arch/sparc/include/asm/backoff.h +++ b/arch/sparc/include/asm/backoff.h @@ -8,6 +8,9 @@ #define BACKOFF_SETUP(reg) \ mov 1, reg +#define BACKOFF_LABEL(spin_label, continue_label) \ + spin_label + #define BACKOFF_SPIN(reg, tmp, label) \ mov reg, tmp; \ 88: brnz,pt tmp, 88b; \ @@ -22,9 +25,11 @@ #else #define BACKOFF_SETUP(reg) -#define BACKOFF_SPIN(reg, tmp, label) \ - ba,pt %xcc, label; \ - nop; + +#define BACKOFF_LABEL(spin_label, continue_label) \ + continue_label + +#define BACKOFF_SPIN(reg, tmp, label) #endif diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 703c9c3935b7..59186e0fcf39 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -21,7 +21,7 @@ atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -36,7 +36,7 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -51,7 +51,7 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) add %g1, %o0, %g1 retl sra %g1, 0, %o0 @@ -66,7 +66,7 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 cas [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %icc, 2f + bne,pn %icc, BACKOFF_LABEL(2f, 1b) sub %g1, %o0, %g1 retl sra %g1, 0, %o0 @@ -81,7 +81,7 @@ atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -96,7 +96,7 @@ atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -111,7 +111,7 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ add %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl add %g1, %o0, %o0 @@ -126,7 +126,7 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ sub %g1, %o0, %g7 casx [%o1], %g1, %g7 cmp %g1, %g7 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl sub %g1, %o0, %o0 diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S index 2b7228cb8c22..3dc61d5537c0 100644 --- a/arch/sparc/lib/bitops.S +++ b/arch/sparc/lib/bitops.S @@ -22,7 +22,7 @@ test_and_set_bit: /* %o0=nr, %o1=addr */ or %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -45,7 +45,7 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */ andn %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -68,7 +68,7 @@ test_and_change_bit: /* %o0=nr, %o1=addr */ xor %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) and %g7, %o2, %g2 clr %o0 movrne %g2, 1, %o0 @@ -91,7 +91,7 @@ set_bit: /* %o0=nr, %o1=addr */ or %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -112,7 +112,7 @@ clear_bit: /* %o0=nr, %o1=addr */ andn %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop @@ -133,7 +133,7 @@ change_bit: /* %o0=nr, %o1=addr */ xor %g7, %o2, %g1 casx [%o1], %g7, %g1 cmp %g7, %g1 - bne,pn %xcc, 2f + bne,pn %xcc, BACKOFF_LABEL(2f, 1b) nop retl nop -- cgit v1.2.3-59-g8ed1b From 4d8ec5f3b65dd64fa785192dc7ab2807916a05b2 Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Thu, 19 Aug 2010 08:06:16 +0200 Subject: ALSA: hda - Add support for IDT 92HD89XX codecs Just added new codec ids. These are almost compatible with existing ones. Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f3f861bd1bf8..95148e58026c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -6303,6 +6303,21 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, + { .id = 0x111d76c0, .name = "92HD89C3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c1, .name = "92HD89C2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c2, .name = "92HD89C1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c3, .name = "92HD89B3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c4, .name = "92HD89B2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c5, .name = "92HD89B1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c6, .name = "92HD89E3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c7, .name = "92HD89E2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c8, .name = "92HD89E1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76c9, .name = "92HD89D3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76ca, .name = "92HD89D2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cb, .name = "92HD89D1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx }, + { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, + { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, {} /* terminator */ }; -- cgit v1.2.3-59-g8ed1b From 274714f55c023c683a6b2deedfb2209a9457f4ec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Aug 2010 08:11:53 +0200 Subject: ALSA: hda - Fix build error with CONFIG_PROC_FS=n hdmi_eld_update_pcm_info() must be always compiled in. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 803b298f7411..26c3ade73583 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -596,6 +596,8 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) } EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); +#endif /* CONFIG_PROC_FS */ + /* update PCM info based on ELD */ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, struct hda_pcm_stream *codec_pars) @@ -644,5 +646,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); } EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info); - -#endif /* CONFIG_PROC_FS */ -- cgit v1.2.3-59-g8ed1b From 9c77b846ec8b4e0c7107dd7f820172462dc84a61 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Wed, 18 Aug 2010 19:33:43 -0400 Subject: ALSA: intel8x0: Mute External Amplifier by default for ThinkPad X31 BugLink: https://bugs.launchpad.net/bugs/619439 This ThinkPad model needs External Amplifier muted for audible playback, so set the inv_eapd quirk for it. Reported-and-tested-by: Dennis Bell Cc: Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6433e65c9507..467749249576 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1774,6 +1774,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "HP/Compaq nx7010", .type = AC97_TUNE_MUTE_LED }, + { + .subvendor = 0x1014, + .subdevice = 0x0534, + .name = "ThinkPad X31", + .type = AC97_TUNE_INV_EAPD + }, { .subvendor = 0x1014, .subdevice = 0x1f00, -- cgit v1.2.3-59-g8ed1b From a49f37eed22b74221f271811ea41323654e40dad Mon Sep 17 00:00:00 2001 From: Sachin Sanap Date: Fri, 13 Aug 2010 21:22:49 +0000 Subject: net: add Fast Ethernet driver for PXA168. Signed-off-by: Sachin Sanap Signed-off-by: David S. Miller --- drivers/net/Kconfig | 10 + drivers/net/Makefile | 1 + drivers/net/pxa168_eth.c | 1666 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/pxa168_eth.h | 30 + 4 files changed, 1707 insertions(+) create mode 100644 drivers/net/pxa168_eth.c create mode 100644 include/linux/pxa168_eth.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ebe68395ecf8..fe581566cb26 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -928,6 +928,16 @@ config SMC91X The module will be called smc91x. If you want to compile it as a module, say M here and read . +config PXA168_ETH + tristate "Marvell pxa168 ethernet support" + depends on CPU_PXA168 + select PHYLIB + help + This driver supports the pxa168 Ethernet ports. + + To compile this driver as a module, choose M here. The module + will be called pxa168_eth. + config NET_NETX tristate "NetX Ethernet support" select MII diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 56e8c27f77ce..3e8f150c4b14 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -244,6 +244,7 @@ obj-$(CONFIG_MYRI10GE) += myri10ge/ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_SMSC911X) += smsc911x.o +obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c new file mode 100644 index 000000000000..ecc64d750cce --- /dev/null +++ b/drivers/net/pxa168_eth.c @@ -0,0 +1,1666 @@ +/* + * PXA168 ethernet driver. + * Most of the code is derived from mv643xx ethernet driver. + * + * Copyright (C) 2010 Marvell International Ltd. + * Sachin Sanap + * Philip Rakity + * Mark Brown + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "pxa168-eth" +#define DRIVER_VERSION "0.3" + +/* + * Registers + */ + +#define PHY_ADDRESS 0x0000 +#define SMI 0x0010 +#define PORT_CONFIG 0x0400 +#define PORT_CONFIG_EXT 0x0408 +#define PORT_COMMAND 0x0410 +#define PORT_STATUS 0x0418 +#define HTPR 0x0428 +#define SDMA_CONFIG 0x0440 +#define SDMA_CMD 0x0448 +#define INT_CAUSE 0x0450 +#define INT_W_CLEAR 0x0454 +#define INT_MASK 0x0458 +#define ETH_F_RX_DESC_0 0x0480 +#define ETH_C_RX_DESC_0 0x04A0 +#define ETH_C_TX_DESC_1 0x04E4 + +/* smi register */ +#define SMI_BUSY (1 << 28) /* 0 - Write, 1 - Read */ +#define SMI_R_VALID (1 << 27) /* 0 - Write, 1 - Read */ +#define SMI_OP_W (0 << 26) /* Write operation */ +#define SMI_OP_R (1 << 26) /* Read operation */ + +#define PHY_WAIT_ITERATIONS 10 + +#define PXA168_ETH_PHY_ADDR_DEFAULT 0 +/* RX & TX descriptor command */ +#define BUF_OWNED_BY_DMA (1 << 31) + +/* RX descriptor status */ +#define RX_EN_INT (1 << 23) +#define RX_FIRST_DESC (1 << 17) +#define RX_LAST_DESC (1 << 16) +#define RX_ERROR (1 << 15) + +/* TX descriptor command */ +#define TX_EN_INT (1 << 23) +#define TX_GEN_CRC (1 << 22) +#define TX_ZERO_PADDING (1 << 18) +#define TX_FIRST_DESC (1 << 17) +#define TX_LAST_DESC (1 << 16) +#define TX_ERROR (1 << 15) + +/* SDMA_CMD */ +#define SDMA_CMD_AT (1 << 31) +#define SDMA_CMD_TXDL (1 << 24) +#define SDMA_CMD_TXDH (1 << 23) +#define SDMA_CMD_AR (1 << 15) +#define SDMA_CMD_ERD (1 << 7) + +/* Bit definitions of the Port Config Reg */ +#define PCR_HS (1 << 12) +#define PCR_EN (1 << 7) +#define PCR_PM (1 << 0) + +/* Bit definitions of the Port Config Extend Reg */ +#define PCXR_2BSM (1 << 28) +#define PCXR_DSCP_EN (1 << 21) +#define PCXR_MFL_1518 (0 << 14) +#define PCXR_MFL_1536 (1 << 14) +#define PCXR_MFL_2048 (2 << 14) +#define PCXR_MFL_64K (3 << 14) +#define PCXR_FLP (1 << 11) +#define PCXR_PRIO_TX_OFF 3 +#define PCXR_TX_HIGH_PRI (7 << PCXR_PRIO_TX_OFF) + +/* Bit definitions of the SDMA Config Reg */ +#define SDCR_BSZ_OFF 12 +#define SDCR_BSZ8 (3 << SDCR_BSZ_OFF) +#define SDCR_BSZ4 (2 << SDCR_BSZ_OFF) +#define SDCR_BSZ2 (1 << SDCR_BSZ_OFF) +#define SDCR_BSZ1 (0 << SDCR_BSZ_OFF) +#define SDCR_BLMR (1 << 6) +#define SDCR_BLMT (1 << 7) +#define SDCR_RIFB (1 << 9) +#define SDCR_RC_OFF 2 +#define SDCR_RC_MAX_RETRANS (0xf << SDCR_RC_OFF) + +/* + * Bit definitions of the Interrupt Cause Reg + * and Interrupt MASK Reg is the same + */ +#define ICR_RXBUF (1 << 0) +#define ICR_TXBUF_H (1 << 2) +#define ICR_TXBUF_L (1 << 3) +#define ICR_TXEND_H (1 << 6) +#define ICR_TXEND_L (1 << 7) +#define ICR_RXERR (1 << 8) +#define ICR_TXERR_H (1 << 10) +#define ICR_TXERR_L (1 << 11) +#define ICR_TX_UDR (1 << 13) +#define ICR_MII_CH (1 << 28) + +#define ALL_INTS (ICR_TXBUF_H | ICR_TXBUF_L | ICR_TX_UDR |\ + ICR_TXERR_H | ICR_TXERR_L |\ + ICR_TXEND_H | ICR_TXEND_L |\ + ICR_RXBUF | ICR_RXERR | ICR_MII_CH) + +#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */ + +#define NUM_RX_DESCS 64 +#define NUM_TX_DESCS 64 + +#define HASH_ADD 0 +#define HASH_DELETE 1 +#define HASH_ADDR_TABLE_SIZE 0x4000 /* 16K (1/2K address - PCR_HS == 1) */ +#define HOP_NUMBER 12 + +/* Bit definitions for Port status */ +#define PORT_SPEED_100 (1 << 0) +#define FULL_DUPLEX (1 << 1) +#define FLOW_CONTROL_ENABLED (1 << 2) +#define LINK_UP (1 << 3) + +/* Bit definitions for work to be done */ +#define WORK_LINK (1 << 0) +#define WORK_TX_DONE (1 << 1) + +/* + * Misc definitions. + */ +#define SKB_DMA_REALIGN ((PAGE_SIZE - NET_SKB_PAD) % SMP_CACHE_BYTES) + +struct rx_desc { + u32 cmd_sts; /* Descriptor command status */ + u16 byte_cnt; /* Descriptor buffer byte count */ + u16 buf_size; /* Buffer size */ + u32 buf_ptr; /* Descriptor buffer pointer */ + u32 next_desc_ptr; /* Next descriptor pointer */ +}; + +struct tx_desc { + u32 cmd_sts; /* Command/status field */ + u16 reserved; + u16 byte_cnt; /* buffer byte count */ + u32 buf_ptr; /* pointer to buffer for this descriptor */ + u32 next_desc_ptr; /* Pointer to next descriptor */ +}; + +struct pxa168_eth_private { + int port_num; /* User Ethernet port number */ + + int rx_resource_err; /* Rx ring resource error flag */ + + /* Next available and first returning Rx resource */ + int rx_curr_desc_q, rx_used_desc_q; + + /* Next available and first returning Tx resource */ + int tx_curr_desc_q, tx_used_desc_q; + + struct rx_desc *p_rx_desc_area; + dma_addr_t rx_desc_dma; + int rx_desc_area_size; + struct sk_buff **rx_skb; + + struct tx_desc *p_tx_desc_area; + dma_addr_t tx_desc_dma; + int tx_desc_area_size; + struct sk_buff **tx_skb; + + struct work_struct tx_timeout_task; + + struct net_device *dev; + struct napi_struct napi; + u8 work_todo; + int skb_size; + + struct net_device_stats stats; + /* Size of Tx Ring per queue */ + int tx_ring_size; + /* Number of tx descriptors in use */ + int tx_desc_count; + /* Size of Rx Ring per queue */ + int rx_ring_size; + /* Number of rx descriptors in use */ + int rx_desc_count; + + /* + * Used in case RX Ring is empty, which can occur when + * system does not have resources (skb's) + */ + struct timer_list timeout; + struct mii_bus *smi_bus; + struct phy_device *phy; + + /* clock */ + struct clk *clk; + struct pxa168_eth_platform_data *pd; + /* + * Ethernet controller base address. + */ + void __iomem *base; + + /* Pointer to the hardware address filter table */ + void *htpr; + dma_addr_t htpr_dma; +}; + +struct addr_table_entry { + __le32 lo; + __le32 hi; +}; + +/* Bit fields of a Hash Table Entry */ +enum hash_table_entry { + HASH_ENTRY_VALID = 1, + SKIP = 2, + HASH_ENTRY_RECEIVE_DISCARD = 4, + HASH_ENTRY_RECEIVE_DISCARD_BIT = 2 +}; + +static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); +static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd); +static int pxa168_init_hw(struct pxa168_eth_private *pep); +static void eth_port_reset(struct net_device *dev); +static void eth_port_start(struct net_device *dev); +static int pxa168_eth_open(struct net_device *dev); +static int pxa168_eth_stop(struct net_device *dev); +static int ethernet_phy_setup(struct net_device *dev); + +static inline u32 rdl(struct pxa168_eth_private *pep, int offset) +{ + return readl(pep->base + offset); +} + +static inline void wrl(struct pxa168_eth_private *pep, int offset, u32 data) +{ + writel(data, pep->base + offset); +} + +static void abort_dma(struct pxa168_eth_private *pep) +{ + int delay; + int max_retries = 40; + + do { + wrl(pep, SDMA_CMD, SDMA_CMD_AR | SDMA_CMD_AT); + udelay(100); + + delay = 10; + while ((rdl(pep, SDMA_CMD) & (SDMA_CMD_AR | SDMA_CMD_AT)) + && delay-- > 0) { + udelay(10); + } + } while (max_retries-- > 0 && delay <= 0); + + if (max_retries <= 0) + printk(KERN_ERR "%s : DMA Stuck\n", __func__); +} + +static int ethernet_phy_get(struct pxa168_eth_private *pep) +{ + unsigned int reg_data; + + reg_data = rdl(pep, PHY_ADDRESS); + + return (reg_data >> (5 * pep->port_num)) & 0x1f; +} + +static void ethernet_phy_set_addr(struct pxa168_eth_private *pep, int phy_addr) +{ + u32 reg_data; + int addr_shift = 5 * pep->port_num; + + reg_data = rdl(pep, PHY_ADDRESS); + reg_data &= ~(0x1f << addr_shift); + reg_data |= (phy_addr & 0x1f) << addr_shift; + wrl(pep, PHY_ADDRESS, reg_data); +} + +static void ethernet_phy_reset(struct pxa168_eth_private *pep) +{ + int data; + + data = phy_read(pep->phy, MII_BMCR); + if (data < 0) + return; + + data |= BMCR_RESET; + if (phy_write(pep->phy, MII_BMCR, data) < 0) + return; + + do { + data = phy_read(pep->phy, MII_BMCR); + } while (data >= 0 && data & BMCR_RESET); +} + +static void rxq_refill(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct sk_buff *skb; + struct rx_desc *p_used_rx_desc; + int used_rx_desc; + + while (pep->rx_desc_count < pep->rx_ring_size) { + int size; + + skb = dev_alloc_skb(pep->skb_size); + if (!skb) + break; + if (SKB_DMA_REALIGN) + skb_reserve(skb, SKB_DMA_REALIGN); + pep->rx_desc_count++; + /* Get 'used' Rx descriptor */ + used_rx_desc = pep->rx_used_desc_q; + p_used_rx_desc = &pep->p_rx_desc_area[used_rx_desc]; + size = skb->end - skb->data; + p_used_rx_desc->buf_ptr = dma_map_single(NULL, + skb->data, + size, + DMA_FROM_DEVICE); + p_used_rx_desc->buf_size = size; + pep->rx_skb[used_rx_desc] = skb; + + /* Return the descriptor to DMA ownership */ + wmb(); + p_used_rx_desc->cmd_sts = BUF_OWNED_BY_DMA | RX_EN_INT; + wmb(); + + /* Move the used descriptor pointer to the next descriptor */ + pep->rx_used_desc_q = (used_rx_desc + 1) % pep->rx_ring_size; + + /* Any Rx return cancels the Rx resource error status */ + pep->rx_resource_err = 0; + + skb_reserve(skb, ETH_HW_IP_ALIGN); + } + + /* + * If RX ring is empty of SKB, set a timer to try allocating + * again at a later time. + */ + if (pep->rx_desc_count == 0) { + pep->timeout.expires = jiffies + (HZ / 10); + add_timer(&pep->timeout); + } +} + +static inline void rxq_refill_timer_wrapper(unsigned long data) +{ + struct pxa168_eth_private *pep = (void *)data; + napi_schedule(&pep->napi); +} + +static inline u8 flip_8_bits(u8 x) +{ + return (((x) & 0x01) << 3) | (((x) & 0x02) << 1) + | (((x) & 0x04) >> 1) | (((x) & 0x08) >> 3) + | (((x) & 0x10) << 3) | (((x) & 0x20) << 1) + | (((x) & 0x40) >> 1) | (((x) & 0x80) >> 3); +} + +static void nibble_swap_every_byte(unsigned char *mac_addr) +{ + int i; + for (i = 0; i < ETH_ALEN; i++) { + mac_addr[i] = ((mac_addr[i] & 0x0f) << 4) | + ((mac_addr[i] & 0xf0) >> 4); + } +} + +static void inverse_every_nibble(unsigned char *mac_addr) +{ + int i; + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = flip_8_bits(mac_addr[i]); +} + +/* + * ---------------------------------------------------------------------------- + * This function will calculate the hash function of the address. + * Inputs + * mac_addr_orig - MAC address. + * Outputs + * return the calculated entry. + */ +static u32 hash_function(unsigned char *mac_addr_orig) +{ + u32 hash_result; + u32 addr0; + u32 addr1; + u32 addr2; + u32 addr3; + unsigned char mac_addr[ETH_ALEN]; + + /* Make a copy of MAC address since we are going to performe bit + * operations on it + */ + memcpy(mac_addr, mac_addr_orig, ETH_ALEN); + + nibble_swap_every_byte(mac_addr); + inverse_every_nibble(mac_addr); + + addr0 = (mac_addr[5] >> 2) & 0x3f; + addr1 = (mac_addr[5] & 0x03) | (((mac_addr[4] & 0x7f)) << 2); + addr2 = ((mac_addr[4] & 0x80) >> 7) | mac_addr[3] << 1; + addr3 = (mac_addr[2] & 0xff) | ((mac_addr[1] & 1) << 8); + + hash_result = (addr0 << 9) | (addr1 ^ addr2 ^ addr3); + hash_result = hash_result & 0x07ff; + return hash_result; +} + +/* + * ---------------------------------------------------------------------------- + * This function will add/del an entry to the address table. + * Inputs + * pep - ETHERNET . + * mac_addr - MAC address. + * skip - if 1, skip this address.Used in case of deleting an entry which is a + * part of chain in the hash table.We cant just delete the entry since + * that will break the chain.We need to defragment the tables time to + * time. + * rd - 0 Discard packet upon match. + * - 1 Receive packet upon match. + * Outputs + * address table entry is added/deleted. + * 0 if success. + * -ENOSPC if table full + */ +static int add_del_hash_entry(struct pxa168_eth_private *pep, + unsigned char *mac_addr, + u32 rd, u32 skip, int del) +{ + struct addr_table_entry *entry, *start; + u32 new_high; + u32 new_low; + u32 i; + + new_low = (((mac_addr[1] >> 4) & 0xf) << 15) + | (((mac_addr[1] >> 0) & 0xf) << 11) + | (((mac_addr[0] >> 4) & 0xf) << 7) + | (((mac_addr[0] >> 0) & 0xf) << 3) + | (((mac_addr[3] >> 4) & 0x1) << 31) + | (((mac_addr[3] >> 0) & 0xf) << 27) + | (((mac_addr[2] >> 4) & 0xf) << 23) + | (((mac_addr[2] >> 0) & 0xf) << 19) + | (skip << SKIP) | (rd << HASH_ENTRY_RECEIVE_DISCARD_BIT) + | HASH_ENTRY_VALID; + + new_high = (((mac_addr[5] >> 4) & 0xf) << 15) + | (((mac_addr[5] >> 0) & 0xf) << 11) + | (((mac_addr[4] >> 4) & 0xf) << 7) + | (((mac_addr[4] >> 0) & 0xf) << 3) + | (((mac_addr[3] >> 5) & 0x7) << 0); + + /* + * Pick the appropriate table, start scanning for free/reusable + * entries at the index obtained by hashing the specified MAC address + */ + start = (struct addr_table_entry *)(pep->htpr); + entry = start + hash_function(mac_addr); + for (i = 0; i < HOP_NUMBER; i++) { + if (!(le32_to_cpu(entry->lo) & HASH_ENTRY_VALID)) { + break; + } else { + /* if same address put in same position */ + if (((le32_to_cpu(entry->lo) & 0xfffffff8) == + (new_low & 0xfffffff8)) && + (le32_to_cpu(entry->hi) == new_high)) { + break; + } + } + if (entry == start + 0x7ff) + entry = start; + else + entry++; + } + + if (((le32_to_cpu(entry->lo) & 0xfffffff8) != (new_low & 0xfffffff8)) && + (le32_to_cpu(entry->hi) != new_high) && del) + return 0; + + if (i == HOP_NUMBER) { + if (!del) { + printk(KERN_INFO "%s: table section is full, need to " + "move to 16kB implementation?\n", + __FILE__); + return -ENOSPC; + } else + return 0; + } + + /* + * Update the selected entry + */ + if (del) { + entry->hi = 0; + entry->lo = 0; + } else { + entry->hi = cpu_to_le32(new_high); + entry->lo = cpu_to_le32(new_low); + } + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * Create an addressTable entry from MAC address info + * found in the specifed net_device struct + * + * Input : pointer to ethernet interface network device structure + * Output : N/A + */ +static void update_hash_table_mac_address(struct pxa168_eth_private *pep, + unsigned char *oaddr, + unsigned char *addr) +{ + /* Delete old entry */ + if (oaddr) + add_del_hash_entry(pep, oaddr, 1, 0, HASH_DELETE); + /* Add new entry */ + add_del_hash_entry(pep, addr, 1, 0, HASH_ADD); +} + +static int init_hash_table(struct pxa168_eth_private *pep) +{ + /* + * Hardware expects CPU to build a hash table based on a predefined + * hash function and populate it based on hardware address. The + * location of the hash table is identified by 32-bit pointer stored + * in HTPR internal register. Two possible sizes exists for the hash + * table 8kB (256kB of DRAM required (4 x 64 kB banks)) and 1/2kB + * (16kB of DRAM required (4 x 4 kB banks)).We currently only support + * 1/2kB. + */ + /* TODO: Add support for 8kB hash table and alternative hash + * function.Driver can dynamically switch to them if the 1/2kB hash + * table is full. + */ + if (pep->htpr == NULL) { + pep->htpr = dma_alloc_coherent(pep->dev->dev.parent, + HASH_ADDR_TABLE_SIZE, + &pep->htpr_dma, GFP_KERNEL); + if (pep->htpr == NULL) + return -ENOMEM; + } + memset(pep->htpr, 0, HASH_ADDR_TABLE_SIZE); + wrl(pep, HTPR, pep->htpr_dma); + return 0; +} + +static void pxa168_eth_set_rx_mode(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct netdev_hw_addr *ha; + u32 val; + + val = rdl(pep, PORT_CONFIG); + if (dev->flags & IFF_PROMISC) + val |= PCR_PM; + else + val &= ~PCR_PM; + wrl(pep, PORT_CONFIG, val); + + /* + * Remove the old list of MAC address and add dev->addr + * and multicast address. + */ + memset(pep->htpr, 0, HASH_ADDR_TABLE_SIZE); + update_hash_table_mac_address(pep, NULL, dev->dev_addr); + + netdev_for_each_mc_addr(ha, dev) + update_hash_table_mac_address(pep, NULL, ha->addr); +} + +static int pxa168_eth_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sa = addr; + struct pxa168_eth_private *pep = netdev_priv(dev); + unsigned char oldMac[ETH_ALEN]; + + if (!is_valid_ether_addr(sa->sa_data)) + return -EINVAL; + memcpy(oldMac, dev->dev_addr, ETH_ALEN); + memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); + netif_addr_lock_bh(dev); + update_hash_table_mac_address(pep, oldMac, dev->dev_addr); + netif_addr_unlock_bh(dev); + return 0; +} + +static void eth_port_start(struct net_device *dev) +{ + unsigned int val = 0; + struct pxa168_eth_private *pep = netdev_priv(dev); + int tx_curr_desc, rx_curr_desc; + + /* Perform PHY reset, if there is a PHY. */ + if (pep->phy != NULL) { + struct ethtool_cmd cmd; + + pxa168_get_settings(pep->dev, &cmd); + ethernet_phy_reset(pep); + pxa168_set_settings(pep->dev, &cmd); + } + + /* Assignment of Tx CTRP of given queue */ + tx_curr_desc = pep->tx_curr_desc_q; + wrl(pep, ETH_C_TX_DESC_1, + (u32) ((struct tx_desc *)pep->tx_desc_dma + tx_curr_desc)); + + /* Assignment of Rx CRDP of given queue */ + rx_curr_desc = pep->rx_curr_desc_q; + wrl(pep, ETH_C_RX_DESC_0, + (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc)); + + wrl(pep, ETH_F_RX_DESC_0, + (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc)); + + /* Clear all interrupts */ + wrl(pep, INT_CAUSE, 0); + + /* Enable all interrupts for receive, transmit and error. */ + wrl(pep, INT_MASK, ALL_INTS); + + val = rdl(pep, PORT_CONFIG); + val |= PCR_EN; + wrl(pep, PORT_CONFIG, val); + + /* Start RX DMA engine */ + val = rdl(pep, SDMA_CMD); + val |= SDMA_CMD_ERD; + wrl(pep, SDMA_CMD, val); +} + +static void eth_port_reset(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + unsigned int val = 0; + + /* Stop all interrupts for receive, transmit and error. */ + wrl(pep, INT_MASK, 0); + + /* Clear all interrupts */ + wrl(pep, INT_CAUSE, 0); + + /* Stop RX DMA */ + val = rdl(pep, SDMA_CMD); + val &= ~SDMA_CMD_ERD; /* abort dma command */ + + /* Abort any transmit and receive operations and put DMA + * in idle state. + */ + abort_dma(pep); + + /* Disable port */ + val = rdl(pep, PORT_CONFIG); + val &= ~PCR_EN; + wrl(pep, PORT_CONFIG, val); +} + +/* + * txq_reclaim - Free the tx desc data for completed descriptors + * If force is non-zero, frees uncompleted descriptors as well + */ +static int txq_reclaim(struct net_device *dev, int force) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct tx_desc *desc; + u32 cmd_sts; + struct sk_buff *skb; + int tx_index; + dma_addr_t addr; + int count; + int released = 0; + + netif_tx_lock(dev); + + pep->work_todo &= ~WORK_TX_DONE; + while (pep->tx_desc_count > 0) { + tx_index = pep->tx_used_desc_q; + desc = &pep->p_tx_desc_area[tx_index]; + cmd_sts = desc->cmd_sts; + if (!force && (cmd_sts & BUF_OWNED_BY_DMA)) { + if (released > 0) { + goto txq_reclaim_end; + } else { + released = -1; + goto txq_reclaim_end; + } + } + pep->tx_used_desc_q = (tx_index + 1) % pep->tx_ring_size; + pep->tx_desc_count--; + addr = desc->buf_ptr; + count = desc->byte_cnt; + skb = pep->tx_skb[tx_index]; + if (skb) + pep->tx_skb[tx_index] = NULL; + + if (cmd_sts & TX_ERROR) { + if (net_ratelimit()) + printk(KERN_ERR "%s: Error in TX\n", dev->name); + dev->stats.tx_errors++; + } + dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE); + if (skb) + dev_kfree_skb_irq(skb); + released++; + } +txq_reclaim_end: + netif_tx_unlock(dev); + return released; +} + +static void pxa168_eth_tx_timeout(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + printk(KERN_INFO "%s: TX timeout desc_count %d\n", + dev->name, pep->tx_desc_count); + + schedule_work(&pep->tx_timeout_task); +} + +static void pxa168_eth_tx_timeout_task(struct work_struct *work) +{ + struct pxa168_eth_private *pep = container_of(work, + struct pxa168_eth_private, + tx_timeout_task); + struct net_device *dev = pep->dev; + pxa168_eth_stop(dev); + pxa168_eth_open(dev); +} + +static int rxq_process(struct net_device *dev, int budget) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + unsigned int received_packets = 0; + struct sk_buff *skb; + + while (budget-- > 0) { + int rx_next_curr_desc, rx_curr_desc, rx_used_desc; + struct rx_desc *rx_desc; + unsigned int cmd_sts; + + /* Do not process Rx ring in case of Rx ring resource error */ + if (pep->rx_resource_err) + break; + rx_curr_desc = pep->rx_curr_desc_q; + rx_used_desc = pep->rx_used_desc_q; + rx_desc = &pep->p_rx_desc_area[rx_curr_desc]; + cmd_sts = rx_desc->cmd_sts; + rmb(); + if (cmd_sts & (BUF_OWNED_BY_DMA)) + break; + skb = pep->rx_skb[rx_curr_desc]; + pep->rx_skb[rx_curr_desc] = NULL; + + rx_next_curr_desc = (rx_curr_desc + 1) % pep->rx_ring_size; + pep->rx_curr_desc_q = rx_next_curr_desc; + + /* Rx descriptors exhausted. */ + /* Set the Rx ring resource error flag */ + if (rx_next_curr_desc == rx_used_desc) + pep->rx_resource_err = 1; + pep->rx_desc_count--; + dma_unmap_single(NULL, rx_desc->buf_ptr, + rx_desc->buf_size, + DMA_FROM_DEVICE); + received_packets++; + /* + * Update statistics. + * Note byte count includes 4 byte CRC count + */ + stats->rx_packets++; + stats->rx_bytes += rx_desc->byte_cnt; + /* + * In case received a packet without first / last bits on OR + * the error summary bit is on, the packets needs to be droped. + */ + if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) + || (cmd_sts & RX_ERROR)) { + + stats->rx_dropped++; + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) { + if (net_ratelimit()) + printk(KERN_ERR + "%s: Rx pkt on multiple desc\n", + dev->name); + } + if (cmd_sts & RX_ERROR) + stats->rx_errors++; + dev_kfree_skb_irq(skb); + } else { + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, rx_desc->byte_cnt - 4); + skb->protocol = eth_type_trans(skb, dev); + netif_receive_skb(skb); + } + dev->last_rx = jiffies; + } + /* Fill RX ring with skb's */ + rxq_refill(dev); + return received_packets; +} + +static int pxa168_eth_collect_events(struct pxa168_eth_private *pep, + struct net_device *dev) +{ + u32 icr; + int ret = 0; + + icr = rdl(pep, INT_CAUSE); + if (icr == 0) + return IRQ_NONE; + + wrl(pep, INT_CAUSE, ~icr); + if (icr & (ICR_TXBUF_H | ICR_TXBUF_L)) { + pep->work_todo |= WORK_TX_DONE; + ret = 1; + } + if (icr & ICR_RXBUF) + ret = 1; + if (icr & ICR_MII_CH) { + pep->work_todo |= WORK_LINK; + ret = 1; + } + return ret; +} + +static void handle_link_event(struct pxa168_eth_private *pep) +{ + struct net_device *dev = pep->dev; + u32 port_status; + int speed; + int duplex; + int fc; + + port_status = rdl(pep, PORT_STATUS); + if (!(port_status & LINK_UP)) { + if (netif_carrier_ok(dev)) { + printk(KERN_INFO "%s: link down\n", dev->name); + netif_carrier_off(dev); + txq_reclaim(dev, 1); + } + return; + } + if (port_status & PORT_SPEED_100) + speed = 100; + else + speed = 10; + + duplex = (port_status & FULL_DUPLEX) ? 1 : 0; + fc = (port_status & FLOW_CONTROL_ENABLED) ? 1 : 0; + printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, " + "flow control %sabled\n", dev->name, + speed, duplex ? "full" : "half", fc ? "en" : "dis"); + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); +} + +static irqreturn_t pxa168_eth_int_handler(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct pxa168_eth_private *pep = netdev_priv(dev); + + if (unlikely(!pxa168_eth_collect_events(pep, dev))) + return IRQ_NONE; + /* Disable interrupts */ + wrl(pep, INT_MASK, 0); + napi_schedule(&pep->napi); + return IRQ_HANDLED; +} + +static void pxa168_eth_recalc_skb_size(struct pxa168_eth_private *pep) +{ + int skb_size; + + /* + * Reserve 2+14 bytes for an ethernet header (the hardware + * automatically prepends 2 bytes of dummy data to each + * received packet), 16 bytes for up to four VLAN tags, and + * 4 bytes for the trailing FCS -- 36 bytes total. + */ + skb_size = pep->dev->mtu + 36; + + /* + * Make sure that the skb size is a multiple of 8 bytes, as + * the lower three bits of the receive descriptor's buffer + * size field are ignored by the hardware. + */ + pep->skb_size = (skb_size + 7) & ~7; + + /* + * If NET_SKB_PAD is smaller than a cache line, + * netdev_alloc_skb() will cause skb->data to be misaligned + * to a cache line boundary. If this is the case, include + * some extra space to allow re-aligning the data area. + */ + pep->skb_size += SKB_DMA_REALIGN; + +} + +static int set_port_config_ext(struct pxa168_eth_private *pep) +{ + int skb_size; + + pxa168_eth_recalc_skb_size(pep); + if (pep->skb_size <= 1518) + skb_size = PCXR_MFL_1518; + else if (pep->skb_size <= 1536) + skb_size = PCXR_MFL_1536; + else if (pep->skb_size <= 2048) + skb_size = PCXR_MFL_2048; + else + skb_size = PCXR_MFL_64K; + + /* Extended Port Configuration */ + wrl(pep, + PORT_CONFIG_EXT, PCXR_2BSM | /* Two byte prefix aligns IP hdr */ + PCXR_DSCP_EN | /* Enable DSCP in IP */ + skb_size | PCXR_FLP | /* do not force link pass */ + PCXR_TX_HIGH_PRI); /* Transmit - high priority queue */ + + return 0; +} + +static int pxa168_init_hw(struct pxa168_eth_private *pep) +{ + int err = 0; + + /* Disable interrupts */ + wrl(pep, INT_MASK, 0); + wrl(pep, INT_CAUSE, 0); + /* Write to ICR to clear interrupts. */ + wrl(pep, INT_W_CLEAR, 0); + /* Abort any transmit and receive operations and put DMA + * in idle state. + */ + abort_dma(pep); + /* Initialize address hash table */ + err = init_hash_table(pep); + if (err) + return err; + /* SDMA configuration */ + wrl(pep, SDMA_CONFIG, SDCR_BSZ8 | /* Burst size = 32 bytes */ + SDCR_RIFB | /* Rx interrupt on frame */ + SDCR_BLMT | /* Little endian transmit */ + SDCR_BLMR | /* Little endian receive */ + SDCR_RC_MAX_RETRANS); /* Max retransmit count */ + /* Port Configuration */ + wrl(pep, PORT_CONFIG, PCR_HS); /* Hash size is 1/2kb */ + set_port_config_ext(pep); + + return err; +} + +static int rxq_init(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct rx_desc *p_rx_desc; + int size = 0, i = 0; + int rx_desc_num = pep->rx_ring_size; + + /* Allocate RX skb rings */ + pep->rx_skb = kmalloc(sizeof(*pep->rx_skb) * pep->rx_ring_size, + GFP_KERNEL); + if (!pep->rx_skb) { + printk(KERN_ERR "%s: Cannot alloc RX skb ring\n", dev->name); + return -ENOMEM; + } + /* Allocate RX ring */ + pep->rx_desc_count = 0; + size = pep->rx_ring_size * sizeof(struct rx_desc); + pep->rx_desc_area_size = size; + pep->p_rx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, + &pep->rx_desc_dma, GFP_KERNEL); + if (!pep->p_rx_desc_area) { + printk(KERN_ERR "%s: Cannot alloc RX ring (size %d bytes)\n", + dev->name, size); + goto out; + } + memset((void *)pep->p_rx_desc_area, 0, size); + /* initialize the next_desc_ptr links in the Rx descriptors ring */ + p_rx_desc = (struct rx_desc *)pep->p_rx_desc_area; + for (i = 0; i < rx_desc_num; i++) { + p_rx_desc[i].next_desc_ptr = pep->rx_desc_dma + + ((i + 1) % rx_desc_num) * sizeof(struct rx_desc); + } + /* Save Rx desc pointer to driver struct. */ + pep->rx_curr_desc_q = 0; + pep->rx_used_desc_q = 0; + pep->rx_desc_area_size = rx_desc_num * sizeof(struct rx_desc); + return 0; +out: + kfree(pep->rx_skb); + return -ENOMEM; +} + +static void rxq_deinit(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + int curr; + + /* Free preallocated skb's on RX rings */ + for (curr = 0; pep->rx_desc_count && curr < pep->rx_ring_size; curr++) { + if (pep->rx_skb[curr]) { + dev_kfree_skb(pep->rx_skb[curr]); + pep->rx_desc_count--; + } + } + if (pep->rx_desc_count) + printk(KERN_ERR + "Error in freeing Rx Ring. %d skb's still\n", + pep->rx_desc_count); + /* Free RX ring */ + if (pep->p_rx_desc_area) + dma_free_coherent(pep->dev->dev.parent, pep->rx_desc_area_size, + pep->p_rx_desc_area, pep->rx_desc_dma); + kfree(pep->rx_skb); +} + +static int txq_init(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct tx_desc *p_tx_desc; + int size = 0, i = 0; + int tx_desc_num = pep->tx_ring_size; + + pep->tx_skb = kmalloc(sizeof(*pep->tx_skb) * pep->tx_ring_size, + GFP_KERNEL); + if (!pep->tx_skb) { + printk(KERN_ERR "%s: Cannot alloc TX skb ring\n", dev->name); + return -ENOMEM; + } + /* Allocate TX ring */ + pep->tx_desc_count = 0; + size = pep->tx_ring_size * sizeof(struct tx_desc); + pep->tx_desc_area_size = size; + pep->p_tx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, + &pep->tx_desc_dma, GFP_KERNEL); + if (!pep->p_tx_desc_area) { + printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n", + dev->name, size); + goto out; + } + memset((void *)pep->p_tx_desc_area, 0, pep->tx_desc_area_size); + /* Initialize the next_desc_ptr links in the Tx descriptors ring */ + p_tx_desc = (struct tx_desc *)pep->p_tx_desc_area; + for (i = 0; i < tx_desc_num; i++) { + p_tx_desc[i].next_desc_ptr = pep->tx_desc_dma + + ((i + 1) % tx_desc_num) * sizeof(struct tx_desc); + } + pep->tx_curr_desc_q = 0; + pep->tx_used_desc_q = 0; + pep->tx_desc_area_size = tx_desc_num * sizeof(struct tx_desc); + return 0; +out: + kfree(pep->tx_skb); + return -ENOMEM; +} + +static void txq_deinit(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + /* Free outstanding skb's on TX ring */ + txq_reclaim(dev, 1); + BUG_ON(pep->tx_used_desc_q != pep->tx_curr_desc_q); + /* Free TX ring */ + if (pep->p_tx_desc_area) + dma_free_coherent(pep->dev->dev.parent, pep->tx_desc_area_size, + pep->p_tx_desc_area, pep->tx_desc_dma); + kfree(pep->tx_skb); +} + +static int pxa168_eth_open(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + int err; + + err = request_irq(dev->irq, pxa168_eth_int_handler, + IRQF_DISABLED, dev->name, dev); + if (err) { + dev_printk(KERN_ERR, &dev->dev, "can't assign irq\n"); + return -EAGAIN; + } + pep->rx_resource_err = 0; + err = rxq_init(dev); + if (err != 0) + goto out_free_irq; + err = txq_init(dev); + if (err != 0) + goto out_free_rx_skb; + pep->rx_used_desc_q = 0; + pep->rx_curr_desc_q = 0; + + /* Fill RX ring with skb's */ + rxq_refill(dev); + pep->rx_used_desc_q = 0; + pep->rx_curr_desc_q = 0; + netif_carrier_off(dev); + eth_port_start(dev); + napi_enable(&pep->napi); + return 0; +out_free_rx_skb: + rxq_deinit(dev); +out_free_irq: + free_irq(dev->irq, dev); + return err; +} + +static int pxa168_eth_stop(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + eth_port_reset(dev); + + /* Disable interrupts */ + wrl(pep, INT_MASK, 0); + wrl(pep, INT_CAUSE, 0); + /* Write to ICR to clear interrupts. */ + wrl(pep, INT_W_CLEAR, 0); + napi_disable(&pep->napi); + del_timer_sync(&pep->timeout); + netif_carrier_off(dev); + free_irq(dev->irq, dev); + rxq_deinit(dev); + txq_deinit(dev); + + return 0; +} + +static int pxa168_eth_change_mtu(struct net_device *dev, int mtu) +{ + int retval; + struct pxa168_eth_private *pep = netdev_priv(dev); + + if ((mtu > 9500) || (mtu < 68)) + return -EINVAL; + + dev->mtu = mtu; + retval = set_port_config_ext(pep); + + if (!netif_running(dev)) + return 0; + + /* + * Stop and then re-open the interface. This will allocate RX + * skbs of the new MTU. + * There is a possible danger that the open will not succeed, + * due to memory being full. + */ + pxa168_eth_stop(dev); + if (pxa168_eth_open(dev)) { + dev_printk(KERN_ERR, &dev->dev, + "fatal error on re-opening device after " + "MTU change\n"); + } + + return 0; +} + +static int eth_alloc_tx_desc_index(struct pxa168_eth_private *pep) +{ + int tx_desc_curr; + + tx_desc_curr = pep->tx_curr_desc_q; + pep->tx_curr_desc_q = (tx_desc_curr + 1) % pep->tx_ring_size; + BUG_ON(pep->tx_curr_desc_q == pep->tx_used_desc_q); + pep->tx_desc_count++; + + return tx_desc_curr; +} + +static int pxa168_rx_poll(struct napi_struct *napi, int budget) +{ + struct pxa168_eth_private *pep = + container_of(napi, struct pxa168_eth_private, napi); + struct net_device *dev = pep->dev; + int work_done = 0; + + if (unlikely(pep->work_todo & WORK_LINK)) { + pep->work_todo &= ~(WORK_LINK); + handle_link_event(pep); + } + /* + * We call txq_reclaim every time since in NAPI interupts are disabled + * and due to this we miss the TX_DONE interrupt,which is not updated in + * interrupt status register. + */ + txq_reclaim(dev, 0); + if (netif_queue_stopped(dev) + && pep->tx_ring_size - pep->tx_desc_count > 1) { + netif_wake_queue(dev); + } + work_done = rxq_process(dev, budget); + if (work_done < budget) { + napi_complete(napi); + wrl(pep, INT_MASK, ALL_INTS); + } + + return work_done; +} + +static int pxa168_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct tx_desc *desc; + int tx_index; + int length; + + tx_index = eth_alloc_tx_desc_index(pep); + desc = &pep->p_tx_desc_area[tx_index]; + length = skb->len; + pep->tx_skb[tx_index] = skb; + desc->byte_cnt = length; + desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); + wmb(); + desc->cmd_sts = BUF_OWNED_BY_DMA | TX_GEN_CRC | TX_FIRST_DESC | + TX_ZERO_PADDING | TX_LAST_DESC | TX_EN_INT; + wmb(); + wrl(pep, SDMA_CMD, SDMA_CMD_TXDH | SDMA_CMD_ERD); + + stats->tx_bytes += skb->len; + stats->tx_packets++; + dev->trans_start = jiffies; + if (pep->tx_ring_size - pep->tx_desc_count <= 1) { + /* We handled the current skb, but now we are out of space.*/ + netif_stop_queue(dev); + } + + return NETDEV_TX_OK; +} + +static int smi_wait_ready(struct pxa168_eth_private *pep) +{ + int i = 0; + + /* wait for the SMI register to become available */ + for (i = 0; rdl(pep, SMI) & SMI_BUSY; i++) { + if (i == PHY_WAIT_ITERATIONS) + return -ETIMEDOUT; + msleep(10); + } + + return 0; +} + +static int pxa168_smi_read(struct mii_bus *bus, int phy_addr, int regnum) +{ + struct pxa168_eth_private *pep = bus->priv; + int i = 0; + int val; + + if (smi_wait_ready(pep)) { + printk(KERN_WARNING "pxa168_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; + } + wrl(pep, SMI, (phy_addr << 16) | (regnum << 21) | SMI_OP_R); + /* now wait for the data to be valid */ + for (i = 0; !((val = rdl(pep, SMI)) & SMI_R_VALID); i++) { + if (i == PHY_WAIT_ITERATIONS) { + printk(KERN_WARNING + "pxa168_eth: SMI bus read not valid\n"); + return -ENODEV; + } + msleep(10); + } + + return val & 0xffff; +} + +static int pxa168_smi_write(struct mii_bus *bus, int phy_addr, int regnum, + u16 value) +{ + struct pxa168_eth_private *pep = bus->priv; + + if (smi_wait_ready(pep)) { + printk(KERN_WARNING "pxa168_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; + } + + wrl(pep, SMI, (phy_addr << 16) | (regnum << 21) | + SMI_OP_W | (value & 0xffff)); + + if (smi_wait_ready(pep)) { + printk(KERN_ERR "pxa168_eth: SMI bus busy timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int pxa168_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, + int cmd) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + if (pep->phy != NULL) + return phy_mii_ioctl(pep->phy, if_mii(ifr), cmd); + + return -EOPNOTSUPP; +} + +static struct phy_device *phy_scan(struct pxa168_eth_private *pep, int phy_addr) +{ + struct mii_bus *bus = pep->smi_bus; + struct phy_device *phydev; + int start; + int num; + int i; + + if (phy_addr == PXA168_ETH_PHY_ADDR_DEFAULT) { + /* Scan entire range */ + start = ethernet_phy_get(pep); + num = 32; + } else { + /* Use phy addr specific to platform */ + start = phy_addr & 0x1f; + num = 1; + } + phydev = NULL; + for (i = 0; i < num; i++) { + int addr = (start + i) & 0x1f; + if (bus->phy_map[addr] == NULL) + mdiobus_scan(bus, addr); + + if (phydev == NULL) { + phydev = bus->phy_map[addr]; + if (phydev != NULL) + ethernet_phy_set_addr(pep, addr); + } + } + + return phydev; +} + +static void phy_init(struct pxa168_eth_private *pep, int speed, int duplex) +{ + struct phy_device *phy = pep->phy; + ethernet_phy_reset(pep); + + phy_attach(pep->dev, dev_name(&phy->dev), 0, PHY_INTERFACE_MODE_MII); + + if (speed == 0) { + phy->autoneg = AUTONEG_ENABLE; + phy->speed = 0; + phy->duplex = 0; + phy->supported &= PHY_BASIC_FEATURES; + phy->advertising = phy->supported | ADVERTISED_Autoneg; + } else { + phy->autoneg = AUTONEG_DISABLE; + phy->advertising = 0; + phy->speed = speed; + phy->duplex = duplex; + } + phy_start_aneg(phy); +} + +static int ethernet_phy_setup(struct net_device *dev) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + if (pep->pd != NULL) { + if (pep->pd->init) + pep->pd->init(); + } + pep->phy = phy_scan(pep, pep->pd->phy_addr & 0x1f); + if (pep->phy != NULL) + phy_init(pep, pep->pd->speed, pep->pd->duplex); + update_hash_table_mac_address(pep, NULL, dev->dev_addr); + + return 0; +} + +static int pxa168_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + int err; + + err = phy_read_status(pep->phy); + if (err == 0) + err = phy_ethtool_gset(pep->phy, cmd); + + return err; +} + +static int pxa168_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct pxa168_eth_private *pep = netdev_priv(dev); + + return phy_ethtool_sset(pep->phy, cmd); +} + +static void pxa168_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strncpy(info->driver, DRIVER_NAME, 32); + strncpy(info->version, DRIVER_VERSION, 32); + strncpy(info->fw_version, "N/A", 32); + strncpy(info->bus_info, "N/A", 32); +} + +static u32 pxa168_get_link(struct net_device *dev) +{ + return !!netif_carrier_ok(dev); +} + +static const struct ethtool_ops pxa168_ethtool_ops = { + .get_settings = pxa168_get_settings, + .set_settings = pxa168_set_settings, + .get_drvinfo = pxa168_get_drvinfo, + .get_link = pxa168_get_link, +}; + +static const struct net_device_ops pxa168_eth_netdev_ops = { + .ndo_open = pxa168_eth_open, + .ndo_stop = pxa168_eth_stop, + .ndo_start_xmit = pxa168_eth_start_xmit, + .ndo_set_rx_mode = pxa168_eth_set_rx_mode, + .ndo_set_mac_address = pxa168_eth_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = pxa168_eth_do_ioctl, + .ndo_change_mtu = pxa168_eth_change_mtu, + .ndo_tx_timeout = pxa168_eth_tx_timeout, +}; + +static int pxa168_eth_probe(struct platform_device *pdev) +{ + struct pxa168_eth_private *pep = NULL; + struct net_device *dev = NULL; + struct resource *res; + struct clk *clk; + int err; + + printk(KERN_NOTICE "PXA168 10/100 Ethernet Driver\n"); + + clk = clk_get(&pdev->dev, "MFUCLK"); + if (IS_ERR(clk)) { + printk(KERN_ERR "%s: Fast Ethernet failed to get clock\n", + DRIVER_NAME); + return -ENODEV; + } + clk_enable(clk); + + dev = alloc_etherdev(sizeof(struct pxa168_eth_private)); + if (!dev) { + err = -ENOMEM; + goto out; + } + + platform_set_drvdata(pdev, dev); + pep = netdev_priv(dev); + pep->dev = dev; + pep->clk = clk; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + err = -ENODEV; + goto out; + } + pep->base = ioremap(res->start, res->end - res->start + 1); + if (pep->base == NULL) { + err = -ENOMEM; + goto out; + } + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + BUG_ON(!res); + dev->irq = res->start; + dev->netdev_ops = &pxa168_eth_netdev_ops; + dev->watchdog_timeo = 2 * HZ; + dev->base_addr = 0; + SET_ETHTOOL_OPS(dev, &pxa168_ethtool_ops); + + INIT_WORK(&pep->tx_timeout_task, pxa168_eth_tx_timeout_task); + + printk(KERN_INFO "%s:Using random mac address\n", DRIVER_NAME); + random_ether_addr(dev->dev_addr); + + pep->pd = pdev->dev.platform_data; + pep->rx_ring_size = NUM_RX_DESCS; + if (pep->pd->rx_queue_size) + pep->rx_ring_size = pep->pd->rx_queue_size; + + pep->tx_ring_size = NUM_TX_DESCS; + if (pep->pd->tx_queue_size) + pep->tx_ring_size = pep->pd->tx_queue_size; + + pep->port_num = pep->pd->port_number; + /* Hardware supports only 3 ports */ + BUG_ON(pep->port_num > 2); + netif_napi_add(dev, &pep->napi, pxa168_rx_poll, pep->rx_ring_size); + + memset(&pep->timeout, 0, sizeof(struct timer_list)); + init_timer(&pep->timeout); + pep->timeout.function = rxq_refill_timer_wrapper; + pep->timeout.data = (unsigned long)pep; + + pep->smi_bus = mdiobus_alloc(); + if (pep->smi_bus == NULL) { + err = -ENOMEM; + goto out; + } + pep->smi_bus->priv = pep; + pep->smi_bus->name = "pxa168_eth smi"; + pep->smi_bus->read = pxa168_smi_read; + pep->smi_bus->write = pxa168_smi_write; + snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id); + pep->smi_bus->parent = &pdev->dev; + pep->smi_bus->phy_mask = 0xffffffff; + if (mdiobus_register(pep->smi_bus) < 0) { + err = -ENOMEM; + goto out; + } + pxa168_init_hw(pep); + err = ethernet_phy_setup(dev); + if (err) + goto out; + SET_NETDEV_DEV(dev, &pdev->dev); + err = register_netdev(dev); + if (err) + goto out; + return 0; +out: + if (pep->clk) { + clk_disable(pep->clk); + clk_put(pep->clk); + pep->clk = NULL; + } + if (pep->base) { + iounmap(pep->base); + pep->base = NULL; + } + if (dev) + free_netdev(dev); + return err; +} + +static int pxa168_eth_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct pxa168_eth_private *pep = netdev_priv(dev); + + if (pep->htpr) { + dma_free_coherent(pep->dev->dev.parent, HASH_ADDR_TABLE_SIZE, + pep->htpr, pep->htpr_dma); + pep->htpr = NULL; + } + if (pep->clk) { + clk_disable(pep->clk); + clk_put(pep->clk); + pep->clk = NULL; + } + if (pep->phy != NULL) + phy_detach(pep->phy); + + iounmap(pep->base); + pep->base = NULL; + unregister_netdev(dev); + flush_scheduled_work(); + free_netdev(dev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static void pxa168_eth_shutdown(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + eth_port_reset(dev); +} + +#ifdef CONFIG_PM +static int pxa168_eth_resume(struct platform_device *pdev) +{ + return -ENOSYS; +} + +static int pxa168_eth_suspend(struct platform_device *pdev, pm_message_t state) +{ + return -ENOSYS; +} + +#else +#define pxa168_eth_resume NULL +#define pxa168_eth_suspend NULL +#endif + +static struct platform_driver pxa168_eth_driver = { + .probe = pxa168_eth_probe, + .remove = pxa168_eth_remove, + .shutdown = pxa168_eth_shutdown, + .resume = pxa168_eth_resume, + .suspend = pxa168_eth_suspend, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init pxa168_init_module(void) +{ + return platform_driver_register(&pxa168_eth_driver); +} + +static void __exit pxa168_cleanup_module(void) +{ + platform_driver_unregister(&pxa168_eth_driver); +} + +module_init(pxa168_init_module); +module_exit(pxa168_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Ethernet driver for Marvell PXA168"); +MODULE_ALIAS("platform:pxa168_eth"); diff --git a/include/linux/pxa168_eth.h b/include/linux/pxa168_eth.h new file mode 100644 index 000000000000..18d75e795606 --- /dev/null +++ b/include/linux/pxa168_eth.h @@ -0,0 +1,30 @@ +/* + *pxa168 ethernet platform device data definition file. + */ +#ifndef __LINUX_PXA168_ETH_H +#define __LINUX_PXA168_ETH_H + +struct pxa168_eth_platform_data { + int port_number; + int phy_addr; + + /* + * If speed is 0, then speed and duplex are autonegotiated. + */ + int speed; /* 0, SPEED_10, SPEED_100 */ + int duplex; /* DUPLEX_HALF or DUPLEX_FULL */ + + /* + * Override default RX/TX queue sizes if nonzero. + */ + int rx_queue_size; + int tx_queue_size; + + /* + * init callback is used for board specific initialization + * e.g on Aspenite its used to initialize the PHY transceiver. + */ + int (*init)(void); +}; + +#endif /* __LINUX_PXA168_ETH_H */ -- cgit v1.2.3-59-g8ed1b From e243f5b6de35b6fc394bc2e1e1737afe538e7e0c Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sun, 15 Aug 2010 10:03:57 +0000 Subject: netfilter: fix userspace header warning "make headers_check" issued the following warning: CHECK include/linux/netfilter (64 files) usr/include/linux/netfilter/xt_ipvs.h:19: found __[us]{8,16,32,64} type without #include Fix this by as suggested including linux/types.h. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- include/linux/netfilter/xt_ipvs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/netfilter/xt_ipvs.h b/include/linux/netfilter/xt_ipvs.h index 1167aeb7a347..eff34ac18808 100644 --- a/include/linux/netfilter/xt_ipvs.h +++ b/include/linux/netfilter/xt_ipvs.h @@ -1,6 +1,8 @@ #ifndef _XT_IPVS_H #define _XT_IPVS_H +#include + enum { XT_IPVS_IPVS_PROPERTY = 1 << 0, /* all other options imply this one */ XT_IPVS_PROTO = 1 << 1, -- cgit v1.2.3-59-g8ed1b From 68d6ac6d2740b6a55f3ae92a4e0be6d881904b32 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 15 Aug 2010 21:20:44 +0000 Subject: netlink: fix compat recvmsg Since commit 1dacc76d0014a034b8aca14237c127d7c19d7726 Author: Johannes Berg Date: Wed Jul 1 11:26:02 2009 +0000 net/compat/wext: send different messages to compat tasks we had a race condition when setting and then restoring frag_list. Eric attempted to fix it, but the fix created even worse problems. However, the original motivation I had when I added the code that turned out to be racy is no longer clear to me, since we only copy up to skb->len to userspace, which doesn't include the frag_list length. As a result, not doing any frag_list clearing and restoring avoids the race condition, while not introducing any other problems. Additionally, while preparing this patch I found that since none of the remaining netlink code is really aware of the frag_list, we need to use the original skb's information for packet information and credentials. This fixes, for example, the group information received by compat tasks. Cc: Eric Dumazet Cc: stable@kernel.org [2.6.31+, for 2.6.35 revert 1235f504aa] Signed-off-by: Johannes Berg Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8648a9922aab..980fe4ad0016 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1406,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, struct netlink_sock *nlk = nlk_sk(sk); int noblock = flags&MSG_DONTWAIT; size_t copied; - struct sk_buff *skb, *frag __maybe_unused = NULL; + struct sk_buff *skb, *data_skb; int err; if (flags&MSG_OOB) @@ -1418,45 +1418,35 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, if (skb == NULL) goto out; + data_skb = skb; + #ifdef CONFIG_COMPAT_NETLINK_MESSAGES if (unlikely(skb_shinfo(skb)->frag_list)) { - bool need_compat = !!(flags & MSG_CMSG_COMPAT); - /* - * If this skb has a frag_list, then here that means that - * we will have to use the frag_list skb for compat tasks - * and the regular skb for non-compat tasks. + * If this skb has a frag_list, then here that means that we + * will have to use the frag_list skb's data for compat tasks + * and the regular skb's data for normal (non-compat) tasks. * - * The skb might (and likely will) be cloned, so we can't - * just reset frag_list and go on with things -- we need to - * keep that. For the compat case that's easy -- simply get - * a reference to the compat skb and free the regular one - * including the frag. For the non-compat case, we need to - * avoid sending the frag to the user -- so assign NULL but - * restore it below before freeing the skb. + * If we need to send the compat skb, assign it to the + * 'data_skb' variable so that it will be used below for data + * copying. We keep 'skb' for everything else, including + * freeing both later. */ - if (need_compat) { - struct sk_buff *compskb = skb_shinfo(skb)->frag_list; - skb_get(compskb); - kfree_skb(skb); - skb = compskb; - } else { - frag = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = NULL; - } + if (flags & MSG_CMSG_COMPAT) + data_skb = skb_shinfo(skb)->frag_list; } #endif msg->msg_namelen = 0; - copied = skb->len; + copied = data_skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; copied = len; } - skb_reset_transport_header(skb); - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + skb_reset_transport_header(data_skb); + err = skb_copy_datagram_iovec(data_skb, 0, msg->msg_iov, copied); if (msg->msg_name) { struct sockaddr_nl *addr = (struct sockaddr_nl *)msg->msg_name; @@ -1476,11 +1466,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, } siocb->scm->creds = *NETLINK_CREDS(skb); if (flags & MSG_TRUNC) - copied = skb->len; - -#ifdef CONFIG_COMPAT_NETLINK_MESSAGES - skb_shinfo(skb)->frag_list = frag; -#endif + copied = data_skb->len; skb_free_datagram(sk, skb); -- cgit v1.2.3-59-g8ed1b From f037590fff3005ce8a1513858d7d44f50053cc8f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Aug 2010 03:25:00 +0000 Subject: rds: fix a leak of kernel memory struct rds_rdma_notify contains a 32 bits hole on 64bit arches, make sure it is zeroed before copying it to user. Signed-off-by: Eric Dumazet CC: Andy Grover Signed-off-by: David S. Miller --- net/rds/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rds/recv.c b/net/rds/recv.c index 795a00b7f2cb..c93588c2d553 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -297,7 +297,7 @@ static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc, int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msghdr) { struct rds_notifier *notifier; - struct rds_rdma_notify cmsg; + struct rds_rdma_notify cmsg = { 0 }; /* fill holes with zero */ unsigned int count = 0, max_messages = ~0U; unsigned long flags; LIST_HEAD(copy); -- cgit v1.2.3-59-g8ed1b From 3971a230f9573cca1cbef96dab05e2682820f1a0 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Mon, 16 Aug 2010 06:34:06 +0000 Subject: bnx2x: Fix PHY locking problem PHY locking is required between two ports for some external PHYs. Since initialization was done in the common init function (called only on the first port initialization) rather than in the port init function, there was in fact no PHY locking between the ports. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index b4ec2b02a465..f8c3f08e4ce7 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -4328,10 +4328,12 @@ static int bnx2x_init_port(struct bnx2x *bp) val |= aeu_gpio_mask; REG_WR(bp, offset, val); } + bp->port.need_hw_lock = 1; break; - case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + bp->port.need_hw_lock = 1; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: /* add SPIO 5 to group 0 */ { u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : @@ -4341,7 +4343,10 @@ static int bnx2x_init_port(struct bnx2x *bp) REG_WR(bp, reg_addr, val); } break; - + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + bp->port.need_hw_lock = 1; + break; default: break; } -- cgit v1.2.3-59-g8ed1b From 96ac4f6b326450af496e82347e207b0fca7a9090 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Mon, 16 Aug 2010 06:34:07 +0000 Subject: bnx2x: Update bnx2x version to 1.52.53-4 Update bnx2x version to 1.52.53-4 Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 53af9c93e75c..0c2d96ed561c 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -20,8 +20,8 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.52.53-3" -#define DRV_MODULE_RELDATE "2010/18/04" +#define DRV_MODULE_VERSION "1.52.53-4" +#define DRV_MODULE_RELDATE "2010/16/08" #define BNX2X_BC_VER 0x040200 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -- cgit v1.2.3-59-g8ed1b From 2928db4c3c62552d3caf9ab53ccc6f7ae9865a23 Mon Sep 17 00:00:00 2001 From: Andre Detsch Date: Tue, 17 Aug 2010 05:49:12 +0000 Subject: ehea: Fix synchronization between HW and SW send queue ehea: Fix synchronization between HW and SW send queue When memory is added to / removed from a partition via the Memory DLPAR mechanism, the eHEA driver has to do a couple of things to reflect the memory change in its own IO address translation tables. This involves stopping and restarting the HW queues. During this operation, it is possible that HW and SW pointer into these queues get out of sync. This results in a situation where packets that are attached to a send queue are not transmitted immediately, but delayed until further X packets have been put on the queue. This patch detects such loss of synchronization, and resets the ehea port when needed. Signed-off-by: Jan-Bernd Themann Signed-off-by: Andre Detsch Signed-off-by: David S. Miller --- drivers/net/ehea/ehea.h | 3 ++- drivers/net/ehea/ehea_main.c | 60 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 0060e422f171..2ce67f6152cd 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0105" +#define DRV_VERSION "EHEA_0106" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 @@ -400,6 +400,7 @@ struct ehea_port_res { u32 poll_counter; struct net_lro_mgr lro_mgr; struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS]; + int sq_restart_flag; }; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 3beba70b7dea..adb5994c125f 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -776,6 +776,53 @@ static int ehea_proc_rwqes(struct net_device *dev, return processed; } +#define SWQE_RESTART_CHECK 0xdeadbeaff00d0000ull + +static void reset_sq_restart_flag(struct ehea_port *port) +{ + int i; + + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { + struct ehea_port_res *pr = &port->port_res[i]; + pr->sq_restart_flag = 0; + } +} + +static void check_sqs(struct ehea_port *port) +{ + struct ehea_swqe *swqe; + int swqe_index; + int i, k; + + for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { + struct ehea_port_res *pr = &port->port_res[i]; + k = 0; + swqe = ehea_get_swqe(pr->qp, &swqe_index); + memset(swqe, 0, SWQE_HEADER_SIZE); + atomic_dec(&pr->swqe_avail); + + swqe->tx_control |= EHEA_SWQE_PURGE; + swqe->wr_id = SWQE_RESTART_CHECK; + swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; + swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT; + swqe->immediate_data_length = 80; + + ehea_post_swqe(pr->qp, swqe); + + while (pr->sq_restart_flag == 0) { + msleep(5); + if (++k == 100) { + ehea_error("HW/SW queues out of sync"); + ehea_schedule_port_reset(pr->port); + return; + } + } + } + + return; +} + + static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) { struct sk_buff *skb; @@ -793,6 +840,13 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) cqe_counter++; rmb(); + + if (cqe->wr_id == SWQE_RESTART_CHECK) { + pr->sq_restart_flag = 1; + swqe_av++; + break; + } + if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { ehea_error("Bad send completion status=0x%04X", cqe->status); @@ -2675,8 +2729,10 @@ static void ehea_flush_sq(struct ehea_port *port) int k = 0; while (atomic_read(&pr->swqe_avail) < swqe_max) { msleep(5); - if (++k == 20) + if (++k == 20) { + ehea_error("WARNING: sq not flushed completely"); break; + } } } } @@ -2917,6 +2973,7 @@ static void ehea_rereg_mrs(struct work_struct *work) port_napi_disable(port); mutex_unlock(&port->port_lock); } + reset_sq_restart_flag(port); } /* Unregister old memory region */ @@ -2951,6 +3008,7 @@ static void ehea_rereg_mrs(struct work_struct *work) mutex_lock(&port->port_lock); port_napi_enable(port); ret = ehea_restart_qps(dev); + check_sqs(port); if (!ret) netif_wake_queue(dev); mutex_unlock(&port->port_lock); -- cgit v1.2.3-59-g8ed1b From 0645bab7da3cb021157e5c661ef35f1d1226785a Mon Sep 17 00:00:00 2001 From: Robert Jennings Date: Tue, 17 Aug 2010 09:15:45 +0000 Subject: ibmveth: Fix opps during MTU change on an active device This fixes the following opps which can occur when trying to deallocate receive buffer pools when changing the MTU of an active ibmveth device. Oops: Kernel access of bad area, sig: 11 [#1] NIP: d000000004db00e8 LR: d000000004db00ac CTR: 0000000000591038 REGS: c00000007fff39d0 TRAP: 0300 Not tainted (2.6.36-rc1) MSR: 8000000000009032 CR: 22248244 XER: 00000002 DAR: 0000000000000488, DSISR: 0000000042000000 TASK = c00000007c463790[6531] 'netserver' THREAD: c00000007a154000 CPU: 0 GPR00: 0000000000000000 c00000007fff3c50 d000000004dbd360 0000000000000001 GPR04: 0000000000000001 1fffffffffffffff 000000000000043c c00000007a8e9f60 GPR08: c00000007a8e9e20 0000000000000245 0000000000000488 0000000000000000 GPR12: 00000000000000c0 c000000006d70000 c00000007bfec098 c00000007bfebc2c GPR16: c00000007a157c78 0000000000000000 0000000000000001 0000000000000000 GPR20: 0000000000000001 0000000000000010 c000000000b51180 c00000007a8e9d90 GPR24: c00000007a8e9da0 c00000007a8e9580 00000000000005ea 00000000000002ff GPR28: 0000000000000004 0000000000000080 c000000000a946f8 c00000007a8e9d80 NIP [d000000004db00e8] .ibmveth_remove_buffer_from_pool+0xe8/0x130 [ibmveth] LR [d000000004db00ac] .ibmveth_remove_buffer_from_pool+0xac/0x130 [ibmveth] Call Trace: [c00000007fff3c50] [d000000004db00ac] .ibmveth_remove_buffer_from_pool+0xac/0x130 [ibmveth] (unreliable) [c00000007fff3cf0] [d000000004db31dc] .ibmveth_poll+0x30c/0x460 [ibmveth] [c00000007fff3dd0] [c00000000042c4b8] .net_rx_action+0x178/0x278 [c00000007fff3eb0] [c000000000093cf0] .__do_softirq+0x118/0x1f8 [c00000007fff3f90] [c00000000002ab3c] .call_do_softirq+0x14/0x24 [c00000007a157600] [c00000000000e3e4] .do_softirq+0xec/0x110 [c00000007a1576a0] [c000000000093394] .local_bh_enable_ip+0xb4/0xe0 [c00000007a157720] [c0000000004f0bac] ._raw_spin_unlock_bh+0x3c/0x50 [c00000007a157790] [c0000000004186e0] .release_sock+0x158/0x188 [c00000007a157840] [c000000000479660] .tcp_recvmsg+0x560/0x9b8 [c00000007a157970] [c0000000004a0d78] .inet_recvmsg+0x80/0xd8 [c00000007a157a00] [c000000000413e28] .sock_recvmsg+0x128/0x178 [c00000007a157bf0] [c0000000004164ac] .SyS_recvfrom+0xb4/0x148 [c00000007a157d70] [c000000000411f3c] .SyS_socketcall+0x274/0x360 [c00000007a157e30] [c0000000000085b4] syscall_exit+0x0/0x40 Reported-by: Rafael Camarda Silva Folco Signed-off-by: Robert Jennings Acked-by: Brian King Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 2602852cc55a..4734c939ad03 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1113,7 +1113,8 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) struct ibmveth_adapter *adapter = netdev_priv(dev); struct vio_dev *viodev = adapter->vdev; int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH; - int i; + int i, rc; + int need_restart = 0; if (new_mtu < IBMVETH_MAX_MTU) return -EINVAL; @@ -1127,35 +1128,32 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) /* Deactivate all the buffer pools so that the next loop can activate only the buffer pools necessary to hold the new MTU */ - for (i = 0; i < IbmVethNumBufferPools; i++) - if (adapter->rx_buff_pool[i].active) { - ibmveth_free_buffer_pool(adapter, - &adapter->rx_buff_pool[i]); - adapter->rx_buff_pool[i].active = 0; - } + if (netif_running(adapter->netdev)) { + need_restart = 1; + adapter->pool_config = 1; + ibmveth_close(adapter->netdev); + adapter->pool_config = 0; + } /* Look for an active buffer pool that can hold the new MTU */ for(i = 0; irx_buff_pool[i].active = 1; if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) { - if (netif_running(adapter->netdev)) { - adapter->pool_config = 1; - ibmveth_close(adapter->netdev); - adapter->pool_config = 0; - dev->mtu = new_mtu; - vio_cmo_set_dev_desired(viodev, - ibmveth_get_desired_dma - (viodev)); - return ibmveth_open(adapter->netdev); - } dev->mtu = new_mtu; vio_cmo_set_dev_desired(viodev, ibmveth_get_desired_dma (viodev)); + if (need_restart) { + return ibmveth_open(adapter->netdev); + } return 0; } } + + if (need_restart && (rc = ibmveth_open(adapter->netdev))) + return rc; + return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From d7d28bc29f4ea7c2d23ed002a9973c64a92bcdb8 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 18 Aug 2010 14:16:54 +0200 Subject: ALSA: pcm midlevel code - add time check for double interrupt acknowledge The current code in pcm_lib.c do all checks using only the position in the ring buffer. Unfortunately, where the interrupts gets delayed or merged into one, we need another timing source to check when the buffer size boundary overlaps to avoid the wrong updating of the ring buffer pointers. This code uses jiffies to check the right time window without any performance impact. Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 1 + sound/core/pcm_lib.c | 14 +++++++++----- sound/core/pcm_native.c | 2 ++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dd76cdede64d..54c4ccf6fec2 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -274,6 +274,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ + unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */ snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ /* -- HW params -- */ diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e9d98be190c5..d6ecca27bb68 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -329,11 +329,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* delta = "expected next hw_ptr" for in_interrupt != 0 */ delta = runtime->hw_ptr_interrupt + runtime->period_size; if (delta > new_hw_ptr) { - hw_base += runtime->buffer_size; - if (hw_base >= runtime->boundary) - hw_base = 0; - new_hw_ptr = hw_base + pos; - goto __delta; + /* check for double acknowledged interrupts */ + hdelta = jiffies - runtime->hw_ptr_jiffies; + if (hdelta > runtime->hw_ptr_buffer_jiffies/2) { + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + goto __delta; + } } } /* new_hw_ptr might be lower than old_hw_ptr in case when */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 303ac04ff6e4..2d2e1b65ee9a 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -867,6 +867,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); runtime->hw_ptr_jiffies = jiffies; + runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / + runtime->rate; runtime->status->state = state; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) -- cgit v1.2.3-59-g8ed1b From 0ac820eebe9008094040955d294ef7b33b418413 Mon Sep 17 00:00:00 2001 From: Phil Oester Date: Tue, 17 Aug 2010 18:45:08 +0000 Subject: vlan: Match underlying dev carrier on vlan add When adding a new vlan, if the underlying interface has no carrier, then the newly added vlan interface should also have no carrier. At present, this is not true - the newly added vlan is added with carrier up. Fix by checking state of real device. Signed-off-by: Phil Oester Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 3d59c9bf8feb..3bccdd12a264 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -510,7 +510,8 @@ static int vlan_dev_open(struct net_device *dev) if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_join(dev); - netif_carrier_on(dev); + if (netif_carrier_ok(real_dev)) + netif_carrier_on(dev); return 0; clear_allmulti: -- cgit v1.2.3-59-g8ed1b From 4be353d5169ef2477814b35fe46734a51dcecd09 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 17 Aug 2010 20:51:51 +0000 Subject: netxen: fix inconsistent lock state Spin lock rds_ring->lock is used in poll routine, so other users should use spin_lock_bh(). While posting rx buffers from netxen_nic_attach, rds_ring->lock is not required, so cleaning it instead of fixing it by spin_lock_bh(). Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_init.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index c865dda2adf1..cabae7bb1fc6 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1805,8 +1805,6 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, netxen_ctx_msg msg = 0; struct list_head *head; - spin_lock(&rds_ring->lock); - producer = rds_ring->producer; head = &rds_ring->free_list; @@ -1853,8 +1851,6 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid, NETXEN_RCV_PRODUCER_OFFSET), msg); } } - - spin_unlock(&rds_ring->lock); } static void -- cgit v1.2.3-59-g8ed1b From 772806bbbc5aa4ddf5ac0de57c1ee7c0ef94e490 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 17 Aug 2010 20:51:52 +0000 Subject: netxen: update version 4.0.74 Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index ffa1b9ce1cc5..6dca3574e355 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -53,8 +53,8 @@ #define _NETXEN_NIC_LINUX_MAJOR 4 #define _NETXEN_NIC_LINUX_MINOR 0 -#define _NETXEN_NIC_LINUX_SUBVERSION 73 -#define NETXEN_NIC_LINUX_VERSIONID "4.0.73" +#define _NETXEN_NIC_LINUX_SUBVERSION 74 +#define NETXEN_NIC_LINUX_VERSIONID "4.0.74" #define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c)) #define _major(v) (((v) >> 24) & 0xff) -- cgit v1.2.3-59-g8ed1b From 9c38657cfcb739b7dc4ce9065a85b4f0c195bef8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 19 Aug 2010 00:39:45 -0700 Subject: net: sh_eth: remove unused variable Signed-off-by: Kuninori Morimoto Signed-off-by: David S. Miller --- drivers/net/sh_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index f5a9eb1df593..79fd02bc69fd 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1437,7 +1437,7 @@ static const struct net_device_ops sh_eth_netdev_ops = { static int sh_eth_drv_probe(struct platform_device *pdev) { - int ret, i, devno = 0; + int ret, devno = 0; struct resource *res; struct net_device *ndev = NULL; struct sh_eth_private *mdp; -- cgit v1.2.3-59-g8ed1b From 79c5f51c639021f7472591239c3867cee4b9ec02 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Aug 2010 00:24:43 +0000 Subject: irda: fix a race in irlan_eth_xmit() After skb is queued, its illegal to dereference it. Cache skb->len into a temporary variable. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/irda/irlan/irlan_eth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 9616c32d1076..5bb8353105cc 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -169,6 +169,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, { struct irlan_cb *self = netdev_priv(dev); int ret; + unsigned int len; /* skb headroom large enough to contain all IrDA-headers? */ if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) { @@ -188,6 +189,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, dev->trans_start = jiffies; + len = skb->len; /* Now queue the packet in the transport layer */ if (self->use_udata) ret = irttp_udata_request(self->tsap_data, skb); @@ -209,7 +211,7 @@ static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, self->stats.tx_dropped++; } else { self->stats.tx_packets++; - self->stats.tx_bytes += skb->len; + self->stats.tx_bytes += len; } return NETDEV_TX_OK; -- cgit v1.2.3-59-g8ed1b From 1003201a73daed739747b9a6c2c39c57aad5878b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Aug 2010 00:42:48 +0000 Subject: qlnic: fix a race in qlcnic_get_stats() Dont clear netdev->stats, it might give transient wrong values to concurrent stat readers. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index bf6d87adda4f..213e3656d953 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -1983,8 +1983,6 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) struct qlcnic_adapter *adapter = netdev_priv(netdev); struct net_device_stats *stats = &netdev->stats; - memset(stats, 0, sizeof(*stats)); - stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes; -- cgit v1.2.3-59-g8ed1b From 502820a3161e2f228125977d133dd80eea2932d1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Aug 2010 02:29:30 +0000 Subject: netxen: fix a race in netxen_nic_get_stats() Dont clear netdev->stats, it might give transient wrong values to concurrent stat readers. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index fd86e18604e6..cb30df106a2c 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2032,8 +2032,6 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) struct netxen_adapter *adapter = netdev_priv(netdev); struct net_device_stats *stats = &netdev->stats; - memset(stats, 0, sizeof(*stats)); - stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes; -- cgit v1.2.3-59-g8ed1b From 8539992f6091eb8206c781421312157d0c282e6e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 18 Aug 2010 00:26:34 +0000 Subject: ll_temac: Fix poll implementation Functions ll_temac_rx_irq and ll_temac_tx_irq have pointer to net_device as second parameter not pointer to temac_local. Signed-off-by: Michal Simek Signed-off-by: David S. Miller --- drivers/net/ll_temac_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 4eea3f70c5cf..09b813f1c3cd 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -902,8 +902,8 @@ temac_poll_controller(struct net_device *ndev) disable_irq(lp->tx_irq); disable_irq(lp->rx_irq); - ll_temac_rx_irq(lp->tx_irq, lp); - ll_temac_tx_irq(lp->rx_irq, lp); + ll_temac_rx_irq(lp->tx_irq, ndev); + ll_temac_tx_irq(lp->rx_irq, ndev); enable_irq(lp->tx_irq); enable_irq(lp->rx_irq); -- cgit v1.2.3-59-g8ed1b From 7cacfa87d3018c68bef2defeda8948f753dfa9d0 Mon Sep 17 00:00:00 2001 From: David Gow Date: Thu, 19 Aug 2010 15:43:56 +0800 Subject: HID: Add support for chicony multitouch screens. Adds a hid quirk for the chicony multitouch screen found in the Acer Aspire 1820pt notebook. Signed-off-by: David Gow Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/usbhid/hid-quirks.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 85c6d13c9ffa..29051425ca0f 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -149,6 +149,7 @@ #define USB_VENDOR_ID_CHICONY 0x04f2 #define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 +#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_VENDOR_ID_CIDC 0x1677 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 2643d3147621..1b222398ff54 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -77,6 +77,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE }, + { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT }, + { 0, 0 } }; -- cgit v1.2.3-59-g8ed1b From 737480a0d525dae13306296da08029dff545bc72 Mon Sep 17 00:00:00 2001 From: KUMANO Syuhei Date: Sun, 15 Aug 2010 15:18:04 +0900 Subject: kprobes/x86: Fix the return address of multiple kretprobes Fix the return address of subsequent kretprobes when multiple kretprobes are set on the same function. For example: # cd /sys/kernel/debug/tracing # echo "r:event1 sys_symlink" > kprobe_events # echo "r:event2 sys_symlink" >> kprobe_events # echo 1 > events/kprobes/enable # ln -s /tmp/foo /tmp/bar (without this patch) # cat trace ln-897 [000] 20404.133727: event1: (kretprobe_trampoline+0x0/0x4c <- sys_symlink) ln-897 [000] 20404.133747: event2: (system_call_fastpath+0x16/0x1b <- sys_symlink) (with this patch) # cat trace ln-740 [000] 13799.491076: event1: (system_call_fastpath+0x16/0x1b <- sys_symlink) ln-740 [000] 13799.491096: event2: (system_call_fastpath+0x16/0x1b <- sys_symlink) Signed-off-by: KUMANO Syuhei Reviewed-by: Masami Hiramatsu Cc: Frederic Weisbecker Cc: Ananth N Mavinakayanahalli Cc: Peter Zijlstra Cc: YOSHIFUJI Hideaki LKML-Reference: <1281853084.3254.11.camel@camp10-laptop> Signed-off-by: Ingo Molnar --- arch/x86/kernel/kprobes.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 1bfb6cf4dd55..770ebfb349e9 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -709,6 +709,7 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) struct hlist_node *node, *tmp; unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; + kprobe_opcode_t *correct_ret_addr = NULL; INIT_HLIST_HEAD(&empty_rp); kretprobe_hash_lock(current, &head, &flags); @@ -740,14 +741,34 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) /* another task is sharing our hash bucket */ continue; + orig_ret_address = (unsigned long)ri->ret_addr; + + if (orig_ret_address != trampoline_address) + /* + * This is the real return address. Any other + * instances associated with this task are for + * other calls deeper on the call stack + */ + break; + } + + kretprobe_assert(ri, orig_ret_address, trampoline_address); + + correct_ret_addr = ri->ret_addr; + hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { + if (ri->task != current) + /* another task is sharing our hash bucket */ + continue; + + orig_ret_address = (unsigned long)ri->ret_addr; if (ri->rp && ri->rp->handler) { __get_cpu_var(current_kprobe) = &ri->rp->kp; get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; + ri->ret_addr = correct_ret_addr; ri->rp->handler(ri, regs); __get_cpu_var(current_kprobe) = NULL; } - orig_ret_address = (unsigned long)ri->ret_addr; recycle_rp_inst(ri, &empty_rp); if (orig_ret_address != trampoline_address) @@ -759,8 +780,6 @@ static __used __kprobes void *trampoline_handler(struct pt_regs *regs) break; } - kretprobe_assert(ri, orig_ret_address, trampoline_address); - kretprobe_hash_unlock(current, &flags); hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { -- cgit v1.2.3-59-g8ed1b From ede1b4290781ae82ccf0f2ecc6dada8d3dd35779 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 18 Aug 2010 15:33:13 -0700 Subject: tracing: Fix timer tracing PowerTOP would like to be able to trace timers. Unfortunately, the current timer tracing is not very useful: the actual timer function is not recorded in the trace at the start of timer execution. Although this is recorded for timer "start" time (when it gets armed), this is not useful; most timers get started early, and a tracer like PowerTOP will never see this event, but will only see the actual running of the timer. This patch just adds the function to the timer tracing; I've verified with PowerTOP that now it can get useful information about timers. Signed-off-by: Arjan van de Ven Cc: xiaoguangrong@cn.fujitsu.com Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: # .35.x, .34.x, .33.x LKML-Reference: <4C6C5FA9.3000405@linux.intel.com> Signed-off-by: Ingo Molnar --- include/trace/events/timer.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h index c624126a9c8a..425bcfe56c62 100644 --- a/include/trace/events/timer.h +++ b/include/trace/events/timer.h @@ -81,14 +81,16 @@ TRACE_EVENT(timer_expire_entry, TP_STRUCT__entry( __field( void *, timer ) __field( unsigned long, now ) + __field( void *, function) ), TP_fast_assign( __entry->timer = timer; __entry->now = jiffies; + __entry->function = timer->function; ), - TP_printk("timer=%p now=%lu", __entry->timer, __entry->now) + TP_printk("timer=%p function=%pf now=%lu", __entry->timer, __entry->function,__entry->now) ); /** @@ -200,14 +202,16 @@ TRACE_EVENT(hrtimer_expire_entry, TP_STRUCT__entry( __field( void *, hrtimer ) __field( s64, now ) + __field( void *, function) ), TP_fast_assign( __entry->hrtimer = hrtimer; __entry->now = now->tv64; + __entry->function = hrtimer->function; ), - TP_printk("hrtimer=%p now=%llu", __entry->hrtimer, + TP_printk("hrtimer=%p function=%pf now=%llu", __entry->hrtimer, __entry->function, (unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now })) ); -- cgit v1.2.3-59-g8ed1b From 065a1ed8de85583888b3d4f22c64b534a1fbdaaa Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 18 Aug 2010 11:25:04 -0700 Subject: mtd: nand: Fix regression in BBM detection Commit c7b28e25cb9beb943aead770ff14551b55fa8c79 ("mtd: nand: refactor BB marker detection") caused a regression in detection of factory-set bad block markers, especially for certain small-page NAND. This fix removes some unneeded constraints on using NAND_SMALL_BADBLOCK_POS, making the detection code more correct. This regression can be seen, for example, in Hynix HY27US081G1M and similar. Signed-off-by: Brian Norris Tested-by: Michael Guntsche Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a3c7473dd409..a22ed7b281ce 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2934,14 +2934,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; /* Set the bad block position */ - if (!(busw & NAND_BUSWIDTH_16) && (*maf_id == NAND_MFR_STMICRO || - (*maf_id == NAND_MFR_SAMSUNG && - mtd->writesize == 512) || - *maf_id == NAND_MFR_AMD)) - chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - else + if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) chip->badblockpos = NAND_LARGE_BADBLOCK_POS; - + else + chip->badblockpos = NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ chip->options &= ~NAND_CHIPOPTIONS_MSK; -- cgit v1.2.3-59-g8ed1b From 6c74340bce253ea95c9ee801b3c411a333937edf Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 16 Aug 2010 21:58:03 +0200 Subject: firewire: sbp2: fix memory leak in sbp2_cancel_orbs or at send error When an ORB was canceled (Command ORB i.e. SCSI request timed out, or Management ORB timed out), or there was a send error in the initial transaction, we missed to drop one of the ORB's references and thus leaked memory. Background: In total, we hold 3 references to each Operation Request Block: - 1 during sbp2_scsi_queuecommand() or sbp2_send_management_orb() respectively, - 1 for the duration of the write transaction to the ORB_Pointer or Management_Agent register of the target, - 1 for as long as the ORB stays within the lu->orb_list, until the ORB is unlinked from the list and the orb->callback was executed. The latter one of these 3 references is finished - normally by sbp2_status_write() when the target wrote status for a pending ORB, - or by sbp2_cancel_orbs() in case of an ORB time-out, - or by complete_transaction() in case of a send error. Of them, the latter two lacked the kref_put. Add the missing kref_put()s. Add comments to the gets and puts of references for transaction callbacks and ORB callbacks so that it is easier to see what is supposed to happen. Signed-off-by: Stefan Richter --- drivers/firewire/sbp2.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 9f76171717e5..e6cbe491f7ee 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -450,7 +450,7 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request, if (&orb->link != &lu->orb_list) { orb->callback(orb, &status); - kref_put(&orb->kref, free_orb); + kref_put(&orb->kref, free_orb); /* orb callback reference */ } else { fw_error("status write for unknown orb\n"); } @@ -480,12 +480,14 @@ static void complete_transaction(struct fw_card *card, int rcode, if (orb->rcode != RCODE_COMPLETE) { list_del(&orb->link); spin_unlock_irqrestore(&card->lock, flags); + orb->callback(orb, NULL); + kref_put(&orb->kref, free_orb); /* orb callback reference */ } else { spin_unlock_irqrestore(&card->lock, flags); } - kref_put(&orb->kref, free_orb); + kref_put(&orb->kref, free_orb); /* transaction callback reference */ } static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, @@ -501,9 +503,8 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, list_add_tail(&orb->link, &lu->orb_list); spin_unlock_irqrestore(&device->card->lock, flags); - /* Take a ref for the orb list and for the transaction callback. */ - kref_get(&orb->kref); - kref_get(&orb->kref); + kref_get(&orb->kref); /* transaction callback reference */ + kref_get(&orb->kref); /* orb callback reference */ fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, node_id, generation, device->max_speed, offset, @@ -530,6 +531,7 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) orb->rcode = RCODE_CANCELLED; orb->callback(orb, NULL); + kref_put(&orb->kref, free_orb); /* orb callback reference */ } return retval; -- cgit v1.2.3-59-g8ed1b From a481e97d3cdc40b9d58271675bd4f0abb79d4872 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 16 Aug 2010 22:13:34 +0200 Subject: firewire: sbp2: fix stall with "Unsolicited response" Fix I/O stalls with some 4-bay RAID enclosures which are based on OXUF936QSE: - Onnto dataTale RSM4QO, old firmware (not anymore with current firmware), - inXtron Hydra Super-S LCM, old as well as current firmware when used in RAID-5 mode, perhaps also in other RAID modes. The stalls happen during heavy or moderate disk traffic in periods that are a multiple of 5 minutes, roughly twice per hour. They are caused by the target responding too late to an ORB_Pointer register write: The target responds after Split_Timeout, hence firewire-core cancels the transaction, and firewire-sbp2 fails the SCSI request. The SCSI core retries the request, that fails again (and again), hence SCSI core calls firewire-sbp2's abort handler (and even the Management_Agent register write in the abort handler has the transaction timeout problem). During all that, the process which issued the I/O is stalled in I/O wait state. Meanwhile, the target actually acts on the first failed SCSI request: It responds to the ORB_Pointer write later (seen in the kernel log as "firewire_core: Unsolicited response") and also finishes the SCSI request with proper status (seen in the kernel log as "firewire_sbp2: status write for unknown orb"). So let's just ignore RCODE_CANCELLED in the transaction callback and wait for the target to complete the ORB nevertheless. This requires a small modification is sbp2_cancel_orbs(); it now needs to call orb->callback() regardless whether fw_cancel_transaction() found the transaction unfinished or finished. A different solution is to increase Split_Timeout on the local node. (Tested: 2000ms timeout; maybe 1000ms or something like that works too. 200ms is insufficient. Standard is 100ms.) However, I rather not do this because any software on any node could change the Split_Timeout to something unsuitable. Or such a large Split_Timeout may be undesirable for other purposes. Signed-off-by: Stefan Richter --- drivers/firewire/sbp2.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index e6cbe491f7ee..bfae4b309791 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -472,12 +472,18 @@ static void complete_transaction(struct fw_card *card, int rcode, * So this callback only sets the rcode if it hasn't already * been set and only does the cleanup if the transaction * failed and we didn't already get a status write. + * + * Here we treat RCODE_CANCELLED like RCODE_COMPLETE because some + * OXUF936QSE firmwares occasionally respond after Split_Timeout and + * complete the ORB just fine. Note, we also get RCODE_CANCELLED + * from sbp2_cancel_orbs() if fw_cancel_transaction() == 0. */ spin_lock_irqsave(&card->lock, flags); if (orb->rcode == -1) orb->rcode = rcode; - if (orb->rcode != RCODE_COMPLETE) { + + if (orb->rcode != RCODE_COMPLETE && orb->rcode != RCODE_CANCELLED) { list_del(&orb->link); spin_unlock_irqrestore(&card->lock, flags); @@ -526,8 +532,7 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) list_for_each_entry_safe(orb, next, &list, link) { retval = 0; - if (fw_cancel_transaction(device->card, &orb->t) == 0) - continue; + fw_cancel_transaction(device->card, &orb->t); orb->rcode = RCODE_CANCELLED; orb->callback(orb, NULL); -- cgit v1.2.3-59-g8ed1b From 1bf145fed572583d4cb7c1784689a0b42c997ba6 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 16 Aug 2010 23:45:54 +0200 Subject: firewire: net: fix unicast reception RCODE in failure paths The incoming request hander fwnet_receive_packet() expects subsequent datagram handling code to return non-zero on errors. However, almost none of the failure paths did so. Fix them all. (This error reporting is used to send and RCODE_CONFLICT_ERROR to the sender node in such failure cases. Two modes of failure exist: Out of memory, or firewire-net is unaware of any peer node to which a fragment or an ARP packet belongs. However, it is unclear whether a sender can actually make use of such information. A Linux peer apparently can't. Maybe it should all be simplified to void functions.) Reported-by: Julia Lawall Signed-off-by: Stefan Richter --- drivers/firewire/net.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index da17d409a244..33f8421c71cc 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -579,7 +579,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, if (!peer) { fw_notify("No peer for ARP packet from %016llx\n", (unsigned long long)peer_guid); - goto failed_proto; + goto no_peer; } /* @@ -656,7 +656,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, return 0; - failed_proto: + no_peer: net->stats.rx_errors++; net->stats.rx_dropped++; @@ -664,7 +664,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, if (netif_queue_stopped(net)) netif_wake_queue(net); - return 0; + return -ENOENT; } static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, @@ -701,7 +701,7 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, fw_error("out of memory\n"); net->stats.rx_dropped++; - return -1; + return -ENOMEM; } skb_reserve(skb, (net->hard_header_len + 15) & ~15); memcpy(skb_put(skb, len), buf, len); @@ -726,8 +726,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, spin_lock_irqsave(&dev->lock, flags); peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation); - if (!peer) - goto bad_proto; + if (!peer) { + retval = -ENOENT; + goto fail; + } pd = fwnet_pd_find(peer, datagram_label); if (pd == NULL) { @@ -741,7 +743,7 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, dg_size, buf, fg_off, len); if (pd == NULL) { retval = -ENOMEM; - goto bad_proto; + goto fail; } peer->pdg_size++; } else { @@ -755,9 +757,9 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, pd = fwnet_pd_new(net, peer, datagram_label, dg_size, buf, fg_off, len); if (pd == NULL) { - retval = -ENOMEM; peer->pdg_size--; - goto bad_proto; + retval = -ENOMEM; + goto fail; } } else { if (!fwnet_pd_update(peer, pd, buf, fg_off, len)) { @@ -768,7 +770,8 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, */ fwnet_pd_delete(pd); peer->pdg_size--; - goto bad_proto; + retval = -ENOMEM; + goto fail; } } } /* new datagram or add to existing one */ @@ -794,14 +797,13 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len, spin_unlock_irqrestore(&dev->lock, flags); return 0; - - bad_proto: + fail: spin_unlock_irqrestore(&dev->lock, flags); if (netif_queue_stopped(net)) netif_wake_queue(net); - return 0; + return retval; } static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r, -- cgit v1.2.3-59-g8ed1b From 2222bcb76790f4f61f39ec1514946a7593b07e02 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 18 Aug 2010 15:05:02 +0200 Subject: firewire: core: do not use del_timer_sync() in interrupt context Because we might be in interrupt context, replace del_timer_sync() with del_timer(). If the timer is already running, we know that it will clean up the transaction, so we do not need to do any further processing in the normal transaction handler. Many thanks to Yong Zhang for diagnosing this. Reported-by: Stefan Richter Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/core-transaction.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index ca7ca56661e0..b42a0bde8494 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -81,6 +81,10 @@ static int close_transaction(struct fw_transaction *transaction, spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t == transaction) { + if (!del_timer(&t->split_timeout_timer)) { + spin_unlock_irqrestore(&card->lock, flags); + goto timed_out; + } list_del_init(&t->link); card->tlabel_mask &= ~(1ULL << t->tlabel); break; @@ -89,11 +93,11 @@ static int close_transaction(struct fw_transaction *transaction, spin_unlock_irqrestore(&card->lock, flags); if (&t->link != &card->transaction_list) { - del_timer_sync(&t->split_timeout_timer); t->callback(card, rcode, NULL, 0, t->callback_data); return 0; } + timed_out: return -ENOENT; } @@ -921,6 +925,10 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t->node_id == source && t->tlabel == tlabel) { + if (!del_timer(&t->split_timeout_timer)) { + spin_unlock_irqrestore(&card->lock, flags); + goto timed_out; + } list_del_init(&t->link); card->tlabel_mask &= ~(1ULL << t->tlabel); break; @@ -929,6 +937,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) spin_unlock_irqrestore(&card->lock, flags); if (&t->link == &card->transaction_list) { + timed_out: fw_notify("Unsolicited response (source %x, tlabel %x)\n", source, tlabel); return; @@ -963,8 +972,6 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) break; } - del_timer_sync(&t->split_timeout_timer); - /* * The response handler may be executed while the request handler * is still pending. Cancel the request handler. -- cgit v1.2.3-59-g8ed1b From 019408f9b89c68cd7b8ddb904960dc17ccf7e531 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Thu, 19 Aug 2010 14:15:32 -0700 Subject: sparc64: Fill a missing delay slot. If the code were already aligned to 64 bytes, wr instruction would be executed twice --- once in delay slot and once in the jump target. Signed-off-by: Mikulas Patocka Signed-off-by: David S. Miller --- arch/sparc/include/asm/system_64.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h index d24cfe16afc1..e3b65d8cf41b 100644 --- a/arch/sparc/include/asm/system_64.h +++ b/arch/sparc/include/asm/system_64.h @@ -106,6 +106,7 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ */ #define write_pic(__p) \ __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \ + " nop\n\t" \ ".align 64\n" \ "99:wr %0, 0x0, %%pic\n\t" \ "rd %%pic, %%g0" : : "r" (__p)) -- cgit v1.2.3-59-g8ed1b From d7c53c9e822a4fefa13a0cae76f3190bfd0d5c11 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 19 Aug 2010 20:10:29 +0200 Subject: x86, hotplug: Serialize CPU hotplug to avoid bringup concurrency issues When testing cpu hotplug code on 32-bit we kept hitting the "CPU%d: Stuck ??" message due to multiple cores concurrently accessing the cpu_callin_mask, among others. Since these codepaths are not protected from concurrent access due to the fact that there's no sane reason for making an already complex code unnecessarily more complex - we hit the issue only when insanely switching cores off- and online - serialize hotplugging cores on the sysfs level and be done with it. [ v2.1: fix !HOTPLUG_CPU build ] Cc: Signed-off-by: Borislav Petkov LKML-Reference: <20100819181029.GC17171@aftab> Signed-off-by: H. Peter Anvin --- arch/x86/Kconfig | 5 +++++ arch/x86/kernel/smpboot.c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a84fc34c8f77..ac7827fc0823 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -245,6 +245,11 @@ config ARCH_HWEIGHT_CFLAGS config KTIME_SCALAR def_bool X86_32 + +config ARCH_CPU_PROBE_RELEASE + def_bool y + depends on HOTPLUG_CPU + source "init/Kconfig" source "kernel/Kconfig.freezer" diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index abf4a86ffc54..8b3bfc4dd708 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -90,6 +90,25 @@ DEFINE_PER_CPU(int, cpu_state) = { 0 }; static DEFINE_PER_CPU(struct task_struct *, idle_thread_array); #define get_idle_for_cpu(x) (per_cpu(idle_thread_array, x)) #define set_idle_for_cpu(x, p) (per_cpu(idle_thread_array, x) = (p)) + +/* + * We need this for trampoline_base protection from concurrent accesses when + * off- and onlining cores wildly. + */ +static DEFINE_MUTEX(x86_cpu_hotplug_driver_mutex); + +void cpu_hotplug_driver_lock() +{ + mutex_lock(&x86_cpu_hotplug_driver_mutex); +} + +void cpu_hotplug_driver_unlock() +{ + mutex_unlock(&x86_cpu_hotplug_driver_mutex); +} + +ssize_t arch_cpu_probe(const char *buf, size_t count) { return -1; } +ssize_t arch_cpu_release(const char *buf, size_t count) { return -1; } #else static struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ; #define get_idle_for_cpu(x) (idle_thread_array[(x)]) -- cgit v1.2.3-59-g8ed1b From 2cbeb4efc2b9739fe6019b613ae658bd2119a3eb Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 16 Aug 2010 11:54:36 -0400 Subject: drm/radeon/kms: fix GTT/VRAM overlapping test GTT/VRAM overlapping test had a typo which leaded to not detecting case when vram_end > gtt_end. This patch fix the logic and should fix #16574 Signed-off-by: Jerome Glisse Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 4f7a170d1566..69b3c2291e92 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -199,7 +199,7 @@ void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 mc->mc_vram_size = mc->aper_size; } mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; - if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_end <= mc->gtt_end) { + if (rdev->flags & RADEON_IS_AGP && mc->vram_end > mc->gtt_start && mc->vram_start <= mc->gtt_end) { dev_warn(rdev->dev, "limiting VRAM to PCI aperture size\n"); mc->real_vram_size = mc->aper_size; mc->mc_vram_size = mc->aper_size; -- cgit v1.2.3-59-g8ed1b From 1d978dac7e99bd551df5001f0cc92369054dca0d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 15 Aug 2010 14:11:24 +0200 Subject: drm/radeon: Fix stack data leak Always zero-init a structure on the stack which is returned by a function. Otherwise you may leak random stack data from previous function calls. This fixes the following warning I was seeing: CC [M] drivers/gpu/drm/radeon/radeon_atombios.o drivers/gpu/drm/radeon/radeon_atombios.c: In function "radeon_atom_get_hpd_info_from_gpio": drivers/gpu/drm/radeon/radeon_atombios.c:261: warning: "hpd.plugged_state" is used uninitialized in this function Signed-off-by: Jean Delvare Cc: David Airlie Cc: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 6d30868744ee..4a4225e601fb 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -226,6 +226,8 @@ static struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device struct radeon_hpd hpd; u32 reg; + memset(&hpd, 0, sizeof(struct radeon_hpd)); + if (ASIC_IS_DCE4(rdev)) reg = EVERGREEN_DC_GPIO_HPD_A; else -- cgit v1.2.3-59-g8ed1b From fbee67a65d16c431ae3c389db13688c6e1b1b9d8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 16 Aug 2010 12:44:47 -0400 Subject: drm/radeon/kms: DCE3/4 AdjustPixelPll updates Add options necessary bits for: - SS on DP - SS on LVDS - set clocks right for DP - deep color on hdmi (needs additional encoder and edid work as well) Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 51 +++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 12ad512bd3d3..577239a24fd5 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -471,6 +471,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, struct radeon_encoder *radeon_encoder = NULL; u32 adjusted_clock = mode->clock; int encoder_mode = 0; + u32 dp_clock = mode->clock; + int bpc = 8; /* reset the pll flags */ pll->flags = 0; @@ -513,6 +515,17 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (encoder->crtc == crtc) { radeon_encoder = to_radeon_encoder(encoder); encoder_mode = atombios_get_encoder_mode(encoder); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + } + } + if (ASIC_IS_AVIVO(rdev)) { /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) @@ -555,6 +568,14 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); args.v1.ucTransmitterID = radeon_encoder->encoder_id; args.v1.ucEncodeMode = encoder_mode; + if (encoder_mode == ATOM_ENCODER_MODE_DP) { + /* may want to enable SS on DP eventually */ + /* args.v1.ucConfig |= + ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/ + } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { + args.v1.ucConfig |= + ADJUST_DISPLAY_CONFIG_SS_ENABLE; + } atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); @@ -568,10 +589,20 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (encoder_mode == ATOM_ENCODER_MODE_DP) + if (encoder_mode == ATOM_ENCODER_MODE_DP) { + /* may want to enable SS on DP/eDP eventually */ + /*args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE;*/ args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; - else { + /* 16200 or 27000 */ + args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); + } else { + if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { + /* deep color support */ + args.v3.sInput.usPixelClock = + cpu_to_le16((mode->clock * bpc / 8) / 10); + } if (dig->coherent_mode) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; @@ -580,13 +611,19 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, DISPPLL_CONFIG_DUAL_LINK; } } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - /* may want to enable SS on DP/eDP eventually */ - /*args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_SS_ENABLE;*/ - if (encoder_mode == ATOM_ENCODER_MODE_DP) + if (encoder_mode == ATOM_ENCODER_MODE_DP) { + /* may want to enable SS on DP/eDP eventually */ + /*args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE;*/ args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; - else { + /* 16200 or 27000 */ + args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); + } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) { + /* want to enable SS on LVDS eventually */ + /*args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_SS_ENABLE;*/ + } else { if (mode->clock > 165000) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_DUAL_LINK; -- cgit v1.2.3-59-g8ed1b From 5137ee940c3e593ae5578a7a12a604eb8f239ac0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:58:47 -0400 Subject: drm/radeon/kms: rework encoder handling On most newer asics, digital encoders have two links each and they can be used independantly. As such, treat them as separate encoders otherwise the individual links will not get programmed properly at modeset time. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 2 +- drivers/gpu/drm/radeon/radeon_atombios.c | 35 ++++---- drivers/gpu/drm/radeon/radeon_combios.c | 104 ++++++++++++------------ drivers/gpu/drm/radeon/radeon_connectors.c | 5 -- drivers/gpu/drm/radeon/radeon_encoders.c | 71 ++++++++-------- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 7 +- drivers/gpu/drm/radeon/radeon_mode.h | 3 +- 7 files changed, 116 insertions(+), 111 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 36e0d4b545e6..4e7778d44b8d 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -610,7 +610,7 @@ void dp_link_train(struct drm_encoder *encoder, enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER; else enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER; - if (dig_connector->linkb) + if (dig->linkb) enc_id |= ATOM_DP_CONFIG_LINK_B; else enc_id |= ATOM_DP_CONFIG_LINK_A; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 4a4225e601fb..b015915441ba 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -32,11 +32,11 @@ /* from radeon_encoder.c */ extern uint32_t -radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, - uint8_t dac); +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); extern void radeon_link_encoder_connector(struct drm_device *dev); extern void -radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device); /* from radeon_connector.c */ @@ -46,14 +46,14 @@ radeon_add_atom_connector(struct drm_device *dev, uint32_t supported_device, int connector_type, struct radeon_i2c_bus_rec *i2c_bus, - bool linkb, uint32_t igp_lane_info, + uint32_t igp_lane_info, uint16_t connector_object_id, struct radeon_hpd *hpd, struct radeon_router *router); /* from radeon_legacy_encoder.c */ extern void -radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device); union atom_supported_devices { @@ -479,7 +479,6 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) int i, j, k, path_size, device_support; int connector_type; u16 igp_lane_info, conn_id, connector_object_id; - bool linkb; struct radeon_i2c_bus_rec ddc_bus; struct radeon_router router; struct radeon_gpio_rec gpio; @@ -512,7 +511,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) addr += path_size; path = (ATOM_DISPLAY_OBJECT_PATH *) addr; path_size += le16_to_cpu(path->usSize); - linkb = false; + if (device_support & le16_to_cpu(path->usDeviceTag)) { uint8_t con_obj_id, con_obj_num, con_obj_type; @@ -603,13 +602,10 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) { - if (grph_obj_num == 2) - linkb = true; - else - linkb = false; + u16 encoder_obj = le16_to_cpu(path->usGraphicObjIds[j]); radeon_add_atom_encoder(dev, - grph_obj_id, + encoder_obj, le16_to_cpu (path-> usDeviceTag)); @@ -746,7 +742,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) le16_to_cpu(path-> usDeviceTag), connector_type, &ddc_bus, - linkb, igp_lane_info, + igp_lane_info, connector_object_id, &hpd, &router); @@ -935,13 +931,13 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) radeon_add_atom_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, (1 << i), dac), (1 << i)); else radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, (1 << i), dac), (1 << i)); @@ -998,7 +994,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct bios_connectors[i]. connector_type, &bios_connectors[i].ddc_bus, - false, 0, + 0, connector_object_id, &bios_connectors[i].hpd, &router); @@ -1307,6 +1303,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct union lvds_info *lvds_info; uint8_t frev, crev; struct radeon_encoder_atom_dig *lvds = NULL; + int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { @@ -1370,6 +1367,12 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct } encoder->native_mode = lvds->native_mode; + + if (encoder_enum == 2) + lvds->linkb = true; + else + lvds->linkb = false; + } return lvds; } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 885dcfac1838..bd74e428bd14 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -39,8 +39,8 @@ /* from radeon_encoder.c */ extern uint32_t -radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, - uint8_t dac); +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); extern void radeon_link_encoder_connector(struct drm_device *dev); /* from radeon_connector.c */ @@ -55,7 +55,7 @@ radeon_add_legacy_connector(struct drm_device *dev, /* from radeon_legacy_encoder.c */ extern void -radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device); /* old legacy ATI BIOS routines */ @@ -1505,7 +1505,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1520,7 +1520,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_NONE_DETECTED, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1535,7 +1535,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1550,12 +1550,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_1; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1571,7 +1571,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1588,7 +1588,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1607,7 +1607,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1619,7 +1619,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1631,7 +1631,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1648,7 +1648,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1660,12 +1660,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_2; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP2_SUPPORT, 0), ATOM_DEVICE_DFP2_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1680,7 +1680,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1697,7 +1697,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1709,12 +1709,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1728,7 +1728,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1745,7 +1745,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -1757,7 +1757,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1769,7 +1769,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1786,12 +1786,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_2; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP2_SUPPORT, 0), ATOM_DEVICE_DFP2_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1806,7 +1806,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1823,12 +1823,12 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1842,7 +1842,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1859,7 +1859,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0); hpd.hpd = RADEON_HPD_1; /* ??? */ radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); @@ -1871,7 +1871,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1883,7 +1883,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1900,7 +1900,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1912,7 +1912,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -1924,7 +1924,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c.valid = false; hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_TV1_SUPPORT, 2), ATOM_DEVICE_TV1_SUPPORT); @@ -1941,7 +1941,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -1952,7 +1952,7 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0); hpd.hpd = RADEON_HPD_NONE; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), ATOM_DEVICE_CRT2_SUPPORT); @@ -2109,7 +2109,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) else devices = ATOM_DEVICE_DFP1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, devices, 0), devices); radeon_add_legacy_connector(dev, i, devices, @@ -2123,7 +2123,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) if (tmp & 0x1) { devices = ATOM_DEVICE_CRT2_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT2_SUPPORT, 2), @@ -2131,7 +2131,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) } else { devices = ATOM_DEVICE_CRT1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT1_SUPPORT, 1), @@ -2151,7 +2151,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) if (tmp & 0x1) { devices |= ATOM_DEVICE_CRT2_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT2_SUPPORT, 2), @@ -2159,7 +2159,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) } else { devices |= ATOM_DEVICE_CRT1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_CRT1_SUPPORT, 1), @@ -2168,7 +2168,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) if ((tmp >> 4) & 0x1) { devices |= ATOM_DEVICE_DFP2_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_DFP2_SUPPORT, 0), @@ -2177,7 +2177,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) } else { devices |= ATOM_DEVICE_DFP1_SUPPORT; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_DFP1_SUPPORT, 0), @@ -2202,7 +2202,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) connector_object_id = CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I; } radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, devices, 0), devices); radeon_add_legacy_connector(dev, i, devices, @@ -2215,7 +2215,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) case CONNECTOR_CTV_LEGACY: case CONNECTOR_STV_LEGACY: radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_TV1_SUPPORT, 2), @@ -2242,12 +2242,12 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) DRM_DEBUG_KMS("Found DFP table, assuming DVI connector\n"); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), ATOM_DEVICE_DFP1_SUPPORT); @@ -2268,7 +2268,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) DRM_DEBUG_KMS("Found CRT table, assuming VGA connector\n"); if (crt_info) { radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), ATOM_DEVICE_CRT1_SUPPORT); @@ -2297,7 +2297,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) COMBIOS_LCD_DDC_INFO_TABLE); radeon_add_legacy_encoder(dev, - radeon_get_encoder_id(dev, + radeon_get_encoder_enum(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), ATOM_DEVICE_LCD1_SUPPORT); @@ -2351,7 +2351,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) hpd.hpd = RADEON_HPD_NONE; ddc_i2c.valid = false; radeon_add_legacy_encoder(dev, - radeon_get_encoder_id + radeon_get_encoder_enum (dev, ATOM_DEVICE_TV1_SUPPORT, 2), diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 47c4b276d30c..20c353c86ce4 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1037,7 +1037,6 @@ radeon_add_atom_connector(struct drm_device *dev, uint32_t supported_device, int connector_type, struct radeon_i2c_bus_rec *i2c_bus, - bool linkb, uint32_t igp_lane_info, uint16_t connector_object_id, struct radeon_hpd *hpd, @@ -1128,7 +1127,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); @@ -1158,7 +1156,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); @@ -1182,7 +1179,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); @@ -1229,7 +1225,6 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); if (!radeon_dig_connector) goto failed; - radeon_dig_connector->linkb = linkb; radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 263c8098d7dd..404320f9c9b0 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -81,7 +81,7 @@ void radeon_setup_encoder_clones(struct drm_device *dev) } uint32_t -radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac) +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8_t dac) { struct radeon_device *rdev = dev->dev_private; uint32_t ret = 0; @@ -97,59 +97,59 @@ radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t if ((rdev->family == CHIP_RS300) || (rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) - ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + ret = ENCODER_INTERNAL_DAC2_ENUM_ID1; else if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1; + ret = ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_DAC1; + ret = ENCODER_INTERNAL_DAC1_ENUM_ID1; break; case 2: /* dac b */ if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2; + ret = ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1; else { /*if (rdev->family == CHIP_R200) - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; else*/ - ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + ret = ENCODER_INTERNAL_DAC2_ENUM_ID1; } break; case 3: /* external dac */ if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; break; } break; case ATOM_DEVICE_LCD1_SUPPORT: if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_LVDS; + ret = ENCODER_INTERNAL_LVDS_ENUM_ID1; break; case ATOM_DEVICE_DFP1_SUPPORT: if ((rdev->family == CHIP_RS300) || (rdev->family == CHIP_RS400) || (rdev->family == CHIP_RS480)) - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; else if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1; + ret = ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1; + ret = ENCODER_INTERNAL_TMDS1_ENUM_ID1; break; case ATOM_DEVICE_LCD2_SUPPORT: case ATOM_DEVICE_DFP2_SUPPORT: if ((rdev->family == CHIP_RS600) || (rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) - ret = ENCODER_OBJECT_ID_INTERNAL_DDI; + ret = ENCODER_INTERNAL_DDI_ENUM_ID1; else if (ASIC_IS_AVIVO(rdev)) - ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1; else - ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + ret = ENCODER_INTERNAL_DVO1_ENUM_ID1; break; case ATOM_DEVICE_DFP3_SUPPORT: - ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1; break; } @@ -562,7 +562,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB) args.v1.ucMisc |= (1 << 1); } else { - if (dig_connector->linkb) + if (dig->linkb) args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; if (radeon_encoder->pixel_clock > 165000) args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; @@ -601,7 +601,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; } } else { - if (dig_connector->linkb) + if (dig->linkb) args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; if (radeon_encoder->pixel_clock > 165000) args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; @@ -781,7 +781,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; break; } - if (dig_connector->linkb) + if (dig->linkb) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; else args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; @@ -864,7 +864,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t else args.v3.ucLaneNum = 4; - if (dig_connector->linkb) { + if (dig->linkb) { args.v3.acConfig.ucLinkSel = 1; args.v3.acConfig.ucEncoderSel = 1; } @@ -904,7 +904,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } } else if (ASIC_IS_DCE32(rdev)) { args.v2.acConfig.ucEncoderSel = dig->dig_encoder; - if (dig_connector->linkb) + if (dig->linkb) args.v2.acConfig.ucLinkSel = 1; switch (radeon_encoder->encoder_id) { @@ -954,7 +954,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } } - if (dig_connector->linkb) + if (dig->linkb) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; else args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; @@ -1290,24 +1290,22 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) uint32_t dig_enc_in_use = 0; if (ASIC_IS_DCE4(rdev)) { - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); - + dig = radeon_encoder->enc_priv; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - if (dig_connector->linkb) + if (dig->linkb) return 1; else return 0; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - if (dig_connector->linkb) + if (dig->linkb) return 3; else return 2; break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (dig_connector->linkb) + if (dig->linkb) return 5; else return 4; @@ -1641,6 +1639,7 @@ radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) struct radeon_encoder_atom_dig * radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) { + int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); if (!dig) @@ -1650,11 +1649,16 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) dig->coherent_mode = true; dig->dig_encoder = -1; + if (encoder_enum == 2) + dig->linkb = true; + else + dig->linkb = false; + return dig; } void -radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device) { struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; @@ -1663,7 +1667,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su /* see if we already added it */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->encoder_id == encoder_id) { + if (radeon_encoder->encoder_enum == encoder_enum) { radeon_encoder->devices |= supported_device; return; } @@ -1691,7 +1695,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su radeon_encoder->enc_priv = NULL; - radeon_encoder->encoder_id = encoder_id; + radeon_encoder->encoder_enum = encoder_enum; + radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; radeon_encoder->underscan_type = UNDERSCAN_OFF; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index b8149cbc0c70..0b8397000f4c 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -1345,7 +1345,7 @@ static struct radeon_encoder_ext_tmds *radeon_legacy_get_ext_tmds_info(struct ra } void -radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device) { struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; @@ -1354,7 +1354,7 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t /* see if we already added it */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->encoder_id == encoder_id) { + if (radeon_encoder->encoder_enum == encoder_enum) { radeon_encoder->devices |= supported_device; return; } @@ -1374,7 +1374,8 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t radeon_encoder->enc_priv = NULL; - radeon_encoder->encoder_id = encoder_id; + radeon_encoder->encoder_enum = encoder_enum; + radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5bbc086b9267..8f93e2b4b0c8 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -342,6 +342,7 @@ struct radeon_atom_ss { }; struct radeon_encoder_atom_dig { + bool linkb; /* atom dig */ bool coherent_mode; int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */ @@ -360,6 +361,7 @@ struct radeon_encoder_atom_dac { struct radeon_encoder { struct drm_encoder base; + uint32_t encoder_enum; uint32_t encoder_id; uint32_t devices; uint32_t active_device; @@ -378,7 +380,6 @@ struct radeon_encoder { struct radeon_connector_atom_dig { uint32_t igp_lane_info; - bool linkb; /* displayport */ struct radeon_i2c_chan *dp_i2c_bus; u8 dpcd[8]; -- cgit v1.2.3-59-g8ed1b From e13b2ac1c46b9194ea9f44904760d3d49669529b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:58:46 -0400 Subject: drm/radeon/kms: DCE3/4 transmitter fixes - INIT action takes the actual connector type id, not the enum id - some evergreen cards have the ENABLE_OUTPUT/DISABLE_OUTPUT actions Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 404320f9c9b0..780bd302f58c 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -843,7 +843,8 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.ucAction = action; if (action == ATOM_TRANSMITTER_ACTION_INIT) { - args.v1.usInitInfo = radeon_connector->connector_object_id; + args.v1.usInitInfo = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { args.v1.asMode.ucLaneSel = lane_num; args.v1.asMode.ucLaneSet = lane_set; @@ -1072,8 +1073,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) if (is_dig) { switch (mode) { case DRM_MODE_DPMS_ON: - if (!ASIC_IS_DCE4(rdev)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); @@ -1085,8 +1085,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (!ASIC_IS_DCE4(rdev)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF); -- cgit v1.2.3-59-g8ed1b From 4aab97e818c255a1bc25bb981f121a7992c6b290 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:58:48 -0400 Subject: drm/radeon/kms/atom: clean up dig atom handling This allows the tables to be run in some additional cases where the connector info isn't necessary. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 115 ++++++++++++++----------------- 1 file changed, 53 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 780bd302f58c..3d38cba81dc5 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -228,32 +228,6 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) return NULL; } -static struct radeon_connector_atom_dig * -radeon_get_atom_connector_priv_from_encoder(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - struct radeon_connector_atom_dig *dig_connector; - - if (!rdev->is_atom_bios) - return NULL; - - connector = radeon_get_connector_for_encoder(encoder); - if (!connector) - return NULL; - - radeon_connector = to_radeon_connector(connector); - - if (!radeon_connector->con_priv) - return NULL; - - dig_connector = radeon_connector->con_priv; - - return dig_connector; -} - void radeon_panel_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { @@ -512,14 +486,12 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); union lvds_encoder_control args; int index = 0; int hdmi_detected = 0; uint8_t frev, crev; - if (!dig || !dig_connector) + if (!dig) return; if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) @@ -729,13 +701,24 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); union dig_encoder_control args; int index = 0; uint8_t frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + } - if (!dig || !dig_connector) + /* no dig encoder assigned */ + if (dig->dig_encoder == -1) return; memset(&args, 0, sizeof(args)); @@ -757,9 +740,9 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dig_connector->dp_clock == 270000) + if (dp_clock == 270000) args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; - args.v1.ucLaneNum = dig_connector->dp_lane_count; + args.v1.ucLaneNum = dp_lane_count; } else if (radeon_encoder->pixel_clock > 165000) args.v1.ucLaneNum = 8; else @@ -804,38 +787,47 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct radeon_connector_atom_dig *dig_connector = - radeon_get_atom_connector_priv_from_encoder(encoder); - struct drm_connector *connector; - struct radeon_connector *radeon_connector; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); union dig_transmitter_control args; int index = 0; uint8_t frev, crev; bool is_dp = false; int pll_id = 0; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + int igp_lane_info = 0; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + igp_lane_info = dig_connector->igp_lane_info; + } - if (!dig || !dig_connector) + /* no dig encoder assigned */ + if (dig->dig_encoder == -1) return; - connector = radeon_get_connector_for_encoder(encoder); - radeon_connector = to_radeon_connector(connector); - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) is_dp = true; memset(&args, 0, sizeof(args)); - if (ASIC_IS_DCE32(rdev) || ASIC_IS_DCE4(rdev)) + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - else { - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); - break; - } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); + break; } if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) @@ -843,15 +835,14 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t args.v1.ucAction = action; if (action == ATOM_TRANSMITTER_ACTION_INIT) { - args.v1.usInitInfo = - (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + args.v1.usInitInfo = connector_object_id; } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { args.v1.asMode.ucLaneSel = lane_num; args.v1.asMode.ucLaneSet = lane_set; } else { if (is_dp) args.v1.usPixelClock = - cpu_to_le16(dig_connector->dp_clock / 10); + cpu_to_le16(dp_clock / 10); else if (radeon_encoder->pixel_clock > 165000) args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); else @@ -859,7 +850,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t } if (ASIC_IS_DCE4(rdev)) { if (is_dp) - args.v3.ucLaneNum = dig_connector->dp_lane_count; + args.v3.ucLaneNum = dp_lane_count; else if (radeon_encoder->pixel_clock > 165000) args.v3.ucLaneNum = 8; else @@ -939,18 +930,18 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t if ((rdev->flags & RADEON_IS_IGP) && (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { if (is_dp || (radeon_encoder->pixel_clock <= 165000)) { - if (dig_connector->igp_lane_info & 0x1) + if (igp_lane_info & 0x1) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; - else if (dig_connector->igp_lane_info & 0x2) + else if (igp_lane_info & 0x2) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; - else if (dig_connector->igp_lane_info & 0x4) + else if (igp_lane_info & 0x4) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; - else if (dig_connector->igp_lane_info & 0x8) + else if (igp_lane_info & 0x8) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; } else { - if (dig_connector->igp_lane_info & 0x3) + if (igp_lane_info & 0x3) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; - else if (dig_connector->igp_lane_info & 0xc) + else if (igp_lane_info & 0xc) args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; } } -- cgit v1.2.3-59-g8ed1b From 4e186b2d6c878793587c35d7f06c94565d76e9b8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 13 Aug 2010 10:53:35 -0400 Subject: drm/radeon/kms/pm: bail early if nothing's changing If we aren't changing the power state, no need to take locks and schedule fences, etc. There seem to be lock ordering issues in the CP and fence code in some cases; see bug 29140 below. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=29140 Possibly also: https://bugzilla.kernel.org/show_bug.cgi?id=16581 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 58038f5cab38..477ba673e1b4 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -226,6 +226,11 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) { int i; + /* no need to take locks, etc. if nothing's going to change */ + if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && + (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) + return; + mutex_lock(&rdev->ddev->struct_mutex); mutex_lock(&rdev->vram_mutex); mutex_lock(&rdev->cp.mutex); -- cgit v1.2.3-59-g8ed1b From 5786e2c5a3f519647c50bbc276e45d36a704415a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 19 Aug 2010 11:19:31 -0400 Subject: drm/radeon/kms/DCE3+: switch pads to ddc mode when going i2c The pins for ddc and aux are shared so you need to switch the mode when doing ddc. The ProcessAuxChannel table already sets the pin mode to DP. This should fix unreliable ddc issues on DP ports using non-DP monitors. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index bfd2ce5f5372..0416804d8f30 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -99,6 +99,13 @@ static void radeon_i2c_do_lock(struct radeon_i2c_chan *i2c, int lock_state) } } + /* switch the pads to ddc mode */ + if (ASIC_IS_DCE3(rdev) && rec->hw_capable) { + temp = RREG32(rec->mask_clk_reg); + temp &= ~(1 << 16); + WREG32(rec->mask_clk_reg, temp); + } + /* clear the output pin values */ temp = RREG32(rec->a_clk_reg) & ~rec->a_clk_mask; WREG32(rec->a_clk_reg, temp); -- cgit v1.2.3-59-g8ed1b From 9c1ac0c6b97c6322c23cf3356028c28029c3b117 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 19 Aug 2010 14:28:33 -0400 Subject: drm/radeon/kms: add missing asic callback assignment for evergreen Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_asic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 646f96f97c77..a21bf88e8c2d 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -733,6 +733,7 @@ static struct radeon_asic evergreen_asic = { .set_engine_clock = &radeon_atom_set_engine_clock, .get_memory_clock = &radeon_atom_get_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock, + .get_pcie_lanes = NULL, .set_pcie_lanes = NULL, .set_clock_gating = NULL, .set_surface_reg = r600_set_surface_reg, -- cgit v1.2.3-59-g8ed1b From 6f50eae75b13e037e11f49128ea44a1a9a9535cb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 19 Aug 2010 17:29:03 -0400 Subject: drm/radeon/kms: rework radeon_dp_detect() logic If the connector is eDP, it can only be DP, not TMDS. Always set the detected sink type. If the sink is detected as non-DP, but there is no EDID, you can still manually force the port on. If the sink type is DP and there's no DPCD, there's no way to force the monitor on since you need both ends to train the link. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 20c353c86ce4..31a09cd279ab 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -977,24 +977,25 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto struct radeon_connector *radeon_connector = to_radeon_connector(connector); enum drm_connector_status ret = connector_status_disconnected; struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - u8 sink_type; if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; } - sink_type = radeon_dp_getsinktype(radeon_connector); - if ((sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || - (sink_type == CONNECTOR_OBJECT_ID_eDP)) { - if (radeon_dp_getdpcd(radeon_connector)) { - radeon_dig_connector->dp_sink_type = sink_type; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + /* eDP is always DP */ + radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; + if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; - } } else { - if (radeon_ddc_probe(radeon_connector)) { - radeon_dig_connector->dp_sink_type = sink_type; - ret = connector_status_connected; + radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector); + if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { + if (radeon_dp_getdpcd(radeon_connector)) + ret = connector_status_connected; + } else { + if (radeon_ddc_probe(radeon_connector)) + ret = connector_status_connected; } } -- cgit v1.2.3-59-g8ed1b From 19833b5dffe2f2e92a1b377f9aae9d5f32239512 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 19 Aug 2010 15:48:30 -0700 Subject: e1000e: disable ASPM L1 on 82573 On the e1000-devel mailing list, Nils Faerber reported latency issues with the 82573 LOM on a ThinkPad X60. It was found to be caused by ASPM L1; disabling it resolves the latency. The issue is present in kernels back to 2.6.34 and possibly 2.6.33. Reported-by: Nils Faerber Signed-off-by: Bruce Allan Cc: stable@kernel.org Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/82571.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index a4a0d2b6eb1c..f844e6c6063b 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -1833,6 +1833,7 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT | FLAG_HAS_SWSM_ON_LOAD, + .flags2 = FLAG2_DISABLE_ASPM_L1, .pba = 20, .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, .get_variants = e1000_get_variants_82571, -- cgit v1.2.3-59-g8ed1b From 161c48100236916e98d33a9c8b5fc8eae6decd15 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 19 Aug 2010 11:39:57 +0200 Subject: drm: fix end of loop test "agpmem" is never NULL here because it is the list cursor of a list_for_each_entry() list. Signed-off-by: Dan Carpenter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 3778360eceea..fda67468e603 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -138,7 +138,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) break; } - if (!agpmem) + if (&agpmem->head == &dev->agp->memory) goto vm_fault_error; /* -- cgit v1.2.3-59-g8ed1b From 09f0c489fa115a8b88a2da3edd0f3de00c8c7e2e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 19 Aug 2010 11:46:29 +0200 Subject: drm: move dereference below check "fb_helper_conn" is dereferenced before the check for NULL. It's never actually NULL here, so this is mostly to keep the static checkers happy. Signed-off-by: Dan Carpenter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 719662034bbf..cef8d8da5952 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -94,10 +94,11 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_conn int i; enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; struct drm_fb_helper_cmdline_mode *cmdline_mode; - struct drm_connector *connector = fb_helper_conn->connector; + struct drm_connector *connector; if (!fb_helper_conn) return false; + connector = fb_helper_conn->connector; cmdline_mode = &fb_helper_conn->cmdline_mode; if (!mode_option) -- cgit v1.2.3-59-g8ed1b From 1aef70ef125165e0114a8e475636eff242a52030 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 19 Aug 2010 15:48:52 -0700 Subject: e1000e: don't check for alternate MAC addr on parts that don't support it From: Bruce Allan The alternate MAC address feature is only supported by 80003ES2LAN and 82571 LOMs as well as a couple 82571 mezzanine cards. Checking for an alternate MAC address on other parts can fail leading to the driver not able to load. This patch limits the check for an alternate MAC address to be done only for parts that support the feature. This issue has been around since support for the feature was introduced to the e1000e driver in 2.6.34. Signed-off-by: Bruce Allan Reported-by: Fabio Varesano Cc: stable@kernel.org Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/82571.c | 30 +++++++++++++++++------------- drivers/net/e1000e/defines.h | 4 ++++ drivers/net/e1000e/lib.c | 10 ++++++++++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index f844e6c6063b..d3d4a57e2450 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -936,12 +936,14 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(IMC, 0xffffffff); icr = er32(ICR); - /* Install any alternate MAC address into RAR0 */ - ret_val = e1000_check_alt_mac_addr_generic(hw); - if (ret_val) - return ret_val; + if (hw->mac.type == e1000_82571) { + /* Install any alternate MAC address into RAR0 */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + return ret_val; - e1000e_set_laa_state_82571(hw, true); + e1000e_set_laa_state_82571(hw, true); + } /* Reinitialize the 82571 serdes link state machine */ if (hw->phy.media_type == e1000_media_type_internal_serdes) @@ -1618,14 +1620,16 @@ static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw) { s32 ret_val = 0; - /* - * If there's an alternate MAC address place it in RAR0 - * so that it will override the Si installed default perm - * address. - */ - ret_val = e1000_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; + if (hw->mac.type == e1000_82571) { + /* + * If there's an alternate MAC address place it in RAR0 + * so that it will override the Si installed default perm + * address. + */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + } ret_val = e1000_read_mac_addr_generic(hw); diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 307a72f483ee..93b3bedae8d2 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -621,6 +621,7 @@ #define E1000_FLASH_UPDATES 2000 /* NVM Word Offsets */ +#define NVM_COMPAT 0x0003 #define NVM_ID_LED_SETTINGS 0x0004 #define NVM_INIT_CONTROL2_REG 0x000F #define NVM_INIT_CONTROL3_PORT_B 0x0014 @@ -643,6 +644,9 @@ /* Mask bits for fields in Word 0x1a of the NVM */ #define NVM_WORD1A_ASPM_MASK 0x000C +/* Mask bits for fields in Word 0x03 of the EEPROM */ +#define NVM_COMPAT_LOM 0x0800 + /* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ #define NVM_SUM 0xBABA diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index df4a27922931..0fd4eb5ac5fb 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -183,6 +183,16 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) u16 offset, nvm_alt_mac_addr_offset, nvm_data; u8 alt_mac_addr[ETH_ALEN]; + ret_val = e1000_read_nvm(hw, NVM_COMPAT, 1, &nvm_data); + if (ret_val) + goto out; + + /* Check for LOM (vs. NIC) or one of two valid mezzanine cards */ + if (!((nvm_data & NVM_COMPAT_LOM) || + (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_DUAL) || + (hw->adapter->pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD))) + goto out; + ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, &nvm_alt_mac_addr_offset); if (ret_val) { -- cgit v1.2.3-59-g8ed1b From e57415d85f72e36029b75fdb556c95fb5346b692 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 18 Aug 2010 13:34:11 -0400 Subject: drm/radeon/kms: fix agp mode setup on cards that use pcie bridges Asics that use an AGP to PCIE bridge don't have the AGP_STATUS register so just use whatever mode the host side setup. Signed-off-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_agp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index f40dfb77f9b1..bd2f33e5c91a 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -156,7 +156,13 @@ int radeon_agp_init(struct radeon_device *rdev) } mode.mode = info.mode; - agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; + /* chips with the agp to pcie bridge don't have the AGP_STATUS register + * Just use the whatever mode the host sets up. + */ + if (rdev->family <= CHIP_RV350) + agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; + else + agp_status = mode.mode; is_v3 = !!(agp_status & RADEON_AGPv3_MODE); if (is_v3) { -- cgit v1.2.3-59-g8ed1b From da7be684c55dbaeebfc1a048d5faf52d52cb3c1f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 18:05:34 -0400 Subject: drm/radeon/kms: don't enable MSIs on AGP boards Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=29327 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 059bfa4098d7..a108c7ed14f5 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -121,11 +121,12 @@ int radeon_irq_kms_init(struct radeon_device *rdev) * chips. Disable MSI on them for now. */ if ((rdev->family >= CHIP_RV380) && - (!(rdev->flags & RADEON_IS_IGP))) { + (!(rdev->flags & RADEON_IS_IGP)) && + (!(rdev->flags & RADEON_IS_AGP))) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; - DRM_INFO("radeon: using MSI.\n"); + dev_info(rdev->dev, "radeon: using MSI.\n"); } } rdev->irq.installed = true; -- cgit v1.2.3-59-g8ed1b From b824b364d9ee001fc8c6bb71cc49f19bf740dd99 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Aug 2010 08:25:47 -0400 Subject: drm/radeon/kms: add back missing break in info ioctl This seems to have gotten lost in the hyper-z merge. Noticed by legume on IRC. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_kms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 27435db0aa48..5eee3c41d124 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -161,6 +161,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) DRM_DEBUG_KMS("tiling config is r6xx+ only!\n"); return -EINVAL; } + break; case RADEON_INFO_WANT_HYPERZ: /* The "value" here is both an input and output parameter. * If the input value is 1, filp requests hyper-z access. -- cgit v1.2.3-59-g8ed1b From bf4f12113812ac5be76c5590c6f50c8346f784a4 Mon Sep 17 00:00:00 2001 From: Igor Druzhinin Date: Fri, 20 Aug 2010 00:27:12 +0400 Subject: cifs: correction of unicode header files This patch corrects a problem of compilation errors at removal of UNIUPR_NOLOWER definition and adds include guards to cifs_unicode.h. Signed-off-by: Igor Druzhinin Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifs_unicode.h | 18 +++++++++++------- fs/cifs/cifs_uniupr.h | 16 ++++++++-------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 650638275a6f..7fe6b52df507 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -30,6 +30,8 @@ * This is a compressed table of upper and lower case conversion. * */ +#ifndef _CIFS_UNICODE_H +#define _CIFS_UNICODE_H #include #include @@ -67,8 +69,8 @@ extern const struct UniCaseRange CifsUniUpperRange[]; #endif /* UNIUPR_NOUPPER */ #ifndef UNIUPR_NOLOWER -extern signed char UniLowerTable[512]; -extern struct UniCaseRange UniLowerRange[]; +extern signed char CifsUniLowerTable[512]; +extern const struct UniCaseRange CifsUniLowerRange[]; #endif /* UNIUPR_NOLOWER */ #ifdef __KERNEL__ @@ -337,15 +339,15 @@ UniStrupr(register wchar_t *upin) * UniTolower: Convert a unicode character to lower case */ static inline wchar_t -UniTolower(wchar_t uc) +UniTolower(register wchar_t uc) { - register struct UniCaseRange *rp; + register const struct UniCaseRange *rp; - if (uc < sizeof(UniLowerTable)) { + if (uc < sizeof(CifsUniLowerTable)) { /* Latin characters */ - return uc + UniLowerTable[uc]; /* Use base tables */ + return uc + CifsUniLowerTable[uc]; /* Use base tables */ } else { - rp = UniLowerRange; /* Use range tables */ + rp = CifsUniLowerRange; /* Use range tables */ while (rp->start) { if (uc < rp->start) /* Before start of range */ return uc; /* Uppercase = input */ @@ -374,3 +376,5 @@ UniStrlwr(register wchar_t *upin) } #endif + +#endif /* _CIFS_UNICODE_H */ diff --git a/fs/cifs/cifs_uniupr.h b/fs/cifs/cifs_uniupr.h index 18a9d978e519..0ac7c5a8633a 100644 --- a/fs/cifs/cifs_uniupr.h +++ b/fs/cifs/cifs_uniupr.h @@ -140,7 +140,7 @@ const struct UniCaseRange CifsUniUpperRange[] = { /* * Latin lower case */ -static signed char CifsUniLowerTable[512] = { +signed char CifsUniLowerTable[512] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ @@ -242,12 +242,12 @@ static signed char UniCaseRangeLff20[27] = { /* * Lower Case Range */ -static const struct UniCaseRange CifsUniLowerRange[] = { - 0x0380, 0x03ab, UniCaseRangeL0380, - 0x0400, 0x042f, UniCaseRangeL0400, - 0x0490, 0x04cb, UniCaseRangeL0490, - 0x1e00, 0x1ff7, UniCaseRangeL1e00, - 0xff20, 0xff3a, UniCaseRangeLff20, - 0, 0, 0 +const struct UniCaseRange CifsUniLowerRange[] = { + {0x0380, 0x03ab, UniCaseRangeL0380}, + {0x0400, 0x042f, UniCaseRangeL0400}, + {0x0490, 0x04cb, UniCaseRangeL0490}, + {0x1e00, 0x1ff7, UniCaseRangeL1e00}, + {0xff20, 0xff3a, UniCaseRangeLff20}, + {0} }; #endif -- cgit v1.2.3-59-g8ed1b From 1495cc9df4e81f5a8fa9b0b8f1034b14d24b7d8c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 17 Aug 2010 21:15:46 -0700 Subject: Input: sysrq - drop tty argument from sysrq ops handlers Noone is using tty argument so let's get rid of it. Acked-by: Alan Cox Acked-by: Jason Wessel Acked-by: Greg Kroah-Hartman Signed-off-by: Dmitry Torokhov --- arch/arm/kernel/etm.c | 2 +- arch/powerpc/xmon/xmon.c | 5 ++--- arch/sparc/kernel/process_64.c | 2 +- drivers/char/sysrq.c | 42 ++++++++++++++++++++--------------------- drivers/gpu/drm/drm_fb_helper.c | 2 +- drivers/net/ibm_newemac/debug.c | 2 +- include/linux/sysrq.h | 6 +++++- kernel/debug/debug_core.c | 2 +- kernel/power/poweroff.c | 2 +- 9 files changed, 34 insertions(+), 31 deletions(-) diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c index 56418f98cd01..33c7077174db 100644 --- a/arch/arm/kernel/etm.c +++ b/arch/arm/kernel/etm.c @@ -230,7 +230,7 @@ static void etm_dump(void) etb_lock(t); } -static void sysrq_etm_dump(int key, struct tty_struct *tty) +static void sysrq_etm_dump(int key) { dev_dbg(tracer.dev, "Dumping ETB buffer\n"); etm_dump(); diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 0554445200bf..d17d04cfb2cd 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -2880,15 +2880,14 @@ static void xmon_init(int enable) } #ifdef CONFIG_MAGIC_SYSRQ -static void sysrq_handle_xmon(int key, struct tty_struct *tty) +static void sysrq_handle_xmon(int key) { /* ensure xmon is enabled */ xmon_init(1); debugger(get_irq_regs()); } -static struct sysrq_key_op sysrq_xmon_op = -{ +static struct sysrq_key_op sysrq_xmon_op = { .handler = sysrq_handle_xmon, .help_msg = "Xmon", .action_msg = "Entering xmon", diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index dbe81a368b45..25b01b43b40d 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -303,7 +303,7 @@ void arch_trigger_all_cpu_backtrace(void) #ifdef CONFIG_MAGIC_SYSRQ -static void sysrq_handle_globreg(int key, struct tty_struct *tty) +static void sysrq_handle_globreg(int key) { arch_trigger_all_cpu_backtrace(); } diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 878ac0c2cc68..a892a3c249dd 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -76,7 +76,7 @@ static int __init sysrq_always_enabled_setup(char *str) __setup("sysrq_always_enabled", sysrq_always_enabled_setup); -static void sysrq_handle_loglevel(int key, struct tty_struct *tty) +static void sysrq_handle_loglevel(int key) { int i; @@ -93,7 +93,7 @@ static struct sysrq_key_op sysrq_loglevel_op = { }; #ifdef CONFIG_VT -static void sysrq_handle_SAK(int key, struct tty_struct *tty) +static void sysrq_handle_SAK(int key) { struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; schedule_work(SAK_work); @@ -109,7 +109,7 @@ static struct sysrq_key_op sysrq_SAK_op = { #endif #ifdef CONFIG_VT -static void sysrq_handle_unraw(int key, struct tty_struct *tty) +static void sysrq_handle_unraw(int key) { struct kbd_struct *kbd = &kbd_table[fg_console]; @@ -126,7 +126,7 @@ static struct sysrq_key_op sysrq_unraw_op = { #define sysrq_unraw_op (*(struct sysrq_key_op *)NULL) #endif /* CONFIG_VT */ -static void sysrq_handle_crash(int key, struct tty_struct *tty) +static void sysrq_handle_crash(int key) { char *killer = NULL; @@ -141,7 +141,7 @@ static struct sysrq_key_op sysrq_crash_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_reboot(int key, struct tty_struct *tty) +static void sysrq_handle_reboot(int key) { lockdep_off(); local_irq_enable(); @@ -154,7 +154,7 @@ static struct sysrq_key_op sysrq_reboot_op = { .enable_mask = SYSRQ_ENABLE_BOOT, }; -static void sysrq_handle_sync(int key, struct tty_struct *tty) +static void sysrq_handle_sync(int key) { emergency_sync(); } @@ -165,7 +165,7 @@ static struct sysrq_key_op sysrq_sync_op = { .enable_mask = SYSRQ_ENABLE_SYNC, }; -static void sysrq_handle_show_timers(int key, struct tty_struct *tty) +static void sysrq_handle_show_timers(int key) { sysrq_timer_list_show(); } @@ -176,7 +176,7 @@ static struct sysrq_key_op sysrq_show_timers_op = { .action_msg = "Show clockevent devices & pending hrtimers (no others)", }; -static void sysrq_handle_mountro(int key, struct tty_struct *tty) +static void sysrq_handle_mountro(int key) { emergency_remount(); } @@ -188,7 +188,7 @@ static struct sysrq_key_op sysrq_mountro_op = { }; #ifdef CONFIG_LOCKDEP -static void sysrq_handle_showlocks(int key, struct tty_struct *tty) +static void sysrq_handle_showlocks(int key) { debug_show_all_locks(); } @@ -226,7 +226,7 @@ static void sysrq_showregs_othercpus(struct work_struct *dummy) static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); -static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) +static void sysrq_handle_showallcpus(int key) { /* * Fall back to the workqueue based printing if the @@ -252,7 +252,7 @@ static struct sysrq_key_op sysrq_showallcpus_op = { }; #endif -static void sysrq_handle_showregs(int key, struct tty_struct *tty) +static void sysrq_handle_showregs(int key) { struct pt_regs *regs = get_irq_regs(); if (regs) @@ -266,7 +266,7 @@ static struct sysrq_key_op sysrq_showregs_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_showstate(int key, struct tty_struct *tty) +static void sysrq_handle_showstate(int key) { show_state(); } @@ -277,7 +277,7 @@ static struct sysrq_key_op sysrq_showstate_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) +static void sysrq_handle_showstate_blocked(int key) { show_state_filter(TASK_UNINTERRUPTIBLE); } @@ -291,7 +291,7 @@ static struct sysrq_key_op sysrq_showstate_blocked_op = { #ifdef CONFIG_TRACING #include -static void sysrq_ftrace_dump(int key, struct tty_struct *tty) +static void sysrq_ftrace_dump(int key) { ftrace_dump(DUMP_ALL); } @@ -305,7 +305,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = { #define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL) #endif -static void sysrq_handle_showmem(int key, struct tty_struct *tty) +static void sysrq_handle_showmem(int key) { show_mem(); } @@ -330,7 +330,7 @@ static void send_sig_all(int sig) } } -static void sysrq_handle_term(int key, struct tty_struct *tty) +static void sysrq_handle_term(int key) { send_sig_all(SIGTERM); console_loglevel = 8; @@ -349,7 +349,7 @@ static void moom_callback(struct work_struct *ignored) static DECLARE_WORK(moom_work, moom_callback); -static void sysrq_handle_moom(int key, struct tty_struct *tty) +static void sysrq_handle_moom(int key) { schedule_work(&moom_work); } @@ -361,7 +361,7 @@ static struct sysrq_key_op sysrq_moom_op = { }; #ifdef CONFIG_BLOCK -static void sysrq_handle_thaw(int key, struct tty_struct *tty) +static void sysrq_handle_thaw(int key) { emergency_thaw_all(); } @@ -373,7 +373,7 @@ static struct sysrq_key_op sysrq_thaw_op = { }; #endif -static void sysrq_handle_kill(int key, struct tty_struct *tty) +static void sysrq_handle_kill(int key) { send_sig_all(SIGKILL); console_loglevel = 8; @@ -385,7 +385,7 @@ static struct sysrq_key_op sysrq_kill_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -static void sysrq_handle_unrt(int key, struct tty_struct *tty) +static void sysrq_handle_unrt(int key) { normalize_rt_tasks(); } @@ -520,7 +520,7 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { printk("%s\n", op_p->action_msg); console_loglevel = orig_log_level; - op_p->handler(key, tty); + op_p->handler(key); } else { printk("This sysrq operation is disabled.\n"); } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index de82e201d682..5efd6d6742ec 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -369,7 +369,7 @@ static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) } static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn); -static void drm_fb_helper_sysrq(int dummy1, struct tty_struct *dummy3) +static void drm_fb_helper_sysrq(int dummy1) { schedule_work(&drm_fb_helper_restore_work); } diff --git a/drivers/net/ibm_newemac/debug.c b/drivers/net/ibm_newemac/debug.c index 3995fafc1e08..8c6c1e2a8750 100644 --- a/drivers/net/ibm_newemac/debug.c +++ b/drivers/net/ibm_newemac/debug.c @@ -238,7 +238,7 @@ void emac_dbg_dump_all(void) } #if defined(CONFIG_MAGIC_SYSRQ) -static void emac_sysrq_handler(int key, struct tty_struct *tty) +static void emac_sysrq_handler(int key) { emac_dbg_dump_all(); } diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 609e8ca5f534..4ee650315119 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -31,7 +31,7 @@ struct tty_struct; #define SYSRQ_ENABLE_RTNICE 0x0100 struct sysrq_key_op { - void (*handler)(int, struct tty_struct *); + void (*handler)(int); char *help_msg; char *action_msg; int enable_mask; @@ -58,6 +58,10 @@ static inline void handle_sysrq(int key, struct tty_struct *tty) { } +static inline void __handle_sysrq(int key, struct tty_struct *tty, int check_mask); +{ +} + static inline int register_sysrq_key(int key, struct sysrq_key_op *op) { return -EINVAL; diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 3c2d4972d235..de407c78178d 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -741,7 +741,7 @@ static struct console kgdbcons = { }; #ifdef CONFIG_MAGIC_SYSRQ -static void sysrq_handle_dbg(int key, struct tty_struct *tty) +static void sysrq_handle_dbg(int key) { if (!dbg_io_ops) { printk(KERN_CRIT "ERROR: No KGDB I/O module available\n"); diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c index e8b337006276..d52359374e85 100644 --- a/kernel/power/poweroff.c +++ b/kernel/power/poweroff.c @@ -24,7 +24,7 @@ static void do_poweroff(struct work_struct *dummy) static DECLARE_WORK(poweroff_work, do_poweroff); -static void handle_poweroff(int key, struct tty_struct *tty) +static void handle_poweroff(int key) { /* run sysrq poweroff on boot cpu */ schedule_work_on(cpumask_first(cpu_online_mask), &poweroff_work); -- cgit v1.2.3-59-g8ed1b From d033af87e2a215a57ac2bbc47e0d7a544f2afcc4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 20 Aug 2010 01:09:22 -0400 Subject: drm/radeon/kms: set encoder type to DVI for HDMI on evergreen Fixes the pink line that shows up with some hdmi monitors. This will need to be revisited when audio support is added. Fixes: http://bugs.freedesktop.org/show_bug.cgi?id=27452 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 3d38cba81dc5..2c293e8304d6 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -595,6 +595,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct radeon_connector_atom_dig *dig_connector; @@ -608,9 +610,13 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ - if (drm_detect_hdmi_monitor(radeon_connector->edid)) - return ATOM_ENCODER_MODE_HDMI; - else if (radeon_connector->use_digital) + if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else if (radeon_connector->use_digital) return ATOM_ENCODER_MODE_DVI; else return ATOM_ENCODER_MODE_CRT; @@ -618,9 +624,13 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) case DRM_MODE_CONNECTOR_DVID: case DRM_MODE_CONNECTOR_HDMIA: default: - if (drm_detect_hdmi_monitor(radeon_connector->edid)) - return ATOM_ENCODER_MODE_HDMI; - else + if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else return ATOM_ENCODER_MODE_DVI; break; case DRM_MODE_CONNECTOR_LVDS: @@ -632,9 +642,13 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) return ATOM_ENCODER_MODE_DP; - else if (drm_detect_hdmi_monitor(radeon_connector->edid)) - return ATOM_ENCODER_MODE_HDMI; - else + else if (drm_detect_hdmi_monitor(radeon_connector->edid)) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else return ATOM_ENCODER_MODE_DVI; break; case DRM_MODE_CONNECTOR_DVIA: -- cgit v1.2.3-59-g8ed1b From 4f34760787c3751a3146f0eecdc79c3e97b94962 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Aug 2010 09:41:59 +0200 Subject: ALSA: hda - Fix conflict of sticky PCM parameter in HDMI codecs Intel and Nvidia HDMI codec drivers have own implementations of sticky PCM parameters. Now HD-audio core part already has it, thus both setups conflict. The fix is simply remove the part in patch_intelhdmi.c and patch_nvhdmi.c and simply call snd_hda_codec_setup_stream() as usual. Reported-and-tested-by: Stephen Warren Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 21 +-------------------- sound/pci/hda/patch_intelhdmi.c | 8 -------- sound/pci/hda/patch_nvhdmi.c | 8 -------- 3 files changed, 1 insertion(+), 36 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 2bc0f07cf33f..afd6022a96a7 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -707,8 +707,6 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int format) { struct hdmi_spec *spec = codec->spec; - int tag; - int fmt; int pinctl; int new_pinctl = 0; int i; @@ -745,24 +743,7 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, return -EINVAL; } - tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; - fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); - - snd_printdd("hdmi_setup_stream: " - "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", - nid, - tag == stream_tag ? "" : "new-", - stream_tag, - fmt == format ? "" : "new-", - format); - - if (tag != stream_tag) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - stream_tag << 4); - if (fmt != format) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, format); + snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); return 0; } diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index d382d3c81c0f..36a9b83a6174 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -69,20 +69,12 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); } -static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; -} - static struct hda_pcm_stream intel_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, .ops = { .open = hdmi_pcm_open, .prepare = intel_hdmi_playback_pcm_prepare, - .cleanup = intel_hdmi_playback_pcm_cleanup, }, }; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index f636870dc718..69b950d527c3 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -326,13 +326,6 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, return 0; } -static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; -} - static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -350,7 +343,6 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { .ops = { .open = hdmi_pcm_open, .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, - .cleanup = nvhdmi_playback_pcm_cleanup, }, }; -- cgit v1.2.3-59-g8ed1b From 3f50ac6a0ec80a83a1a033fe5004fb319ad72db7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 20 Aug 2010 09:44:36 +0200 Subject: ALSA: hda - Fix stream and channel-ids codec-bus wide The new sticky PCM parameter introduced the delayed clean-ups of stream- and channel-id tags. In the current implementation, this check (adding dirty flag) and actual clean-ups are done only for the codec chip. However, with HD-audio architecture, multiple codecs can be on a single bus, and the controller assign stream- and channel-ids in the bus-wide. In this patch, the stream-id and channel-id are checked over all codecs connected to the corresponding bus. Together with it, the mutex is moved to struct hda_bus, as this becomes also bus-wide. Reported-and-tested-by: Stephen Warren Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 33 ++++++++++++++++++++------------- sound/pci/hda/hda_codec.h | 2 +- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index dd8fb86c842b..3827092cc1d2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -589,6 +589,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, bus->ops = temp->ops; mutex_init(&bus->cmd_mutex); + mutex_init(&bus->prepare_mutex); INIT_LIST_HEAD(&bus->codec_list); snprintf(bus->workq_name, sizeof(bus->workq_name), @@ -1068,7 +1069,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); mutex_init(&codec->control_mutex); - mutex_init(&codec->prepare_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); @@ -1213,6 +1213,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format) { + struct hda_codec *c; struct hda_cvt_setup *p; unsigned int oldval, newval; int i; @@ -1253,10 +1254,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, p->dirty = 0; /* make other inactive cvts with the same stream-tag dirty */ - for (i = 0; i < codec->cvt_setups.used; i++) { - p = snd_array_elem(&codec->cvt_setups, i); - if (!p->active && p->stream_tag == stream_tag) - p->dirty = 1; + list_for_each_entry(c, &codec->bus->codec_list, list) { + for (i = 0; i < c->cvt_setups.used; i++) { + p = snd_array_elem(&c->cvt_setups, i); + if (!p->active && p->stream_tag == stream_tag) + p->dirty = 1; + } } } EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); @@ -1306,12 +1309,16 @@ static void really_cleanup_stream(struct hda_codec *codec, /* clean up the all conflicting obsolete streams */ static void purify_inactive_streams(struct hda_codec *codec) { + struct hda_codec *c; int i; - for (i = 0; i < codec->cvt_setups.used; i++) { - struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i); - if (p->dirty) - really_cleanup_stream(codec, p); + list_for_each_entry(c, &codec->bus->codec_list, list) { + for (i = 0; i < c->cvt_setups.used; i++) { + struct hda_cvt_setup *p; + p = snd_array_elem(&c->cvt_setups, i); + if (p->dirty) + really_cleanup_stream(c, p); + } } } @@ -3502,11 +3509,11 @@ int snd_hda_codec_prepare(struct hda_codec *codec, struct snd_pcm_substream *substream) { int ret; - mutex_lock(&codec->prepare_mutex); + mutex_lock(&codec->bus->prepare_mutex); ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream); if (ret >= 0) purify_inactive_streams(codec); - mutex_unlock(&codec->prepare_mutex); + mutex_unlock(&codec->bus->prepare_mutex); return ret; } EXPORT_SYMBOL_HDA(snd_hda_codec_prepare); @@ -3515,9 +3522,9 @@ void snd_hda_codec_cleanup(struct hda_codec *codec, struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { - mutex_lock(&codec->prepare_mutex); + mutex_lock(&codec->bus->prepare_mutex); hinfo->ops.cleanup(hinfo, codec, substream); - mutex_unlock(&codec->prepare_mutex); + mutex_unlock(&codec->bus->prepare_mutex); } EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 4303353feda9..62c702240108 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -648,6 +648,7 @@ struct hda_bus { struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; struct mutex cmd_mutex; + struct mutex prepare_mutex; /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; @@ -826,7 +827,6 @@ struct hda_codec { struct mutex spdif_mutex; struct mutex control_mutex; - struct mutex prepare_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ -- cgit v1.2.3-59-g8ed1b From 05e407603e527f9d808dd3866d3a17c2ce4dfcc5 Mon Sep 17 00:00:00 2001 From: Daniel Kiper Date: Fri, 20 Aug 2010 00:46:16 +0200 Subject: x86, apic: Fix apic=debug boot crash Fix a boot crash when apic=debug is used and the APIC is not properly initialized. This issue appears during Xen Dom0 kernel boot but the fix is generic and the crash could occur on real hardware as well. Signed-off-by: Daniel Kiper Cc: xen-devel@lists.xensource.com Cc: konrad.wilk@oracle.com Cc: jeremy@goop.org Cc: # .35.x, .34.x, .33.x, .32.x LKML-Reference: <20100819224616.GB9967@router-fw-old.local.net-space.pl> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/io_apic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 4dc0084ec1b1..f1efebaf5510 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1728,6 +1728,8 @@ __apicdebuginit(void) print_IO_APIC(void) struct irq_pin_list *entry; cfg = desc->chip_data; + if (!cfg) + continue; entry = cfg->irq_2_pin; if (!entry) continue; -- cgit v1.2.3-59-g8ed1b From 410d878bd05315a19894b8b4685107f2cd0712a5 Mon Sep 17 00:00:00 2001 From: Arnd Hannemann Date: Wed, 18 Aug 2010 16:24:13 +0000 Subject: ARM: mach-shmobile: ap4evb: fix write protect for SDHI1 SDHI1 on AP4EVB has no pin to detect write protection of a card. This had the result that a card inserted in this slot was always detected as read only. This patch adds the corresponding flag to disable write protection detection for SDHI1. Signed-off-by: Arnd Hannemann Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 1b95f122ecf5..95935c83c306 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -308,6 +309,7 @@ static struct sh_mobile_sdhi_info sdhi1_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX, .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX, .tmio_ocr_mask = MMC_VDD_165_195, + .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE, }; static struct resource sdhi1_resources[] = { -- cgit v1.2.3-59-g8ed1b From 7b8ea53d7f1865cd8f05dfb8f706a4ff5a72abcf Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Fri, 20 Aug 2010 05:36:06 -0400 Subject: makefile: not need to regenerate kernel.release file when make kernelrelease Brice reported that 'kernelrelease' has a dependence on include/config/kernel.release, causes this file to be regenerated every time when invoke it. It doesn't have to. Reported-by: Brice Goglin Tested-by: Brice Goglin Signed-off-by: WANG Cong Signed-off-by: Michal Marek --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f3bdff8c8d78..25da2521dd41 100644 --- a/Makefile +++ b/Makefile @@ -1408,8 +1408,8 @@ checkstack: $(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \ $(PERL) $(src)/scripts/checkstack.pl $(CHECKSTACK_ARCH) -kernelrelease: include/config/kernel.release - @echo $(KERNELRELEASE) +kernelrelease: + @echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" kernelversion: @echo $(KERNELVERSION) -- cgit v1.2.3-59-g8ed1b From 861d034ee814917a83bd5de4b26e3b8336ddeeb8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 19 Aug 2010 13:31:43 +0200 Subject: sched: Fix rq->clock synchronization when migrating tasks sched_fork() -- we do task placement in ->task_fork_fair() ensure we update_rq_clock() so we work with current time. We leave the vruntime in relative state, so the time delay until wake_up_new_task() doesn't matter. wake_up_new_task() -- Since task_fork_fair() left p->vruntime in relative state we can safely migrate, the activate_task() on the remote rq will call update_rq_clock() and causes the clock to be synced (enough). Tested-by: Jack Daniel Tested-by: Philby John Signed-off-by: Peter Zijlstra LKML-Reference: <1281002322.1923.1708.camel@laptop> Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 806d1b227a21..ab661ebc4895 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -3752,6 +3752,8 @@ static void task_fork_fair(struct task_struct *p) raw_spin_lock_irqsave(&rq->lock, flags); + update_rq_clock(rq); + if (unlikely(task_cpu(p) != this_cpu)) __set_task_cpu(p, this_cpu); -- cgit v1.2.3-59-g8ed1b From cd7240c0b900eb6d690ccee088a6c9b46dae815a Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Thu, 19 Aug 2010 17:03:38 -0700 Subject: x86, tsc, sched: Recompute cyc2ns_offset's during resume from sleep states TSC's get reset after suspend/resume (even on cpu's with invariant TSC which runs at a constant rate across ACPI P-, C- and T-states). And in some systems BIOS seem to reinit TSC to arbitrary large value (still sync'd across cpu's) during resume. This leads to a scenario of scheduler rq->clock (sched_clock_cpu()) less than rq->age_stamp (introduced in 2.6.32). This leads to a big value returned by scale_rt_power() and the resulting big group power set by the update_group_power() is causing improper load balancing between busy and idle cpu's after suspend/resume. This resulted in multi-threaded workloads (like kernel-compilation) go slower after suspend/resume cycle on core i5 laptops. Fix this by recomputing cyc2ns_offset's during resume, so that sched_clock() continues from the point where it was left off during suspend. Reported-by: Florian Pritz Signed-off-by: Suresh Siddha Cc: # [v2.6.32+] Signed-off-by: Peter Zijlstra LKML-Reference: <1282262618.2675.24.camel@sbsiddha-MOBL3.sc.intel.com> Signed-off-by: Ingo Molnar --- arch/x86/include/asm/tsc.h | 2 ++ arch/x86/kernel/tsc.c | 38 ++++++++++++++++++++++++++++++++++++++ arch/x86/power/cpu.c | 2 ++ 3 files changed, 42 insertions(+) diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index c0427295e8f5..1ca132fc0d03 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -59,5 +59,7 @@ extern void check_tsc_sync_source(int cpu); extern void check_tsc_sync_target(void); extern int notsc_setup(char *); +extern void save_sched_clock_state(void); +extern void restore_sched_clock_state(void); #endif /* _ASM_X86_TSC_H */ diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index ce8e50239332..d632934cb638 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -626,6 +626,44 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) local_irq_restore(flags); } +static unsigned long long cyc2ns_suspend; + +void save_sched_clock_state(void) +{ + if (!sched_clock_stable) + return; + + cyc2ns_suspend = sched_clock(); +} + +/* + * Even on processors with invariant TSC, TSC gets reset in some the + * ACPI system sleep states. And in some systems BIOS seem to reinit TSC to + * arbitrary value (still sync'd across cpu's) during resume from such sleep + * states. To cope up with this, recompute the cyc2ns_offset for each cpu so + * that sched_clock() continues from the point where it was left off during + * suspend. + */ +void restore_sched_clock_state(void) +{ + unsigned long long offset; + unsigned long flags; + int cpu; + + if (!sched_clock_stable) + return; + + local_irq_save(flags); + + get_cpu_var(cyc2ns_offset) = 0; + offset = cyc2ns_suspend - sched_clock(); + + for_each_possible_cpu(cpu) + per_cpu(cyc2ns_offset, cpu) = offset; + + local_irq_restore(flags); +} + #ifdef CONFIG_CPU_FREQ /* Frequency scaling support. Adjust the TSC based timer when the cpu frequency diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c index e7e8c5f54956..87bb35e34ef1 100644 --- a/arch/x86/power/cpu.c +++ b/arch/x86/power/cpu.c @@ -113,6 +113,7 @@ static void __save_processor_state(struct saved_context *ctxt) void save_processor_state(void) { __save_processor_state(&saved_context); + save_sched_clock_state(); } #ifdef CONFIG_X86_32 EXPORT_SYMBOL(save_processor_state); @@ -229,6 +230,7 @@ static void __restore_processor_state(struct saved_context *ctxt) void restore_processor_state(void) { __restore_processor_state(&saved_context); + restore_sched_clock_state(); } #ifdef CONFIG_X86_32 EXPORT_SYMBOL(restore_processor_state); -- cgit v1.2.3-59-g8ed1b From c81476df1b4241aefba4ff83a7701b3a926bd7ce Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Thu, 19 Aug 2010 14:13:25 -0700 Subject: matroxfb: fix incorrect use of memcpy_toio() Screen is completely corrupted since 2.6.34. Bisection revealed that it's caused by commit 6175ddf06b61720 ("x86: Clean up mem*io functions."). H. Peter Anvin explained that memcpy_toio() does not copy data in 32bit chunks anymore on x86. Signed-off-by: Ondrej Zary Cc: Brian Gerst Cc: H. Peter Anvin Cc: Petr Vandrovec Cc: Jean Delvare Cc: [2.6.34.x, 2.6.35.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/matrox/matroxfb_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index f3a4e15672d9..f96a471cb1a8 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -151,13 +151,13 @@ static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) { static inline void mga_memcpy_toio(vaddr_t va, const void* src, int len) { #if defined(__alpha__) || defined(__i386__) || defined(__x86_64__) /* - * memcpy_toio works for us if: + * iowrite32_rep works for us if: * (1) Copies data as 32bit quantities, not byte after byte, * (2) Performs LE ordered stores, and * (3) It copes with unaligned source (destination is guaranteed to be page * aligned and length is guaranteed to be multiple of 4). */ - memcpy_toio(va.vaddr, src, len); + iowrite32_rep(va.vaddr, src, len >> 2); #else u_int32_t __iomem* addr = va.vaddr; -- cgit v1.2.3-59-g8ed1b From b35de43b31040828f83046f40fd34ba33146409d Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:27 -0700 Subject: kfifo: implement missing __kfifo_skip_r() kfifo_skip() is currently broken, due to the missing of the internal helper function. Add it. Signed-off-by: Andrea Righi Cc: Greg KH Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kfifo.h | 2 ++ kernel/kfifo.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index 311f8753d713..4aa95f203f3e 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -836,6 +836,8 @@ extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize); extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize); +extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize); + extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf, unsigned int len, size_t recsize); diff --git a/kernel/kfifo.c b/kernel/kfifo.c index 4502604ecadf..6b5580c57644 100644 --- a/kernel/kfifo.c +++ b/kernel/kfifo.c @@ -503,6 +503,15 @@ unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf, } EXPORT_SYMBOL(__kfifo_out_r); +void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize) +{ + unsigned int n; + + n = __kfifo_peek_n(fifo, recsize); + fifo->out += n + recsize; +} +EXPORT_SYMBOL(__kfifo_skip_r); + int __kfifo_from_user_r(struct __kfifo *fifo, const void __user *from, unsigned long len, unsigned int *copied, size_t recsize) { -- cgit v1.2.3-59-g8ed1b From 5ddf83912c8b49a24ab0841f6d77f33781dcf10f Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:28 -0700 Subject: kfifo: add kfifo_skip() testcase Add a testcase for kfifo_skip() to the byte stream fifo example. Signed-off-by: Andrea Righi Cc: Greg KH Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/bytestream-example.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index 642eef3f6336..2e3a7a8128a2 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -73,6 +73,10 @@ static int __init testfunc(void) ret = kfifo_in(&test, buf, ret); printk(KERN_INFO "ret: %d\n", ret); + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + /* put values into the fifo until is full */ for (i = 20; kfifo_put(&test, &i); i++) ; -- cgit v1.2.3-59-g8ed1b From 2aaf2092c168fc02df0645415f524b357ee7ec2e Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:29 -0700 Subject: kfifo: add explicit error checking in byte stream example Provide a static array of expected items that kfifo should contain at the end of the test to validate it. Signed-off-by: Andrea Righi Cc: Stefani Seibold Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/bytestream-example.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index 2e3a7a8128a2..a94e6948b30d 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -44,10 +44,17 @@ static struct kfifo test; static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE); #endif +static unsigned char expected_result[FIFO_SIZE] = { + 3, 4, 5, 6, 7, 8, 9, 0, + 1, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, +}; + static int __init testfunc(void) { unsigned char buf[6]; - unsigned char i; + unsigned char i, j; unsigned int ret; printk(KERN_INFO "byte stream fifo test start\n"); @@ -83,10 +90,19 @@ static int __init testfunc(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); - /* print out all values in the fifo */ - while (kfifo_get(&test, &i)) - printk("%d ", i); - printk("\n"); + /* check the correctness of all values in the fifo */ + j = 0; + while (kfifo_get(&test, &i)) { + if (i != expected_result[j++]) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (j != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); return 0; } @@ -142,7 +158,12 @@ static int __init example_init(void) #else INIT_KFIFO(test); #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC -- cgit v1.2.3-59-g8ed1b From 7b34d5257a90c419d67c1c3b52f87a679845ef1e Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:29 -0700 Subject: kfifo: fix kernel BUG in dma example The scatterlist is used uninitialized in kfifo_dma_in_prepare(). This triggers the following bug if CONFIG_DEBUG_SG=y: ------------[ cut here ]------------ kernel BUG at include/linux/scatterlist.h:65! invalid opcode: 0000 [#1] PREEMPT SMP ... Call Trace: [] setup_sgl+0x6b/0xe0 [] ? example_init+0x0/0x265 [dma_example] [] __kfifo_dma_in_prepare+0x21/0x30 [] example_init+0x124/0x265 [dma_example] [] ? trace_module_notify+0x25/0x370 [] ? free_pages_prepare+0x11e/0x1e0 [] ? get_parent_ip+0x11/0x50 [] ? trace_module_notify+0x25/0x370 [] ? trace_hardirqs_on+0xd/0x10 [] ? mutex_unlock+0xe/0x10 [] ? trace_module_notify+0x41/0x370 [] ? __blocking_notifier_call_chain+0x45/0x80 [] ? vfree+0x2a/0x30 [] ? up_read+0x23/0x40 [] ? __blocking_notifier_call_chain+0x65/0x80 [] do_one_initcall+0x43/0x180 [] sys_init_module+0xba/0x200 [] system_call_fastpath+0x16/0x1b RIP [] setup_sgl_buf+0x1a1/0x1b0 RSP ---[ end trace a72b979fd3c1d3a5 ]--- Add the proper initialization to avoid the bug. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/dma-example.c | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index b9482c28b41a..03433ca5bdad 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -45,6 +45,7 @@ static int __init example_init(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + sg_init_table(sg, ARRAY_SIZE(sg)); ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE); printk(KERN_INFO "DMA sgl entries: %d\n", ret); -- cgit v1.2.3-59-g8ed1b From d83a71c4219191a9a881318ae5ca9b39aa1d0540 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:30 -0700 Subject: kfifo: fix a memory leak in dma example We use a dynamically allocated kfifo in the dma example, so we need to free it when unloading the module. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/dma-example.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index 03433ca5bdad..3682278785f7 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -105,9 +105,7 @@ static int __init example_init(void) static void __exit example_exit(void) { -#ifdef DYNAMIC - kfifo_free(&test); -#endif + kfifo_free(&fifo); } module_init(example_init); -- cgit v1.2.3-59-g8ed1b From a25effa4d265eb5028c7d4a92a0ddd9267c3c43d Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Thu, 19 Aug 2010 14:13:30 -0700 Subject: kfifo: add explicit error checking in all the examples Provide a check in all the kfifo examples to validate the correct execution of each testcase. Signed-off-by: Andrea Righi Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- samples/kfifo/bytestream-example.c | 7 ++- samples/kfifo/dma-example.c | 106 +++++++++++++++++++++++-------------- samples/kfifo/inttype-example.c | 43 ++++++++++++--- samples/kfifo/record-example.c | 39 ++++++++++++-- 4 files changed, 144 insertions(+), 51 deletions(-) diff --git a/samples/kfifo/bytestream-example.c b/samples/kfifo/bytestream-example.c index a94e6948b30d..178061e87ffe 100644 --- a/samples/kfifo/bytestream-example.c +++ b/samples/kfifo/bytestream-example.c @@ -44,7 +44,7 @@ static struct kfifo test; static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE); #endif -static unsigned char expected_result[FIFO_SIZE] = { +static const unsigned char expected_result[FIFO_SIZE] = { 3, 4, 5, 6, 7, 8, 9, 0, 1, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, @@ -90,9 +90,14 @@ static int __init testfunc(void) printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); + /* show the first value without removing from the fifo */ + if (kfifo_peek(&test, &i)) + printk(KERN_INFO "%d\n", i); + /* check the correctness of all values in the fifo */ j = 0; while (kfifo_get(&test, &i)) { + printk(KERN_INFO "item = %d\n", i); if (i != expected_result[j++]) { printk(KERN_WARNING "value mismatch: test failed\n"); return -EIO; diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index 3682278785f7..ee03a4f0b64f 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -29,8 +29,8 @@ static int __init example_init(void) printk(KERN_INFO "DMA fifo test start\n"); if (kfifo_alloc(&fifo, FIFO_SIZE, GFP_KERNEL)) { - printk(KERN_ERR "error kfifo_alloc\n"); - return 1; + printk(KERN_WARNING "error kfifo_alloc\n"); + return -ENOMEM; } printk(KERN_INFO "queue size: %u\n", kfifo_size(&fifo)); @@ -41,65 +41,93 @@ static int __init example_init(void) kfifo_put(&fifo, &i); /* kick away first byte */ - ret = kfifo_get(&fifo, &i); + kfifo_skip(&fifo); printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + /* + * Configure the kfifo buffer to receive data from DMA input. + * + * .--------------------------------------. + * | 0 | 1 | 2 | ... | 12 | 13 | ... | 31 | + * |---|------------------|---------------| + * \_/ \________________/ \_____________/ + * \ \ \ + * \ \_allocated data \ + * \_*free space* \_*free space* + * + * We need two different SG entries: one for the free space area at the + * end of the kfifo buffer (19 bytes) and another for the first free + * byte at the beginning, after the kfifo_skip(). + */ sg_init_table(sg, ARRAY_SIZE(sg)); ret = kfifo_dma_in_prepare(&fifo, sg, ARRAY_SIZE(sg), FIFO_SIZE); printk(KERN_INFO "DMA sgl entries: %d\n", ret); + if (!ret) { + /* fifo is full and no sgl was created */ + printk(KERN_WARNING "error kfifo_dma_in_prepare\n"); + return -EIO; + } - /* if 0 was returned, fifo is full and no sgl was created */ - if (ret) { - printk(KERN_INFO "scatterlist for receive:\n"); - for (i = 0; i < ARRAY_SIZE(sg); i++) { - printk(KERN_INFO - "sg[%d] -> " - "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", - i, sg[i].page_link, sg[i].offset, sg[i].length); + /* receive data */ + printk(KERN_INFO "scatterlist for receive:\n"); + for (i = 0; i < ARRAY_SIZE(sg); i++) { + printk(KERN_INFO + "sg[%d] -> " + "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", + i, sg[i].page_link, sg[i].offset, sg[i].length); - if (sg_is_last(&sg[i])) - break; - } + if (sg_is_last(&sg[i])) + break; + } - /* but here your code to setup and exectute the dma operation */ - /* ... */ + /* put here your code to setup and exectute the dma operation */ + /* ... */ - /* example: zero bytes received */ - ret = 0; + /* example: zero bytes received */ + ret = 0; - /* finish the dma operation and update the received data */ - kfifo_dma_in_finish(&fifo, ret); - } + /* finish the dma operation and update the received data */ + kfifo_dma_in_finish(&fifo, ret); + /* Prepare to transmit data, example: 8 bytes */ ret = kfifo_dma_out_prepare(&fifo, sg, ARRAY_SIZE(sg), 8); printk(KERN_INFO "DMA sgl entries: %d\n", ret); + if (!ret) { + /* no data was available and no sgl was created */ + printk(KERN_WARNING "error kfifo_dma_out_prepare\n"); + return -EIO; + } - /* if 0 was returned, no data was available and no sgl was created */ - if (ret) { - printk(KERN_INFO "scatterlist for transmit:\n"); - for (i = 0; i < ARRAY_SIZE(sg); i++) { - printk(KERN_INFO - "sg[%d] -> " - "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", - i, sg[i].page_link, sg[i].offset, sg[i].length); + printk(KERN_INFO "scatterlist for transmit:\n"); + for (i = 0; i < ARRAY_SIZE(sg); i++) { + printk(KERN_INFO + "sg[%d] -> " + "page_link 0x%.8lx offset 0x%.8x length 0x%.8x\n", + i, sg[i].page_link, sg[i].offset, sg[i].length); - if (sg_is_last(&sg[i])) - break; - } + if (sg_is_last(&sg[i])) + break; + } - /* but here your code to setup and exectute the dma operation */ - /* ... */ + /* put here your code to setup and exectute the dma operation */ + /* ... */ - /* example: 5 bytes transmitted */ - ret = 5; + /* example: 5 bytes transmitted */ + ret = 5; - /* finish the dma operation and update the transmitted data */ - kfifo_dma_out_finish(&fifo, ret); - } + /* finish the dma operation and update the transmitted data */ + kfifo_dma_out_finish(&fifo, ret); + ret = kfifo_len(&fifo); printk(KERN_INFO "queue len: %u\n", kfifo_len(&fifo)); + if (ret != 7) { + printk(KERN_WARNING "size mismatch: test failed"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); + return 0; } diff --git a/samples/kfifo/inttype-example.c b/samples/kfifo/inttype-example.c index d6c5b7d9df64..71b2aabca96a 100644 --- a/samples/kfifo/inttype-example.c +++ b/samples/kfifo/inttype-example.c @@ -44,10 +44,17 @@ static DECLARE_KFIFO_PTR(test, int); static DEFINE_KFIFO(test, int, FIFO_SIZE); #endif +static const int expected_result[FIFO_SIZE] = { + 3, 4, 5, 6, 7, 8, 9, 0, + 1, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, +}; + static int __init testfunc(void) { int buf[6]; - int i; + int i, j; unsigned int ret; printk(KERN_INFO "int fifo test start\n"); @@ -66,8 +73,13 @@ static int __init testfunc(void) ret = kfifo_in(&test, buf, ret); printk(KERN_INFO "ret: %d\n", ret); - for (i = 20; i != 30; i++) - kfifo_put(&test, &i); + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + + /* put values into the fifo until is full */ + for (i = 20; kfifo_put(&test, &i); i++) + ; printk(KERN_INFO "queue len: %u\n", kfifo_len(&test)); @@ -75,10 +87,20 @@ static int __init testfunc(void) if (kfifo_peek(&test, &i)) printk(KERN_INFO "%d\n", i); - /* print out all values in the fifo */ - while (kfifo_get(&test, &i)) - printk("%d ", i); - printk("\n"); + /* check the correctness of all values in the fifo */ + j = 0; + while (kfifo_get(&test, &i)) { + printk(KERN_INFO "item = %d\n", i); + if (i != expected_result[j++]) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (j != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; + } + printk(KERN_INFO "test passed\n"); return 0; } @@ -132,7 +154,12 @@ static int __init example_init(void) return ret; } #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC diff --git a/samples/kfifo/record-example.c b/samples/kfifo/record-example.c index 32c6e0bda744..e68bd16a5da4 100644 --- a/samples/kfifo/record-example.c +++ b/samples/kfifo/record-example.c @@ -55,6 +55,19 @@ typedef STRUCT_KFIFO_REC_1(FIFO_SIZE) mytest; static mytest test; #endif +static const char *expected_result[] = { + "a", + "bb", + "ccc", + "dddd", + "eeeee", + "ffffff", + "ggggggg", + "hhhhhhhh", + "iiiiiiiii", + "jjjjjjjjjj", +}; + static int __init testfunc(void) { char buf[100]; @@ -75,6 +88,10 @@ static int __init testfunc(void) kfifo_in(&test, buf, i + 1); } + /* skip first element of the fifo */ + printk(KERN_INFO "skip 1st element\n"); + kfifo_skip(&test); + printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test)); /* show the first record without removing from the fifo */ @@ -82,11 +99,22 @@ static int __init testfunc(void) if (ret) printk(KERN_INFO "%.*s\n", ret, buf); - /* print out all records in the fifo */ + /* check the correctness of all values in the fifo */ + i = 0; while (!kfifo_is_empty(&test)) { ret = kfifo_out(&test, buf, sizeof(buf)); - printk(KERN_INFO "%.*s\n", ret, buf); + buf[ret] = '\0'; + printk(KERN_INFO "item = %.*s\n", ret, buf); + if (strcmp(buf, expected_result[i++])) { + printk(KERN_WARNING "value mismatch: test failed\n"); + return -EIO; + } + } + if (i != ARRAY_SIZE(expected_result)) { + printk(KERN_WARNING "size mismatch: test failed\n"); + return -EIO; } + printk(KERN_INFO "test passed\n"); return 0; } @@ -142,7 +170,12 @@ static int __init example_init(void) #else INIT_KFIFO(test); #endif - testfunc(); + if (testfunc() < 0) { +#ifdef DYNAMIC + kfifo_free(&test); +#endif + return -EIO; + } if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) { #ifdef DYNAMIC -- cgit v1.2.3-59-g8ed1b From f2e41e910320197d55b52e28d99a07130f2ae738 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Aug 2010 14:13:31 -0700 Subject: revert "hwmon: f71882fg: add support for the Fintek F71808E" Revert commit 7721fea3d0fd93fb4d000eb737b444369358d6d3 ("hwmon: f71882fg: add support for the Fintek F71808E"). Hans said: : A second review after I've received a data sheet for this device from : Fintek has turned up a few bugs. : : Unfortunately Giel (nor I) have time to fix this in time for the 2.6.36 : cycle. Therefor I would like to see this patch reverted as not having any : support for the hwmon function of this superio chip is better then having : unreliable support. Cc: Giel van Schijndel Cc: Jean Delvare Cc: Hans de Goede Cc: Jonathan Cameron Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/hwmon/f71882fg | 4 --- drivers/hwmon/Kconfig | 6 ++-- drivers/hwmon/f71882fg.c | 83 +++++--------------------------------------- 3 files changed, 11 insertions(+), 82 deletions(-) diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg index 1a07fd674cd0..a7952c2bd959 100644 --- a/Documentation/hwmon/f71882fg +++ b/Documentation/hwmon/f71882fg @@ -2,10 +2,6 @@ Kernel driver f71882fg ====================== Supported chips: - * Fintek F71808E - Prefix: 'f71808fg' - Addresses scanned: none, address read from Super I/O config space - Datasheet: Not public * Fintek F71858FG Prefix: 'f71858fg' Addresses scanned: none, address read from Super I/O config space diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 0fba82943125..4d4d09bdec0a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -332,11 +332,11 @@ config SENSORS_F71805F will be called f71805f. config SENSORS_F71882FG - tristate "Fintek F71808E, F71858FG, F71862FG, F71882FG, F71889FG and F8000" + tristate "Fintek F71858FG, F71862FG, F71882FG, F71889FG and F8000" depends on EXPERIMENTAL help - If you say yes here you get support for hardware monitoring features - of the Fintek F71808E, F71858FG, F71862FG/71863FG, F71882FG/F71883FG, + If you say yes here you get support for hardware monitoring + features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG, F71889FG and F8000 Super-I/O chips. This driver can also be built as a module. If so, the module diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 6207120dcd4d..537841ef44b9 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -45,7 +45,6 @@ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ -#define SIO_F71808_ID 0x0901 /* Chipset ID */ #define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ @@ -97,10 +96,9 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg, f8000 }; +enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 }; static const char *f71882fg_names[] = { - "f71808fg", "f71858fg", "f71862fg", "f71882fg", @@ -308,8 +306,8 @@ static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = { SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), }; -/* In attr common to the f71862fg, f71882fg and f71889fg */ -static struct sensor_device_attribute_2 fxxxx_in_attr[] = { +/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */ +static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = { SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), @@ -319,22 +317,6 @@ static struct sensor_device_attribute_2 fxxxx_in_attr[] = { SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6), SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7), SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8), -}; - -/* In attr for the f71808fg */ -static struct sensor_device_attribute_2 f71808_in_attr[] = { - SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), - SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), - SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), - SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3), - SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4), - SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5), - SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 7), - SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 8), -}; - -/* Temp attr common to the f71808fg, f71862fg, f71882fg and f71889fg */ -static struct sensor_device_attribute_2 fxxxx_temp_attr[] = { SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1), SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 1), @@ -373,10 +355,6 @@ static struct sensor_device_attribute_2 fxxxx_temp_attr[] = { store_temp_beep, 0, 6), SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2), SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), -}; - -/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */ -static struct sensor_device_attribute_2 f71862_temp_attr[] = { SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3), SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, store_temp_max, 0, 3), @@ -1011,11 +989,6 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) data->temp_type[1] = 6; break; } - } else if (data->type == f71808fg) { - reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); - data->temp_type[1] = (reg & 0x02) ? 2 : 4; - data->temp_type[2] = (reg & 0x04) ? 2 : 4; - } else { reg2 = f71882fg_read8(data, F71882FG_REG_PECI); if ((reg2 & 0x03) == 0x01) @@ -1898,8 +1871,7 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, val /= 1000; - if (data->type == f71889fg - || data->type == f71808fg) + if (data->type == f71889fg) val = SENSORS_LIMIT(val, -128, 127); else val = SENSORS_LIMIT(val, 0, 127); @@ -2002,28 +1974,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) /* fall through! */ case f71862fg: err = f71882fg_create_sysfs_files(pdev, - f71862_temp_attr, - ARRAY_SIZE(f71862_temp_attr)); - if (err) - goto exit_unregister_sysfs; - err = f71882fg_create_sysfs_files(pdev, - fxxxx_in_attr, - ARRAY_SIZE(fxxxx_in_attr)); - if (err) - goto exit_unregister_sysfs; - err = f71882fg_create_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); - break; - case f71808fg: - err = f71882fg_create_sysfs_files(pdev, - f71808_in_attr, - ARRAY_SIZE(f71808_in_attr)); - if (err) - goto exit_unregister_sysfs; - err = f71882fg_create_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); + fxxxx_in_temp_attr, + ARRAY_SIZE(fxxxx_in_temp_attr)); break; case f8000: err = f71882fg_create_sysfs_files(pdev, @@ -2050,7 +2002,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) case f71862fg: err = (data->pwm_enable & 0x15) != 0x15; break; - case f71808fg: case f71882fg: case f71889fg: err = 0; @@ -2096,7 +2047,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) f8000_auto_pwm_attr, ARRAY_SIZE(f8000_auto_pwm_attr)); break; - case f71808fg: case f71889fg: for (i = 0; i < nr_fans; i++) { data->pwm_auto_point_mapping[i] = @@ -2176,22 +2126,8 @@ static int f71882fg_remove(struct platform_device *pdev) /* fall through! */ case f71862fg: f71882fg_remove_sysfs_files(pdev, - f71862_temp_attr, - ARRAY_SIZE(f71862_temp_attr)); - f71882fg_remove_sysfs_files(pdev, - fxxxx_in_attr, - ARRAY_SIZE(fxxxx_in_attr)); - f71882fg_remove_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); - break; - case f71808fg: - f71882fg_remove_sysfs_files(pdev, - f71808_in_attr, - ARRAY_SIZE(f71808_in_attr)); - f71882fg_remove_sysfs_files(pdev, - fxxxx_temp_attr, - ARRAY_SIZE(fxxxx_temp_attr)); + fxxxx_in_temp_attr, + ARRAY_SIZE(fxxxx_in_temp_attr)); break; case f8000: f71882fg_remove_sysfs_files(pdev, @@ -2259,9 +2195,6 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); switch (devid) { - case SIO_F71808_ID: - sio_data->type = f71808fg; - break; case SIO_F71858_ID: sio_data->type = f71858fg; break; -- cgit v1.2.3-59-g8ed1b From d5ed3a4af77b851b6271ad3d9abc4c57fa3ce0f5 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 19 Aug 2010 14:13:33 -0700 Subject: lib/radix-tree.c: fix overflow in radix_tree_range_tag_if_tagged() When radix_tree_maxindex() is ~0UL, it can happen that scanning overflows index and tree traversal code goes astray reading memory until it hits unreadable memory. Check for overflow and exit in that case. Signed-off-by: Jan Kara Cc: Christoph Hellwig Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/radix-tree.c | 5 ++++- mm/page-writeback.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index e907858498a6..5b7d4623f0b7 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -625,6 +625,8 @@ EXPORT_SYMBOL(radix_tree_tag_get); * * The function returns number of leaves where the tag was set and sets * *first_indexp to the first unscanned index. + * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must + * be prepared to handle that. */ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, unsigned long *first_indexp, unsigned long last_index, @@ -675,7 +677,8 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, next: /* Go to next item at level determined by 'shift' */ index = ((index >> shift) + 1) << shift; - if (index > last_index) + /* Overflow can happen when last_index is ~0UL... */ + if (index > last_index || !index) break; if (tagged >= nr_to_tag) break; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 7262aacea8a2..c09ef5219cbe 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -836,7 +836,8 @@ void tag_pages_for_writeback(struct address_space *mapping, spin_unlock_irq(&mapping->tree_lock); WARN_ON_ONCE(tagged > WRITEBACK_TAG_BATCH); cond_resched(); - } while (tagged >= WRITEBACK_TAG_BATCH); + /* We check 'start' to handle wrapping when end == ~0UL */ + } while (tagged >= WRITEBACK_TAG_BATCH && start); } EXPORT_SYMBOL(tag_pages_for_writeback); -- cgit v1.2.3-59-g8ed1b From 944645c33e4ada914f4c045525a9293610085ccd Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:34 -0700 Subject: s5pc110: SDHCI-s3c can override host capabilities Each board can override the default sdhci host capabilities. Some board has broken features by hardwares and support 8-bit bandwidth. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/plat-samsung/dev-hsmmc.c | 2 ++ arch/arm/plat-samsung/dev-hsmmc1.c | 2 ++ arch/arm/plat-samsung/dev-hsmmc2.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/arch/arm/plat-samsung/dev-hsmmc.c b/arch/arm/plat-samsung/dev-hsmmc.c index b0f93f11e281..9d2be0941410 100644 --- a/arch/arm/plat-samsung/dev-hsmmc.c +++ b/arch/arm/plat-samsung/dev-hsmmc.c @@ -70,4 +70,6 @@ void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd) set->cfg_gpio = pd->cfg_gpio; if (pd->cfg_card) set->cfg_card = pd->cfg_card; + if (pd->host_caps) + set->host_caps = pd->host_caps; } diff --git a/arch/arm/plat-samsung/dev-hsmmc1.c b/arch/arm/plat-samsung/dev-hsmmc1.c index 1504fd802865..a6c8295840af 100644 --- a/arch/arm/plat-samsung/dev-hsmmc1.c +++ b/arch/arm/plat-samsung/dev-hsmmc1.c @@ -70,4 +70,6 @@ void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd) set->cfg_gpio = pd->cfg_gpio; if (pd->cfg_card) set->cfg_card = pd->cfg_card; + if (pd->host_caps) + set->host_caps = pd->host_caps; } diff --git a/arch/arm/plat-samsung/dev-hsmmc2.c b/arch/arm/plat-samsung/dev-hsmmc2.c index b28ef173444d..cb0d7143381a 100644 --- a/arch/arm/plat-samsung/dev-hsmmc2.c +++ b/arch/arm/plat-samsung/dev-hsmmc2.c @@ -71,4 +71,6 @@ void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd) set->cfg_gpio = pd->cfg_gpio; if (pd->cfg_card) set->cfg_card = pd->cfg_card; + if (pd->host_caps) + set->host_caps = pd->host_caps; } -- cgit v1.2.3-59-g8ed1b From 930a6f70fa3b9c79a57dd6850ef9cb1efa470575 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:35 -0700 Subject: s5pc110: SDHCI-s3c support on s5pc110 s5pc110 (aka s5pv210) uses the same SDHCI IP. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 283190bc2a40..68d12794cfd9 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -132,7 +132,7 @@ config MMC_SDHCI_CNS3XXX config MMC_SDHCI_S3C tristate "SDHCI support on Samsung S3C SoC" - depends on MMC_SDHCI && (PLAT_S3C24XX || PLAT_S3C64XX) + depends on MMC_SDHCI && PLAT_SAMSUNG help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the Samsung S3C -- cgit v1.2.3-59-g8ed1b From 5193250168ccdf87364e35a11965336dc088578c Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:35 -0700 Subject: sdhci: add no hi-speed bit quirk support Some SDHCI controllers like s5pc110 don't have an HISPD bit in the HOSTCTL register. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/sdhci.c | 3 ++- drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 785512133b50..401527d273b5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1180,7 +1180,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) else ctrl &= ~SDHCI_CTRL_4BITBUS; - if (ios->timing == MMC_TIMING_SD_HS) + if (ios->timing == MMC_TIMING_SD_HS && + !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) ctrl |= SDHCI_CTRL_HISPD; else ctrl &= ~SDHCI_CTRL_HISPD; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 036cfae76368..d316bc79b636 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -245,6 +245,8 @@ struct sdhci_host { #define SDHCI_QUIRK_MISSING_CAPS (1<<27) /* Controller uses Auto CMD12 command to stop the transfer */ #define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28) +/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ +#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ -- cgit v1.2.3-59-g8ed1b From f522886e202a34a2191dd5d471b3c4d46410a9a0 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Thu, 19 Aug 2010 14:13:37 -0700 Subject: drivers/mmc/host/sdhci-s3c.c: use the correct mutex and card detect function There's some merge problem between sdhic core and sdhci-s3c host. After mutex is changed to spinlock. It needs to use use spin lock functions and use the correct card detection function. Signed-off-by: Kyungmin Park Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/sdhci-s3c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 0a7f2614c6f0..71ad4163b95e 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -242,7 +242,7 @@ static void sdhci_s3c_notify_change(struct platform_device *dev, int state) { struct sdhci_host *host = platform_get_drvdata(dev); if (host) { - mutex_lock(&host->lock); + spin_lock(&host->lock); if (state) { dev_dbg(&dev->dev, "card inserted.\n"); host->flags &= ~SDHCI_DEVICE_DEAD; @@ -252,8 +252,8 @@ static void sdhci_s3c_notify_change(struct platform_device *dev, int state) host->flags |= SDHCI_DEVICE_DEAD; host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; } - sdhci_card_detect(host); - mutex_unlock(&host->lock); + tasklet_schedule(&host->card_tasklet); + spin_unlock(&host->lock); } } -- cgit v1.2.3-59-g8ed1b From be71cf2202971e50ce4953d473649c724799eb8a Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 19 Aug 2010 14:13:38 -0700 Subject: oom: fix NULL pointer dereference Commit b940fd7035 ("oom: remove unnecessary code and cleanup") added an unnecessary NULL pointer dereference. remove it. Signed-off-by: KOSAKI Motohiro Reviewed-by: Minchan Kim Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/oom_kill.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 5014e50644d1..17d48a67e7b7 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -401,10 +401,9 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, static int oom_kill_task(struct task_struct *p, struct mem_cgroup *mem) { p = find_lock_task_mm(p); - if (!p) { - task_unlock(p); + if (!p) return 1; - } + pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n", task_pid_nr(p), p->comm, K(p->mm->total_vm), K(get_mm_counter(p->mm, MM_ANONPAGES)), -- cgit v1.2.3-59-g8ed1b From b52723c5607f7684c2c0c075f86f86da0d7fb6d0 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 19 Aug 2010 14:13:39 -0700 Subject: oom: fix tasklist_lock leak Commit 0aad4b3124 ("oom: fold __out_of_memory into out_of_memory") introduced a tasklist_lock leak. Then it caused following obvious danger warnings and panic. ================================================ [ BUG: lock held when returning to user space! ] ------------------------------------------------ rsyslogd/1422 is leaving the kernel with locks still held! 1 lock held by rsyslogd/1422: #0: (tasklist_lock){.+.+.+}, at: [] out_of_memory+0x164/0x3f0 BUG: scheduling while atomic: rsyslogd/1422/0x00000002 INFO: lockdep is turned off. This patch fixes it. Signed-off-by: KOSAKI Motohiro Reviewed-by: Minchan Kim Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/oom_kill.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 17d48a67e7b7..c48c5ef3ccfd 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -646,6 +646,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, unsigned long freed = 0; unsigned int points; enum oom_constraint constraint = CONSTRAINT_NONE; + int killed = 0; blocking_notifier_call_chain(&oom_notify_list, 0, &freed); if (freed > 0) @@ -683,7 +684,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, if (!oom_kill_process(current, gfp_mask, order, 0, totalpages, NULL, nodemask, "Out of memory (oom_kill_allocating_task)")) - return; + goto out; } retry: @@ -691,7 +692,7 @@ retry: constraint == CONSTRAINT_MEMORY_POLICY ? nodemask : NULL); if (PTR_ERR(p) == -1UL) - return; + goto out; /* Found nothing?!?! Either we hang forever, or we panic. */ if (!p) { @@ -703,13 +704,15 @@ retry: if (oom_kill_process(p, gfp_mask, order, points, totalpages, NULL, nodemask, "Out of memory")) goto retry; + killed = 1; +out: read_unlock(&tasklist_lock); /* * Give "p" a good chance of killing itself before we * retry to allocate memory unless "p" is current */ - if (!test_thread_flag(TIF_MEMDIE)) + if (killed && !test_thread_flag(TIF_MEMDIE)) schedule_timeout_uninterruptible(1); } -- cgit v1.2.3-59-g8ed1b From 8d6c83f0ba5e1bd1e8bb2e3c7de4c276dc247f99 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Thu, 19 Aug 2010 14:13:39 -0700 Subject: oom: __task_cred() need rcu_read_lock() dump_tasks() needs to hold the RCU read lock around its access of the target task's UID. To this end it should use task_uid() as it only needs that one thing from the creds. The fact that dump_tasks() holds tasklist_lock is insufficient to prevent the target process replacing its credentials on another CPU. Then, this patch change to call rcu_read_lock() explicitly. =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- mm/oom_kill.c:410 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 1 4 locks held by kworker/1:2/651: #0: (events){+.+.+.}, at: [] process_one_work+0x137/0x4a0 #1: (moom_work){+.+...}, at: [] process_one_work+0x137/0x4a0 #2: (tasklist_lock){.+.+..}, at: [] out_of_memory+0x164/0x3f0 #3: (&(&p->alloc_lock)->rlock){+.+...}, at: [] find_lock_task_mm+0x2e/0x70 Signed-off-by: KOSAKI Motohiro Signed-off-by: David Howells Acked-by: Paul E. McKenney Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/oom_kill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index c48c5ef3ccfd..fc81cb22869e 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -372,7 +372,7 @@ static void dump_tasks(const struct mem_cgroup *mem) } pr_info("[%5d] %5d %5d %8lu %8lu %3u %3d %5d %s\n", - task->pid, __task_cred(task)->uid, task->tgid, + task->pid, task_uid(task), task->tgid, task->mm->total_vm, get_mm_rss(task->mm), task_cpu(task), task->signal->oom_adj, task->signal->oom_score_adj, task->comm); -- cgit v1.2.3-59-g8ed1b From f3c072ad727617f00bffae17dba8cd895f5b7bdb Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 19 Aug 2010 14:13:40 -0700 Subject: uml: fix compile error in dma_get_cache_alignment() Fix uml compile error: include/linux/dma-mapping.h:145: error: redefinition of 'dma_get_cache_alignment' arch/um/include/asm/dma-mapping.h:99: note: previous definition of 'dma_get_cache_alignment' was here Introduced by commit 4565f0170dfc ("dma-mapping: unify dma_get_cache_alignment implementations") Signed-off-by: Miklos Szeredi Cc: Jeff Dike Cc: FUJITA Tomonori Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/asm/dma-mapping.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/um/include/asm/dma-mapping.h b/arch/um/include/asm/dma-mapping.h index 17a2cb5a4178..1f469e80fdd3 100644 --- a/arch/um/include/asm/dma-mapping.h +++ b/arch/um/include/asm/dma-mapping.h @@ -95,13 +95,6 @@ dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -static inline int -dma_get_cache_alignment(void) -{ - BUG(); - return(0); -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) -- cgit v1.2.3-59-g8ed1b From 626115cda9a31d7618cfd5ca8928811e5947d360 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 19 Aug 2010 14:13:42 -0700 Subject: drivers/scsi/qla4xxx: fix build gcc-4.0.2: drivers/scsi/qla4xxx/ql4_os.c: In function 'qla4_8xxx_error_recovery': drivers/scsi/qla4xxx/ql4_glbl.h:135: sorry, unimplemented: inlining failed in call to 'qla4_8xxx_set_drv_active': function body not available drivers/scsi/qla4xxx/ql4_os.c:2377: sorry, unimplemented: called from here drivers/scsi/qla4xxx/ql4_glbl.h:135: sorry, unimplemented: inlining failed in call to 'qla4_8xxx_set_drv_active': function body not available drivers/scsi/qla4xxx/ql4_os.c:2393: sorry, unimplemented: called from here Cc: Ravi Anand Cc: Vikas Chaudhary Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/qla4xxx/ql4_glbl.h | 2 +- drivers/scsi/qla4xxx/ql4_nx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index f065204e401b..95a26fb1626c 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -132,7 +132,7 @@ void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha); int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha); void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha); void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); -inline void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); +void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index e031a734836e..5d4a3822382d 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -1418,7 +1418,7 @@ static int qla4_8xxx_rcvpeg_ready(struct scsi_qla_host *ha) return QLA_SUCCESS; } -inline void +void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) { uint32_t drv_active; -- cgit v1.2.3-59-g8ed1b From 1ee41680572971e34d90d5f584daf33195ec6dcb Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Thu, 19 Aug 2010 14:13:43 -0700 Subject: Documentation: kernel-locking: mutex_trylock cannot be used in interrupt context Chapter 6 is right about mutex_trylock, but chapter 10 wasn't. This error was introduced during semaphore-to-mutex conversion of the Unreliable guide. :-) If user context which performs mutex_lock() or mutex_trylock() is preempted by interrupt context which performs mutex_trylock() on the same mutex instance, a deadlock occurs. This is because these functions do not disable local IRQs when they operate on mutex->wait_lock. Signed-off-by: Stefan Richter Acked-by: Rusty Russell Cc: Matthew Wilcox Cc: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/DocBook/kernel-locking.tmpl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl index 084f6ad7b7a0..0b1a3f97f285 100644 --- a/Documentation/DocBook/kernel-locking.tmpl +++ b/Documentation/DocBook/kernel-locking.tmpl @@ -1922,9 +1922,12 @@ machines due to caching. mutex_lock() - There is a mutex_trylock() which can be - used inside interrupt context, as it will not sleep. + There is a mutex_trylock() which does not + sleep. Still, it must not be used inside interrupt context since + its implementation is not safe for that. mutex_unlock() will also never sleep. + It cannot be used in interrupt context either since a mutex + must be released by the same task that acquired it. -- cgit v1.2.3-59-g8ed1b From a4724ed6f084fd294b001103a68c3196eb60364c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 20 Aug 2010 19:52:45 +1000 Subject: MAINTAINERS: Fix ozlabs.org mailing list addresses All these lists moved to lists.ozlabs.org quite a while ago. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- MAINTAINERS | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index b5b8baa1d70e..433f35385756 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -456,7 +456,7 @@ F: drivers/infiniband/hw/amso1100/ AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: sound/aoa/ @@ -1472,8 +1472,8 @@ F: include/linux/can/platform/ CELL BROADBAND ENGINE ARCHITECTURE M: Arnd Bergmann -L: linuxppc-dev@ozlabs.org -L: cbe-oss-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org W: http://www.ibm.com/developerworks/power/cell/ S: Supported F: arch/powerpc/include/asm/cell*.h @@ -2371,13 +2371,13 @@ F: include/linux/fb.h FREESCALE DMA DRIVER M: Li Yang M: Zhang Wei -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/dma/fsldma.* FREESCALE I2C CPM DRIVER M: Jochen Friedrich -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-cpm.c @@ -2393,7 +2393,7 @@ F: drivers/video/imxfb.c FREESCALE SOC FS_ENET DRIVER M: Pantelis Antoniou M: Vitaly Bordug -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: netdev@vger.kernel.org S: Maintained F: drivers/net/fs_enet/ @@ -2401,7 +2401,7 @@ F: include/linux/fs_enet_pd.h FREESCALE QUICC ENGINE LIBRARY M: Timur Tabi -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Supported F: arch/powerpc/sysdev/qe_lib/ F: arch/powerpc/include/asm/*qe.h @@ -2409,27 +2409,27 @@ F: arch/powerpc/include/asm/*qe.h FREESCALE USB PERIPHERAL DRIVERS M: Li Yang L: linux-usb@vger.kernel.org -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/usb/gadget/fsl* FREESCALE QUICC ENGINE UCC ETHERNET DRIVER M: Li Yang L: netdev@vger.kernel.org -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: drivers/net/ucc_geth* FREESCALE QUICC ENGINE UCC UART DRIVER M: Timur Tabi -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Supported F: drivers/serial/ucc_uart.c FREESCALE SOC SOUND DRIVERS M: Timur Tabi L: alsa-devel@alsa-project.org (moderated for non-subscribers) -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Supported F: sound/soc/fsl/fsl* F: sound/soc/fsl/mpc8610_hpcd.c @@ -2564,7 +2564,7 @@ F: mm/memory-failure.c F: mm/hwpoison-inject.c HYPERVISOR VIRTUAL CONSOLE DRIVER -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Odd Fixes F: drivers/char/hvc_* @@ -3476,7 +3476,7 @@ F: drivers/usb/misc/legousbtower.c LGUEST M: Rusty Russell -L: lguest@ozlabs.org +L: lguest@lists.ozlabs.org W: http://lguest.ozlabs.org/ S: Maintained F: Documentation/lguest/ @@ -3495,7 +3495,7 @@ LINUX FOR POWERPC (32-BIT AND 64-BIT) M: Benjamin Herrenschmidt M: Paul Mackerras W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git S: Supported @@ -3505,14 +3505,14 @@ F: arch/powerpc/ LINUX FOR POWER MACINTOSH M: Benjamin Herrenschmidt W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/powermac/ F: drivers/macintosh/ LINUX FOR POWERPC EMBEDDED MPC5XXX M: Grant Likely -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org T: git git://git.secretlab.ca/git/linux-2.6.git S: Maintained F: arch/powerpc/platforms/512x/ @@ -3522,7 +3522,7 @@ LINUX FOR POWERPC EMBEDDED PPC4XX M: Josh Boyer M: Matt Porter W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git S: Maintained F: arch/powerpc/platforms/40x/ @@ -3531,7 +3531,7 @@ F: arch/powerpc/platforms/44x/ LINUX FOR POWERPC EMBEDDED XILINX VIRTEX M: Grant Likely W: http://wiki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org T: git git://git.secretlab.ca/git/linux-2.6.git S: Maintained F: arch/powerpc/*/*virtex* @@ -3541,20 +3541,20 @@ LINUX FOR POWERPC EMBEDDED PPC8XX M: Vitaly Bordug M: Marcelo Tosatti W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/8xx/ LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX M: Kumar Gala W: http://www.penguinppc.org/ -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/83xx/ LINUX FOR POWERPC PA SEMI PWRFICIENT M: Olof Johansson -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/pasemi/ F: drivers/*/*pasemi* @@ -4601,14 +4601,14 @@ F: drivers/ata/sata_promise.* PS3 NETWORK SUPPORT M: Geoff Levand L: netdev@vger.kernel.org -L: cbe-oss-dev@ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org S: Maintained F: drivers/net/ps3_gelic_net.* PS3 PLATFORM SUPPORT M: Geoff Levand -L: linuxppc-dev@ozlabs.org -L: cbe-oss-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/boot/ps3* F: arch/powerpc/include/asm/lv1call.h @@ -4622,7 +4622,7 @@ F: sound/ppc/snd_ps3* PS3VRAM DRIVER M: Jim Paris -L: cbe-oss-dev@ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org S: Maintained F: drivers/block/ps3vram.c @@ -5068,7 +5068,7 @@ F: drivers/mmc/host/sdhci.* SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF) M: Anton Vorontsov -L: linuxppc-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org L: linux-mmc@vger.kernel.org S: Maintained F: drivers/mmc/host/sdhci-of.* @@ -5485,8 +5485,8 @@ F: drivers/net/spider_net* SPU FILE SYSTEM M: Jeremy Kerr -L: linuxppc-dev@ozlabs.org -L: cbe-oss-dev@ozlabs.org +L: linuxppc-dev@lists.ozlabs.org +L: cbe-oss-dev@lists.ozlabs.org W: http://www.ibm.com/developerworks/power/cell/ S: Supported F: Documentation/filesystems/spufs.txt -- cgit v1.2.3-59-g8ed1b From f6143a9b732977859cb6e04c604d04976aa5ccbd Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 20 Aug 2010 19:56:31 +1000 Subject: Documentation: fix ozlabs.org mailing list address This list moved to lists.ozlabs.org quite some time ago. Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- Documentation/powerpc/hvcs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt index f93462c5db25..6d8be3468d7d 100644 --- a/Documentation/powerpc/hvcs.txt +++ b/Documentation/powerpc/hvcs.txt @@ -560,7 +560,7 @@ The proper channel for reporting bugs is either through the Linux OS distribution company that provided your OS or by posting issues to the PowerPC development mailing list at: -linuxppc-dev@ozlabs.org +linuxppc-dev@lists.ozlabs.org This request is to provide a documented and searchable public exchange of the problems and solutions surrounding this driver for the benefit of -- cgit v1.2.3-59-g8ed1b From 9fbc590860e75785bdaf8b83e48fabfe4d4f7d58 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 20 Aug 2010 20:42:26 +0000 Subject: [CIFS] Fix ntlmv2 auth with ntlmssp Make ntlmv2 as an authentication mechanism within ntlmssp instead of ntlmv1. Parse type 2 response in ntlmssp negotiation to pluck AV pairs and use them to calculate ntlmv2 response token. Also, assign domain name from the sever response in type 2 packet of ntlmssp and use that (netbios) domain name in calculation of response. Enable cifs/smb signing using rc4 and md5. Changed name of the structure mac_key to session_key to reflect the type of key it holds. Use kernel crypto_shash_* APIs instead of the equivalent cifs functions. Signed-off-by: Shirish Pargaonkar Acked-by: Herbert Xu Signed-off-by: Steve French --- fs/cifs/Kconfig | 2 + fs/cifs/asn1.c | 6 +- fs/cifs/cifsencrypt.c | 416 +++++++++++++++++++++++++++++++++++--------------- fs/cifs/cifsglob.h | 18 ++- fs/cifs/cifspdu.h | 7 +- fs/cifs/cifsproto.h | 12 +- fs/cifs/cifssmb.c | 13 +- fs/cifs/connect.c | 13 +- fs/cifs/ntlmssp.h | 13 ++ fs/cifs/sess.c | 118 ++++++++++---- fs/cifs/transport.c | 6 +- 11 files changed, 452 insertions(+), 172 deletions(-) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 917b7d449bb2..0da1debd499d 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -2,6 +2,8 @@ config CIFS tristate "CIFS support (advanced network filesystem, SMBFS successor)" depends on INET select NLS + select CRYPTO_MD5 + select CRYPTO_ARC4 help This is the client VFS module for the Common Internet File System (CIFS) protocol which is the successor to the Server Message Block diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index cfd1ce34e0bc..21f0fbd86989 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -597,13 +597,13 @@ decode_negTokenInit(unsigned char *security_blob, int length, if (compare_oid(oid, oidlen, MSKRB5_OID, MSKRB5_OID_LEN)) server->sec_mskerberos = true; - else if (compare_oid(oid, oidlen, KRB5U2U_OID, + if (compare_oid(oid, oidlen, KRB5U2U_OID, KRB5U2U_OID_LEN)) server->sec_kerberosu2u = true; - else if (compare_oid(oid, oidlen, KRB5_OID, + if (compare_oid(oid, oidlen, KRB5_OID, KRB5_OID_LEN)) server->sec_kerberos = true; - else if (compare_oid(oid, oidlen, NTLMSSP_OID, + if (compare_oid(oid, oidlen, NTLMSSP_OID, NTLMSSP_OID_LEN)) server->sec_ntlmssp = true; diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 847628dfdc44..051d00011ca3 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -27,6 +27,7 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" +#include "ntlmssp.h" #include #include @@ -42,21 +43,44 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, - const struct mac_key *key, char *signature) + struct TCP_Server_Info *server, char *signature) { - struct MD5Context context; + int rc = 0; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; + } sdesc; - if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) + if (cifs_pdu == NULL || server == NULL || signature == NULL) return -EINVAL; - cifs_MD5_init(&context); - cifs_MD5_update(&context, (char *)&key->data, key->len); - cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); + sdesc.shash.tfm = server->ntlmssp.md5; + sdesc.shash.flags = 0x0; + + rc = crypto_shash_init(&sdesc.shash); + if (rc) { + cERROR(1, "could not initialize master crypto API hmacmd5\n"); + return rc; + } + + if (server->secType == RawNTLMSSP) + crypto_shash_update(&sdesc.shash, + server->session_key.data.ntlmv2.key, + CIFS_NTLMV2_SESSKEY_SIZE); + else + crypto_shash_update(&sdesc.shash, + (char *)&server->session_key.data, + server->session_key.len); + + crypto_shash_update(&sdesc.shash, + cifs_pdu->Protocol, cifs_pdu->smb_buf_length); + + rc = crypto_shash_final(&sdesc.shash, signature); - cifs_MD5_final(signature, &context); return 0; } + int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, __u32 *pexpected_response_sequence_number) { @@ -78,8 +102,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, - smb_signature); + rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else @@ -89,16 +112,36 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, } static int cifs_calc_signature2(const struct kvec *iov, int n_vec, - const struct mac_key *key, char *signature) + struct TCP_Server_Info *server, char *signature) { - struct MD5Context context; int i; + int rc = 0; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; + } sdesc; - if ((iov == NULL) || (signature == NULL) || (key == NULL)) + if (iov == NULL || server == NULL || signature == NULL) return -EINVAL; - cifs_MD5_init(&context); - cifs_MD5_update(&context, (char *)&key->data, key->len); + sdesc.shash.tfm = server->ntlmssp.md5; + sdesc.shash.flags = 0x0; + + rc = crypto_shash_init(&sdesc.shash); + if (rc) { + cERROR(1, "could not initialize master crypto API hmacmd5\n"); + return rc; + } + + if (server->secType == RawNTLMSSP) + crypto_shash_update(&sdesc.shash, + server->session_key.data.ntlmv2.key, + CIFS_NTLMV2_SESSKEY_SIZE); + else + crypto_shash_update(&sdesc.shash, + (char *)&server->session_key.data, + server->session_key.len); + for (i = 0; i < n_vec; i++) { if (iov[i].iov_len == 0) continue; @@ -111,18 +154,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, if (i == 0) { if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ break; /* nothing to sign or corrupt header */ - cifs_MD5_update(&context, iov[0].iov_base+4, - iov[0].iov_len-4); + crypto_shash_update(&sdesc.shash, + iov[i].iov_base + 4, iov[i].iov_len - 4); } else - cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); + crypto_shash_update(&sdesc.shash, + iov[i].iov_base, iov[i].iov_len); } - cifs_MD5_final(signature, &context); + rc = crypto_shash_final(&sdesc.shash, signature); return 0; } - int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, __u32 *pexpected_response_sequence_number) { @@ -145,8 +188,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, - smb_signature); + rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else @@ -156,14 +198,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, } int cifs_verify_signature(struct smb_hdr *cifs_pdu, - const struct mac_key *mac_key, + struct TCP_Server_Info *server, __u32 expected_sequence_number) { - unsigned int rc; + int rc; char server_response_sig[8]; char what_we_think_sig_should_be[20]; - if ((cifs_pdu == NULL) || (mac_key == NULL)) + if (cifs_pdu == NULL || server == NULL) return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) @@ -192,7 +234,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; - rc = cifs_calculate_signature(cifs_pdu, mac_key, + rc = cifs_calculate_signature(cifs_pdu, server, what_we_think_sig_should_be); if (rc) @@ -209,7 +251,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } /* We fill in key by putting in 40 byte array which was allocated by caller */ -int cifs_calculate_mac_key(struct mac_key *key, const char *rn, +int cifs_calculate_session_key(struct session_key *key, const char *rn, const char *password) { char temp_key[16]; @@ -223,63 +265,6 @@ int cifs_calculate_mac_key(struct mac_key *key, const char *rn, return 0; } -int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses, - const struct nls_table *nls_info) -{ - char temp_hash[16]; - struct HMACMD5Context ctx; - char *ucase_buf; - __le16 *unicode_buf; - unsigned int i, user_name_len, dom_name_len; - - if (ses == NULL) - return -EINVAL; - - E_md4hash(ses->password, temp_hash); - - hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); - user_name_len = strlen(ses->userName); - if (user_name_len > MAX_USERNAME_SIZE) - return -EINVAL; - if (ses->domainName == NULL) - return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ - dom_name_len = strlen(ses->domainName); - if (dom_name_len > MAX_USERNAME_SIZE) - return -EINVAL; - - ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); - if (ucase_buf == NULL) - return -ENOMEM; - unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); - if (unicode_buf == NULL) { - kfree(ucase_buf); - return -ENOMEM; - } - - for (i = 0; i < user_name_len; i++) - ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; - ucase_buf[i] = 0; - user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, - MAX_USERNAME_SIZE*2, nls_info); - unicode_buf[user_name_len] = 0; - user_name_len++; - - for (i = 0; i < dom_name_len; i++) - ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; - ucase_buf[i] = 0; - dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, - MAX_USERNAME_SIZE*2, nls_info); - - unicode_buf[user_name_len + dom_name_len] = 0; - hmac_md5_update((const unsigned char *) unicode_buf, - (user_name_len+dom_name_len)*2, &ctx); - - hmac_md5_final(ses->server->ntlmv2_hash, &ctx); - kfree(ucase_buf); - kfree(unicode_buf); - return 0; -} - #ifdef CONFIG_CIFS_WEAK_PW_HASH void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key) @@ -324,21 +309,29 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, { int rc = 0; int len; - char nt_hash[16]; - struct HMACMD5Context *pctxt; + char nt_hash[CIFS_NTHASH_SIZE]; wchar_t *user; wchar_t *domain; - - pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); - - if (pctxt == NULL) - return -ENOMEM; + wchar_t *server; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; + } sdesc; /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); - /* convert Domainname to unicode and uppercase */ - hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); + sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; + sdesc.shash.flags = 0x0; + + crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, nt_hash, + CIFS_NTHASH_SIZE); + + rc = crypto_shash_init(&sdesc.shash); + if (rc) { + cERROR(1, "could not initialize master crypto API hmacmd5\n"); + return rc; + } /* convert ses->userName to unicode and uppercase */ len = strlen(ses->userName); @@ -347,7 +340,8 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, goto calc_exit_2; len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); - hmac_md5_update((char *)user, 2*len, pctxt); + + crypto_shash_update(&sdesc.shash, (char *)user, 2 * len); /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { @@ -363,65 +357,243 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, Maybe converting the domain name earlier makes sense */ /* UniStrupr(domain); */ - hmac_md5_update((char *)domain, 2*len, pctxt); + crypto_shash_update(&sdesc.shash, (char *)domain, 2 * len); kfree(domain); + } else if (ses->serverName) { + len = strlen(ses->serverName); + + server = kmalloc(2 + (len * 2), GFP_KERNEL); + if (server == NULL) + goto calc_exit_1; + len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, + nls_cp); + /* the following line was removed since it didn't work well + with lower cased domain name that passed as an option. + Maybe converting the domain name earlier makes sense */ + /* UniStrupr(domain); */ + + crypto_shash_update(&sdesc.shash, (char *)server, 2 * len); + + kfree(server); } calc_exit_1: kfree(user); calc_exit_2: /* BB FIXME what about bytes 24 through 40 of the signing key? compare with the NTLM example */ - hmac_md5_final(ses->server->ntlmv2_hash, pctxt); + rc = crypto_shash_final(&sdesc.shash, ses->server->ntlmv2_hash); - kfree(pctxt); return rc; } -void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, - const struct nls_table *nls_cp) +static int +find_domain_name(struct cifsSesInfo *ses) +{ + int rc = 0; + unsigned int attrsize; + unsigned int type; + unsigned char *blobptr; + struct ntlmssp2_name *attrptr; + + if (ses->server->tiblob) { + blobptr = ses->server->tiblob; + attrptr = (struct ntlmssp2_name *) blobptr; + + while ((type = attrptr->type) != 0) { + blobptr += 2; /* advance attr type */ + attrsize = attrptr->length; + blobptr += 2; /* advance attr size */ + if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { + if (!ses->domainName) { + ses->domainName = + kmalloc(attrptr->length + 1, + GFP_KERNEL); + if (!ses->domainName) + return -ENOMEM; + cifs_from_ucs2(ses->domainName, + (__le16 *)blobptr, + attrptr->length, + attrptr->length, + load_nls_default(), false); + } + } + blobptr += attrsize; /* advance attr value */ + attrptr = (struct ntlmssp2_name *) blobptr; + } + } else { + ses->server->tilen = 2 * sizeof(struct ntlmssp2_name); + ses->server->tiblob = kmalloc(ses->server->tilen, GFP_KERNEL); + if (!ses->server->tiblob) { + ses->server->tilen = 0; + cERROR(1, "Challenge target info allocation failure"); + return -ENOMEM; + } + memset(ses->server->tiblob, 0x0, ses->server->tilen); + attrptr = (struct ntlmssp2_name *) ses->server->tiblob; + attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); + } + + return rc; +} + +static int +CalcNTLMv2_response(const struct TCP_Server_Info *server, + char *v2_session_response) { int rc; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(server->ntlmssp.hmacmd5)]; + } sdesc; + + sdesc.shash.tfm = server->ntlmssp.hmacmd5; + sdesc.shash.flags = 0x0; + + crypto_shash_setkey(server->ntlmssp.hmacmd5, server->ntlmv2_hash, + CIFS_HMAC_MD5_HASH_SIZE); + + rc = crypto_shash_init(&sdesc.shash); + if (rc) { + cERROR(1, "could not initialize master crypto API hmacmd5\n"); + return rc; + } + + memcpy(v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, + server->cryptKey, CIFS_SERVER_CHALLENGE_SIZE); + crypto_shash_update(&sdesc.shash, + v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, + sizeof(struct ntlmv2_resp) - CIFS_SERVER_CHALLENGE_SIZE); + + if (server->tilen) + crypto_shash_update(&sdesc.shash, + server->tiblob, server->tilen); + + rc = crypto_shash_final(&sdesc.shash, v2_session_response); + + return rc; +} + +int +setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, + const struct nls_table *nls_cp) +{ + int rc = 0; struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; - struct HMACMD5Context context; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; + } sdesc; buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; - buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); - buf->names[0].length = 0; - buf->names[1].type = 0; - buf->names[1].length = 0; + + if (!ses->domainName) { + rc = find_domain_name(ses); + if (rc) { + cERROR(1, "could not get domain/server name rc %d", rc); + return rc; + } + } /* calculate buf->ntlmv2_hash */ rc = calc_ntlmv2_hash(ses, nls_cp); - if (rc) + if (rc) { + cERROR(1, "could not get v2 hash rc %d", rc); + return rc; + } + rc = CalcNTLMv2_response(ses->server, resp_buf); + if (rc) { cERROR(1, "could not get v2 hash rc %d", rc); - CalcNTLMv2_response(ses, resp_buf); + return rc; + } + + crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, + ses->server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); + + sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; + sdesc.shash.flags = 0x0; + + rc = crypto_shash_init(&sdesc.shash); + if (rc) { + cERROR(1, "could not initialize master crypto API hmacmd5\n"); + return rc; + } + + crypto_shash_update(&sdesc.shash, resp_buf, CIFS_HMAC_MD5_HASH_SIZE); - /* now calculate the MAC key for NTLMv2 */ - hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); - hmac_md5_update(resp_buf, 16, &context); - hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); + rc = crypto_shash_final(&sdesc.shash, + ses->server->session_key.data.ntlmv2.key); - memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, - sizeof(struct ntlmv2_resp)); - ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); + memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, + sizeof(struct ntlmv2_resp)); + ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); + + return rc; } -void CalcNTLMv2_response(const struct cifsSesInfo *ses, - char *v2_session_response) +int +calc_seckey(struct TCP_Server_Info *server) { - struct HMACMD5Context context; - /* rest of v2 struct already generated */ - memcpy(v2_session_response + 8, ses->server->cryptKey, 8); - hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); + int rc; + unsigned char sec_key[CIFS_NTLMV2_SESSKEY_SIZE]; + struct crypto_blkcipher *tfm_arc4; + struct scatterlist sgin, sgout; + struct blkcipher_desc desc; + + get_random_bytes(sec_key, CIFS_NTLMV2_SESSKEY_SIZE); + + tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", + 0, CRYPTO_ALG_ASYNC); + if (!tfm_arc4 || IS_ERR(tfm_arc4)) { + cERROR(1, "could not allocate " "master crypto API arc4\n"); + return 1; + } + + crypto_blkcipher_setkey(tfm_arc4, + server->session_key.data.ntlmv2.key, CIFS_CPHTXT_SIZE); + sg_init_one(&sgin, sec_key, CIFS_CPHTXT_SIZE); + sg_init_one(&sgout, server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); + rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); + + if (!rc) + memcpy(server->session_key.data.ntlmv2.key, + sec_key, CIFS_NTLMV2_SESSKEY_SIZE); - hmac_md5_update(v2_session_response+8, - sizeof(struct ntlmv2_resp) - 8, &context); + crypto_free_blkcipher(tfm_arc4); - hmac_md5_final(v2_session_response, &context); -/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ + return 0; +} + +void +cifs_crypto_shash_release(struct TCP_Server_Info *server) +{ + if (server->ntlmssp.md5) + crypto_free_shash(server->ntlmssp.md5); + + if (server->ntlmssp.hmacmd5) + crypto_free_shash(server->ntlmssp.hmacmd5); +} + +int +cifs_crypto_shash_allocate(struct TCP_Server_Info *server) +{ + server->ntlmssp.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); + if (!server->ntlmssp.hmacmd5 || + IS_ERR(server->ntlmssp.hmacmd5)) { + cERROR(1, "could not allocate master crypto API hmacmd5\n"); + return 1; + } + + server->ntlmssp.md5 = crypto_alloc_shash("md5", 0, 0); + if (!server->ntlmssp.md5 || IS_ERR(server->ntlmssp.md5)) { + crypto_free_shash(server->ntlmssp.hmacmd5); + cERROR(1, "could not allocate master crypto API md5\n"); + return 1; + } + + return 0; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0cdfb8c32ac6..49563e0c1725 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -25,6 +25,9 @@ #include #include "cifs_fs_sb.h" #include "cifsacl.h" +#include +#include + /* * The sizes of various internal tables and strings */ @@ -97,7 +100,7 @@ enum protocolEnum { /* Netbios frames protocol not supported at this time */ }; -struct mac_key { +struct session_key { unsigned int len; union { char ntlm[CIFS_SESS_KEY_SIZE + 16]; @@ -120,6 +123,14 @@ struct cifs_cred { struct cifs_ace *aces; }; +struct ntlmssp_auth { + __u32 client_flags; + __u32 server_flags; + unsigned char ciphertext[CIFS_CPHTXT_SIZE]; + struct crypto_shash *hmacmd5; + struct crypto_shash *md5; +}; + /* ***************************************************************** * Except the CIFS PDUs themselves all the @@ -182,11 +193,14 @@ struct TCP_Server_Info { /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ - struct mac_key mac_signing_key; + struct session_key session_key; char ntlmv2_hash[16]; unsigned long lstrp; /* when we got last response from this server */ u16 dialect; /* dialect index that server chose */ /* extended security flavors that server supports */ + unsigned int tilen; /* length of the target info blob */ + unsigned char *tiblob; /* target info blob in challenge response */ + struct ntlmssp_auth ntlmssp; /* various keys, ciphers, flags */ bool sec_kerberos; /* supports plain Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_kerberosu2u; /* supports U2U Kerberos */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 14d036d8db11..320e0fd0ba7b 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -134,6 +134,12 @@ * Size of the session key (crypto key encrypted with the password */ #define CIFS_SESS_KEY_SIZE (24) +#define CIFS_CLIENT_CHALLENGE_SIZE (8) +#define CIFS_SERVER_CHALLENGE_SIZE (8) +#define CIFS_HMAC_MD5_HASH_SIZE (16) +#define CIFS_CPHTXT_SIZE (16) +#define CIFS_NTLMV2_SESSKEY_SIZE (16) +#define CIFS_NTHASH_SIZE (16) /* * Maximum user name length @@ -663,7 +669,6 @@ struct ntlmv2_resp { __le64 time; __u64 client_chal; /* random */ __u32 reserved2; - struct ntlmssp2_name names[2]; /* array of name entries could follow ending in minimum 4 byte struct */ } __attribute__((packed)); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1f5450814087..1378d9133844 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -361,15 +361,15 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, __u32 *); extern int cifs_verify_signature(struct smb_hdr *, - const struct mac_key *mac_key, + struct TCP_Server_Info *server, __u32 expected_sequence_number); -extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, +extern int cifs_calculate_session_key(struct session_key *key, const char *rn, const char *pass); -extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, - const struct nls_table *); -extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); -extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, +extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *, const struct nls_table *); +extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); +extern void cifs_crypto_shash_release(struct TCP_Server_Info *); +extern int calc_seckey(struct TCP_Server_Info *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index c65c3419dd37..4bda920d1f75 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -604,11 +604,14 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) else rc = -EINVAL; - if (server->sec_kerberos || server->sec_mskerberos) - server->secType = Kerberos; - else if (server->sec_ntlmssp) - server->secType = RawNTLMSSP; - else + if (server->secType == Kerberos) { + if (!server->sec_kerberos && + !server->sec_mskerberos) + rc = -EOPNOTSUPP; + } else if (server->secType == RawNTLMSSP) { + if (!server->sec_ntlmssp) + rc = -EOPNOTSUPP; + } else rc = -EOPNOTSUPP; } } else diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 446e2486d5f0..18af707f00f1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1707,6 +1707,7 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) CIFSSMBLogoff(xid, ses); _FreeXid(xid); } + cifs_crypto_shash_release(server); sesInfoFree(ses); cifs_put_tcp_session(server); } @@ -1786,13 +1787,23 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ses->linux_uid = volume_info->linux_uid; ses->overrideSecFlg = volume_info->secFlg; + rc = cifs_crypto_shash_allocate(server); + if (rc) { + cERROR(1, "could not setup hash structures rc %d", rc); + goto get_ses_fail; + } + server->tilen = 0; + server->tiblob = NULL; + mutex_lock(&ses->session_mutex); rc = cifs_negotiate_protocol(xid, ses); if (!rc) rc = cifs_setup_session(xid, ses, volume_info->local_nls); mutex_unlock(&ses->session_mutex); - if (rc) + if (rc) { + cifs_crypto_shash_release(ses->server); goto get_ses_fail; + } /* success, put it on the list */ write_lock(&cifs_tcp_ses_lock); diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 49c9a4e75319..1db0f0746a5b 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h @@ -61,6 +61,19 @@ #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 #define NTLMSSP_NEGOTIATE_56 0x80000000 +/* Define AV Pair Field IDs */ +#define NTLMSSP_AV_EOL 0 +#define NTLMSSP_AV_NB_COMPUTER_NAME 1 +#define NTLMSSP_AV_NB_DOMAIN_NAME 2 +#define NTLMSSP_AV_DNS_COMPUTER_NAME 3 +#define NTLMSSP_AV_DNS_DOMAIN_NAME 4 +#define NTLMSSP_AV_DNS_TREE_NAME 5 +#define NTLMSSP_AV_FLAGS 6 +#define NTLMSSP_AV_TIMESTAMP 7 +#define NTLMSSP_AV_RESTRICTION 8 +#define NTLMSSP_AV_TARGET_NAME 9 +#define NTLMSSP_AV_CHANNEL_BINDINGS 10 + /* Although typedefs are not commonly used for structure definitions */ /* in the Linux kernel, in this particular case they are useful */ /* to more closely match the standards document for NTLMSSP from */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 0a57cb7db5dd..41fc5328120d 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifsSesInfo *ses) { + unsigned int tioffset; /* challeng message target info area */ + unsigned int tilen; /* challeng message target info area length */ + CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; if (blob_len < sizeof(CHALLENGE_MESSAGE)) { @@ -405,6 +408,18 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ + tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); + tilen = cpu_to_le16(pblob->TargetInfoArray.Length); + ses->server->tilen = tilen; + if (tilen) { + ses->server->tiblob = kmalloc(tilen, GFP_KERNEL); + if (!ses->server->tiblob) { + cERROR(1, "Challenge target info allocation failure"); + return -ENOMEM; + } + memcpy(ses->server->tiblob, bcc_ptr + tioffset, tilen); + } + return 0; } @@ -451,10 +466,12 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, struct cifsSesInfo *ses, const struct nls_table *nls_cp, bool first) { + int rc; + unsigned int size; AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; __u32 flags; unsigned char *tmp; - char ntlm_session_key[CIFS_SESS_KEY_SIZE]; + struct ntlmv2_resp ntlmv2_response = {}; memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); sec_blob->MessageType = NtLmAuthenticate; @@ -477,19 +494,25 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->LmChallengeResponse.Length = 0; sec_blob->LmChallengeResponse.MaximumLength = 0; - /* calculate session key, BB what about adding similar ntlmv2 path? */ - SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); - if (first) - cifs_calculate_mac_key(&ses->server->mac_signing_key, - ntlm_session_key, ses->password); - - memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); - sec_blob->NtChallengeResponse.MaximumLength = - cpu_to_le16(CIFS_SESS_KEY_SIZE); + rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); + if (rc) { + cERROR(1, "error rc: %d during ntlmssp ntlmv2 setup", rc); + goto setup_ntlmv2_ret; + } + size = sizeof(struct ntlmv2_resp); + memcpy(tmp, (char *)&ntlmv2_response, size); + tmp += size; + if (ses->server->tilen > 0) { + memcpy(tmp, ses->server->tiblob, ses->server->tilen); + tmp += ses->server->tilen; + } else + ses->server->tilen = 0; - tmp += CIFS_SESS_KEY_SIZE; + sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + + ses->server->tilen); + sec_blob->NtChallengeResponse.MaximumLength = + cpu_to_le16(size + ses->server->tilen); if (ses->domainName == NULL) { sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); @@ -501,7 +524,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ - len += 2; /* trailing null */ sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.Length = cpu_to_le16(len); sec_blob->DomainName.MaximumLength = cpu_to_le16(len); @@ -518,7 +540,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, len = cifs_strtoUCS((__le16 *)tmp, ses->userName, MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ - len += 2; /* trailing null */ sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.Length = cpu_to_le16(len); sec_blob->UserName.MaximumLength = cpu_to_le16(len); @@ -530,9 +551,26 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->WorkstationName.MaximumLength = 0; tmp += 2; - sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->SessionKey.Length = 0; - sec_blob->SessionKey.MaximumLength = 0; + if ((ses->server->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && + !calc_seckey(ses->server)) { + memcpy(tmp, ses->server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); + sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); + sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); + sec_blob->SessionKey.MaximumLength = + cpu_to_le16(CIFS_CPHTXT_SIZE); + tmp += CIFS_CPHTXT_SIZE; + } else { + sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); + sec_blob->SessionKey.Length = 0; + sec_blob->SessionKey.MaximumLength = 0; + } + + ses->server->sequence_number = 0; + +setup_ntlmv2_ret: + if (ses->server->tilen > 0) + kfree(ses->server->tiblob); + return tmp - pbuffer; } @@ -546,15 +584,14 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, return; } -static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, +static int setup_ntlmssp_auth_req(char *ntlmsspblob, struct cifsSesInfo *ses, const struct nls_table *nls, bool first_time) { int bloblen; - bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, + bloblen = build_ntlmssp_auth_blob(ntlmsspblob, ses, nls, first_time); - pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); return bloblen; } @@ -580,6 +617,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, struct key *spnego_key = NULL; __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ bool first_time; + char *ntlmsspblob; if (ses == NULL) return -EINVAL; @@ -690,7 +728,7 @@ ssetup_ntlmssp_authenticate: if (first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_mac_key(&ses->server->mac_signing_key, + cifs_calculate_session_key(&ses->server->session_key, ntlm_session_key, ses->password); /* copy session key */ @@ -729,12 +767,21 @@ ssetup_ntlmssp_authenticate: cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); + rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); + if (rc) { + kfree(v2_sess_key); + goto ssetup_exit; + } /* FIXME: calculate MAC key */ memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); + if (ses->server->tilen > 0) { + memcpy(bcc_ptr, ses->server->tiblob, + ses->server->tilen); + bcc_ptr += ses->server->tilen; + } if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; @@ -765,15 +812,15 @@ ssetup_ntlmssp_authenticate: } /* bail out if key is too long */ if (msg->sesskey_len > - sizeof(ses->server->mac_signing_key.data.krb5)) { + sizeof(ses->server->session_key.data.krb5)) { cERROR(1, "Kerberos signing key too long (%u bytes)", msg->sesskey_len); rc = -EOVERFLOW; goto ssetup_exit; } if (first_time) { - ses->server->mac_signing_key.len = msg->sesskey_len; - memcpy(ses->server->mac_signing_key.data.krb5, + ses->server->session_key.len = msg->sesskey_len; + memcpy(ses->server->session_key.data.krb5, msg->data, msg->sesskey_len); } pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; @@ -815,12 +862,26 @@ ssetup_ntlmssp_authenticate: if (phase == NtLmNegotiate) { setup_ntlmssp_neg_req(pSMB, ses); iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); + iov[1].iov_base = &pSMB->req.SecurityBlob[0]; } else if (phase == NtLmAuthenticate) { int blob_len; - blob_len = setup_ntlmssp_auth_req(pSMB, ses, - nls_cp, - first_time); + ntlmsspblob = kmalloc(5 * + sizeof(struct _AUTHENTICATE_MESSAGE), + GFP_KERNEL); + if (!ntlmsspblob) { + cERROR(1, "Can't allocate NTLMSSP"); + rc = -ENOMEM; + goto ssetup_exit; + } + + blob_len = setup_ntlmssp_auth_req(ntlmsspblob, + ses, + nls_cp, + first_time); iov[1].iov_len = blob_len; + iov[1].iov_base = ntlmsspblob; + pSMB->req.SecurityBlobLength = + cpu_to_le16(blob_len); /* Make sure that we tell the server that we are using the uid that it just gave us back on the response (challenge) */ @@ -830,7 +891,6 @@ ssetup_ntlmssp_authenticate: rc = -ENOSYS; goto ssetup_exit; } - iov[1].iov_base = &pSMB->req.SecurityBlob[0]; /* unicode strings must be word aligned */ if ((iov[0].iov_len + iov[1].iov_len) % 2) { *bcc_ptr = 0; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 82f78c4d6978..e0588cdf4cc5 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -543,7 +543,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(midQ->resp_buf, - &ses->server->mac_signing_key, + ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -731,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - &ses->server->mac_signing_key, + ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -981,7 +981,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - &ses->server->mac_signing_key, + ses->server, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); -- cgit v1.2.3-59-g8ed1b From cfe3fdadb16162327773ef01a575a32000b8c7f4 Mon Sep 17 00:00:00 2001 From: Tilman Sauerbeck Date: Fri, 20 Aug 2010 14:01:47 -0700 Subject: mtd: nand: Fix probe of Samsung NAND chips Apparently, the check for a 6-byte ID string introduced by commit 426c457a3216fac74e3d44dd39729b0689f4c7ab ("mtd: nand: extend NAND flash detection to new MLC chips") is NOT sufficient to determine whether or not a Samsung chip uses their new MLC detection scheme or the old, standard scheme. This adds a condition to check cell type. Signed-off-by: Tilman Sauerbeck Signed-off-by: Brian Norris Signed-off-by: David Woodhouse Cc: stable@kernel.org --- drivers/mtd/nand/nand_base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a22ed7b281ce..d551ddd9537a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2866,6 +2866,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, */ if (id_data[0] == id_data[6] && id_data[1] == id_data[7] && id_data[0] == NAND_MFR_SAMSUNG && + (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && id_data[5] != 0x00) { /* Calc pagesize */ mtd->writesize = 2048 << (extid & 0x03); -- cgit v1.2.3-59-g8ed1b From 51e3c1b558b31b11bf5fc66d3c6f5adacf3573f7 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Fri, 20 Aug 2010 10:36:34 +0300 Subject: x86, hwmon: Fix unsafe smp_processor_id() in thermal_throttle_add_dev Fix BUG: using smp_processor_id() in preemptible thermal_throttle_add_dev. We know the cpu number when calling thermal_throttle_add_dev, so we can remove smp_processor_id call in thermal_throttle_add_dev by supplying the cpu number as argument. This should resolve kernel bugzilla 16615/16629. Signed-off-by: Sergey Senozhatsky LKML-Reference: <20100820073634.GB5209@swordfish.minsk.epam.com> Cc: Fenghua Yu Cc: Joerg Roedel Cc: Maciej Rutecki Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/mcheck/therm_throt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index c2a8b26d4fea..d9368eeda309 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -202,10 +202,11 @@ static int therm_throt_process(bool new_event, int event, int level) #ifdef CONFIG_SYSFS /* Add/Remove thermal_throttle interface for CPU device: */ -static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev) +static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev, + unsigned int cpu) { int err; - struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); + struct cpuinfo_x86 *c = &cpu_data(cpu); err = sysfs_create_group(&sys_dev->kobj, &thermal_attr_group); if (err) @@ -251,7 +252,7 @@ thermal_throttle_cpu_callback(struct notifier_block *nfb, case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: mutex_lock(&therm_cpu_lock); - err = thermal_throttle_add_dev(sys_dev); + err = thermal_throttle_add_dev(sys_dev, cpu); mutex_unlock(&therm_cpu_lock); WARN_ON(err); break; @@ -287,7 +288,7 @@ static __init int thermal_throttle_init_device(void) #endif /* connect live CPUs to sysfs */ for_each_online_cpu(cpu) { - err = thermal_throttle_add_dev(get_cpu_sysdev(cpu)); + err = thermal_throttle_add_dev(get_cpu_sysdev(cpu), cpu); WARN_ON(err); } #ifdef CONFIG_HOTPLUG_CPU -- cgit v1.2.3-59-g8ed1b From f335397d177c906256ee1bba28e8c49e8ec63817 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 17 Aug 2010 21:15:47 -0700 Subject: Input: sysrq - drop tty argument form handle_sysrq() Sysrq operations do not accept tty argument anymore so no need to pass it to us. [Stephen Rothwell : fix build breakage in drm code caused by sysrq using bool but not including linux/types.h] [Sachin Sant : fix build breakage in s390 keyboadr driver] Acked-by: Alan Cox Acked-by: Jason Wessel Acked-by: Greg Kroah-Hartman Signed-off-by: Dmitry Torokhov --- arch/ia64/hp/sim/simserial.c | 2 +- arch/um/drivers/mconsole_kern.c | 2 +- drivers/char/hangcheck-timer.c | 2 +- drivers/char/hvc_console.c | 2 +- drivers/char/hvsi.c | 2 +- drivers/char/sysrq.c | 11 +++++------ drivers/s390/char/ctrlchar.c | 4 +--- drivers/s390/char/keyboard.c | 2 +- drivers/serial/sn_console.c | 2 +- drivers/usb/serial/generic.c | 2 +- drivers/xen/manage.c | 2 +- include/linux/serial_core.h | 2 +- include/linux/sysrq.h | 12 +++++------- kernel/debug/kdb/kdb_main.c | 2 +- 14 files changed, 22 insertions(+), 27 deletions(-) diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 2bef5261d96d..1e8d71ad93ef 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -149,7 +149,7 @@ static void receive_chars(struct tty_struct *tty) ch = ia64_ssc(0, 0, 0, 0, SSC_GETCHAR); while (!ch); - handle_sysrq(ch, NULL); + handle_sysrq(ch); } #endif seen_esc = 0; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index de317d0c3294..ebc680717e59 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -690,7 +690,7 @@ static void with_console(struct mc_request *req, void (*proc)(void *), static void sysrq_proc(void *arg) { char *op = arg; - handle_sysrq(*op, NULL); + handle_sysrq(*op); } void mconsole_sysrq(struct mc_request *req) diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index e0249722d25f..f953c96efc86 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -159,7 +159,7 @@ static void hangcheck_fire(unsigned long data) if (hangcheck_dump_tasks) { printk(KERN_CRIT "Hangcheck: Task state:\n"); #ifdef CONFIG_MAGIC_SYSRQ - handle_sysrq('t', NULL); + handle_sysrq('t'); #endif /* CONFIG_MAGIC_SYSRQ */ } if (hangcheck_reboot) { diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index fa27d1676ee5..3afd62e856eb 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -651,7 +651,7 @@ int hvc_poll(struct hvc_struct *hp) if (sysrq_pressed) continue; } else if (sysrq_pressed) { - handle_sysrq(buf[i], tty); + handle_sysrq(buf[i]); sysrq_pressed = 0; continue; } diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 1f4b6de65a2d..a2bc885ce60a 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -403,7 +403,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) hp->sysrq = 1; continue; } else if (hp->sysrq) { - handle_sysrq(c, hp->tty); + handle_sysrq(c); hp->sysrq = 0; continue; } diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index a892a3c249dd..ef31bb81e843 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -493,7 +492,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) sysrq_key_table[i] = op_p; } -void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) +void __handle_sysrq(int key, bool check_mask) { struct sysrq_key_op *op_p; int orig_log_level; @@ -545,10 +544,10 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) spin_unlock_irqrestore(&sysrq_key_table_lock, flags); } -void handle_sysrq(int key, struct tty_struct *tty) +void handle_sysrq(int key) { if (sysrq_on()) - __handle_sysrq(key, tty, 1); + __handle_sysrq(key, true); } EXPORT_SYMBOL(handle_sysrq); @@ -597,7 +596,7 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type, default: if (sysrq_down && value && value != 2) - __handle_sysrq(sysrq_xlate[code], NULL, 1); + __handle_sysrq(sysrq_xlate[code], true); break; } @@ -765,7 +764,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, if (get_user(c, buf)) return -EFAULT; - __handle_sysrq(c, NULL, 0); + __handle_sysrq(c, false); } return count; diff --git a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c index c6cbcb3f925e..0e9a309b9669 100644 --- a/drivers/s390/char/ctrlchar.c +++ b/drivers/s390/char/ctrlchar.c @@ -16,12 +16,11 @@ #ifdef CONFIG_MAGIC_SYSRQ static int ctrlchar_sysrq_key; -static struct tty_struct *sysrq_tty; static void ctrlchar_handle_sysrq(struct work_struct *work) { - handle_sysrq(ctrlchar_sysrq_key, sysrq_tty); + handle_sysrq(ctrlchar_sysrq_key); } static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq); @@ -54,7 +53,6 @@ ctrlchar_handle(const unsigned char *buf, int len, struct tty_struct *tty) /* racy */ if (len == 3 && buf[1] == '-') { ctrlchar_sysrq_key = buf[2]; - sysrq_tty = tty; schedule_work(&ctrlchar_work); return CTRLCHAR_SYSRQ; } diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 18d9a497863b..8cd58e412b5e 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -305,7 +305,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode) if (kbd->sysrq) { if (kbd->sysrq == K(KT_LATIN, '-')) { kbd->sysrq = 0; - handle_sysrq(value, kbd->tty); + handle_sysrq(value); return; } if (value == '-') { diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 7e5e5efea4e2..cff9a306660f 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -492,7 +492,7 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags) sysrq_requested = 0; if (ch && time_before(jiffies, sysrq_timeout)) { spin_unlock_irqrestore(&port->sc_port.lock, flags); - handle_sysrq(ch, NULL); + handle_sysrq(ch); spin_lock_irqsave(&port->sc_port.lock, flags); /* ignore actual sysrq command char */ continue; diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index ca92f67747cc..1e846cc3c7a4 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -453,7 +453,7 @@ int usb_serial_handle_sysrq_char(struct tty_struct *tty, { if (port->sysrq && port->port.console) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, tty); + handle_sysrq(ch); port->sysrq = 0; return 1; } diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 1799bd890315..ef9c7db52077 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -237,7 +237,7 @@ static void sysrq_handler(struct xenbus_watch *watch, const char **vec, goto again; if (sysrq_key != '\0') - handle_sysrq(sysrq_key, NULL); + handle_sysrq(sysrq_key); } static struct xenbus_watch sysrq_watch = { diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 3c2ad99fed34..64458a9a8938 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -465,7 +465,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) #ifdef SUPPORT_SYSRQ if (port->sysrq) { if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch, port->state->port.tty); + handle_sysrq(ch); port->sysrq = 0; return 1; } diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 4ee650315119..387fa7d05c98 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -15,9 +15,7 @@ #define _LINUX_SYSRQ_H #include - -struct pt_regs; -struct tty_struct; +#include /* Possible values of bitmask for enabling sysrq functions */ /* 0x0001 is reserved for enable everything */ @@ -44,8 +42,8 @@ struct sysrq_key_op { * are available -- else NULL's). */ -void handle_sysrq(int key, struct tty_struct *tty); -void __handle_sysrq(int key, struct tty_struct *tty, int check_mask); +void handle_sysrq(int key); +void __handle_sysrq(int key, bool check_mask); int register_sysrq_key(int key, struct sysrq_key_op *op); int unregister_sysrq_key(int key, struct sysrq_key_op *op); struct sysrq_key_op *__sysrq_get_key_op(int key); @@ -54,11 +52,11 @@ int sysrq_toggle_support(int enable_mask); #else -static inline void handle_sysrq(int key, struct tty_struct *tty) +static inline void handle_sysrq(int key) { } -static inline void __handle_sysrq(int key, struct tty_struct *tty, int check_mask); +static inline void __handle_sysrq(int key, bool check_mask) { } diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 28b844118bbd..caf057a3de0e 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1929,7 +1929,7 @@ static int kdb_sr(int argc, const char **argv) if (argc != 1) return KDB_ARGCOUNT; kdb_trap_printk++; - __handle_sysrq(*argv[1], NULL, 0); + __handle_sysrq(*argv[1], false); kdb_trap_printk--; return 0; -- cgit v1.2.3-59-g8ed1b From 6ee9f4b4affe751d313d2538999aeec134d413a6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 17 Aug 2010 21:15:47 -0700 Subject: USB: drop tty argument from usb_serial_handle_sysrq_char() Since handle_sysrq() does not take tty as argument anymore we can drop it from usb_serial_handle_sysrq_char() as well. Acked-by: Alan Cox Acked-by: Jason Wessel Acked-by: Greg Kroah-Hartman Signed-off-by: Dmitry Torokhov --- drivers/usb/serial/ftdi_sio.c | 2 +- drivers/usb/serial/generic.c | 8 +++----- drivers/usb/serial/pl2303.c | 2 +- drivers/usb/serial/ssu100.c | 2 +- include/linux/usb/serial.h | 3 +-- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index eb12d9b096b4..5d47983b533c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1831,7 +1831,7 @@ static int ftdi_process_packet(struct tty_struct *tty, if (port->port.console && port->sysrq) { for (i = 0; i < len; i++, ch++) { - if (!usb_serial_handle_sysrq_char(tty, port, *ch)) + if (!usb_serial_handle_sysrq_char(port, *ch)) tty_insert_flip_char(tty, *ch, flag); } } else { diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 1e846cc3c7a4..1abe34c38c08 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -343,7 +343,7 @@ void usb_serial_generic_process_read_urb(struct urb *urb) tty_insert_flip_string(tty, ch, urb->actual_length); else { for (i = 0; i < urb->actual_length; i++, ch++) { - if (!usb_serial_handle_sysrq_char(tty, port, *ch)) + if (!usb_serial_handle_sysrq_char(port, *ch)) tty_insert_flip_char(tty, *ch, TTY_NORMAL); } } @@ -448,8 +448,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); #ifdef CONFIG_MAGIC_SYSRQ -int usb_serial_handle_sysrq_char(struct tty_struct *tty, - struct usb_serial_port *port, unsigned int ch) +int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) { if (port->sysrq && port->port.console) { if (ch && time_before(jiffies, port->sysrq)) { @@ -462,8 +461,7 @@ int usb_serial_handle_sysrq_char(struct tty_struct *tty, return 0; } #else -int usb_serial_handle_sysrq_char(struct tty_struct *tty, - struct usb_serial_port *port, unsigned int ch) +int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) { return 0; } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 6b6001822279..34ad7b3d5948 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -788,7 +788,7 @@ static void pl2303_process_read_urb(struct urb *urb) if (port->port.console && port->sysrq) { for (i = 0; i < urb->actual_length; ++i) - if (!usb_serial_handle_sysrq_char(tty, port, data[i])) + if (!usb_serial_handle_sysrq_char(port, data[i])) tty_insert_flip_char(tty, data[i], tty_flag); } else { tty_insert_flip_string_fixed_flag(tty, data, tty_flag, diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 6e82d4f54bc8..819de4740388 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -596,7 +596,7 @@ static int ssu100_process_packet(struct tty_struct *tty, if (port->port.console && port->sysrq) { for (i = 0; i < len; i++, ch++) { - if (!usb_serial_handle_sysrq_char(tty, port, *ch)) + if (!usb_serial_handle_sysrq_char(port, *ch)) tty_insert_flip_char(tty, *ch, flag); } } else diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 84a4c44c208b..55675b1efb28 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -342,8 +342,7 @@ extern int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, extern void usb_serial_generic_process_read_urb(struct urb *urb); extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, void *dest, size_t size); -extern int usb_serial_handle_sysrq_char(struct tty_struct *tty, - struct usb_serial_port *port, +extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch); extern int usb_serial_handle_break(struct usb_serial_port *port); -- cgit v1.2.3-59-g8ed1b From 77edf0c7515cd8268a0cce2daa3f3c87e9afe005 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 17 Aug 2010 21:22:13 -0700 Subject: Input: hil_kbd - fix compile error Fix another compile breakage stemming from 987a6c02 ("Input: switch to input_abs_*() access functions") Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/hil_kbd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index dcc86b97a153..19fa94af207a 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -232,13 +232,13 @@ static void hil_dev_handle_ptr_events(struct hil_dev *ptr) if (absdev) { val = lo + (hi << 8); #ifdef TABLET_AUTOADJUST - if (val < input_abs_min(dev, ABS_X + i)) + if (val < input_abs_get_min(dev, ABS_X + i)) input_abs_set_min(dev, ABS_X + i, val); - if (val > input_abs_max(dev, ABS_X + i)) + if (val > input_abs_get_max(dev, ABS_X + i)) input_abs_set_max(dev, ABS_X + i, val); #endif if (i % 3) - val = input_abs_max(dev, ABS_X + i) - val; + val = input_abs_get_max(dev, ABS_X + i) - val; input_report_abs(dev, ABS_X + i, val); } else { val = (int) (((int8_t) lo) | ((int8_t) hi << 8)); @@ -388,11 +388,11 @@ static void hil_dev_pointer_setup(struct hil_dev *ptr) #ifdef TABLET_AUTOADJUST for (i = 0; i < ABS_MAX; i++) { - int diff = input_abs_max(input_dev, ABS_X + i) / 10; + int diff = input_abs_get_max(input_dev, ABS_X + i) / 10; input_abs_set_min(input_dev, ABS_X + i, - input_abs_min(input_dev, ABS_X + i) + diff) + input_abs_get_min(input_dev, ABS_X + i) + diff); input_abs_set_max(input_dev, ABS_X + i, - input_abs_max(input_dev, ABS_X + i) - diff) + input_abs_get_max(input_dev, ABS_X + i) - diff); } #endif -- cgit v1.2.3-59-g8ed1b From 8905aaafb4b5d9764c5b4b54c7d03eb41bb0a7e9 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 19 Aug 2010 09:52:28 -0700 Subject: Input: uinput - add devname alias to allow module on-demand load Recent modprobe and udev versions allow to create device nodes for modules which are not loaded. Only the first access will cause the in-kernel module loader to pull-in the module. Systems which never access the device node will not needlessly load the module, and no longer need init scripts or other facilities to unconditionally load it. Signed-off-by: Kay Sievers Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 2 ++ include/linux/miscdevice.h | 1 + include/linux/uinput.h | 1 - 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index bb53fd33cd1c..0d4266a533a5 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -811,6 +811,8 @@ static struct miscdevice uinput_misc = { .minor = UINPUT_MINOR, .name = UINPUT_NAME, }; +MODULE_ALIAS_MISCDEV(UINPUT_MINOR); +MODULE_ALIAS("devname:" UINPUT_NAME); static int __init uinput_init(void) { diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index bafffc737903..18fd13028ba1 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -33,6 +33,7 @@ #define MWAVE_MINOR 219 /* ACP/Mwave Modem */ #define MPT_MINOR 220 #define MPT2SAS_MINOR 221 +#define UINPUT_MINOR 223 #define HPET_MINOR 228 #define FUSE_MINOR 229 #define KVM_MINOR 232 diff --git a/include/linux/uinput.h b/include/linux/uinput.h index 60c81da77f0f..05f7fed2b173 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h @@ -37,7 +37,6 @@ #define UINPUT_VERSION 3 #ifdef __KERNEL__ -#define UINPUT_MINOR 223 #define UINPUT_NAME "uinput" #define UINPUT_BUFFER_SIZE 16 #define UINPUT_NUM_REQUESTS 16 -- cgit v1.2.3-59-g8ed1b From a38b372fc2a3d8fe7ddbeab94d4c8bcb721f2403 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 21 Aug 2010 16:24:03 +0800 Subject: mxc/tzic: add base address when accessing TZIC registers When we call tzic_enable_wake function, the kernel will crash because of access to an unmapped address. This is because two register access operations forgot to add base address. Signed-off-by: Jason Wang Signed-off-by: Sascha Hauer --- arch/arm/plat-mxc/tzic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c index b3da9aad4295..3703ab28257f 100644 --- a/arch/arm/plat-mxc/tzic.c +++ b/arch/arm/plat-mxc/tzic.c @@ -164,8 +164,9 @@ int tzic_enable_wake(int is_idle) return -EAGAIN; for (i = 0; i < 4; i++) { - v = is_idle ? __raw_readl(TZIC_ENSET0(i)) : wakeup_intr[i]; - __raw_writel(v, TZIC_WAKEUP0(i)); + v = is_idle ? __raw_readl(tzic_base + TZIC_ENSET0(i)) : + wakeup_intr[i]; + __raw_writel(v, tzic_base + TZIC_WAKEUP0(i)); } return 0; -- cgit v1.2.3-59-g8ed1b From 7f67bff58662604874778e6853e5c394f944e554 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 21 Aug 2010 16:24:04 +0800 Subject: mx5/clock: fix clear bit fields issue in _clk_ccgr_disable function We can see MXC_CCM_CCGRx_MOD_OFF is defined as 0 while MXC_CCM_CCGRx_CG_MASK is defined as 0x3 in crm_regs.h, here in the _clk_ccgr_disable function, we want to clear the corresponding enable bit fields to disable this clock, so we should choose MASK instead of OFF otherwise clocks can't be disabled. Signed-off-by: Jason Wang Signed-off-by: Sascha Hauer --- arch/arm/mach-mx5/clock-mx51.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c index 6af69def357f..57c10a9926cc 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c @@ -56,7 +56,7 @@ static void _clk_ccgr_disable(struct clk *clk) { u32 reg; reg = __raw_readl(clk->enable_reg); - reg &= ~(MXC_CCM_CCGRx_MOD_OFF << clk->enable_shift); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); __raw_writel(reg, clk->enable_reg); } -- cgit v1.2.3-59-g8ed1b From 14f0f512ba6f4eccc9b7cf67be47439ed2917afb Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 21 Aug 2010 16:24:05 +0800 Subject: ARM: imx: set cache line size to 64 bytes for i.MX5 The core of i.MX5 series is cortex-A8, its cache line size is 64 bytes instead of 32 bytes. Refer to the OMAP3's selection, we choose 64 bytes for i.MX5, this can increase a little bit performance when perform cache operations. Signed-off-by: Jason Wang Signed-off-by: Sascha Hauer --- arch/arm/plat-mxc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index 0527e65318f4..6785db4179b8 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -43,6 +43,7 @@ config ARCH_MXC91231 config ARCH_MX5 bool "MX5-based" select CPU_V7 + select ARM_L1_CACHE_SHIFT_6 help This enables support for systems based on the Freescale i.MX51 family -- cgit v1.2.3-59-g8ed1b From 8558f59edf935cf5ee5ffc29a9e9458fd9a71be1 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Mon, 16 Aug 2010 17:09:52 +0200 Subject: setlocalversion: Ignote SCMs above the linux source tree Dan McGee writes: > Note that when in git, you get the appended "+" sign. If > LOCALVERSION_AUTO is set, you will get something like > "eee-gb01b08c-dirty" (whereas the copy of the tree in /tmp still > returns "eee"). It doesn't matter whether the working tree is dirty or > clean. > > Is there a way to disable this? I'm building from a clean tarball that > just happens to be unpacked inside a git repository. One would think > setting LOCALVERSION_AUTO to false would do it, but no such luck... Fix this by checking if the kernel source tree is the root of the git or hg repository. No fix for svn: If the kernel source is not tracked in the svn repository, it works as expected, otherwise determining the 'repository root' is not really a defined task. Reported-and-tested-by: Dan McGee Signed-off-by: Michal Marek --- scripts/setlocalversion | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index e90a91cc5185..057b6b3c5dfb 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -43,7 +43,7 @@ scm_version() fi # Check for git and a git repo. - if head=`git rev-parse --verify --short HEAD 2>/dev/null`; then + if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore # it, because this version is defined in the top level Makefile. @@ -85,7 +85,7 @@ scm_version() fi # Check for mercurial and a mercurial repo. - if hgid=`hg id 2>/dev/null`; then + if test -d .hg && hgid=`hg id 2>/dev/null`; then tag=`printf '%s' "$hgid" | cut -s -d' ' -f2` # Do we have an untagged version? -- cgit v1.2.3-59-g8ed1b From 297c5eee372478fc32fec5fe8eed711eedb13f3d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Aug 2010 16:24:55 -0700 Subject: mm: make the vma list be doubly linked It's a really simple list, and several of the users want to go backwards in it to find the previous vma. So rather than have to look up the previous entry with 'find_vma_prev()' or something similar, just make it doubly linked instead. Tested-by: Ian Campbell Signed-off-by: Linus Torvalds --- include/linux/mm_types.h | 2 +- kernel/fork.c | 7 +++++-- mm/mmap.c | 21 +++++++++++++++++---- mm/nommu.c | 7 +++++-- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index b8bb9a6a1f37..ee7e258627f9 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -134,7 +134,7 @@ struct vm_area_struct { within vm_mm. */ /* linked list of VM areas per task, sorted by address */ - struct vm_area_struct *vm_next; + struct vm_area_struct *vm_next, *vm_prev; pgprot_t vm_page_prot; /* Access permissions of this VMA. */ unsigned long vm_flags; /* Flags, see mm.h. */ diff --git a/kernel/fork.c b/kernel/fork.c index 856eac3ec52e..b7e9d60a675d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -300,7 +300,7 @@ out: #ifdef CONFIG_MMU static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) { - struct vm_area_struct *mpnt, *tmp, **pprev; + struct vm_area_struct *mpnt, *tmp, *prev, **pprev; struct rb_node **rb_link, *rb_parent; int retval; unsigned long charge; @@ -328,6 +328,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) if (retval) goto out; + prev = NULL; for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { struct file *file; @@ -359,7 +360,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) goto fail_nomem_anon_vma_fork; tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; - tmp->vm_next = NULL; + tmp->vm_next = tmp->vm_prev = NULL; file = tmp->vm_file; if (file) { struct inode *inode = file->f_path.dentry->d_inode; @@ -392,6 +393,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) */ *pprev = tmp; pprev = &tmp->vm_next; + tmp->vm_prev = prev; + prev = tmp; __vma_link_rb(mm, tmp, rb_link, rb_parent); rb_link = &tmp->vm_rb.rb_right; diff --git a/mm/mmap.c b/mm/mmap.c index 31003338b978..331e51af38c9 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -388,17 +388,23 @@ static inline void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, struct rb_node *rb_parent) { + struct vm_area_struct *next; + + vma->vm_prev = prev; if (prev) { - vma->vm_next = prev->vm_next; + next = prev->vm_next; prev->vm_next = vma; } else { mm->mmap = vma; if (rb_parent) - vma->vm_next = rb_entry(rb_parent, + next = rb_entry(rb_parent, struct vm_area_struct, vm_rb); else - vma->vm_next = NULL; + next = NULL; } + vma->vm_next = next; + if (next) + next->vm_prev = vma; } void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, @@ -483,7 +489,11 @@ static inline void __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev) { - prev->vm_next = vma->vm_next; + struct vm_area_struct *next = vma->vm_next; + + prev->vm_next = next; + if (next) + next->vm_prev = prev; rb_erase(&vma->vm_rb, &mm->mm_rb); if (mm->mmap_cache == vma) mm->mmap_cache = prev; @@ -1915,6 +1925,7 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr; insertion_point = (prev ? &prev->vm_next : &mm->mmap); + vma->vm_prev = NULL; do { rb_erase(&vma->vm_rb, &mm->mm_rb); mm->map_count--; @@ -1922,6 +1933,8 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma, vma = vma->vm_next; } while (vma && vma->vm_start < end); *insertion_point = vma; + if (vma) + vma->vm_prev = prev; tail_vma->vm_next = NULL; if (mm->unmap_area == arch_unmap_area) addr = prev ? prev->vm_end : mm->mmap_base; diff --git a/mm/nommu.c b/mm/nommu.c index efa9a380335e..88ff091eb07a 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -604,7 +604,7 @@ static void protect_vma(struct vm_area_struct *vma, unsigned long flags) */ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma) { - struct vm_area_struct *pvma, **pp; + struct vm_area_struct *pvma, **pp, *next; struct address_space *mapping; struct rb_node **p, *parent; @@ -664,8 +664,11 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma) break; } - vma->vm_next = *pp; + next = *pp; *pp = vma; + vma->vm_next = next; + if (next) + next->vm_prev = vma; } /* -- cgit v1.2.3-59-g8ed1b From 7798330ac8114c731cfab83e634c6ecedaa233d7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Aug 2010 16:39:25 -0700 Subject: mm: make the mlock() stack guard page checks stricter If we've split the stack vma, only the lowest one has the guard page. Now that we have a doubly linked list of vma's, checking this is trivial. Tested-by: Ian Campbell Signed-off-by: Linus Torvalds --- mm/mlock.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mm/mlock.c b/mm/mlock.c index 49e5e4cb8232..cbae7c5b9568 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -135,6 +135,19 @@ void munlock_vma_page(struct page *page) } } +/* Is the vma a continuation of the stack vma above it? */ +static inline int vma_stack_continue(struct vm_area_struct *vma, unsigned long addr) +{ + return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); +} + +static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) +{ + return (vma->vm_flags & VM_GROWSDOWN) && + (vma->vm_start == addr) && + !vma_stack_continue(vma->vm_prev, addr); +} + /** * __mlock_vma_pages_range() - mlock a range of pages in the vma. * @vma: target vma @@ -168,11 +181,9 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, gup_flags |= FOLL_WRITE; /* We don't try to access the guard page of a stack vma */ - if (vma->vm_flags & VM_GROWSDOWN) { - if (start == vma->vm_start) { - start += PAGE_SIZE; - nr_pages--; - } + if (stack_guard_page(vma, start)) { + addr += PAGE_SIZE; + nr_pages--; } while (nr_pages > 0) { -- cgit v1.2.3-59-g8ed1b From 0e8e50e20c837eeec8323bba7dcd25fe5479194c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 20 Aug 2010 16:49:40 -0700 Subject: mm: make stack guard page logic use vm_prev pointer Like the mlock() change previously, this makes the stack guard check code use vma->vm_prev to see what the mapping below the current stack is, rather than have to look it up with find_vma(). Also, accept an abutting stack segment, since that happens naturally if you split the stack with mlock or mprotect. Tested-by: Ian Campbell Signed-off-by: Linus Torvalds --- mm/memory.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index b6e5fd23cc5a..2ed2267439df 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2770,11 +2770,18 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo { address &= PAGE_MASK; if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) { - address -= PAGE_SIZE; - if (find_vma(vma->vm_mm, address) != vma) - return -ENOMEM; + struct vm_area_struct *prev = vma->vm_prev; + + /* + * Is there a mapping abutting this one below? + * + * That's only ok if it's the same stack mapping + * that has gotten split.. + */ + if (prev && prev->vm_end == address) + return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; - expand_stack(vma, address); + expand_stack(vma, address - PAGE_SIZE); } return 0; } -- cgit v1.2.3-59-g8ed1b From ddb0c5a689c857bb13a42d9a3f0a7604497b3a29 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 21 Aug 2010 21:32:41 +0200 Subject: Replace Configure with Enable in description of MAXSMP The "Configure" word tends to make user believe they have to say 'yes' to be able to choose the number of procs/nodes. "Enable" should be unambiguous enough. Signed-off-by: Samuel Thibault Signed-off-by: Linus Torvalds --- arch/x86/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ac7827fc0823..cea0cd9a316f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -754,11 +754,11 @@ config IOMMU_API def_bool (AMD_IOMMU || DMAR) config MAXSMP - bool "Configure Maximum number of SMP Processors and NUMA Nodes" + bool "Enable Maximum number of SMP Processors and NUMA Nodes" depends on X86_64 && SMP && DEBUG_KERNEL && EXPERIMENTAL select CPUMASK_OFFSTACK ---help--- - Configure maximum number of CPUS and NUMA Nodes for this architecture. + Enable maximum number of CPUS and NUMA Nodes for this architecture. If unsure, say N. config NR_CPUS -- cgit v1.2.3-59-g8ed1b From e36c886a0f9d624377977fa6cae309cfd7f362fa Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 21 Aug 2010 13:07:26 -0700 Subject: workqueue: Add basic tracepoints to track workqueue execution With the introduction of the new unified work queue thread pools, we lost one feature: It's no longer possible to know which worker is causing the CPU to wake out of idle. The result is that PowerTOP now reports a lot of "kworker/a:b" instead of more readable results. This patch adds a pair of tracepoints to the new workqueue code, similar in style to the timer/hrtimer tracepoints. With this pair of tracepoints, the next PowerTOP can correctly report which work item caused the wakeup (and how long it took): Interrupt (43) i915 time 3.51ms wakeups 141 Work ieee80211_iface_work time 0.81ms wakeups 29 Work do_dbs_timer time 0.55ms wakeups 24 Process Xorg time 21.36ms wakeups 4 Timer sched_rt_period_timer time 0.01ms wakeups 1 Signed-off-by: Arjan van de Ven Signed-off-by: Linus Torvalds --- include/trace/events/workqueue.h | 62 ++++++++++++++++++++++++++++++++++++++++ kernel/workqueue.c | 9 ++++++ 2 files changed, 71 insertions(+) create mode 100644 include/trace/events/workqueue.h diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h new file mode 100644 index 000000000000..49682d7e9d60 --- /dev/null +++ b/include/trace/events/workqueue.h @@ -0,0 +1,62 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM workqueue + +#if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_WORKQUEUE_H + +#include +#include + +/** + * workqueue_execute_start - called immediately before the workqueue callback + * @work: pointer to struct work_struct + * + * Allows to track workqueue execution. + */ +TRACE_EVENT(workqueue_execute_start, + + TP_PROTO(struct work_struct *work), + + TP_ARGS(work), + + TP_STRUCT__entry( + __field( void *, work ) + __field( void *, function) + ), + + TP_fast_assign( + __entry->work = work; + __entry->function = work->func; + ), + + TP_printk("work struct %p: function %pf", __entry->work, __entry->function) +); + +/** + * workqueue_execute_end - called immediately before the workqueue callback + * @work: pointer to struct work_struct + * + * Allows to track workqueue execution. + */ +TRACE_EVENT(workqueue_execute_end, + + TP_PROTO(struct work_struct *work), + + TP_ARGS(work), + + TP_STRUCT__entry( + __field( void *, work ) + ), + + TP_fast_assign( + __entry->work = work; + ), + + TP_printk("work struct %p", __entry->work) +); + + +#endif /* _TRACE_WORKQUEUE_H */ + +/* This part must be outside protection */ +#include diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2994a0e3a61c..8bd600c020e5 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -35,6 +35,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include "workqueue_sched.h" enum { @@ -1790,7 +1793,13 @@ static void process_one_work(struct worker *worker, struct work_struct *work) work_clear_pending(work); lock_map_acquire(&cwq->wq->lockdep_map); lock_map_acquire(&lockdep_map); + trace_workqueue_execute_start(work); f(work); + /* + * While we must be careful to not use "work" after this, the trace + * point will only record its address. + */ + trace_workqueue_execute_end(work); lock_map_release(&lockdep_map); lock_map_release(&cwq->wq->lockdep_map); -- cgit v1.2.3-59-g8ed1b From 9d0498a2bf7455159b317f19531a3e5db2ecc9c4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Aug 2010 13:20:54 -0700 Subject: drm/i915: wait for actual vblank, not just 20ms Waiting for a hard coded 20ms isn't always enough to make sure a vblank period has actually occurred, so add code to make sure we really have passed through a vblank period (or that the pipe is off when disabling). This prevents problems with mode setting and link training, and seems to fix a bug like https://bugs.freedesktop.org/show_bug.cgi?id=29278, but on an HP 8440p instead. Hopefully also fixes https://bugs.freedesktop.org/show_bug.cgi?id=29141. Signed-off-by: Jesse Barnes Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 78 ++++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_dp.c | 3 +- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_sdvo.c | 3 +- drivers/gpu/drm/i915/intel_tv.c | 9 +++-- 7 files changed, 69 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a63e9a176386..67e3ec1a6af9 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2081,6 +2081,7 @@ #define PIPE_DITHER_TYPE_ST01 (1 << 2) /* Pipe A */ #define PIPEADSL 0x70000 +#define DSL_LINEMASK 0x00000fff #define PIPEACONF 0x70008 #define PIPEACONF_ENABLE (1<<31) #define PIPEACONF_DISABLE 0 diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index c43176d77549..eb31fdf758e8 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -328,7 +328,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); /* Wait for next Vblank to substitue * border color for Color info */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); st00 = I915_READ8(VGA_MSR_WRITE); status = ((st00 & (1 << 4)) != 0) ? connector_status_connected : diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 14c45b1e8778..bdea9464b678 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -977,14 +977,54 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, return true; } -void -intel_wait_for_vblank(struct drm_device *dev) +/** + * intel_wait_for_vblank - wait for vblank on a given pipe + * @dev: drm device + * @pipe: pipe to wait for + * + * Wait for vblank to occur on a given pipe. Needed for various bits of + * mode setting code. + */ +void intel_wait_for_vblank(struct drm_device *dev, int pipe) { - /* Wait for 20ms, i.e. one cycle at 50hz. */ - if (in_dbg_master()) - mdelay(20); /* The kernel debugger cannot call msleep() */ - else - msleep(20); + struct drm_i915_private *dev_priv = dev->dev_private; + int pipestat_reg = (pipe == 0 ? PIPEASTAT : PIPEBSTAT); + + /* Wait for vblank interrupt bit to set */ + if (wait_for((I915_READ(pipestat_reg) & + PIPE_VBLANK_INTERRUPT_STATUS) == 0, + 50, 0)) + DRM_DEBUG_KMS("vblank wait timed out\n"); +} + +/** + * intel_wait_for_vblank_off - wait for vblank after disabling a pipe + * @dev: drm device + * @pipe: pipe to wait for + * + * After disabling a pipe, we can't wait for vblank in the usual way, + * spinning on the vblank interrupt status bit, since we won't actually + * see an interrupt when the pipe is disabled. + * + * So this function waits for the display line value to settle (it + * usually ends up stopping at the start of the next frame). + */ +void intel_wait_for_vblank_off(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL); + unsigned long timeout = jiffies + msecs_to_jiffies(100); + u32 last_line; + + /* Wait for the display line to settle */ + do { + last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK; + mdelay(5); + } while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) && + time_after(timeout, jiffies)); + + if (time_after(jiffies, timeout)) + DRM_DEBUG_KMS("vblank wait timed out\n"); } /* Parameters have changed, update FBC info */ @@ -1057,8 +1097,6 @@ void i8xx_disable_fbc(struct drm_device *dev) return; } - intel_wait_for_vblank(dev); - DRM_DEBUG_KMS("disabled FBC\n"); } @@ -1115,7 +1153,6 @@ void g4x_disable_fbc(struct drm_device *dev) dpfc_ctl = I915_READ(DPFC_CONTROL); dpfc_ctl &= ~DPFC_CTL_EN; I915_WRITE(DPFC_CONTROL, dpfc_ctl); - intel_wait_for_vblank(dev); DRM_DEBUG_KMS("disabled FBC\n"); } @@ -1176,7 +1213,6 @@ void ironlake_disable_fbc(struct drm_device *dev) dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); dpfc_ctl &= ~DPFC_CTL_EN; I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); - intel_wait_for_vblank(dev); DRM_DEBUG_KMS("disabled FBC\n"); } @@ -1475,7 +1511,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, if ((IS_I965G(dev) || plane == 0)) intel_update_fbc(crtc, &crtc->mode); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); intel_increase_pllclock(crtc, true); return 0; @@ -1593,7 +1629,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if ((IS_I965G(dev) || plane == 0)) intel_update_fbc(crtc, &crtc->mode); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); if (old_fb) { intel_fb = to_intel_framebuffer(old_fb); @@ -2343,10 +2379,8 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(dspbase_reg); } - if (!IS_I9XX(dev)) { - /* Wait for vblank for the disable to take effect */ - intel_wait_for_vblank(dev); - } + /* Wait for vblank for the disable to take effect */ + intel_wait_for_vblank_off(dev, pipe); /* Don't disable pipe A or pipe A PLLs if needed */ if (pipeconf_reg == PIPEACONF && @@ -2361,7 +2395,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) } /* Wait for vblank for the disable to take effect. */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank_off(dev, pipe); temp = I915_READ(dpll_reg); if ((temp & DPLL_VCO_ENABLE) != 0) { @@ -4096,7 +4130,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(pipeconf_reg, pipeconf); I915_READ(pipeconf_reg); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); if (IS_IRONLAKE(dev)) { /* enable address swizzle for tiling buffer */ @@ -4508,7 +4542,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, encoder_funcs->commit(encoder); } /* let the connector get through one full cycle before testing */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); return crtc; } @@ -4713,7 +4747,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule) dpll &= ~DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); dpll = I915_READ(dpll_reg); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); dpll = I915_READ(dpll_reg); if (dpll & DISPLAY_RATE_SELECT_FPA1) DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); @@ -4757,7 +4791,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) dpll |= DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); dpll = I915_READ(dpll_reg); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, pipe); dpll = I915_READ(dpll_reg); if (!(dpll & DISPLAY_RATE_SELECT_FPA1)) DRM_DEBUG_DRIVER("failed to downclock LVDS!\n"); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index caaaa8f9db3e..9caccd03dccb 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1145,12 +1145,13 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, { struct drm_device *dev = intel_dp->base.enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc); int ret; I915_WRITE(intel_dp->output_reg, dp_reg_value); POSTING_READ(intel_dp->output_reg); if (first) - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6ba56e1796ce..0e92aa07b382 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -219,7 +219,8 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void intel_wait_for_vblank(struct drm_device *dev); +extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe); +extern void intel_wait_for_vblank(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 5c765bb0845d..093e914e8a41 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1218,6 +1218,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 temp; if (mode != DRM_MODE_DPMS_ON) { @@ -1240,7 +1241,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) if ((temp & SDVO_ENABLE) == 0) intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE); for (i = 0; i < 2; i++) - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2); /* Warn if the device reported failure to sync. diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 1bd6e8795011..d2029efee982 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1158,11 +1158,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, /* Wait for vblank for the disable to take effect */ if (!IS_I9XX(dev)) - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); /* Wait for vblank for the disable to take effect. */ - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); /* Filter ctl must be set before TV_WIN_SIZE */ I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); @@ -1231,6 +1231,7 @@ intel_tv_detect_type (struct intel_tv *intel_tv) struct drm_encoder *encoder = &intel_tv->base.enc; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); unsigned long irqflags; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; @@ -1267,11 +1268,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv) DAC_C_0_7_V); I915_WRITE(TV_CTL, tv_ctl); I915_WRITE(TV_DAC, tv_dac); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); tv_dac = I915_READ(TV_DAC); I915_WRITE(TV_DAC, save_tv_dac); I915_WRITE(TV_CTL, save_tv_ctl); - intel_wait_for_vblank(dev); + intel_wait_for_vblank(dev, intel_crtc->pipe); /* * A B C * 0 1 1 Composite -- cgit v1.2.3-59-g8ed1b From d5dd96cb280993a6096b42ab082f9cfd9c7ae0bd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Aug 2010 15:52:19 +1000 Subject: i915: disable DAC on Ironlake also when doing CRT load detection. Like on Sandybridge, disabling the DAC here when doing CRT load detect avoids forever hangs waiting on the hardware. test procedure on HP 2740p: boot with no VGA plugged in, start X, plug in VGA monitor (1280x1024) chvt 3 machine hangs waiting forever. Signed-off-by: Dave Airlie Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/intel_crt.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index eb31fdf758e8..4b7735196cd5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -160,19 +160,20 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; u32 adpa, temp; bool ret; + bool turn_off_dac = false; temp = adpa = I915_READ(PCH_ADPA); - if (HAS_PCH_CPT(dev)) { - /* Disable DAC before force detect */ - I915_WRITE(PCH_ADPA, adpa & ~ADPA_DAC_ENABLE); - (void)I915_READ(PCH_ADPA); - } else { - adpa &= ~ADPA_CRT_HOTPLUG_MASK; - /* disable HPD first */ - I915_WRITE(PCH_ADPA, adpa); - (void)I915_READ(PCH_ADPA); - } + if (HAS_PCH_SPLIT(dev)) + turn_off_dac = true; + + adpa &= ~ADPA_CRT_HOTPLUG_MASK; + if (turn_off_dac) + adpa &= ~ADPA_DAC_ENABLE; + + /* disable HPD first */ + I915_WRITE(PCH_ADPA, adpa); + (void)I915_READ(PCH_ADPA); adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | ADPA_CRT_HOTPLUG_WARMUP_10MS | @@ -189,7 +190,7 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) 1000, 1)) DRM_ERROR("timed out waiting for FORCE_TRIGGER"); - if (HAS_PCH_CPT(dev)) { + if (turn_off_dac) { I915_WRITE(PCH_ADPA, temp); (void)I915_READ(PCH_ADPA); } -- cgit v1.2.3-59-g8ed1b From 72bcb2690927f04c0479cd0d83825f09f3bf4d4f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Aug 2010 14:41:22 +0100 Subject: drm/i915/suspend: Flush register writes before busy-waiting. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_suspend.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 6e2025274db5..05acc26fabf7 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -395,16 +395,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev) if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A & ~DPLL_VCO_ENABLE); - DRM_UDELAY(150); + POSTING_READ(dpll_a_reg); + udelay(150); } I915_WRITE(fpa0_reg, dev_priv->saveFPA0); I915_WRITE(fpa1_reg, dev_priv->saveFPA1); /* Actually enable it */ I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); - DRM_UDELAY(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + POSTING_READ(dpll_a_reg); + udelay(150); + if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); - DRM_UDELAY(150); + POSTING_READ(DPLL_A_MD); + } + udelay(150); /* Restore mode */ I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); @@ -460,16 +464,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev) if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B & ~DPLL_VCO_ENABLE); - DRM_UDELAY(150); + POSTING_READ(dpll_b_reg); + udelay(150); } I915_WRITE(fpb0_reg, dev_priv->saveFPB0); I915_WRITE(fpb1_reg, dev_priv->saveFPB1); /* Actually enable it */ I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); - DRM_UDELAY(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + POSTING_READ(dpll_b_reg); + udelay(150); + if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); - DRM_UDELAY(150); + POSTING_READ(DPLL_B_MD); + } + udelay(150); /* Restore mode */ I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); @@ -730,7 +738,8 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(VGA0, dev_priv->saveVGA0); I915_WRITE(VGA1, dev_priv->saveVGA1); I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); - DRM_UDELAY(150); + POSTING_READ(VGA_PD); + udelay(150); i915_restore_vga(dev); } -- cgit v1.2.3-59-g8ed1b From 90eb77baaea35c591bd324b31e9eac032bd603c9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Aug 2010 14:41:23 +0100 Subject: drm/i915/suspend: s/IS_IRONLAKE/HAS_PCH_SPLIT/ For the shared paths on the next generation chipsets. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_suspend.c | 74 ++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 05acc26fabf7..2c6b98f2440e 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -34,7 +34,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) struct drm_i915_private *dev_priv = dev->dev_private; u32 dpll_reg; - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dpll_reg = (pipe == PIPE_A) ? PCH_DPLL_A: PCH_DPLL_B; } else { dpll_reg = (pipe == PIPE_A) ? DPLL_A: DPLL_B; @@ -53,7 +53,7 @@ static void i915_save_palette(struct drm_device *dev, enum pipe pipe) if (!i915_pipe_enabled(dev, pipe)) return; - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; if (pipe == PIPE_A) @@ -75,7 +75,7 @@ static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) if (!i915_pipe_enabled(dev, pipe)) return; - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; if (pipe == PIPE_A) @@ -239,7 +239,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); } @@ -247,7 +247,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) /* Pipe & plane A info */ dev_priv->savePIPEACONF = I915_READ(PIPEACONF); dev_priv->savePIPEASRC = I915_READ(PIPEASRC); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveFPA0 = I915_READ(PCH_FPA0); dev_priv->saveFPA1 = I915_READ(PCH_FPA1); dev_priv->saveDPLL_A = I915_READ(PCH_DPLL_A); @@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveFPA1 = I915_READ(FPA1); dev_priv->saveDPLL_A = I915_READ(DPLL_A); } - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); @@ -264,10 +264,10 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1); dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1); dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1); @@ -304,7 +304,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) /* Pipe & plane B info */ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveFPB0 = I915_READ(PCH_FPB0); dev_priv->saveFPB1 = I915_READ(PCH_FPB1); dev_priv->saveDPLL_B = I915_READ(PCH_DPLL_B); @@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveFPB1 = I915_READ(FPB1); dev_priv->saveDPLL_B = I915_READ(DPLL_B); } - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); @@ -321,10 +321,10 @@ static void i915_save_modeset_reg(struct drm_device *dev) dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1); dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1); dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1); @@ -369,7 +369,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dpll_a_reg = PCH_DPLL_A; dpll_b_reg = PCH_DPLL_B; fpa0_reg = PCH_FPA0; @@ -385,7 +385,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) fpb1_reg = FPB1; } - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL); I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL); } @@ -404,7 +404,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); POSTING_READ(dpll_a_reg); udelay(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); POSTING_READ(DPLL_A_MD); } @@ -417,10 +417,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1); I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1); I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1); @@ -473,7 +473,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); POSTING_READ(dpll_b_reg); udelay(150); - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); POSTING_READ(DPLL_B_MD); } @@ -486,10 +486,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); - if (!IS_IRONLAKE(dev)) + if (!HAS_PCH_SPLIT(dev)) I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1); I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1); I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1); @@ -554,14 +554,14 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveCURSIZE = I915_READ(CURSIZE); /* CRT state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveADPA = I915_READ(PCH_ADPA); } else { dev_priv->saveADPA = I915_READ(ADPA); } /* LVDS state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePP_CONTROL = I915_READ(PCH_PP_CONTROL); dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); @@ -579,10 +579,10 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveLVDS = I915_READ(LVDS); } - if (!IS_I830(dev) && !IS_845G(dev) && !IS_IRONLAKE(dev)) + if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); dev_priv->savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); dev_priv->savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); @@ -610,7 +610,7 @@ void i915_save_display(struct drm_device *dev) /* Only save FBC state on the platform that supports FBC */ if (I915_HAS_FBC(dev)) { - if (IS_IRONLAKE_M(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); } else if (IS_GM45(dev)) { dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); @@ -626,7 +626,7 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveVGA0 = I915_READ(VGA0); dev_priv->saveVGA1 = I915_READ(VGA1); dev_priv->saveVGA_PD = I915_READ(VGA_PD); - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) dev_priv->saveVGACNTRL = I915_READ(CPU_VGACNTRL); else dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); @@ -668,24 +668,24 @@ void i915_restore_display(struct drm_device *dev) I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); /* CRT state */ - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) I915_WRITE(PCH_ADPA, dev_priv->saveADPA); else I915_WRITE(ADPA, dev_priv->saveADPA); /* LVDS state */ - if (IS_I965G(dev) && !IS_IRONLAKE(dev)) + if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(PCH_LVDS, dev_priv->saveLVDS); } else if (IS_MOBILE(dev) && !IS_I830(dev)) I915_WRITE(LVDS, dev_priv->saveLVDS); - if (!IS_I830(dev) && !IS_845G(dev) && !IS_IRONLAKE(dev)) + if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL); I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2); I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL); @@ -716,7 +716,7 @@ void i915_restore_display(struct drm_device *dev) /* only restore FBC info on the platform that supports FBC*/ if (I915_HAS_FBC(dev)) { - if (IS_IRONLAKE_M(dev)) { + if (HAS_PCH_SPLIT(dev)) { ironlake_disable_fbc(dev); I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); } else if (IS_GM45(dev)) { @@ -731,7 +731,7 @@ void i915_restore_display(struct drm_device *dev) } } /* VGA state */ - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL); else I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); @@ -757,7 +757,7 @@ int i915_save_state(struct drm_device *dev) i915_save_display(dev); /* Interrupt state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { dev_priv->saveDEIER = I915_READ(DEIER); dev_priv->saveDEIMR = I915_READ(DEIMR); dev_priv->saveGTIER = I915_READ(GTIER); @@ -771,7 +771,7 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveIMR = I915_READ(IMR); } - if (IS_IRONLAKE_M(dev)) + if (HAS_PCH_SPLIT(dev)) ironlake_disable_drps(dev); /* Cache mode state */ @@ -829,7 +829,7 @@ int i915_restore_state(struct drm_device *dev) i915_restore_display(dev); /* Interrupt state */ - if (IS_IRONLAKE(dev)) { + if (HAS_PCH_SPLIT(dev)) { I915_WRITE(DEIER, dev_priv->saveDEIER); I915_WRITE(DEIMR, dev_priv->saveDEIMR); I915_WRITE(GTIER, dev_priv->saveGTIER); @@ -844,7 +844,7 @@ int i915_restore_state(struct drm_device *dev) /* Clock gating state */ intel_init_clock_gating(dev); - if (IS_IRONLAKE_M(dev)) + if (HAS_PCH_SPLIT(dev)) ironlake_enable_drps(dev); /* Cache mode state */ -- cgit v1.2.3-59-g8ed1b From 156dadc180a1bd3a25d644ee6c361afc465ccd0e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Aug 2010 10:52:34 +0100 Subject: drm/i915: Remove the conflicting BUG_ON() We now attempt to free "active" objects following a GPU hang as either the GPU will be reset or the hang is permenant. In either case, the GPU writes will not be flushed to main memory and it should be safe to return that memory back to the system. The BUG_ON(active) is thus overkill and can erroneously fire after a EIO. Signed-off-by: Chris Wilson Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_gem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b4b25e17d4e9..994e9f2d688b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1979,8 +1979,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj) * cause memory corruption through use-after-free. */ - BUG_ON(obj_priv->active); - /* release the fence reg _after_ flushing */ if (obj_priv->fence_reg != I915_FENCE_REG_NONE) i915_gem_clear_fence_reg(obj); -- cgit v1.2.3-59-g8ed1b From 877fdacf8291d7627f339885b5ae52c2f6061734 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 19 Aug 2010 09:46:13 +0800 Subject: agp/intel: set 40-bit dma mask on Sandybridge Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/char/agp/intel-agp.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index ddf5def1b0da..ab1903955ac0 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -825,7 +825,8 @@ static const struct intel_driver_description { static int __devinit intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge) { - int i; + int i, mask; + bridge->driver = NULL; for (i = 0; intel_agp_chipsets[i].name != NULL; i++) { @@ -845,14 +846,19 @@ static int __devinit intel_gmch_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); - if (bridge->driver->mask_memory == intel_i965_mask_memory) { - if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36))) - dev_err(&intel_private.pcidev->dev, - "set gfx device dma mask 36bit failed!\n"); - else - pci_set_consistent_dma_mask(intel_private.pcidev, - DMA_BIT_MASK(36)); - } + if (bridge->driver->mask_memory == intel_gen6_mask_memory) + mask = 40; + else if (bridge->driver->mask_memory == intel_i965_mask_memory) + mask = 36; + else + mask = 32; + + if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) + dev_err(&intel_private.pcidev->dev, + "set gfx device dma mask %d-bit failed!\n", mask); + else + pci_set_consistent_dma_mask(intel_private.pcidev, + DMA_BIT_MASK(mask)); return 1; } -- cgit v1.2.3-59-g8ed1b From 3fdef0205e69b80c4219f14b834cb85eb719039f Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 19 Aug 2010 09:46:15 +0800 Subject: drm/i915: fix render pipe control notify on sandybridge This one is missed in last pipe control fix for sandybridge, that really unmask interrupt bit for notify in render engine IMR. Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/gpu/drm/i915/i915_irq.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 69a36fc035dc..16861b800fee 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1381,12 +1381,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); (void) I915_READ(DEIER); - /* user interrupt should be enabled, but masked initial */ + /* Gen6 only needs render pipe_control now */ + if (IS_GEN6(dev)) + render_mask = GT_PIPE_NOTIFY; + dev_priv->gt_irq_mask_reg = ~render_mask; dev_priv->gt_irq_enable_reg = render_mask; I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + if (IS_GEN6(dev)) + I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT); I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); (void) I915_READ(GTIER); -- cgit v1.2.3-59-g8ed1b From 4fefe435626758b14e6c05d2a5f8d71a997c0ad6 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 19 Aug 2010 09:46:16 +0800 Subject: drm/i915,intel_agp: Add support for Sandybridge D0 Signed-off-by: Zhenyu Wang Signed-off-by: Eric Anholt --- drivers/char/agp/intel-agp.c | 2 ++ drivers/char/agp/intel-agp.h | 1 + drivers/gpu/drm/i915/i915_drv.c | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index ab1903955ac0..710af89b176d 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -819,6 +819,8 @@ static const struct intel_driver_description { "Sandybridge", NULL, &intel_gen6_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG, + "Sandybridge", NULL, &intel_gen6_driver }, { 0, 0, NULL, NULL, NULL } }; diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index c05e3e518268..08d47532e605 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -204,6 +204,7 @@ #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG 0x0126 /* cover 915 and 945 variants */ #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5044f653e8ea..00befce8fbb7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -181,6 +181,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info), INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info), INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info), + INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info), {0, 0, 0} }; -- cgit v1.2.3-59-g8ed1b From a68820db790351076039f936fa6317a2b3439e55 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 18 Aug 2010 01:18:43 -0500 Subject: arm: tegra: fix compilation of board-harmony.c The patch "ARM: Remove DISCONTIGMEM support" removed the node id from the meminfo struct and the PHYS_TO_NID macro, causing compilation errors: arch/arm/mach-tegra/board-harmony.c: In function 'tegra_harmony_fixup': arch/arm/mach-tegra/board-harmony.c:94: error: 'struct membank' has no member named 'node' arch/arm/mach-tegra/board-harmony.c:94: error: implicit declaration of function 'PHYS_TO_NID' arch/arm/mach-tegra/board-harmony.c:97: error: 'struct membank' has no member named 'node' Signed-off-by: Olof Johansson Signed-off-by: Colin Cross --- arch/arm/mach-tegra/board-harmony.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c index 05e78dd9b50c..9e305de56be9 100644 --- a/arch/arm/mach-tegra/board-harmony.c +++ b/arch/arm/mach-tegra/board-harmony.c @@ -91,10 +91,8 @@ static void __init tegra_harmony_fixup(struct machine_desc *desc, { mi->nr_banks = 2; mi->bank[0].start = PHYS_OFFSET; - mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET); mi->bank[0].size = 448 * SZ_1M; mi->bank[1].start = SZ_512M; - mi->bank[1].node = PHYS_TO_NID(SZ_512M); mi->bank[1].size = SZ_512M; } -- cgit v1.2.3-59-g8ed1b From 42537eff861baccf3912e16ac4fd15a10fda2136 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 18 Aug 2010 18:26:47 -0500 Subject: arm: tegra: VMALLOC_END should be unsigned long Silences following build warning: arch/arm/mm/init.c: In function 'mem_init': arch/arm/mm/init.c:644: warning: format '%08lx' expects type 'long unsigned int', but argument 12 has type 'unsigned int' Signed-off-by: Olof Johansson Signed-off-by: Colin Cross --- arch/arm/mach-tegra/include/mach/vmalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/include/mach/vmalloc.h b/arch/arm/mach-tegra/include/mach/vmalloc.h index 267a141730d9..fd6aa65b2dc6 100644 --- a/arch/arm/mach-tegra/include/mach/vmalloc.h +++ b/arch/arm/mach-tegra/include/mach/vmalloc.h @@ -23,6 +23,6 @@ #include -#define VMALLOC_END 0xFE000000 +#define VMALLOC_END 0xFE000000UL #endif -- cgit v1.2.3-59-g8ed1b From f3c60c5918f26ea16761ddc8b12d8401a3db626b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 11 Aug 2010 14:51:23 -0700 Subject: ceph: fix multiple mds session shutdown The use of a completion when waiting for session shutdown during umount is inappropriate, given the complexity of the condition. For multiple MDS's, this resulted in the umount thread spinning, often preventing the session close message from being processed in some cases. Switch to a waitqueue and defined a condition helper. This cleans things up nicely. Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 68 +++++++++++++++++++++++++++------------------------- fs/ceph/mds_client.h | 3 ++- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index a75ddbf9fe37..397a47b696ce 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2208,7 +2208,7 @@ static void handle_session(struct ceph_mds_session *session, pr_info("mds%d reconnect denied\n", session->s_mds); remove_session_caps(session); wake = 1; /* for good measure */ - complete_all(&mdsc->session_close_waiters); + wake_up_all(&mdsc->session_close_wq); kick_requests(mdsc, mds); break; @@ -2876,7 +2876,7 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client) return -ENOMEM; init_completion(&mdsc->safe_umount_waiters); - init_completion(&mdsc->session_close_waiters); + init_waitqueue_head(&mdsc->session_close_wq); INIT_LIST_HEAD(&mdsc->waiting_for_map); mdsc->sessions = NULL; mdsc->max_sessions = 0; @@ -3021,6 +3021,23 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) wait_event(mdsc->cap_flushing_wq, check_cap_flush(mdsc, want_flush)); } +/* + * true if all sessions are closed, or we force unmount + */ +bool done_closing_sessions(struct ceph_mds_client *mdsc) +{ + int i, n = 0; + + if (mdsc->client->mount_state == CEPH_MOUNT_SHUTDOWN) + return true; + + mutex_lock(&mdsc->mutex); + for (i = 0; i < mdsc->max_sessions; i++) + if (mdsc->sessions[i]) + n++; + mutex_unlock(&mdsc->mutex); + return n == 0; +} /* * called after sb is ro. @@ -3029,45 +3046,32 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) { struct ceph_mds_session *session; int i; - int n; struct ceph_client *client = mdsc->client; - unsigned long started, timeout = client->mount_args->mount_timeout * HZ; + unsigned long timeout = client->mount_args->mount_timeout * HZ; dout("close_sessions\n"); - mutex_lock(&mdsc->mutex); - /* close sessions */ - started = jiffies; - while (time_before(jiffies, started + timeout)) { - dout("closing sessions\n"); - n = 0; - for (i = 0; i < mdsc->max_sessions; i++) { - session = __ceph_lookup_mds_session(mdsc, i); - if (!session) - continue; - mutex_unlock(&mdsc->mutex); - mutex_lock(&session->s_mutex); - __close_session(mdsc, session); - mutex_unlock(&session->s_mutex); - ceph_put_mds_session(session); - mutex_lock(&mdsc->mutex); - n++; - } - if (n == 0) - break; - - if (client->mount_state == CEPH_MOUNT_SHUTDOWN) - break; - - dout("waiting for sessions to close\n"); + mutex_lock(&mdsc->mutex); + for (i = 0; i < mdsc->max_sessions; i++) { + session = __ceph_lookup_mds_session(mdsc, i); + if (!session) + continue; mutex_unlock(&mdsc->mutex); - wait_for_completion_timeout(&mdsc->session_close_waiters, - timeout); + mutex_lock(&session->s_mutex); + __close_session(mdsc, session); + mutex_unlock(&session->s_mutex); + ceph_put_mds_session(session); mutex_lock(&mdsc->mutex); } + mutex_unlock(&mdsc->mutex); + + dout("waiting for sessions to close\n"); + wait_event_timeout(mdsc->session_close_wq, done_closing_sessions(mdsc), + timeout); /* tear down remaining sessions */ + mutex_lock(&mdsc->mutex); for (i = 0; i < mdsc->max_sessions; i++) { if (mdsc->sessions[i]) { session = get_session(mdsc->sessions[i]); @@ -3080,9 +3084,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) mutex_lock(&mdsc->mutex); } } - WARN_ON(!list_empty(&mdsc->cap_delay_list)); - mutex_unlock(&mdsc->mutex); ceph_cleanup_empty_realms(mdsc); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index ab7e89f5e344..c98267ce6d2a 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -234,7 +234,8 @@ struct ceph_mds_client { struct mutex mutex; /* all nested structures */ struct ceph_mdsmap *mdsmap; - struct completion safe_umount_waiters, session_close_waiters; + struct completion safe_umount_waiters; + wait_queue_head_t session_close_wq; struct list_head waiting_for_map; struct ceph_mds_session **sessions; /* NULL for mds if no session */ -- cgit v1.2.3-59-g8ed1b From 082afec92d1052305af1195f591602f4d0f44277 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 22 Aug 2010 15:16:41 -0700 Subject: ceph: fix xattr cap writeback We should include the xattr metadata blob in the cap update message any time we are flushing dirty state, NOT just when we are also dropping the cap. This fixes async xattr writeback. Also, clean up the code slightly to avoid duplicating the bit test. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 7bf182b03973..0ac2703f3bdf 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1082,6 +1082,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, gid_t gid; struct ceph_mds_session *session; u64 xattr_version = 0; + struct ceph_buffer *xattr_blob = NULL; int delayed = 0; u64 flush_tid = 0; int i; @@ -1160,9 +1161,10 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, gid = inode->i_gid; mode = inode->i_mode; - if (dropping & CEPH_CAP_XATTR_EXCL) { + if (flushing & CEPH_CAP_XATTR_EXCL) { __ceph_build_xattrs_blob(ci); - xattr_version = ci->i_xattrs.version + 1; + xattr_blob = ci->i_xattrs.blob; + xattr_version = ci->i_xattrs.version; } spin_unlock(&inode->i_lock); @@ -1170,9 +1172,7 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, ret = send_cap_msg(session, ceph_vino(inode).ino, cap_id, op, keep, want, flushing, seq, flush_tid, issue_seq, mseq, size, max_size, &mtime, &atime, time_warp_seq, - uid, gid, mode, - xattr_version, - (flushing & CEPH_CAP_XATTR_EXCL) ? ci->i_xattrs.blob : NULL, + uid, gid, mode, xattr_version, xattr_blob, follows); if (ret < 0) { dout("error sending cap msg, must requeue %p\n", inode); -- cgit v1.2.3-59-g8ed1b From 4a625be47243e0e07dedd0a1a6b94c66c2ab93ba Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 22 Aug 2010 15:03:56 -0700 Subject: ceph: include dirty xattrs state in snapped caps When we snapshot dirty metadata that needs to be written back to the MDS, include dirty xattr metadata. Make the capsnap reference the encoded xattr blob so that it will be written back in the FLUSHSNAP op. Also fix the capsnap creation guard to include dirty auth or file bits, not just tests specific to dirty file data or file writes in progress (this fixes auth metadata writeback). Signed-off-by: Sage Weil --- fs/ceph/caps.c | 2 +- fs/ceph/snap.c | 23 ++++++++++++++++------- fs/ceph/super.h | 8 +++++--- fs/ceph/xattr.c | 1 + 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 0ac2703f3bdf..ba5bbf318fe1 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1282,7 +1282,7 @@ retry: &capsnap->mtime, &capsnap->atime, capsnap->time_warp_seq, capsnap->uid, capsnap->gid, capsnap->mode, - 0, NULL, + capsnap->xattr_version, capsnap->xattr_blob, capsnap->follows); next_follows = capsnap->follows + 1; diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index c0b26b6badba..2cb190c2bd99 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -435,7 +435,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) { struct inode *inode = &ci->vfs_inode; struct ceph_cap_snap *capsnap; - int used; + int used, dirty; capsnap = kzalloc(sizeof(*capsnap), GFP_NOFS); if (!capsnap) { @@ -445,6 +445,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) spin_lock(&inode->i_lock); used = __ceph_caps_used(ci); + dirty = __ceph_caps_dirty(ci); if (__ceph_have_pending_cap_snap(ci)) { /* there is no point in queuing multiple "pending" cap_snaps, as no new writes are allowed to start when pending, so any @@ -452,11 +453,13 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) cap_snap. lucky us. */ dout("queue_cap_snap %p already pending\n", inode); kfree(capsnap); - } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) { + } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR) || + (dirty & (CEPH_CAP_AUTH_EXCL|CEPH_CAP_XATTR_EXCL| + CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR))) { struct ceph_snap_context *snapc = ci->i_head_snapc; igrab(inode); - + atomic_set(&capsnap->nref, 1); capsnap->ci = ci; INIT_LIST_HEAD(&capsnap->ci_item); @@ -464,15 +467,21 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) capsnap->follows = snapc->seq - 1; capsnap->issued = __ceph_caps_issued(ci, NULL); - capsnap->dirty = __ceph_caps_dirty(ci); + capsnap->dirty = dirty; capsnap->mode = inode->i_mode; capsnap->uid = inode->i_uid; capsnap->gid = inode->i_gid; - /* fixme? */ - capsnap->xattr_blob = NULL; - capsnap->xattr_len = 0; + if (dirty & CEPH_CAP_XATTR_EXCL) { + __ceph_build_xattrs_blob(ci); + capsnap->xattr_blob = + ceph_buffer_get(ci->i_xattrs.blob); + capsnap->xattr_version = ci->i_xattrs.version; + } else { + capsnap->xattr_blob = NULL; + capsnap->xattr_version = 0; + } /* dirty page count moved from _head to this cap_snap; all subsequent writes page dirties occur _after_ this diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 2482d696f0de..b33929d8f287 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -216,8 +216,7 @@ struct ceph_cap_snap { uid_t uid; gid_t gid; - void *xattr_blob; - int xattr_len; + struct ceph_buffer *xattr_blob; u64 xattr_version; u64 size; @@ -229,8 +228,11 @@ struct ceph_cap_snap { static inline void ceph_put_cap_snap(struct ceph_cap_snap *capsnap) { - if (atomic_dec_and_test(&capsnap->nref)) + if (atomic_dec_and_test(&capsnap->nref)) { + if (capsnap->xattr_blob) + ceph_buffer_put(capsnap->xattr_blob); kfree(capsnap); + } } /* diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 097a2654c00f..9578af610b73 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -485,6 +485,7 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci) ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob; ci->i_xattrs.prealloc_blob = NULL; ci->i_xattrs.dirty = false; + ci->i_xattrs.version++; } } -- cgit v1.2.3-59-g8ed1b From ed326044489ed89c740c50a3df5dffc9c3b20b96 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 16 Aug 2010 13:37:31 -0700 Subject: ceph: queue cap snap writeback for realm children on snap update When a realm is updated, we need to queue writeback on inodes in that realm _and_ its children. Otherwise, if the inode gets cowed on the server, we can get a hang later due to out-of-sync cap/snap state. Signed-off-by: Sage Weil --- fs/ceph/snap.c | 60 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 2cb190c2bd99..6bdbf3ae7082 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -548,6 +548,41 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, return 1; /* caller may want to ceph_flush_snaps */ } +/* + * Queue cap_snaps for snap writeback for this realm and its children. + * Called under snap_rwsem, so realm topology won't change. + */ +static void queue_realm_cap_snaps(struct ceph_snap_realm *realm) +{ + struct ceph_inode_info *ci; + struct inode *lastinode = NULL; + struct ceph_snap_realm *child; + + dout("queue_realm_cap_snaps %p %llx inodes\n", realm, realm->ino); + + spin_lock(&realm->inodes_with_caps_lock); + list_for_each_entry(ci, &realm->inodes_with_caps, + i_snap_realm_item) { + struct inode *inode = igrab(&ci->vfs_inode); + if (!inode) + continue; + spin_unlock(&realm->inodes_with_caps_lock); + if (lastinode) + iput(lastinode); + lastinode = inode; + ceph_queue_cap_snap(ci); + spin_lock(&realm->inodes_with_caps_lock); + } + spin_unlock(&realm->inodes_with_caps_lock); + if (lastinode) + iput(lastinode); + + dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino); + list_for_each_entry(child, &realm->children, child_item) + queue_realm_cap_snaps(child); + + dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); +} /* * Parse and apply a snapblob "snap trace" from the MDS. This specifies @@ -598,29 +633,8 @@ more: * * ...unless it's a snap deletion! */ - if (!deletion) { - struct ceph_inode_info *ci; - struct inode *lastinode = NULL; - - spin_lock(&realm->inodes_with_caps_lock); - list_for_each_entry(ci, &realm->inodes_with_caps, - i_snap_realm_item) { - struct inode *inode = igrab(&ci->vfs_inode); - if (!inode) - continue; - spin_unlock(&realm->inodes_with_caps_lock); - if (lastinode) - iput(lastinode); - lastinode = inode; - ceph_queue_cap_snap(ci); - spin_lock(&realm->inodes_with_caps_lock); - } - spin_unlock(&realm->inodes_with_caps_lock); - if (lastinode) - iput(lastinode); - dout("update_snap_trace cap_snaps queued\n"); - } - + if (!deletion) + queue_realm_cap_snaps(realm); } else { dout("update_snap_trace %llx %p seq %lld unchanged\n", realm->ino, realm, realm->seq); -- cgit v1.2.3-59-g8ed1b From eb6bb1c5bdc6e455a9d16cb845cc65afc9b0a617 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 16 Aug 2010 09:21:27 -0700 Subject: ceph: direct requests in snapped namespace based on nonsnap parent When making a request in the virtual snapdir or a snapped portion of the namespace, we should choose the MDS based on the first nonsnap parent (and its caps). If that is not the best place, we will get forward hints to find the right MDS in the cluster. This fixes ESTALE errors when using the .snap directory and namespace with multiple MDSs. Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 397a47b696ce..8d1f11c7a5a2 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -560,6 +560,13 @@ static void __unregister_request(struct ceph_mds_client *mdsc, * * Called under mdsc->mutex. */ +struct dentry *get_nonsnap_parent(struct dentry *dentry) +{ + while (!IS_ROOT(dentry) && ceph_snap(dentry->d_inode) != CEPH_NOSNAP) + dentry = dentry->d_parent; + return dentry; +} + static int __choose_mds(struct ceph_mds_client *mdsc, struct ceph_mds_request *req) { @@ -590,14 +597,29 @@ static int __choose_mds(struct ceph_mds_client *mdsc, if (req->r_inode) { inode = req->r_inode; } else if (req->r_dentry) { - if (req->r_dentry->d_inode) { + struct inode *dir = req->r_dentry->d_parent->d_inode; + + if (dir->i_sb != mdsc->client->sb) { + /* not this fs! */ + inode = req->r_dentry->d_inode; + } else if (ceph_snap(dir) != CEPH_NOSNAP) { + /* direct snapped/virtual snapdir requests + * based on parent dir inode */ + struct dentry *dn = + get_nonsnap_parent(req->r_dentry->d_parent); + inode = dn->d_inode; + dout("__choose_mds using nonsnap parent %p\n", inode); + } else if (req->r_dentry->d_inode) { + /* dentry target */ inode = req->r_dentry->d_inode; } else { - inode = req->r_dentry->d_parent->d_inode; + /* dir + name */ + inode = dir; hash = req->r_dentry->d_name.hash; is_hash = true; } } + dout("__choose_mds %p is_hash=%d (%d) mode %d\n", inode, (int)is_hash, (int)hash, mode); if (!inode) -- cgit v1.2.3-59-g8ed1b From 679ceace848e9fd570678396ffe1ef034e00e82d Mon Sep 17 00:00:00 2001 From: Michael Rubin Date: Fri, 20 Aug 2010 02:31:26 -0700 Subject: mm: exporting account_page_dirty This allows code outside of the mm core to safely manipulate page state and not worry about the other accounting. Not using these routines means that some code will lose track of the accounting and we get bugs. This has happened once already. Signed-off-by: Michael Rubin Signed-off-by: Sage Weil --- fs/ceph/addr.c | 8 +------- mm/page-writeback.c | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 5598a0d02295..420d46974ec8 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -105,13 +105,7 @@ static int ceph_set_page_dirty(struct page *page) spin_lock_irq(&mapping->tree_lock); if (page->mapping) { /* Race with truncate? */ WARN_ON_ONCE(!PageUptodate(page)); - - if (mapping_cap_account_dirty(mapping)) { - __inc_zone_page_state(page, NR_FILE_DIRTY); - __inc_bdi_stat(mapping->backing_dev_info, - BDI_RECLAIMABLE); - task_io_account_write(PAGE_CACHE_SIZE); - } + account_page_dirtied(page, page->mapping); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 37498ef61548..849d0ccbe914 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1096,6 +1096,7 @@ void account_page_dirtied(struct page *page, struct address_space *mapping) task_io_account_write(PAGE_CACHE_SIZE); } } +EXPORT_SYMBOL(account_page_dirtied); /* * For address_spaces which do not use buffers. Just tag the page as dirty in -- cgit v1.2.3-59-g8ed1b From 4dfe947e74a1de3eb638cc36d51bf56d6609057b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 23 Aug 2010 08:27:47 +1000 Subject: drm/radeon: fix passing wrong type to gem object create. We are passing a ttm type when we want to pass true/false. Reported-by: Dr. David Alan Gilbert Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index dc1634bb0c11..11f4f30ded5d 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -118,7 +118,7 @@ static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, aligned_size = ALIGN(size, PAGE_SIZE); ret = radeon_gem_object_create(rdev, aligned_size, 0, RADEON_GEM_DOMAIN_VRAM, - false, ttm_bo_type_kernel, + false, true, &gobj); if (ret) { printk(KERN_ERR "failed to allocate framebuffer (%d)\n", -- cgit v1.2.3-59-g8ed1b From 4b80d954a7e54c13a5063af18d01719ad6a0daf3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 20 Aug 2010 12:47:54 -0400 Subject: drm/radeon/kms: fix sideport detection on newer rs880 boards The meaning of ucMemoryType changed on recent boards, however, ulBootUpSidePortClock should be set properly across all boards. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index b015915441ba..61141981880d 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1181,7 +1181,7 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev) return true; break; case 2: - if (igp_info->info_2.ucMemoryType & 0x0f) + if (igp_info->info_2.ulBootUpSidePortClock) return true; break; default: -- cgit v1.2.3-59-g8ed1b From 039ed2d9a24b3c4e272439b1551762fcb77c188a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 20 Aug 2010 11:57:19 -0400 Subject: drm/radeon/kms: try to detect tv vs monitor for underscan When enabling underscan for hdmi monitors, attempt to detect whether we are driving a TV or a monitor. The should hopefully prevent underscan from being enabled on monitors attached via hdmi that do not overscan the image. Only enable underscan if the mode is a common hdtv mode (480p, 720p, etc.). Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 5764f4d3b4f1..6dd434ad2429 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1094,6 +1094,18 @@ void radeon_modeset_fini(struct radeon_device *rdev) radeon_i2c_fini(rdev); } +static bool is_hdtv_mode(struct drm_display_mode *mode) +{ + /* try and guess if this is a tv or a monitor */ + if ((mode->vdisplay == 480 && mode->hdisplay == 720) || /* 480p */ + (mode->vdisplay == 576) || /* 576p */ + (mode->vdisplay == 720) || /* 720p */ + (mode->vdisplay == 1080)) /* 1080p */ + return true; + else + return false; +} + bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -1141,7 +1153,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, if (ASIC_IS_AVIVO(rdev) && ((radeon_encoder->underscan_type == UNDERSCAN_ON) || ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && - drm_detect_hdmi_monitor(radeon_connector->edid)))) { + drm_detect_hdmi_monitor(radeon_connector->edid) && + is_hdtv_mode(mode)))) { radeon_crtc->h_border = (mode->hdisplay >> 5) + 16; radeon_crtc->v_border = (mode->vdisplay >> 5) + 16; radeon_crtc->rmx_type = RMX_FULL; -- cgit v1.2.3-59-g8ed1b From 0537398b211b4f040564beec458e23571042d335 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 17 Aug 2010 00:35:45 -0400 Subject: drm/radeon/kms: fix typo in radeon_compute_pll_gain Looks like this got copied from the ddx wrong. Cc: Benjamin Herrenschmidt Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 989df519a1e4..305049afde15 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -272,7 +272,7 @@ static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, if (!ref_div) return 1; - vcoFreq = ((unsigned)ref_freq & fb_div) / ref_div; + vcoFreq = ((unsigned)ref_freq * fb_div) / ref_div; /* * This is horribly crude: the VCO frequency range is divided into -- cgit v1.2.3-59-g8ed1b From faa9560ae76ef50a3cbfb1a6afc0343fd8172374 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 18 Aug 2010 12:25:49 -0400 Subject: fanotify: do not dereference inode_mark when it is unset The fanotify code is supposed to get the group from the mark. It accidentally only used the inode_mark. If the vfsmount_mark was set but not the inode_mark it would deref the NULL inode_mark. Get the group from the correct place. Reported-by: Tvrtko Ursulin Signed-off-by: Eric Paris --- fs/notify/fsnotify.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 3970392b2722..f3e3b355ba7f 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -148,13 +148,14 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, const unsigned char *file_name, struct fsnotify_event **event) { - struct fsnotify_group *group = inode_mark->group; + struct fsnotify_group *group = NULL; __u32 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); __u32 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); - pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p" - " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell, - mnt, inode_mark, mask, data, data_is, cookie, *event); + if (unlikely(!inode_mark && !vfsmount_mark)) { + BUG(); + return 0; + } /* clear ignored on inode modification */ if (mask & FS_MODIFY) { @@ -168,18 +169,24 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, /* does the inode mark tell us to do something? */ if (inode_mark) { + group = inode_mark->group; inode_test_mask &= inode_mark->mask; inode_test_mask &= ~inode_mark->ignored_mask; } /* does the vfsmount_mark tell us to do something? */ if (vfsmount_mark) { + group = vfsmount_mark->group; vfsmount_test_mask &= vfsmount_mark->mask; vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; if (inode_mark) vfsmount_test_mask &= ~inode_mark->ignored_mask; } + pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p" + " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell, + mnt, inode_mark, mask, data, data_is, cookie, *event); + if (!inode_test_mask && !vfsmount_test_mask) return 0; -- cgit v1.2.3-59-g8ed1b From 5f3f259fa8f1d7969360acfad5307d03c2f53d63 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 18 Aug 2010 12:25:49 -0400 Subject: fsnotify: reset used_inode and used_vfsmount on each pass The fsnotify main loop has 2 booleans which tell if a particular mark was sent to the listeners or if it should be processed in the next pass. The problem is that the booleans were not reset on each traversal of the loop. So marks could get skipped even when they were not sent to the notifiers. Reported-by: Tvrtko Ursulin Signed-off-by: Eric Paris --- fs/notify/fsnotify.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index f3e3b355ba7f..59dc7a02bd0c 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -220,7 +220,7 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, struct fsnotify_event *event = NULL; struct vfsmount *mnt; int idx, ret = 0; - bool used_inode = false, used_vfsmount = false; + bool used_inode, used_vfsmount; /* global tests shouldn't care about events on child only the specific event */ __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); @@ -261,6 +261,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, } while (inode_node || vfsmount_node) { + used_inode = used_vfsmount = false; + if (inode_node) { inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), struct fsnotify_mark, i.i_list); -- cgit v1.2.3-59-g8ed1b From 88b2dbdbed551e4e21fdc8c56a15e198c52274e2 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 18 Aug 2010 12:25:50 -0400 Subject: fanotify: add MAINTAINERS entry add myself as the maintainer. Reported-by: Andy Gospodarek Signed-off-by: Eric Paris +S: Maintained +F: fs/notify/fanotify/ +F: include/linux/fanotify.h + FARSYNC SYNCHRONOUS DRIVER M: Kevin Curtis W: http://www.farsite.co.uk/ -- cgit v1.2.3-59-g8ed1b From 84e1ab4d875922c034db7f4f814ac445a20a14bd Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 18 Aug 2010 12:25:50 -0400 Subject: fsnotify: fix ignored mask handling between inode and vfsmount marks The interesting 2 list lockstep walking didn't quite work out if the inode marks only had ignores and the vfsmount list requested events. The code to shortcut list traversal would not run the inode list since it didn't have real event requests. This code forces inode list traversal when a vfsmount mark matches the event type. Maybe we could add an i_fsnotify_ignored_mask field to struct inode to get the shortcut back, but it doesn't seem worth it to grow struct inode again. I bet with the recent changes to lock the way we do now it would actually not be a major perf hit to just drop i_fsnotify_mark_mask altogether. But that is for another day. Signed-off-by: Eric Paris --- fs/notify/fsnotify.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 59dc7a02bd0c..6f2777ce87a1 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -149,8 +149,8 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, struct fsnotify_event **event) { struct fsnotify_group *group = NULL; - __u32 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); - __u32 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); + __u32 inode_test_mask = 0; + __u32 vfsmount_test_mask = 0; if (unlikely(!inode_mark && !vfsmount_mark)) { BUG(); @@ -170,12 +170,14 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, /* does the inode mark tell us to do something? */ if (inode_mark) { group = inode_mark->group; + inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); inode_test_mask &= inode_mark->mask; inode_test_mask &= ~inode_mark->ignored_mask; } /* does the vfsmount_mark tell us to do something? */ if (vfsmount_mark) { + vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); group = vfsmount_mark->group; vfsmount_test_mask &= vfsmount_mark->mask; vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; @@ -183,9 +185,12 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, vfsmount_test_mask &= ~inode_mark->ignored_mask; } - pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p" - " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell, - mnt, inode_mark, mask, data, data_is, cookie, *event); + pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x inode_mark=%p" + " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x" + " data=%p data_is=%d cookie=%d event=%p\n", + __func__, group, to_tell, mnt, mask, inode_mark, + inode_test_mask, vfsmount_mark, vfsmount_test_mask, data, + data_is, cookie, *event); if (!inode_test_mask && !vfsmount_test_mask) return 0; @@ -214,7 +219,7 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const unsigned char *file_name, u32 cookie) { - struct hlist_node *inode_node, *vfsmount_node; + struct hlist_node *inode_node = NULL, *vfsmount_node = NULL; struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; struct fsnotify_group *inode_group, *vfsmount_group; struct fsnotify_event *event = NULL; @@ -245,19 +250,13 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, (test_mask & to_tell->i_fsnotify_mask)) inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first, &fsnotify_mark_srcu); - else - inode_node = NULL; - if (mnt) { - if ((mask & FS_MODIFY) || - (test_mask & mnt->mnt_fsnotify_mask)) - vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first, - &fsnotify_mark_srcu); - else - vfsmount_node = NULL; - } else { - mnt = NULL; - vfsmount_node = NULL; + if (mnt && ((mask & FS_MODIFY) || + (test_mask & mnt->mnt_fsnotify_mask))) { + vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first, + &fsnotify_mark_srcu); + inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first, + &fsnotify_mark_srcu); } while (inode_node || vfsmount_node) { -- cgit v1.2.3-59-g8ed1b From 2eebf582c9b3106abb9c33f4fc0a347fb9391037 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 18 Aug 2010 12:25:50 -0400 Subject: fanotify: flush outstanding perm requests on group destroy When an fanotify listener is closing it may cause a deadlock between the listener and the original task doing an fs operation. If the original task is waiting for a permissions response it will be holding the srcu lock. The listener cannot clean up and exit until after that srcu lock is syncronized. Thus deadlock. The fix introduced here is to stop accepting new permissions events when a listener is shutting down and to grant permission for all outstanding events. Thus the original task will eventually release the srcu lock and the listener can complete shutdown. Reported-by: Andreas Gruenbacher Cc: Andreas Gruenbacher Signed-off-by: Eric Paris --- fs/notify/fanotify/fanotify_user.c | 27 +++++++++++++++++++++++++++ include/linux/fanotify.h | 7 ------- include/linux/fsnotify_backend.h | 1 + 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 032b837fcd11..b966b7230f47 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -195,6 +195,14 @@ static int prepare_for_access_response(struct fsnotify_group *group, re->fd = fd; mutex_lock(&group->fanotify_data.access_mutex); + + if (group->fanotify_data.bypass_perm) { + mutex_unlock(&group->fanotify_data.access_mutex); + kmem_cache_free(fanotify_response_event_cache, re); + event->response = FAN_ALLOW; + return 0; + } + list_add_tail(&re->list, &group->fanotify_data.access_list); mutex_unlock(&group->fanotify_data.access_mutex); @@ -364,9 +372,28 @@ static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t static int fanotify_release(struct inode *ignored, struct file *file) { struct fsnotify_group *group = file->private_data; + struct fanotify_response_event *re, *lre; pr_debug("%s: file=%p group=%p\n", __func__, file, group); +#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + mutex_lock(&group->fanotify_data.access_mutex); + + group->fanotify_data.bypass_perm = true; + + list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) { + pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group, + re, re->event); + + list_del_init(&re->list); + re->event->response = FAN_ALLOW; + + kmem_cache_free(fanotify_response_event_cache, re); + } + mutex_unlock(&group->fanotify_data.access_mutex); + + wake_up(&group->fanotify_data.access_waitq); +#endif /* matches the fanotify_init->fsnotify_alloc_group */ fsnotify_put_group(group); diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index f0949a57ca9d..985435622ecd 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -95,11 +95,4 @@ struct fanotify_response { (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \ (long)(meta)->event_len <= (long)(len)) -#ifdef __KERNEL__ - -struct fanotify_wait { - struct fsnotify_event *event; - __s32 fd; -}; -#endif /* __KERNEL__ */ #endif /* _LINUX_FANOTIFY_H */ diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index ed36fb57c426..e40190d16878 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -156,6 +156,7 @@ struct fsnotify_group { struct mutex access_mutex; struct list_head access_list; wait_queue_head_t access_waitq; + bool bypass_perm; /* protected by access_mutex */ #endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */ int f_flags; } fanotify_data; -- cgit v1.2.3-59-g8ed1b From ff8d6e983185ce19fa92bb836eb52b589957be65 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 20 Aug 2010 10:24:18 +0100 Subject: fanotify: drop duplicate pr_debug statement This reminded me... you have two pr_debugs in fanotify_should_send_event which output redundant information. Maybe you intended it like that so it is selectable how much log spam you want, or if not you may want to apply this patch. Signed-off-by: Tvrtko Ursulin Signed-off-by: Eric Paris --- fs/notify/fanotify/fanotify.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 756566fe8449..85366c78cc37 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -165,9 +165,6 @@ static bool fanotify_should_send_event(struct fsnotify_group *group, "mask=%x data=%p data_type=%d\n", __func__, group, to_tell, inode_mark, vfsmnt_mark, event_mask, data, data_type); - pr_debug("%s: group=%p vfsmount_mark=%p inode_mark=%p mask=%x\n", - __func__, group, vfsmnt_mark, inode_mark, event_mask); - /* sorry, fanotify only gives a damn about files and dirs */ if (!S_ISREG(to_tell->i_mode) && !S_ISDIR(to_tell->i_mode)) -- cgit v1.2.3-59-g8ed1b From b6dd08652e2b70e73661c4975ae46398066c06f8 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 23 Aug 2010 10:33:19 +1000 Subject: radix-tree: clear all tags in radix_tree_node_rcu_free Commit f446daaea9d4a420d16c606f755f3689dcb2d0ce ("mm: implement writeback livelock avoidance using page tagging") introduced a new radix tree tag, increasing the number of tags in each node from 2 to 3. It did not, however, fix up the code in radix_tree_node_rcu_free() that cleans up after radix_tree_shrink() and hence could leave stray tags set in the new tag array. The result is that the livelock avoidance code added in the the above commit would hit stale tags when doing tag based lookups, resulting in livelocks when trying to traverse the tree. Fix this problem in radix_tree_node_rcu_free() so it doesn't happen again in the future by using a loop to walk all the tags up to RADIX_TREE_MAX_TAGS to clear the stray tags radix_tree_shrink() leaves behind. Signed-off-by: Dave Chinner Acked-by: Nick Piggin Acked-by: Jan Kara --- lib/radix-tree.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index e907858498a6..1014171dd1c5 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -174,14 +174,16 @@ static void radix_tree_node_rcu_free(struct rcu_head *head) { struct radix_tree_node *node = container_of(head, struct radix_tree_node, rcu_head); + int i; /* * must only free zeroed nodes into the slab. radix_tree_shrink * can leave us with a non-NULL entry in the first slot, so clear * that here to make sure. */ - tag_clear(node, 0, 0); - tag_clear(node, 1, 0); + for (i = 0; i < RADIX_TREE_MAX_TAGS; i++) + tag_clear(node, i, 0); + node->slots[0] = NULL; node->count = 0; -- cgit v1.2.3-59-g8ed1b From 144dcfc01221e1a79fa47ca897df7d5e3ab298e6 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Mon, 23 Aug 2010 10:33:53 +1000 Subject: radix-tree: radix_tree_range_tag_if_tagged() can set incorrect tags Commit ebf8aa44beed48cd17893a83d92a4403e5f9d9e2 ("radix-tree: omplement function radix_tree_range_tag_if_tagged") does not safely set tags on on intermediate tree nodes. The code walks down the tree setting tags before it has fully resolved the path to the leaf under the assumption there will be a leaf slot with the tag set in the range it is searching. Unfortunately, this is not a valid assumption - we can abort after setting a tag on an intermediate node if we overrun the number of tags we are allowed to set in a batch, or stop scanning because we we have passed the last scan index before we reach a leaf slot with the tag we are searching for set. As a result, we can leave the function with tags set on intemediate nodes which can be tripped over later by tag-based lookups. The result of these stale tags is that lookup may end prematurely or livelock because the lookup cannot make progress. The fix for the problem involves reocrding the traversal path we take to the leaf nodes, and only propagating the tags back up the tree once the tag is set in the leaf node slot. We are already recording the path for efficient traversal, so there is no additional overhead to do the intermediately node tag setting in this manner. This fixes a radix tree lookup livelock triggered by the new writeback sync livelock avoidance code introduced in commit f446daaea9d4a420d16c606f755f3689dcb2d0ce ("mm: implement writeback livelock avoidance using page tagging"). Signed-off-by: Dave Chinner Acked-by: Jan Kara --- lib/radix-tree.c | 57 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 1014171dd1c5..e0ee8cb37e41 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -625,6 +625,13 @@ EXPORT_SYMBOL(radix_tree_tag_get); * also settag. The function stops either after tagging nr_to_tag items or * after reaching last_index. * + * The tags must be set from the leaf level only and propagated back up the + * path to the root. We must do this so that we resolve the full path before + * setting any tags on intermediate nodes. If we set tags as we descend, then + * we can get to the leaf node and find that the index that has the iftag + * set is outside the range we are scanning. This reults in dangling tags and + * can lead to problems with later tag operations (e.g. livelocks on lookups). + * * The function returns number of leaves where the tag was set and sets * *first_indexp to the first unscanned index. */ @@ -633,9 +640,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, unsigned long nr_to_tag, unsigned int iftag, unsigned int settag) { - unsigned int height = root->height, shift; - unsigned long tagged = 0, index = *first_indexp; - struct radix_tree_node *open_slots[height], *slot; + unsigned int height = root->height; + struct radix_tree_path path[height]; + struct radix_tree_path *pathp = path; + struct radix_tree_node *slot; + unsigned int shift; + unsigned long tagged = 0; + unsigned long index = *first_indexp; last_index = min(last_index, radix_tree_maxindex(height)); if (index > last_index) @@ -655,6 +666,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = radix_tree_indirect_to_ptr(root->rnode); + /* + * we fill the path from (root->height - 2) to 0, leaving the index at + * (root->height - 1) as a terminator. Zero the node in the terminator + * so that we can use this to end walk loops back up the path. + */ + path[height - 1].node = NULL; + for (;;) { int offset; @@ -663,17 +681,30 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, goto next; if (!tag_get(slot, iftag, offset)) goto next; + if (height > 1) { + /* Go down one level */ + height--; + shift -= RADIX_TREE_MAP_SHIFT; + path[height - 1].node = slot; + path[height - 1].offset = offset; + slot = slot->slots[offset]; + continue; + } + + /* tag the leaf */ + tagged++; tag_set(slot, settag, offset); - if (height == 1) { - tagged++; - goto next; + + /* walk back up the path tagging interior nodes */ + pathp = &path[0]; + while (pathp->node) { + /* stop if we find a node with the tag already set */ + if (tag_get(pathp->node, settag, pathp->offset)) + break; + tag_set(pathp->node, settag, pathp->offset); + pathp++; } - /* Go down one level */ - height--; - shift -= RADIX_TREE_MAP_SHIFT; - open_slots[height] = slot; - slot = slot->slots[offset]; - continue; + next: /* Go to next item at level determined by 'shift' */ index = ((index >> shift) + 1) << shift; @@ -687,7 +718,7 @@ next: * last_index is guaranteed to be in the tree, what * we do below cannot wander astray. */ - slot = open_slots[height]; + slot = path[height - 1].node; height++; shift += RADIX_TREE_MAP_SHIFT; } -- cgit v1.2.3-59-g8ed1b From 76be97c1fc945db08aae1f1b746012662d643e97 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 22 Aug 2010 17:43:29 -0700 Subject: Linux 2.6.36-rc2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f3bdff8c8d78..2c0299f18d71 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 36 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Sheep on Meth # *DOCUMENTATION* -- cgit v1.2.3-59-g8ed1b From c1eea3756a9b16d8def6cf194a6ee74eb65b7aef Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Sat, 21 Aug 2010 09:09:27 +0900 Subject: ARM: S5P: VMALLOC_END should be unsigned long Silences following build warning: arch/arm/mm/init.c: In function 'mem_init': arch/arm/mm/init.c:644: warning: format '%08lx' expects type 'long unsigned int', but argument 12 has type 'unsigned int' Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv210/include/mach/vmalloc.h | 2 +- arch/arm/mach-s5pv310/include/mach/vmalloc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s5pv210/include/mach/vmalloc.h b/arch/arm/mach-s5pv210/include/mach/vmalloc.h index 58f515e0747e..df9a28808323 100644 --- a/arch/arm/mach-s5pv210/include/mach/vmalloc.h +++ b/arch/arm/mach-s5pv210/include/mach/vmalloc.h @@ -17,6 +17,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H __FILE__ -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END (0xE0000000UL) #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-s5pv310/include/mach/vmalloc.h b/arch/arm/mach-s5pv310/include/mach/vmalloc.h index 3f565ebb7daa..256f221edf3a 100644 --- a/arch/arm/mach-s5pv310/include/mach/vmalloc.h +++ b/arch/arm/mach-s5pv310/include/mach/vmalloc.h @@ -17,6 +17,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H __FILE__ -#define VMALLOC_END (0xF0000000) +#define VMALLOC_END (0xF0000000UL) #endif /* __ASM_ARCH_VMALLOC_H */ -- cgit v1.2.3-59-g8ed1b From 09cd2b99c6cdd1e14e84c1febca2fb91e9f4e5ba Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Sun, 22 Aug 2010 17:25:05 +0000 Subject: header: fix broken headers for user space __packed is only defined in kernel space, so we should use __attribute__((packed)) for the code shared between kernel and user space. Two __attribute() annotations are replaced with __attribute__() too. Signed-off-by: Changli Gao Signed-off-by: David S. Miller --- include/linux/if_ether.h | 2 +- include/linux/if_fddi.h | 8 ++++---- include/linux/if_hippi.h | 8 ++++---- include/linux/if_pppox.h | 10 +++++----- include/linux/ipv6.h | 4 ++-- include/linux/nbd.h | 2 +- include/linux/ncp.h | 10 +++++----- include/linux/netfilter/xt_IDLETIMER.h | 2 +- include/linux/phonet.h | 4 ++-- include/linux/rfkill.h | 2 +- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index c831467774d0..bed7a4682b90 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -119,7 +119,7 @@ struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ __be16 h_proto; /* packet type ID field */ -} __packed; +} __attribute__((packed)); #ifdef __KERNEL__ #include diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h index 9947c39e62f6..e6dc11e7f9a5 100644 --- a/include/linux/if_fddi.h +++ b/include/linux/if_fddi.h @@ -67,7 +67,7 @@ struct fddi_8022_1_hdr { __u8 dsap; /* destination service access point */ __u8 ssap; /* source service access point */ __u8 ctrl; /* control byte #1 */ -} __packed; +} __attribute__((packed)); /* Define 802.2 Type 2 header */ struct fddi_8022_2_hdr { @@ -75,7 +75,7 @@ struct fddi_8022_2_hdr { __u8 ssap; /* source service access point */ __u8 ctrl_1; /* control byte #1 */ __u8 ctrl_2; /* control byte #2 */ -} __packed; +} __attribute__((packed)); /* Define 802.2 SNAP header */ #define FDDI_K_OUI_LEN 3 @@ -85,7 +85,7 @@ struct fddi_snap_hdr { __u8 ctrl; /* always 0x03 */ __u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */ __be16 ethertype; /* packet type ID field */ -} __packed; +} __attribute__((packed)); /* Define FDDI LLC frame header */ struct fddihdr { @@ -98,7 +98,7 @@ struct fddihdr { struct fddi_8022_2_hdr llc_8022_2; struct fddi_snap_hdr llc_snap; } hdr; -} __packed; +} __attribute__((packed)); #ifdef __KERNEL__ #include diff --git a/include/linux/if_hippi.h b/include/linux/if_hippi.h index 5fe5f307c6f5..cdc049f1829a 100644 --- a/include/linux/if_hippi.h +++ b/include/linux/if_hippi.h @@ -104,7 +104,7 @@ struct hippi_fp_hdr { __be32 fixed; #endif __be32 d2_size; -} __packed; +} __attribute__((packed)); struct hippi_le_hdr { #if defined (__BIG_ENDIAN_BITFIELD) @@ -129,7 +129,7 @@ struct hippi_le_hdr { __u8 daddr[HIPPI_ALEN]; __u16 locally_administered; __u8 saddr[HIPPI_ALEN]; -} __packed; +} __attribute__((packed)); #define HIPPI_OUI_LEN 3 /* @@ -142,12 +142,12 @@ struct hippi_snap_hdr { __u8 ctrl; /* always 0x03 */ __u8 oui[HIPPI_OUI_LEN]; /* organizational universal id (zero)*/ __be16 ethertype; /* packet type ID field */ -} __packed; +} __attribute__((packed)); struct hippi_hdr { struct hippi_fp_hdr fp; struct hippi_le_hdr le; struct hippi_snap_hdr snap; -} __packed; +} __attribute__((packed)); #endif /* _LINUX_IF_HIPPI_H */ diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h index 1925e0c3f162..27741e05446f 100644 --- a/include/linux/if_pppox.h +++ b/include/linux/if_pppox.h @@ -59,7 +59,7 @@ struct sockaddr_pppox { union{ struct pppoe_addr pppoe; }sa_addr; -} __packed; +} __attribute__((packed)); /* The use of the above union isn't viable because the size of this * struct must stay fixed over time -- applications use sizeof(struct @@ -70,7 +70,7 @@ struct sockaddr_pppol2tp { sa_family_t sa_family; /* address family, AF_PPPOX */ unsigned int sa_protocol; /* protocol identifier */ struct pppol2tp_addr pppol2tp; -} __packed; +} __attribute__((packed)); /* The L2TPv3 protocol changes tunnel and session ids from 16 to 32 * bits. So we need a different sockaddr structure. @@ -79,7 +79,7 @@ struct sockaddr_pppol2tpv3 { sa_family_t sa_family; /* address family, AF_PPPOX */ unsigned int sa_protocol; /* protocol identifier */ struct pppol2tpv3_addr pppol2tp; -} __packed; +} __attribute__((packed)); /********************************************************************* * @@ -101,7 +101,7 @@ struct pppoe_tag { __be16 tag_type; __be16 tag_len; char tag_data[0]; -} __attribute ((packed)); +} __attribute__ ((packed)); /* Tag identifiers */ #define PTT_EOL __cpu_to_be16(0x0000) @@ -129,7 +129,7 @@ struct pppoe_hdr { __be16 sid; __be16 length; struct pppoe_tag tag[0]; -} __packed; +} __attribute__((packed)); /* Length of entire PPPoE + PPP header */ #define PPPOE_SES_HLEN 8 diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index ab9e9e89e407..e62683ba88e6 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -58,7 +58,7 @@ struct ipv6_opt_hdr { /* * TLV encoded option data follows. */ -} __packed; /* required for some archs */ +} __attribute__((packed)); /* required for some archs */ #define ipv6_destopt_hdr ipv6_opt_hdr #define ipv6_hopopt_hdr ipv6_opt_hdr @@ -99,7 +99,7 @@ struct ipv6_destopt_hao { __u8 type; __u8 length; struct in6_addr addr; -} __packed; +} __attribute__((packed)); /* * IPv6 fixed header diff --git a/include/linux/nbd.h b/include/linux/nbd.h index bb58854a8061..d146ca10c0f5 100644 --- a/include/linux/nbd.h +++ b/include/linux/nbd.h @@ -88,7 +88,7 @@ struct nbd_request { char handle[8]; __be64 from; __be32 len; -} __packed; +} __attribute__((packed)); /* * This is the reply packet that nbd-server sends back to the client after diff --git a/include/linux/ncp.h b/include/linux/ncp.h index 3ace8370e61e..99f0adeeb3f3 100644 --- a/include/linux/ncp.h +++ b/include/linux/ncp.h @@ -27,7 +27,7 @@ struct ncp_request_header { __u8 conn_high; __u8 function; __u8 data[0]; -} __packed; +} __attribute__((packed)); #define NCP_REPLY (0x3333) #define NCP_WATCHDOG (0x3E3E) @@ -42,7 +42,7 @@ struct ncp_reply_header { __u8 completion_code; __u8 connection_state; __u8 data[0]; -} __packed; +} __attribute__((packed)); #define NCP_VOLNAME_LEN (16) #define NCP_NUMBER_OF_VOLUMES (256) @@ -158,7 +158,7 @@ struct nw_info_struct { #ifdef __KERNEL__ struct nw_nfs_info nfs; #endif -} __packed; +} __attribute__((packed)); /* modify mask - use with MODIFY_DOS_INFO structure */ #define DM_ATTRIBUTES (cpu_to_le32(0x02)) @@ -190,12 +190,12 @@ struct nw_modify_dos_info { __u16 inheritanceGrantMask; __u16 inheritanceRevokeMask; __u32 maximumSpace; -} __packed; +} __attribute__((packed)); struct nw_search_sequence { __u8 volNumber; __u32 dirBase; __u32 sequence; -} __packed; +} __attribute__((packed)); #endif /* _LINUX_NCP_H */ diff --git a/include/linux/netfilter/xt_IDLETIMER.h b/include/linux/netfilter/xt_IDLETIMER.h index 3e1aa1be942e..208ae9387331 100644 --- a/include/linux/netfilter/xt_IDLETIMER.h +++ b/include/linux/netfilter/xt_IDLETIMER.h @@ -39,7 +39,7 @@ struct idletimer_tg_info { char label[MAX_IDLETIMER_LABEL_SIZE]; /* for kernel module internal use only */ - struct idletimer_tg *timer __attribute((aligned(8))); + struct idletimer_tg *timer __attribute__((aligned(8))); }; #endif diff --git a/include/linux/phonet.h b/include/linux/phonet.h index 24426c3d6b5a..76edadf046d3 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h @@ -56,7 +56,7 @@ struct phonethdr { __be16 pn_length; __u8 pn_robj; __u8 pn_sobj; -} __packed; +} __attribute__((packed)); /* Common Phonet payload header */ struct phonetmsg { @@ -98,7 +98,7 @@ struct sockaddr_pn { __u8 spn_dev; __u8 spn_resource; __u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3]; -} __packed; +} __attribute__((packed)); /* Well known address */ #define PN_DEV_PC 0x10 diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 4f82326eb294..08c32e4f261a 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -81,7 +81,7 @@ struct rfkill_event { __u8 type; __u8 op; __u8 soft, hard; -} __packed; +} __attribute__((packed)); /* * We are planning to be backward and forward compatible with changes -- cgit v1.2.3-59-g8ed1b From 124514918b030d74f1f3e15483b7bf3b85268082 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sun, 22 Aug 2010 21:33:32 -0700 Subject: ceph: don't improperly set dir complete when holding EXCL cap If we hold the EXCL cap, we cannot trust the dir stats from the MDS (num files, subdirs) and must not incorrectly conclude that the directory is empty. If we do, we get can bad results from lookup (bad ENOENT) and bad readdir results. Signed-off-by: Sage Weil --- fs/ceph/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 5d893d31e399..3e6b52cb5ee8 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -677,6 +677,7 @@ static int fill_inode(struct inode *inode, if (ci->i_files == 0 && ci->i_subdirs == 0 && ceph_snap(inode) == CEPH_NOSNAP && (le32_to_cpu(info->cap.caps) & CEPH_CAP_FILE_SHARED) && + (issued & CEPH_CAP_FILE_EXCL) == 0 && (ci->i_ceph_flags & CEPH_I_COMPLETE) == 0) { dout(" marking %p complete (empty)\n", inode); ci->i_ceph_flags |= CEPH_I_COMPLETE; -- cgit v1.2.3-59-g8ed1b From 07a27e226d1ed210d2d4218bd0642b40f5405c6a Mon Sep 17 00:00:00 2001 From: Henry C Chang Date: Sun, 22 Aug 2010 21:34:27 -0700 Subject: ceph: fix osd request lru adjustment when sending request Fix argument order. We want to move the item to the end of the list, not change the position of the head. Signed-off-by: Henry C Chang Signed-off-by: Sage Weil --- fs/ceph/osd_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index bed6391e52c7..dfced1dacbcd 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c @@ -661,7 +661,7 @@ static int __send_request(struct ceph_osd_client *osdc, reqhead->reassert_version = req->r_reassert_version; req->r_stamp = jiffies; - list_move_tail(&osdc->req_lru, &req->r_req_lru_item); + list_move_tail(&req->r_req_lru_item, &osdc->req_lru); ceph_msg_get(req->r_request); /* send consumes a ref */ ceph_con_send(&req->r_osd->o_con, req->r_request); -- cgit v1.2.3-59-g8ed1b From 6a6d01d374d03bd2f90030200cb78567444addc4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 19 Aug 2010 07:07:23 +0000 Subject: isdn/avm: fix build when PCMCIA is not enabled Why wouldn't kconfig symbol ISDN_DRV_AVMB1_B1PCMCIA also depend on PCMCIA? Fix build for PCMCIA not enabled: ERROR: "b1_free_card" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1ctl_proc_fops" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_reset_ctr" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_load_firmware" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_send_message" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_release_appl" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_register_appl" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_getrevision" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_detect" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_interrupt" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! ERROR: "b1_alloc_card" [drivers/isdn/hardware/avm/b1pcmcia.ko] undefined! Signed-off-by: Randy Dunlap Cc: Carsten Paeth Cc: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/avm/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/isdn/hardware/avm/Kconfig index 5dbcbe3a54a6..b99b906ea9b1 100644 --- a/drivers/isdn/hardware/avm/Kconfig +++ b/drivers/isdn/hardware/avm/Kconfig @@ -36,12 +36,13 @@ config ISDN_DRV_AVMB1_T1ISA config ISDN_DRV_AVMB1_B1PCMCIA tristate "AVM B1/M1/M2 PCMCIA support" + depends on PCMCIA help Enable support for the PCMCIA version of the AVM B1 card. config ISDN_DRV_AVMB1_AVM_CS tristate "AVM B1/M1/M2 PCMCIA cs module" - depends on ISDN_DRV_AVMB1_B1PCMCIA && PCMCIA + depends on ISDN_DRV_AVMB1_B1PCMCIA help Enable the PCMCIA client driver for the AVM B1/M1/M2 PCMCIA cards. -- cgit v1.2.3-59-g8ed1b From 23b224d9d42a111ce451e4300304415a0ba5da75 Mon Sep 17 00:00:00 2001 From: Garnet MacPhee Date: Sat, 21 Aug 2010 14:37:34 -0600 Subject: ALSA: ice1712: Add support for Edirol DA-2496 This device is similar to the M-Audio Delta 1010LT in that it uses the AK4524VF ADC/DAC, but it does not use the CS8427 for SPDIF. The SPDIF appears to be set up correctly, but I am not able to test it as I do not have any devices that use it. This patch makes the ADC/DAC's and the hardware mixer visible to apps such as alsamixer and envy24control. Signed-off-by: Garnet MacPhee Signed-off-by: Takashi Iwai --- sound/pci/ice1712/delta.c | 10 ++++++++++ sound/pci/ice1712/delta.h | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index d216362626d0..712c1710f9a2 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) case ICE1712_SUBDEVICE_DELTA1010E: case ICE1712_SUBDEVICE_DELTA1010LT: case ICE1712_SUBDEVICE_MEDIASTATION: + case ICE1712_SUBDEVICE_EDIROLDA2496: ice->num_total_dacs = 8; ice->num_total_adcs = 8; break; @@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); break; case ICE1712_SUBDEVICE_DELTA1010LT: + case ICE1712_SUBDEVICE_EDIROLDA2496: err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); break; case ICE1712_SUBDEVICE_DELTA66: @@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) case ICE1712_SUBDEVICE_DELTA66: case ICE1712_SUBDEVICE_VX442: case ICE1712_SUBDEVICE_DELTA66E: + case ICE1712_SUBDEVICE_EDIROLDA2496: err = snd_ice1712_akm4xxx_build_controls(ice); if (err < 0) return err; @@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { .chip_init = snd_ice1712_delta_init, .build_controls = snd_ice1712_delta_add_controls, }, + { + .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496, + .name = "Edirol DA2496", + .model = "da2496", + .chip_init = snd_ice1712_delta_init, + .build_controls = snd_ice1712_delta_add_controls, + }, { } /* terminator */ }; diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index f7f14df81f26..1a0ac6cd6501 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h @@ -34,7 +34,8 @@ "{MidiMan M Audio,Delta 410},"\ "{MidiMan M Audio,Audiophile 24/96},"\ "{Digigram,VX442},"\ - "{Lionstracs,Mediastation}," + "{Lionstracs,Mediastation},"\ + "{Edirol,DA2496}," #define ICE1712_SUBDEVICE_DELTA1010 0x121430d6 #define ICE1712_SUBDEVICE_DELTA1010E 0xff1430d6 @@ -47,6 +48,7 @@ #define ICE1712_SUBDEVICE_DELTA1010LT 0x12143bd6 #define ICE1712_SUBDEVICE_VX442 0x12143cd6 #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100 +#define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010 /* entry point */ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[]; -- cgit v1.2.3-59-g8ed1b From 6f0ef6ea1d11ef242de584e345355b0de756fcb2 Mon Sep 17 00:00:00 2001 From: Jerone Young Date: Mon, 23 Aug 2010 08:34:36 +0200 Subject: ALSA: hda - Add support for Lenovo S10-3t This patch adds quirk for the Lenovo S10-3t so the headphone & microphone jacks will now work. Signed-off-by: Jerone Young Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c424952a734e..5cdb80edbd7f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3059,6 +3059,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), {} -- cgit v1.2.3-59-g8ed1b From 97e94c3a57c5999dde878449f17238ae98f74e42 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 13 Aug 2010 17:42:39 -0400 Subject: Blackfin: fix hweight breakage The recent commit to add constant optimization to hweight implicitly broke the Blackfin arch. Seems we were missed when all the other arches were fixed with renames. Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/bitops.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h index d5872cd967ab..3f7ef4d97791 100644 --- a/arch/blackfin/include/asm/bitops.h +++ b/arch/blackfin/include/asm/bitops.h @@ -22,7 +22,9 @@ #include #include +#include #include + #include #include #include @@ -115,7 +117,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) * of bits set) of a N-bit word */ -static inline unsigned int hweight32(unsigned int w) +static inline unsigned int __arch_hweight32(unsigned int w) { unsigned int res; @@ -125,19 +127,20 @@ static inline unsigned int hweight32(unsigned int w) return res; } -static inline unsigned int hweight64(__u64 w) +static inline unsigned int __arch_hweight64(__u64 w) { - return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w); + return __arch_hweight32((unsigned int)(w >> 32)) + + __arch_hweight32((unsigned int)w); } -static inline unsigned int hweight16(unsigned int w) +static inline unsigned int __arch_hweight16(unsigned int w) { - return hweight32(w & 0xffff); + return __arch_hweight32(w & 0xffff); } -static inline unsigned int hweight8(unsigned int w) +static inline unsigned int __arch_hweight8(unsigned int w) { - return hweight32(w & 0xff); + return __arch_hweight32(w & 0xff); } #endif /* _BLACKFIN_BITOPS_H */ -- cgit v1.2.3-59-g8ed1b From 4bdef3bd7e59a3cabb3dc02ccff9f056d3a06f99 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 11 Aug 2010 23:52:23 -0400 Subject: ADI/ASoC: add MAINTAINERS entries Signed-off-by: Mike Frysinger --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 433f35385756..a1df54b0af79 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -454,6 +454,17 @@ L: linux-rdma@vger.kernel.org S: Maintained F: drivers/infiniband/hw/amso1100/ +ANALOG DEVICES INC ASOC DRIVERS +L: uclinux-dist-devel@blackfin.uclinux.org +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +W: http://blackfin.uclinux.org/ +S: Supported +F: sound/soc/blackfin/* +F: sound/soc/codecs/ad1* +F: sound/soc/codecs/adau* +F: sound/soc/codecs/adav* +F: sound/soc/codecs/ssm* + AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg L: linuxppc-dev@lists.ozlabs.org -- cgit v1.2.3-59-g8ed1b From f3411b16c790e52b5abe174b33c7d213dbf5c259 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 18 Aug 2010 15:25:30 -0400 Subject: Blackfin: wire up new fanotify/prlimit64 syscalls Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/unistd.h | 5 ++++- arch/blackfin/mach-common/entry.S | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h index 22886cbdae7a..14fcd254b185 100644 --- a/arch/blackfin/include/asm/unistd.h +++ b/arch/blackfin/include/asm/unistd.h @@ -389,8 +389,11 @@ #define __NR_rt_tgsigqueueinfo 368 #define __NR_perf_event_open 369 #define __NR_recvmmsg 370 +#define __NR_fanotify_init 371 +#define __NR_fanotify_mark 372 +#define __NR_prlimit64 373 -#define __NR_syscall 371 +#define __NR_syscall 374 #define NR_syscalls __NR_syscall /* Old optional stuff no one actually uses */ diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index a5847f5d67c7..af1bffa21dc1 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -1628,6 +1628,9 @@ ENTRY(_sys_call_table) .long _sys_rt_tgsigqueueinfo .long _sys_perf_event_open .long _sys_recvmmsg /* 370 */ + .long _sys_fanotify_init + .long _sys_fanotify_mark + .long _sys_prlimit64 .rept NR_syscalls-(.-_sys_call_table)/4 .long _sys_ni_syscall -- cgit v1.2.3-59-g8ed1b From c6db67cda735d8ace5f19c3831240e1408679790 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 20 Aug 2010 11:49:15 +0200 Subject: watchdog: Don't throttle the watchdog Stephane reported that when the machine locks up, the regular ticks, which are responsible to resetting the throttle count, stop too. Hence the NMI watchdog can end up being throttled before it reports on the locked up state, and we end up being sad.. Cure this by having the watchdog overflow reset its own throttle count. Reported-by: Stephane Eranian Tested-by: Stephane Eranian Cc: Don Zickus Cc: Frederic Weisbecker Signed-off-by: Peter Zijlstra LKML-Reference: <1282215916.1926.4696.camel@laptop> Signed-off-by: Ingo Molnar --- kernel/watchdog.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 613bc1f04610..0d53c8e853b1 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -206,6 +206,9 @@ void watchdog_overflow_callback(struct perf_event *event, int nmi, struct perf_sample_data *data, struct pt_regs *regs) { + /* Ensure the watchdog never gets throttled */ + event->hw.interrupts = 0; + if (__get_cpu_var(watchdog_nmi_touch) == true) { __get_cpu_var(watchdog_nmi_touch) = false; return; -- cgit v1.2.3-59-g8ed1b From 9d0f4dcc5c4d1c5dd01172172684a45b5f49d740 Mon Sep 17 00:00:00 2001 From: Tim Chen Date: Wed, 18 Aug 2010 15:00:27 -0700 Subject: mutex: Improve the scalability of optimistic spinning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a scalability issue for current implementation of optimistic mutex spin in the kernel. It is found on a 8 node 64 core Nehalem-EX system (HT mode). The intention of the optimistic mutex spin is to busy wait and spin on a mutex if the owner of the mutex is running, in the hope that the mutex will be released soon and be acquired, without the thread trying to acquire mutex going to sleep. However, when we have a large number of threads, contending for the mutex, we could have the mutex grabbed by other thread, and then another ……, and we will keep spinning, wasting cpu cycles and adding to the contention. One possible fix is to quit spinning and put the current thread on wait-list if mutex lock switch to a new owner while we spin, indicating heavy contention (see the patch included). I did some testing on a 8 socket Nehalem-EX system with a total of 64 cores. Using Ingo's test-mutex program that creates/delete files with 256 threads (http://lkml.org/lkml/2006/1/8/50) , I see the following speed up after putting in the mutex spin fix: ./mutex-test V 256 10 Ops/sec 2.6.34 62864 With fix 197200 Repeating the test with Aim7 fserver workload, again there is a speed up with the fix: Jobs/min 2.6.34 91657 With fix 149325 To look at the impact on the distribution of mutex acquisition time, I collected the mutex acquisition time on Aim7 fserver workload with some instrumentation. The average acquisition time is reduced by 48% and number of contentions reduced by 32%. #contentions Time to acquire mutex (cycles) 2.6.34 72973 44765791 With fix 49210 23067129 The histogram of mutex acquisition time is listed below. The acquisition time is in 2^bin cycles. We see that without the fix, the acquisition time is mostly around 2^26 cycles. With the fix, we the distribution get spread out a lot more towards the lower cycles, starting from 2^13. However, there is an increase of the tail distribution with the fix at 2^28 and 2^29 cycles. It seems a small price to pay for the reduced average acquisition time and also getting the cpu to do useful work. Mutex acquisition time distribution (acq time = 2^bin cycles): 2.6.34 With Fix bin #occurrence % #occurrence % 11 2 0.00% 120 0.24% 12 10 0.01% 790 1.61% 13 14 0.02% 2058 4.18% 14 86 0.12% 3378 6.86% 15 393 0.54% 4831 9.82% 16 710 0.97% 4893 9.94% 17 815 1.12% 4667 9.48% 18 790 1.08% 5147 10.46% 19 580 0.80% 6250 12.70% 20 429 0.59% 6870 13.96% 21 311 0.43% 1809 3.68% 22 255 0.35% 2305 4.68% 23 317 0.44% 916 1.86% 24 610 0.84% 233 0.47% 25 3128 4.29% 95 0.19% 26 63902 87.69% 122 0.25% 27 619 0.85% 286 0.58% 28 0 0.00% 3536 7.19% 29 0 0.00% 903 1.83% 30 0 0.00% 0 0.00% I've done similar experiments with 2.6.35 kernel on smaller boxes as well. One is on a dual-socket Westmere box (12 cores total, with HT). Another experiment is on an old dual-socket Core 2 box (4 cores total, no HT) On the 12-core Westmere box, I see a 250% increase for Ingo's mutex-test program with my mutex patch but no significant difference in aim7's fserver workload. On the 4-core Core 2 box, I see the difference with the patch for both mutex-test and aim7 fserver are negligible. So far, it seems like the patch has not caused regression on smaller systems. Signed-off-by: Tim Chen Acked-by: Peter Zijlstra Cc: Linus Torvalds Cc: Andrew Morton Cc: Thomas Gleixner Cc: Frederic Weisbecker Cc: # .35.x LKML-Reference: <1282168827.9542.72.camel@schen9-DESK> Signed-off-by: Ingo Molnar --- kernel/sched.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 41541d79e3c8..09b574e7f4df 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3865,8 +3865,16 @@ int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner) /* * Owner changed, break to re-assess state. */ - if (lock->owner != owner) + if (lock->owner != owner) { + /* + * If the lock has switched to a different owner, + * we likely have heavy contention. Return 0 to quit + * optimistic spinning and not contend further: + */ + if (lock->owner) + return 0; break; + } /* * Is that owner really running on that cpu? -- cgit v1.2.3-59-g8ed1b From 96aa1b419d47286db446f292cf898bb1a8b27f24 Mon Sep 17 00:00:00 2001 From: Ciju Rajan K Date: Mon, 23 Aug 2010 10:56:30 +0200 Subject: blkio: Fix return code for mkdir calls If the cgroup hierarchy for blkio control groups is deeper than two levels, kernel should not allow the creation of further levels. mkdir system call does not except EINVAL as a return value. This patch replaces EINVAL with more appropriate EPERM Signed-off-by: Ciju Rajan K Reviewed-by: KAMEZAWA Hiroyuki Signed-off-by: Jens Axboe --- block/blk-cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index a6809645d212..2fef1ef931a0 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -966,7 +966,7 @@ blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup) /* Currently we do not support hierarchy deeper than two level (0,1) */ if (parent != cgroup->top_cgroup) - return ERR_PTR(-EINVAL); + return ERR_PTR(-EPERM); blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL); if (!blkcg) -- cgit v1.2.3-59-g8ed1b From 75230ff2751e88d594a13a70eae2c146f45e323b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Mon, 23 Aug 2010 11:02:17 +0200 Subject: cciss: disable doorbell reset on reset_devices The doorbell reset initially appears to work correctly, the controller resets, comes up, some i/o can even be done, but on at least some Smart Arrays in some servers, it eventually causes a subsequent controller lockup due to some kind of PCIe error, and kdump can end up leaving the root filesystem in an unbootable state. For this reason, until the problem is fixed, or at least isolated to certain hardware enough to be avoided, the doorbell reset should not be used at all. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 31064df1370a..ce1a75df5902 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4519,6 +4519,12 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev) misc_fw_support = readl(&cfgtable->misc_fw_support); use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; + /* The doorbell reset seems to cause lockups on some Smart + * Arrays (e.g. P410, P410i, maybe others). Until this is + * fixed or at least isolated, avoid the doorbell reset. + */ + use_doorbell = 0; + rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell); if (rc) goto unmap_cfgtable; -- cgit v1.2.3-59-g8ed1b From 06bd6ebffae36d3b105677598c48e8bd0a10b205 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 22 Aug 2010 23:19:42 +0900 Subject: workqueue: annotate lock context change Some of internal functions called within gcwq->lock context releases and regrabs the lock but were missing proper annotations. Add it. Signed-off-by: Namhyung Kim Signed-off-by: Tejun Heo --- kernel/workqueue.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 1001b6e3fcbd..7415f27a8aa7 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1485,6 +1485,8 @@ static void gcwq_mayday_timeout(unsigned long __gcwq) * otherwise. */ static bool maybe_create_worker(struct global_cwq *gcwq) +__releases(&gcwq->lock) +__acquires(&gcwq->lock) { if (!need_to_create_worker(gcwq)) return false; @@ -1722,6 +1724,8 @@ static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color) * spin_lock_irq(gcwq->lock) which is released and regrabbed. */ static void process_one_work(struct worker *worker, struct work_struct *work) +__releases(&gcwq->lock) +__acquires(&gcwq->lock) { struct cpu_workqueue_struct *cwq = get_work_cwq(work); struct global_cwq *gcwq = cwq->gcwq; @@ -3230,6 +3234,8 @@ static int __cpuinit trustee_thread(void *__gcwq) * multiple times. To be used by cpu_callback. */ static void __cpuinit wait_trustee_state(struct global_cwq *gcwq, int state) +__releases(&gcwq->lock) +__acquires(&gcwq->lock) { if (!(gcwq->trustee_state == state || gcwq->trustee_state == TRUSTEE_DONE)) { -- cgit v1.2.3-59-g8ed1b From 972fa1c5316d18c8297123e08e9b6930ca34f888 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 22 Aug 2010 23:19:43 +0900 Subject: workqueue: mark lock acquisition on worker_maybe_bind_and_lock() worker_maybe_bind_and_lock() actually grabs gcwq->lock but was missing proper annotation. Add it. So this patch will remove following sparse warnings: kernel/workqueue.c:1214:13: warning: context imbalance in 'worker_maybe_bind_and_lock' - wrong count at exit arch/x86/include/asm/irqflags.h:44:9: warning: context imbalance in 'worker_rebind_fn' - unexpected unlock kernel/workqueue.c:1991:17: warning: context imbalance in 'rescuer_thread' - unexpected unlock Signed-off-by: Namhyung Kim Signed-off-by: Tejun Heo --- kernel/workqueue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 7415f27a8aa7..cc3456f96c56 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1212,6 +1212,7 @@ static void worker_leave_idle(struct worker *worker) * bound), %false if offline. */ static bool worker_maybe_bind_and_lock(struct worker *worker) +__acquires(&gcwq->lock) { struct global_cwq *gcwq = worker->gcwq; struct task_struct *task = worker->task; -- cgit v1.2.3-59-g8ed1b From b6508c1618e7aab085f191efb41b7b019a94ea38 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Mon, 23 Aug 2010 12:23:33 +0200 Subject: cfq-iosched: Do not idle if slice_idle=0 Do not idle either on cfq queue or service tree if slice_idle=0. User does not want any queue or service tree idling. Currently even if slice_idle=0, we were waiting for request to finish before expiring the queue and that can lead to lower queue depths. Acked-by: Jeff Moyer Signed-off-by: Vivek Goyal Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index eb4086f7dfef..8830569542c4 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1839,6 +1839,9 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq) BUG_ON(!service_tree); BUG_ON(!service_tree->count); + if (!cfqd->cfq_slice_idle) + return false; + /* We never do for idle class queues. */ if (prio == IDLE_WORKLOAD) return false; @@ -1879,7 +1882,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) /* * idle is disabled, either manually or by past process history */ - if (!cfqd->cfq_slice_idle || !cfq_should_idle(cfqd, cfqq)) + if (!cfq_should_idle(cfqd, cfqq)) return; /* -- cgit v1.2.3-59-g8ed1b From 02b35081fc98f681411586d3acf9eaad8b8f6e07 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Mon, 23 Aug 2010 12:23:53 +0200 Subject: cfq-iosched: Do group share accounting in IOPS when slice_idle=0 o Implement another CFQ mode where we charge group in terms of number of requests dispatched instead of measuring the time. Measuring in terms of time is not possible when we are driving deeper queue depths and there are requests from multiple cfq queues in the request queue. o This mode currently gets activated if one sets slice_idle=0 and associated disk supports NCQ. Again the idea is that on an NCQ disk with idling disabled most of the queues will dispatch 1 or more requests and then cfq queue expiry happens and we don't have a way to measure time. So start providing fairness in terms of IOPS. o Currently IOPS mode works only with cfq group scheduling. CFQ is following different scheduling algorithms for queue and group scheduling. These IOPS stats are used only for group scheduling hence in non-croup mode nothing should change. o For CFQ group scheduling one can disable slice idling so that we don't idle on queue and drive deeper request queue depths (achieving better throughput), at the same time group idle is enabled so one should get service differentiation among groups. Signed-off-by: Vivek Goyal Acked-by: Jeff Moyer Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 8830569542c4..3fc6be110c1d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -378,6 +378,21 @@ CFQ_CFQQ_FNS(wait_busy); &cfqg->service_trees[i][j]: NULL) \ +static inline bool iops_mode(struct cfq_data *cfqd) +{ + /* + * If we are not idling on queues and it is a NCQ drive, parallel + * execution of requests is on and measuring time is not possible + * in most of the cases until and unless we drive shallower queue + * depths and that becomes a performance bottleneck. In such cases + * switch to start providing fairness in terms of number of IOs. + */ + if (!cfqd->cfq_slice_idle && cfqd->hw_tag) + return true; + else + return false; +} + static inline enum wl_prio_t cfqq_prio(struct cfq_queue *cfqq) { if (cfq_class_idle(cfqq)) @@ -906,7 +921,6 @@ static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq) slice_used = cfqq->allocated_slice; } - cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u", slice_used); return slice_used; } @@ -914,19 +928,21 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg, struct cfq_queue *cfqq) { struct cfq_rb_root *st = &cfqd->grp_service_tree; - unsigned int used_sl, charge_sl; + unsigned int used_sl, charge; int nr_sync = cfqg->nr_cfqq - cfqg_busy_async_queues(cfqd, cfqg) - cfqg->service_tree_idle.count; BUG_ON(nr_sync < 0); - used_sl = charge_sl = cfq_cfqq_slice_usage(cfqq); + used_sl = charge = cfq_cfqq_slice_usage(cfqq); - if (!cfq_cfqq_sync(cfqq) && !nr_sync) - charge_sl = cfqq->allocated_slice; + if (iops_mode(cfqd)) + charge = cfqq->slice_dispatch; + else if (!cfq_cfqq_sync(cfqq) && !nr_sync) + charge = cfqq->allocated_slice; /* Can't update vdisktime while group is on service tree */ cfq_rb_erase(&cfqg->rb_node, st); - cfqg->vdisktime += cfq_scale_slice(charge_sl, cfqg); + cfqg->vdisktime += cfq_scale_slice(charge, cfqg); __cfq_group_service_tree_add(st, cfqg); /* This group is being expired. Save the context */ @@ -940,6 +956,8 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg, cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime, st->min_vdisktime); + cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u disp=%u charge=%u iops=%u", + used_sl, cfqq->slice_dispatch, charge, iops_mode(cfqd)); cfq_blkiocg_update_timeslice_used(&cfqg->blkg, used_sl); cfq_blkiocg_set_start_empty_time(&cfqg->blkg); } -- cgit v1.2.3-59-g8ed1b From 80bdf0c78fff075dfa21576273c8b0c7db22bdfe Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Mon, 23 Aug 2010 12:24:26 +0200 Subject: cfq-iosched: Implement tunable group_idle o Implement a new tunable group_idle, which allows idling on the group instead of a cfq queue. Hence one can set slice_idle = 0 and not idle on the individual queues but idle on the group. This way on fast storage we can get fairness between groups at the same time overall throughput improves. Signed-off-by: Vivek Goyal Acked-by: Jeff Moyer Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 65 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3fc6be110c1d..85e48192754d 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -30,6 +30,7 @@ static const int cfq_slice_sync = HZ / 10; static int cfq_slice_async = HZ / 25; static const int cfq_slice_async_rq = 2; static int cfq_slice_idle = HZ / 125; +static int cfq_group_idle = HZ / 125; static const int cfq_target_latency = HZ * 3/10; /* 300 ms */ static const int cfq_hist_divisor = 4; @@ -198,6 +199,8 @@ struct cfq_group { struct hlist_node cfqd_node; atomic_t ref; #endif + /* number of requests that are on the dispatch list or inside driver */ + int dispatched; }; /* @@ -271,6 +274,7 @@ struct cfq_data { unsigned int cfq_slice[2]; unsigned int cfq_slice_async_rq; unsigned int cfq_slice_idle; + unsigned int cfq_group_idle; unsigned int cfq_latency; unsigned int cfq_group_isolation; @@ -1884,7 +1888,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) { struct cfq_queue *cfqq = cfqd->active_queue; struct cfq_io_context *cic; - unsigned long sl; + unsigned long sl, group_idle = 0; /* * SSD device without seek penalty, disable idling. But only do so @@ -1900,8 +1904,13 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) /* * idle is disabled, either manually or by past process history */ - if (!cfq_should_idle(cfqd, cfqq)) - return; + if (!cfq_should_idle(cfqd, cfqq)) { + /* no queue idling. Check for group idling */ + if (cfqd->cfq_group_idle) + group_idle = cfqd->cfq_group_idle; + else + return; + } /* * still active requests from this queue, don't idle @@ -1928,13 +1937,21 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) return; } + /* There are other queues in the group, don't do group idle */ + if (group_idle && cfqq->cfqg->nr_cfqq > 1) + return; + cfq_mark_cfqq_wait_request(cfqq); - sl = cfqd->cfq_slice_idle; + if (group_idle) + sl = cfqd->cfq_group_idle; + else + sl = cfqd->cfq_slice_idle; mod_timer(&cfqd->idle_slice_timer, jiffies + sl); cfq_blkiocg_update_set_idle_time_stats(&cfqq->cfqg->blkg); - cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu", sl); + cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu group_idle: %d", sl, + group_idle ? 1 : 0); } /* @@ -1950,6 +1967,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) cfqq->next_rq = cfq_find_next_rq(cfqd, cfqq, rq); cfq_remove_request(rq); cfqq->dispatched++; + (RQ_CFQG(rq))->dispatched++; elv_dispatch_sort(q, rq); cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++; @@ -2219,7 +2237,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) cfqq = NULL; goto keep_queue; } else - goto expire; + goto check_group_idle; } /* @@ -2247,8 +2265,23 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) * flight or is idling for a new request, allow either of these * conditions to happen (or time out) before selecting a new queue. */ - if (timer_pending(&cfqd->idle_slice_timer) || - (cfqq->dispatched && cfq_should_idle(cfqd, cfqq))) { + if (timer_pending(&cfqd->idle_slice_timer)) { + cfqq = NULL; + goto keep_queue; + } + + if (cfqq->dispatched && cfq_should_idle(cfqd, cfqq)) { + cfqq = NULL; + goto keep_queue; + } + + /* + * If group idle is enabled and there are requests dispatched from + * this group, wait for requests to complete. + */ +check_group_idle: + if (cfqd->cfq_group_idle && cfqq->cfqg->nr_cfqq == 1 + && cfqq->cfqg->dispatched) { cfqq = NULL; goto keep_queue; } @@ -3396,6 +3429,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) WARN_ON(!cfqq->dispatched); cfqd->rq_in_driver--; cfqq->dispatched--; + (RQ_CFQG(rq))->dispatched--; cfq_blkiocg_update_completion_stats(&cfqq->cfqg->blkg, rq_start_time_ns(rq), rq_io_start_time_ns(rq), rq_data_dir(rq), rq_is_sync(rq)); @@ -3425,7 +3459,10 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) * the queue. */ if (cfq_should_wait_busy(cfqd, cfqq)) { - cfqq->slice_end = jiffies + cfqd->cfq_slice_idle; + unsigned long extend_sl = cfqd->cfq_slice_idle; + if (!cfqd->cfq_slice_idle) + extend_sl = cfqd->cfq_group_idle; + cfqq->slice_end = jiffies + extend_sl; cfq_mark_cfqq_wait_busy(cfqq); cfq_log_cfqq(cfqd, cfqq, "will busy wait"); } @@ -3871,6 +3908,7 @@ static void *cfq_init_queue(struct request_queue *q) cfqd->cfq_slice[1] = cfq_slice_sync; cfqd->cfq_slice_async_rq = cfq_slice_async_rq; cfqd->cfq_slice_idle = cfq_slice_idle; + cfqd->cfq_group_idle = cfq_group_idle; cfqd->cfq_latency = 1; cfqd->cfq_group_isolation = 0; cfqd->hw_tag = -1; @@ -3943,6 +3981,7 @@ SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1); SHOW_FUNCTION(cfq_back_seek_max_show, cfqd->cfq_back_max, 0); SHOW_FUNCTION(cfq_back_seek_penalty_show, cfqd->cfq_back_penalty, 0); SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1); +SHOW_FUNCTION(cfq_group_idle_show, cfqd->cfq_group_idle, 1); SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1); SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1); SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0); @@ -3975,6 +4014,7 @@ STORE_FUNCTION(cfq_back_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0); STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0); STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1); +STORE_FUNCTION(cfq_group_idle_store, &cfqd->cfq_group_idle, 0, UINT_MAX, 1); STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1); STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1); STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, @@ -3996,6 +4036,7 @@ static struct elv_fs_entry cfq_attrs[] = { CFQ_ATTR(slice_async), CFQ_ATTR(slice_async_rq), CFQ_ATTR(slice_idle), + CFQ_ATTR(group_idle), CFQ_ATTR(low_latency), CFQ_ATTR(group_isolation), __ATTR_NULL @@ -4049,6 +4090,12 @@ static int __init cfq_init(void) if (!cfq_slice_idle) cfq_slice_idle = 1; +#ifdef CONFIG_CFQ_GROUP_IOSCHED + if (!cfq_group_idle) + cfq_group_idle = 1; +#else + cfq_group_idle = 0; +#endif if (cfq_slab_setup()) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From c4e7893ebc3a5c507b53f59b9de448db20849944 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Mon, 23 Aug 2010 12:25:03 +0200 Subject: cfq-iosched: blktrace print per slice sector stats o Divyesh had gotten rid of this code in the past. I want to re-introduce it back as it helps me a lot during debugging. Reviewed-by: Jeff Moyer Reviewed-by: Divyesh Shah Signed-off-by: Vivek Goyal Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 85e48192754d..f65c6f01c475 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -148,6 +148,8 @@ struct cfq_queue { struct cfq_queue *new_cfqq; struct cfq_group *cfqg; struct cfq_group *orig_cfqg; + /* Number of sectors dispatched from queue in single dispatch round */ + unsigned long nr_sectors; }; /* @@ -960,8 +962,9 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg, cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime, st->min_vdisktime); - cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u disp=%u charge=%u iops=%u", - used_sl, cfqq->slice_dispatch, charge, iops_mode(cfqd)); + cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u disp=%u charge=%u iops=%u" + " sect=%u", used_sl, cfqq->slice_dispatch, charge, + iops_mode(cfqd), cfqq->nr_sectors); cfq_blkiocg_update_timeslice_used(&cfqg->blkg, used_sl); cfq_blkiocg_set_start_empty_time(&cfqg->blkg); } @@ -1609,6 +1612,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd, cfqq->allocated_slice = 0; cfqq->slice_end = 0; cfqq->slice_dispatch = 0; + cfqq->nr_sectors = 0; cfq_clear_cfqq_wait_request(cfqq); cfq_clear_cfqq_must_dispatch(cfqq); @@ -1971,6 +1975,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) elv_dispatch_sort(q, rq); cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++; + cfqq->nr_sectors += blk_rq_sectors(rq); cfq_blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq), rq_data_dir(rq), rq_is_sync(rq)); } -- cgit v1.2.3-59-g8ed1b From 6d6ac1c1a3d4f95953aa3b085e8f16692d3a7179 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Mon, 23 Aug 2010 12:25:29 +0200 Subject: cfq-iosched: Documentation help for new tunables Some documentation to provide help with tunables. Signed-off-by: Vivek Goyal Acked-by: Jeff Moyer Signed-off-by: Jens Axboe --- Documentation/block/cfq-iosched.txt | 45 ++++++++++++++++++++++++++++++ Documentation/cgroups/blkio-controller.txt | 28 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 Documentation/block/cfq-iosched.txt diff --git a/Documentation/block/cfq-iosched.txt b/Documentation/block/cfq-iosched.txt new file mode 100644 index 000000000000..e578feed6d81 --- /dev/null +++ b/Documentation/block/cfq-iosched.txt @@ -0,0 +1,45 @@ +CFQ ioscheduler tunables +======================== + +slice_idle +---------- +This specifies how long CFQ should idle for next request on certain cfq queues +(for sequential workloads) and service trees (for random workloads) before +queue is expired and CFQ selects next queue to dispatch from. + +By default slice_idle is a non-zero value. That means by default we idle on +queues/service trees. This can be very helpful on highly seeky media like +single spindle SATA/SAS disks where we can cut down on overall number of +seeks and see improved throughput. + +Setting slice_idle to 0 will remove all the idling on queues/service tree +level and one should see an overall improved throughput on faster storage +devices like multiple SATA/SAS disks in hardware RAID configuration. The down +side is that isolation provided from WRITES also goes down and notion of +IO priority becomes weaker. + +So depending on storage and workload, it might be useful to set slice_idle=0. +In general I think for SATA/SAS disks and software RAID of SATA/SAS disks +keeping slice_idle enabled should be useful. For any configurations where +there are multiple spindles behind single LUN (Host based hardware RAID +controller or for storage arrays), setting slice_idle=0 might end up in better +throughput and acceptable latencies. + +CFQ IOPS Mode for group scheduling +=================================== +Basic CFQ design is to provide priority based time slices. Higher priority +process gets bigger time slice and lower priority process gets smaller time +slice. Measuring time becomes harder if storage is fast and supports NCQ and +it would be better to dispatch multiple requests from multiple cfq queues in +request queue at a time. In such scenario, it is not possible to measure time +consumed by single queue accurately. + +What is possible though is to measure number of requests dispatched from a +single queue and also allow dispatch from multiple cfq queue at the same time. +This effectively becomes the fairness in terms of IOPS (IO operations per +second). + +If one sets slice_idle=0 and if storage supports NCQ, CFQ internally switches +to IOPS mode and starts providing fairness in terms of number of requests +dispatched. Note that this mode switching takes effect only for group +scheduling. For non-cgroup users nothing should change. diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt index 48e0b21b0059..6919d62591d9 100644 --- a/Documentation/cgroups/blkio-controller.txt +++ b/Documentation/cgroups/blkio-controller.txt @@ -217,6 +217,7 @@ Details of cgroup files CFQ sysfs tunable ================= /sys/block//queue/iosched/group_isolation +----------------------------------------------- If group_isolation=1, it provides stronger isolation between groups at the expense of throughput. By default group_isolation is 0. In general that @@ -243,6 +244,33 @@ By default one should run with group_isolation=0. If that is not sufficient and one wants stronger isolation between groups, then set group_isolation=1 but this will come at cost of reduced throughput. +/sys/block//queue/iosched/slice_idle +------------------------------------------ +On a faster hardware CFQ can be slow, especially with sequential workload. +This happens because CFQ idles on a single queue and single queue might not +drive deeper request queue depths to keep the storage busy. In such scenarios +one can try setting slice_idle=0 and that would switch CFQ to IOPS +(IO operations per second) mode on NCQ supporting hardware. + +That means CFQ will not idle between cfq queues of a cfq group and hence be +able to driver higher queue depth and achieve better throughput. That also +means that cfq provides fairness among groups in terms of IOPS and not in +terms of disk time. + +/sys/block//queue/iosched/group_idle +------------------------------------------ +If one disables idling on individual cfq queues and cfq service trees by +setting slice_idle=0, group_idle kicks in. That means CFQ will still idle +on the group in an attempt to provide fairness among groups. + +By default group_idle is same as slice_idle and does not do anything if +slice_idle is enabled. + +One can experience an overall throughput drop if you have created multiple +groups and put applications in that group which are not driving enough +IO to keep disk busy. In that case set group_idle=0, and CFQ will not idle +on individual groups and throughput should improve. + What works ========== - Currently only sync IO queues are support. All the buffered writes are -- cgit v1.2.3-59-g8ed1b From 4ee69851cd4880f574d22f5ce08bec35b01c94e3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 23 Aug 2010 12:28:15 +0200 Subject: cciss: handle allocation failure If kmalloc() fails then cleanup and return failure (-1). Signed-off-by: Dan Carpenter Acked-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index ce1a75df5902..7191c16954d2 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4718,6 +4718,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, h->scatter_list = kmalloc(h->max_commands * sizeof(struct scatterlist *), GFP_KERNEL); + if (!h->scatter_list) + goto clean4; + for (k = 0; k < h->nr_cmds; k++) { h->scatter_list[k] = kmalloc(sizeof(struct scatterlist) * h->maxsgentries, -- cgit v1.2.3-59-g8ed1b From c87ffbb812cf6150097a5095b031f4013a8f78a5 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Mon, 23 Aug 2010 12:30:29 +0200 Subject: block: put dev->kobj in blk_register_queue fail path kernel needs to kobject_put on dev->kobj if elv_register_queue fails. Signed-off-by: Xiaotian Feng Cc: "Martin K. Petersen" Cc: Stephen Hemminger Cc: Nikanth Karthikesan Cc: David Teigland Signed-off-by: Jens Axboe --- block/blk-sysfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 001ab18078f5..0749b89c6885 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -511,6 +511,7 @@ int blk_register_queue(struct gendisk *disk) kobject_uevent(&q->kobj, KOBJ_REMOVE); kobject_del(&q->kobj); blk_trace_remove_sysfs(disk_to_dev(disk)); + kobject_put(&dev->kobj); return ret; } -- cgit v1.2.3-59-g8ed1b From 5e00d1b5b4c10fb839afd5ce61db8e24339454b0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 12 Aug 2010 14:31:06 +0200 Subject: BLOCK: fix bio.bi_rw handling Return of the bi_rw tests is no longer bool after commit 74450be1. But results of such tests are stored in bools. This doesn't fit in there for some compilers (gcc 4.5 here), so either use !! magic to get real bools or use ulong where the result is assigned somewhere. Signed-off-by: Jiri Slaby Cc: Christoph Hellwig Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- block/blk-core.c | 6 +++--- drivers/block/loop.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index ee1a1e7e63cc..32a1c123dfb3 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1198,9 +1198,9 @@ static int __make_request(struct request_queue *q, struct bio *bio) int el_ret; unsigned int bytes = bio->bi_size; const unsigned short prio = bio_prio(bio); - const bool sync = (bio->bi_rw & REQ_SYNC); - const bool unplug = (bio->bi_rw & REQ_UNPLUG); - const unsigned int ff = bio->bi_rw & REQ_FAILFAST_MASK; + const bool sync = !!(bio->bi_rw & REQ_SYNC); + const bool unplug = !!(bio->bi_rw & REQ_UNPLUG); + const unsigned long ff = bio->bi_rw & REQ_FAILFAST_MASK; int rw_flags; if ((bio->bi_rw & REQ_HARDBARRIER) && diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f3c636d23718..91797bbbe702 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -477,7 +477,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset; if (bio_rw(bio) == WRITE) { - bool barrier = (bio->bi_rw & REQ_HARDBARRIER); + bool barrier = !!(bio->bi_rw & REQ_HARDBARRIER); struct file *file = lo->lo_backing_file; if (barrier) { -- cgit v1.2.3-59-g8ed1b From f95d76ab82c381ce2221fbe75f331ff1478732db Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 23 Aug 2010 12:39:29 +0200 Subject: ipheth: add support for iPhone 4 This adds support for the iPhone 4 to the ipheth driver. Acked-by: Diego Giagio Signed-off-by: Jens Axboe --- drivers/net/usb/ipheth.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 08e7b6abacdd..8ed30fa35d0a 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -58,6 +58,7 @@ #define USB_PRODUCT_IPHONE 0x1290 #define USB_PRODUCT_IPHONE_3G 0x1292 #define USB_PRODUCT_IPHONE_3GS 0x1294 +#define USB_PRODUCT_IPHONE_4 0x1297 #define IPHETH_USBINTF_CLASS 255 #define IPHETH_USBINTF_SUBCLASS 253 @@ -92,6 +93,10 @@ static struct usb_device_id ipheth_table[] = { USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_3GS, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, { } }; MODULE_DEVICE_TABLE(usb, ipheth_table); -- cgit v1.2.3-59-g8ed1b From c93a4dfb31f2c023da3ad1238c352452f2cc0e05 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 23 Aug 2010 11:59:28 +0100 Subject: xen: pvhvm: allow user to request no emulated device unplug this allows the user to disable pvhvm and revert to emulated devices in case of a system misconfiguration (e.g. initramfs with only emulated drivers in it). Signed-off-by: Ian Campbell Acked-by: Jeremy Fitzhardinge Acked-by: Stefano Stabellini --- Documentation/kernel-parameters.txt | 1 + arch/x86/xen/platform-pci-unplug.c | 5 +++++ include/xen/platform_pci.h | 1 + 3 files changed, 7 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 2c85c0692b01..8bbe83b9d0b2 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2631,6 +2631,7 @@ and is between 256 and 4096 characters. It is defined in the file all -- unplug all emulated devices (NICs and IDE disks) ignore -- continue loading the Xen platform PCI driver even if the version check failed + never -- do not unplug even if version check succeeds xirc2ps_cs= [NET,PCMCIA] Format: diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index 554c002a1e1a..070dfa0654bd 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c @@ -72,6 +72,9 @@ void __init xen_unplug_emulated_devices(void) { int r; + /* user explicitly requested no unplug */ + if (xen_emul_unplug & XEN_UNPLUG_NEVER) + return; /* check the version of the xen platform PCI device */ r = check_platform_magic(); /* If the version matches enable the Xen platform PCI driver. @@ -127,6 +130,8 @@ static int __init parse_xen_emul_unplug(char *arg) xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; else if (!strncmp(p, "ignore", l)) xen_emul_unplug |= XEN_UNPLUG_IGNORE; + else if (!strncmp(p, "never", l)) + xen_emul_unplug |= XEN_UNPLUG_NEVER; else printk(KERN_WARNING "unrecognised option '%s' " "in parameter 'xen_emul_unplug'\n", p); diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h index ce9d671c636c..123b7752fa6a 100644 --- a/include/xen/platform_pci.h +++ b/include/xen/platform_pci.h @@ -21,6 +21,7 @@ #define XEN_UNPLUG_AUX_IDE_DISKS 4 #define XEN_UNPLUG_ALL 7 #define XEN_UNPLUG_IGNORE 8 +#define XEN_UNPLUG_NEVER 16 static inline int xen_must_unplug_nics(void) { #if (defined(CONFIG_XEN_NETDEV_FRONTEND) || \ -- cgit v1.2.3-59-g8ed1b From 1dc7ce99b091a11cce0f34456c1ffcb928f17edd Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 23 Aug 2010 11:59:29 +0100 Subject: xen: pvhvm: rename xen_emul_unplug=ignore to =unnnecessary It is not immediately clear what this option causes to become ignored. The actual meaning is that it is not necessary to unplug the emulated devices to safely use the PV ones, even if the platform does not support the unplug protocol. (pressumably the user will only add this option if they have ensured that their domain configuration is safe). I think xen_emul_unplug=unnecessary better captures this. Signed-off-by: Ian Campbell Acked-by: Jeremy Fitzhardinge Acked-by: Stefano Stabellini --- Documentation/kernel-parameters.txt | 5 +++-- arch/x86/xen/platform-pci-unplug.c | 13 +++++++------ drivers/block/xen-blkfront.c | 2 +- include/xen/platform_pci.h | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8bbe83b9d0b2..f084af0cb8e0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2629,8 +2629,9 @@ and is between 256 and 4096 characters. It is defined in the file aux-ide-disks -- unplug non-primary-master IDE devices nics -- unplug network devices all -- unplug all emulated devices (NICs and IDE disks) - ignore -- continue loading the Xen platform PCI driver even - if the version check failed + unnecessary -- unplugging emulated devices is + unnecessary even if the host did not respond to + the unplug protocol never -- do not unplug even if version check succeeds xirc2ps_cs= [NET,PCMCIA] diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c index 070dfa0654bd..0f456386cce5 100644 --- a/arch/x86/xen/platform-pci-unplug.c +++ b/arch/x86/xen/platform-pci-unplug.c @@ -78,10 +78,11 @@ void __init xen_unplug_emulated_devices(void) /* check the version of the xen platform PCI device */ r = check_platform_magic(); /* If the version matches enable the Xen platform PCI driver. - * Also enable the Xen platform PCI driver if the version is really old - * and the user told us to ignore it. */ + * Also enable the Xen platform PCI driver if the host does + * not support the unplug protocol (XEN_PLATFORM_ERR_MAGIC) + * but the user told us that unplugging is unnecessary. */ if (r && !(r == XEN_PLATFORM_ERR_MAGIC && - (xen_emul_unplug & XEN_UNPLUG_IGNORE))) + (xen_emul_unplug & XEN_UNPLUG_UNNECESSARY))) return; /* Set the default value of xen_emul_unplug depending on whether or * not the Xen PV frontends and the Xen platform PCI driver have @@ -102,7 +103,7 @@ void __init xen_unplug_emulated_devices(void) } } /* Now unplug the emulated devices */ - if (!(xen_emul_unplug & XEN_UNPLUG_IGNORE)) + if (!(xen_emul_unplug & XEN_UNPLUG_UNNECESSARY)) outw(xen_emul_unplug, XEN_IOPORT_UNPLUG); xen_platform_pci_unplug = xen_emul_unplug; } @@ -128,8 +129,8 @@ static int __init parse_xen_emul_unplug(char *arg) xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS; else if (!strncmp(p, "nics", l)) xen_emul_unplug |= XEN_UNPLUG_ALL_NICS; - else if (!strncmp(p, "ignore", l)) - xen_emul_unplug |= XEN_UNPLUG_IGNORE; + else if (!strncmp(p, "unnecessary", l)) + xen_emul_unplug |= XEN_UNPLUG_UNNECESSARY; else if (!strncmp(p, "never", l)) xen_emul_unplug |= XEN_UNPLUG_NEVER; else diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index ac1b682edecb..ab735a605cf3 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -834,7 +834,7 @@ static int blkfront_probe(struct xenbus_device *dev, char *type; int len; /* no unplug has been done: do not hook devices != xen vbds */ - if (xen_platform_pci_unplug & XEN_UNPLUG_IGNORE) { + if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY) { int major; if (!VDEV_IS_EXTENDED(vdevice)) diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h index 123b7752fa6a..590ccfd82645 100644 --- a/include/xen/platform_pci.h +++ b/include/xen/platform_pci.h @@ -20,7 +20,7 @@ #define XEN_UNPLUG_ALL_NICS 2 #define XEN_UNPLUG_AUX_IDE_DISKS 4 #define XEN_UNPLUG_ALL 7 -#define XEN_UNPLUG_IGNORE 8 +#define XEN_UNPLUG_UNNECESSARY 8 #define XEN_UNPLUG_NEVER 16 static inline int xen_must_unplug_nics(void) { -- cgit v1.2.3-59-g8ed1b From 9c35e90c6fcf7f5baf27a63d9565e9f47633f299 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 23 Aug 2010 12:01:35 +0100 Subject: xen: pvhvm: make it clearer that XEN_UNPLUG_* define bits in a bitfield by defining in terms of (1< Acked-by: Jeremy Fitzhardinge Acked-by: Stefano Stabellini --- include/xen/platform_pci.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/include/xen/platform_pci.h b/include/xen/platform_pci.h index 590ccfd82645..a785a3b0c8c7 100644 --- a/include/xen/platform_pci.h +++ b/include/xen/platform_pci.h @@ -16,12 +16,15 @@ #define XEN_IOPORT_PROTOVER (XEN_IOPORT_BASE + 2) /* 1 byte access (R) */ #define XEN_IOPORT_PRODNUM (XEN_IOPORT_BASE + 2) /* 2 byte access (W) */ -#define XEN_UNPLUG_ALL_IDE_DISKS 1 -#define XEN_UNPLUG_ALL_NICS 2 -#define XEN_UNPLUG_AUX_IDE_DISKS 4 -#define XEN_UNPLUG_ALL 7 -#define XEN_UNPLUG_UNNECESSARY 8 -#define XEN_UNPLUG_NEVER 16 +#define XEN_UNPLUG_ALL_IDE_DISKS (1<<0) +#define XEN_UNPLUG_ALL_NICS (1<<1) +#define XEN_UNPLUG_AUX_IDE_DISKS (1<<2) +#define XEN_UNPLUG_ALL (XEN_UNPLUG_ALL_IDE_DISKS|\ + XEN_UNPLUG_ALL_NICS|\ + XEN_UNPLUG_AUX_IDE_DISKS) + +#define XEN_UNPLUG_UNNECESSARY (1<<16) +#define XEN_UNPLUG_NEVER (1<<17) static inline int xen_must_unplug_nics(void) { #if (defined(CONFIG_XEN_NETDEV_FRONTEND) || \ -- cgit v1.2.3-59-g8ed1b From 31fc0bd4aab30cac3e3388883b1b62750cc2f648 Mon Sep 17 00:00:00 2001 From: Rupjyoti Sarmah Date: Fri, 4 Jun 2010 00:03:12 +0000 Subject: powerpc/4xx: Device tree update for the 460ex DWC SATA Device tree update for the Applied micro processor 460ex on-chip SATA Signed-off-by: Rupjyoti Sarmah Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/canyonlands.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts index 5806ef0b860b..a30370396250 100644 --- a/arch/powerpc/boot/dts/canyonlands.dts +++ b/arch/powerpc/boot/dts/canyonlands.dts @@ -163,6 +163,14 @@ interrupts = <0x1e 4>; }; + SATA0: sata@bffd1000 { + compatible = "amcc,sata-460ex"; + reg = <4 0xbffd1000 0x800 4 0xbffd0800 0x400>; + interrupt-parent = <&UIC3>; + interrupts = <0x0 0x4 /* SATA */ + 0x5 0x4>; /* AHBDMA */ + }; + POB0: opb { compatible = "ibm,opb-460ex", "ibm,opb"; #address-cells = <1>; -- cgit v1.2.3-59-g8ed1b From 72f465033702ebfe20db8f50edaad59f0f38b0f5 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Mon, 23 Aug 2010 13:35:09 +0200 Subject: bio-integrity.c: remove dependency on __GFP_NOFAIL The kmalloc() in bio_integrity_prep() is failable, so remove __GFP_NOFAIL from its mask. Signed-off-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- fs/bio-integrity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 612a5c38d3c1..a8f4cc679983 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -413,7 +413,7 @@ int bio_integrity_prep(struct bio *bio) /* Allocate kernel buffer for protection data */ len = sectors * blk_integrity_tuple_size(bi); - buf = kmalloc(len, GFP_NOIO | __GFP_NOFAIL | q->bounce_gfp); + buf = kmalloc(len, GFP_NOIO | q->bounce_gfp); if (unlikely(buf == NULL)) { printk(KERN_ERR "could not allocate integrity buffer\n"); return -EIO; -- cgit v1.2.3-59-g8ed1b From 029b8f662b24a35aab20a81087822f1badf5463c Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:23 +0000 Subject: powerpc/47x: Make sure mcsr is cleared before enabling machine check interrupts Clear the machine check syndrom register before enabling machine check interrupts. The initial state of the tlb can lead to parity errors being flagged early after a cold boot. Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer --- arch/powerpc/kernel/head_44x.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 5ab484ef06a7..562305b40a8e 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -113,6 +113,10 @@ _ENTRY(_start); stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ stw r6, 0(r5) + /* Clear the Machine Check Syndrome Register */ + li r0,0 + mtspr SPRN_MCSR,r0 + /* Let's move on */ lis r4,start_kernel@h ori r4,r4,start_kernel@l -- cgit v1.2.3-59-g8ed1b From 220eb7fd984bfc7e6b4005fdf32efe9cd8af7cf2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 23 Aug 2010 13:36:20 +0200 Subject: fs/bio-integrity.c: return -ENOMEM on kmalloc failure Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- fs/bio-integrity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index a8f4cc679983..4d0ff5ee27b8 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -416,7 +416,7 @@ int bio_integrity_prep(struct bio *bio) buf = kmalloc(len, GFP_NOIO | q->bounce_gfp); if (unlikely(buf == NULL)) { printk(KERN_ERR "could not allocate integrity buffer\n"); - return -EIO; + return -ENOMEM; } end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT; -- cgit v1.2.3-59-g8ed1b From 66477466b8b79c98af17f1c2267596c8b6b4b561 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:24 +0000 Subject: powerpc/47x: Remove redundant line from cputable.c There are two entries for .cpu_user_features in arch/powerpc/kernel/cputable.c. Remove the one that doesn't belong Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer --- arch/powerpc/kernel/cputable.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 65e2b4e10f97..1f9123f412ec 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1826,7 +1826,6 @@ static struct cpu_spec __initdata cpu_specs[] = { .cpu_features = CPU_FTRS_47X, .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, - .cpu_user_features = COMMON_USER_BOOKE, .mmu_features = MMU_FTR_TYPE_47x | MMU_FTR_USE_TLBIVAX_BCAST | MMU_FTR_LOCK_BCAST_INVAL, .icache_bsize = 32, -- cgit v1.2.3-59-g8ed1b From 3e7f45ad521ac3e38889d255ec7676037fa84ae2 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:25 +0000 Subject: powerpc/4xx: Index interrupt stacks by physical cpu The interrupt stacks need to be indexed by the physical cpu since the critical, debug and machine check handlers use the contents of SPRN_PIR to index the critirq_ctx, dbgirq_ctx, and mcheckirq_ctx arrays. Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer --- arch/powerpc/kernel/irq.c | 16 +++++++++------- arch/powerpc/kernel/setup_32.c | 9 +++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index d3ce67cf03be..4a65386995d7 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -67,6 +67,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include @@ -446,22 +447,23 @@ struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly; void exc_lvl_ctx_init(void) { struct thread_info *tp; - int i; + int i, hw_cpu; for_each_possible_cpu(i) { - memset((void *)critirq_ctx[i], 0, THREAD_SIZE); - tp = critirq_ctx[i]; + hw_cpu = get_hard_smp_processor_id(i); + memset((void *)critirq_ctx[hw_cpu], 0, THREAD_SIZE); + tp = critirq_ctx[hw_cpu]; tp->cpu = i; tp->preempt_count = 0; #ifdef CONFIG_BOOKE - memset((void *)dbgirq_ctx[i], 0, THREAD_SIZE); - tp = dbgirq_ctx[i]; + memset((void *)dbgirq_ctx[hw_cpu], 0, THREAD_SIZE); + tp = dbgirq_ctx[hw_cpu]; tp->cpu = i; tp->preempt_count = 0; - memset((void *)mcheckirq_ctx[i], 0, THREAD_SIZE); - tp = mcheckirq_ctx[i]; + memset((void *)mcheckirq_ctx[hw_cpu], 0, THREAD_SIZE); + tp = mcheckirq_ctx[hw_cpu]; tp->cpu = i; tp->preempt_count = HARDIRQ_OFFSET; #endif diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index a10ffc85ada7..93666f9cabf1 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -258,17 +258,18 @@ static void __init irqstack_early_init(void) #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) static void __init exc_lvl_early_init(void) { - unsigned int i; + unsigned int i, hw_cpu; /* interrupt stacks must be in lowmem, we get that for free on ppc32 * as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */ for_each_possible_cpu(i) { - critirq_ctx[i] = (struct thread_info *) + hw_cpu = get_hard_smp_processor_id(i); + critirq_ctx[hw_cpu] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); #ifdef CONFIG_BOOKE - dbgirq_ctx[i] = (struct thread_info *) + dbgirq_ctx[hw_cpu] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); - mcheckirq_ctx[i] = (struct thread_info *) + mcheckirq_ctx[hw_cpu] = (struct thread_info *) __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); #endif } -- cgit v1.2.3-59-g8ed1b From 32412aa214e05308833a89e6090406294833f989 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 18 Aug 2010 06:44:26 +0000 Subject: powerpc/47x: Add an isync before the tlbivax instruction Signed-off-by: Dave Kleikamp Signed-off-by: Josh Boyer --- arch/powerpc/mm/tlb_nohash_low.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S index cfa768203d08..b9d9fed8f36e 100644 --- a/arch/powerpc/mm/tlb_nohash_low.S +++ b/arch/powerpc/mm/tlb_nohash_low.S @@ -200,6 +200,7 @@ _GLOBAL(_tlbivax_bcast) rlwimi r5,r4,0,16,31 wrteei 0 mtspr SPRN_MMUCR,r5 + isync /* tlbivax 0,r3 - use .long to avoid binutils deps */ .long 0x7c000624 | (r3 << 11) isync -- cgit v1.2.3-59-g8ed1b From 5dd531a03ad721b41911ddb32e6e0481404e7aaf Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 23 Aug 2010 13:52:19 +0200 Subject: block: add function call to switch the IO scheduler from a driver Currently drivers must do an elevator_exit() + elevator_init() to switch IO schedulers. There are a few problems with this: - Since commit 1abec4fdbb142e3ccb6ce99832fae42129134a96, elevator_init() requires a zeroed out q->elevator pointer. The two existing in-kernel users don't do that. - It will only work at initialization time, since using the above two-staged construct does not properly quisce the queue. So add elevator_change() which takes care of this, and convert the elv_iosched_store() sysfs interface to use this helper as well. Reported-by: Peter Oberparleiter Reported-by: Kevin Vigor Signed-off-by: Jens Axboe --- block/elevator.c | 44 +++++++++++++++++++++++++++++++------------- include/linux/elevator.h | 1 + 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index ec585c9554d3..205b09a5bd9e 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -1009,18 +1009,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) { struct elevator_queue *old_elevator, *e; void *data; + int err; /* * Allocate new elevator */ e = elevator_alloc(q, new_e); if (!e) - return 0; + return -ENOMEM; data = elevator_init_queue(q, e); if (!data) { kobject_put(&e->kobj); - return 0; + return -ENOMEM; } /* @@ -1043,7 +1044,8 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) __elv_unregister_queue(old_elevator); - if (elv_register_queue(q)) + err = elv_register_queue(q); + if (err) goto fail_register; /* @@ -1056,7 +1058,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name); - return 1; + return 0; fail_register: /* @@ -1071,17 +1073,19 @@ fail_register: queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); spin_unlock_irq(q->queue_lock); - return 0; + return err; } -ssize_t elv_iosched_store(struct request_queue *q, const char *name, - size_t count) +/* + * Switch this queue to the given IO scheduler. + */ +int elevator_change(struct request_queue *q, const char *name) { char elevator_name[ELV_NAME_MAX]; struct elevator_type *e; if (!q->elevator) - return count; + return -ENXIO; strlcpy(elevator_name, name, sizeof(elevator_name)); e = elevator_get(strstrip(elevator_name)); @@ -1092,13 +1096,27 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name, if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) { elevator_put(e); - return count; + return 0; } - if (!elevator_switch(q, e)) - printk(KERN_ERR "elevator: switch to %s failed\n", - elevator_name); - return count; + return elevator_switch(q, e); +} +EXPORT_SYMBOL(elevator_change); + +ssize_t elv_iosched_store(struct request_queue *q, const char *name, + size_t count) +{ + int ret; + + if (!q->elevator) + return count; + + ret = elevator_change(q, name); + if (!ret) + return count; + + printk(KERN_ERR "elevator: switch to %s failed\n", name); + return ret; } ssize_t elv_iosched_show(struct request_queue *q, char *name) diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 2c958f4fce1e..926b50322a46 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -136,6 +136,7 @@ extern ssize_t elv_iosched_store(struct request_queue *, const char *, size_t); extern int elevator_init(struct request_queue *, char *); extern void elevator_exit(struct elevator_queue *); +extern int elevator_change(struct request_queue *, const char *); extern int elv_rq_merge_ok(struct request *, struct bio *); /* -- cgit v1.2.3-59-g8ed1b From 52cc2eef31587b22ce9fbe77b064a031a9613ab0 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 23 Aug 2010 14:02:44 +0200 Subject: block: switch s390 tape_block and mg_disk to elevator_change() Now that we have this API, switch the two in-kernel users to it. Resolves an oops introduced by commit 1abec4fdbb142e3ccb6ce99832fae42129134a96. Signed-off-by: Jens Axboe --- drivers/block/mg_disk.c | 3 +-- drivers/s390/char/tape_block.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index b82c5ce5e9df..76fa3deaee84 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -974,8 +974,7 @@ static int mg_probe(struct platform_device *plat_dev) host->breq->queuedata = host; /* mflash is random device, thanx for the noop */ - elevator_exit(host->breq->elevator); - err = elevator_init(host->breq, "noop"); + err = elevator_change(host->breq, "noop"); if (err) { printk(KERN_ERR "%s:%d (elevator_init) fail\n", __func__, __LINE__); diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index b7de02525ec9..85cf607fc78f 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -217,8 +217,7 @@ tapeblock_setup_device(struct tape_device * device) if (!blkdat->request_queue) return -ENOMEM; - elevator_exit(blkdat->request_queue->elevator); - rc = elevator_init(blkdat->request_queue, "noop"); + rc = elevator_change(blkdat->request_queue, "noop"); if (rc) goto cleanup_queue; -- cgit v1.2.3-59-g8ed1b From 3ec6bbcdb4e85403f2c5958876ca9492afdf4031 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Mon, 23 Aug 2010 11:04:07 -0500 Subject: missing changes during ntlmv2/ntlmssp auth and sign Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 2 ++ fs/cifs/sess.c | 13 ++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 051d00011ca3..eef78c24e0cc 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -553,6 +553,8 @@ calc_seckey(struct TCP_Server_Info *server) return 1; } + desc.tfm = tfm_arc4; + crypto_blkcipher_setkey(tfm_arc4, server->session_key.data.ntlmv2.key, CIFS_CPHTXT_SIZE); sg_init_one(&sgin, sec_key, CIFS_CPHTXT_SIZE); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 41fc5328120d..4788e16a02cc 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -408,6 +408,8 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ + ses->server->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags); + tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); tilen = cpu_to_le16(pblob->TargetInfoArray.Length); ses->server->tilen = tilen; @@ -440,12 +442,13 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, /* BB is NTLMV2 session security format easier to use here? */ flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; + NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - flags |= NTLMSSP_NEGOTIATE_SIGN; - if (ses->server->secMode & SECMODE_SIGN_REQUIRED) - flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { + flags |= NTLMSSP_NEGOTIATE_SIGN | + NTLMSSP_NEGOTIATE_KEY_XCH | + NTLMSSP_NEGOTIATE_EXTENDED_SEC; + } sec_blob->NegotiateFlags |= cpu_to_le32(flags); -- cgit v1.2.3-59-g8ed1b From 24e6cf92fde1f140d8eb0bf7cd24c2c78149b6b2 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 23 Aug 2010 11:38:04 -0400 Subject: cifs: check for NULL session password It's possible for a cifsSesInfo struct to have a NULL password, so we need to check for that prior to running strncmp on it. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 18af707f00f1..ec0ea4a43bdb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1673,6 +1673,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) MAX_USERNAME_SIZE)) continue; if (strlen(vol->username) != 0 && + ses->password != NULL && strncmp(ses->password, vol->password ? vol->password : "", MAX_PASSWORD_SIZE)) -- cgit v1.2.3-59-g8ed1b From 6e0c64f4ddf4a76a04108c1e24132d5d7dea8872 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 23 Aug 2010 14:31:34 +0100 Subject: arch/mn10300/mm: eliminate NULL dereference dev_name always dereferences its argument, so it should not be called if the argument is NULL. The function indeed later tests the argument for being NULL. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression dev,E; @@ *dev_name(dev) ... when != dev = E ( *dev == NULL | *dev != NULL ) // Signed-off-by: Julia Lawall Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/mn10300/mm/dma-alloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mn10300/mm/dma-alloc.c b/arch/mn10300/mm/dma-alloc.c index 4e34880bea03..159acb02cfd4 100644 --- a/arch/mn10300/mm/dma-alloc.c +++ b/arch/mn10300/mm/dma-alloc.c @@ -25,7 +25,8 @@ void *dma_alloc_coherent(struct device *dev, size_t size, unsigned long addr; void *ret; - printk("dma_alloc_coherent(%s,%zu,,%x)\n", dev_name(dev), size, gfp); + pr_debug("dma_alloc_coherent(%s,%zu,%x)\n", + dev ? dev_name(dev) : "?", size, gfp); if (0xbe000000 - pci_sram_allocated >= size) { size = (size + 255) & ~255; -- cgit v1.2.3-59-g8ed1b From c76a3e1d6c52c5cc1371f1abc7381c5715ebdf7f Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Mon, 23 Aug 2010 11:32:36 -0600 Subject: ACPI_TOSHIBA needs LEDS support Don't ask how ACPI_TOSHIBA got enabled on in desktop system's .config - I don't know. But it has silently been there until I tried 2.6.36-rc2, where it broke the build because I don't have LED support turned on. Attached patch fixes things up. (I had to change BACKLIGHT_CLASS_DEVICE to "depends" because otherwise I get unsightly core dumps out of scripts/kconfig/conf). jon -- toshiba: make sure we pull in LED support The Toshiba extras driver uses the LED module, so make sure we have it configure in. Signed-off-by: Jonathan Corbet Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 044f430f3b43..cff7cc2c1f02 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -486,10 +486,12 @@ config TOPSTAR_LAPTOP config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI + depends on LEDS_CLASS + depends on NEW_LEDS + depends on BACKLIGHT_CLASS_DEVICE depends on INPUT depends on RFKILL || RFKILL = n select INPUT_POLLDEV - select BACKLIGHT_CLASS_DEVICE ---help--- This driver adds support for access to certain system settings on "legacy free" Toshiba laptops. These laptops can be recognized by -- cgit v1.2.3-59-g8ed1b From a8ec105c0764c848d59f18a31f91fa00c99b2e7f Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 23 Aug 2010 15:52:34 -0400 Subject: hp-wmi: Fix query interface The machines I have appear to provide their return value in the arguments structure, not the output structure. Rework the driver to use that again in order to get rfkill working again. Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 64 +++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f15516374987..c1741142a4cb 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -79,12 +79,13 @@ struct bios_args { u32 command; u32 commandtype; u32 datasize; - char *data; + u32 data; }; struct bios_return { u32 sigpass; u32 return_code; + u32 value; }; struct key_entry { @@ -148,7 +149,7 @@ static struct platform_driver hp_wmi_driver = { * buffer = kzalloc(128, GFP_KERNEL); * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) */ -static int hp_wmi_perform_query(int query, int write, char *buffer, +static int hp_wmi_perform_query(int query, int write, u32 *buffer, int buffersize) { struct bios_return bios_return; @@ -159,7 +160,7 @@ static int hp_wmi_perform_query(int query, int write, char *buffer, .command = write ? 0x2 : 0x1, .commandtype = query, .datasize = buffersize, - .data = buffer, + .data = *buffer, }; struct acpi_buffer input = { sizeof(struct bios_args), &args }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -177,29 +178,14 @@ static int hp_wmi_perform_query(int query, int write, char *buffer, bios_return = *((struct bios_return *)obj->buffer.pointer); - if (bios_return.return_code) { - printk(KERN_WARNING PREFIX "Query %d returned %d\n", query, - bios_return.return_code); - kfree(obj); - return bios_return.return_code; - } - if (obj->buffer.length - sizeof(bios_return) > buffersize) { - kfree(obj); - return -EINVAL; - } - - memset(buffer, 0, buffersize); - memcpy(buffer, - ((char *)obj->buffer.pointer) + sizeof(struct bios_return), - obj->buffer.length - sizeof(bios_return)); - kfree(obj); + memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); return 0; } static int hp_wmi_display_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, sizeof(state)); if (ret) return -EINVAL; @@ -208,8 +194,8 @@ static int hp_wmi_display_state(void) static int hp_wmi_hddtemp_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, sizeof(state)); if (ret) return -EINVAL; @@ -218,8 +204,8 @@ static int hp_wmi_hddtemp_state(void) static int hp_wmi_als_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, sizeof(state)); if (ret) return -EINVAL; @@ -228,8 +214,8 @@ static int hp_wmi_als_state(void) static int hp_wmi_dock_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, sizeof(state)); if (ret) @@ -240,8 +226,8 @@ static int hp_wmi_dock_state(void) static int hp_wmi_tablet_state(void) { - int state; - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state, + int state = 0; + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, sizeof(state)); if (ret) return ret; @@ -256,7 +242,7 @@ static int hp_wmi_set_block(void *data, bool blocked) int ret; ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, - (char *)&query, sizeof(query)); + &query, sizeof(query)); if (ret) return -EINVAL; return 0; @@ -268,10 +254,10 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = { static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) { - int wireless; + int wireless = 0; int mask; hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, - (char *)&wireless, sizeof(wireless)); + &wireless, sizeof(wireless)); /* TBD: Pass error */ mask = 0x200 << (r * 8); @@ -284,10 +270,10 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) { - int wireless; + int wireless = 0; int mask; hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, - (char *)&wireless, sizeof(wireless)); + &wireless, sizeof(wireless)); /* TBD: Pass error */ mask = 0x800 << (r * 8); @@ -347,7 +333,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u32 tmp = simple_strtoul(buf, NULL, 10); - int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, (char *)&tmp, + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, sizeof(tmp)); if (ret) return -EINVAL; @@ -421,7 +407,7 @@ static void hp_wmi_notify(u32 value, void *context) static struct key_entry *key; union acpi_object *obj; u32 event_id, event_data; - int key_code, ret; + int key_code = 0, ret; u32 *location; acpi_status status; @@ -475,7 +461,7 @@ static void hp_wmi_notify(u32 value, void *context) break; case HPWMI_BEZEL_BUTTON: ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, - (char *)&key_code, + &key_code, sizeof(key_code)); if (ret) break; @@ -578,9 +564,9 @@ static void cleanup_sysfs(struct platform_device *device) static int __devinit hp_wmi_bios_setup(struct platform_device *device) { int err; - int wireless; + int wireless = 0; - err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, (char *)&wireless, + err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, sizeof(wireless)); if (err) return err; -- cgit v1.2.3-59-g8ed1b From cca77b7c81876d819a5806f408b3c29b5b61a815 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 23 Aug 2010 14:41:22 -0700 Subject: netfilter: fix CONFIG_COMPAT support commit f3c5c1bfd430858d3a05436f82c51e53104feb6b (netfilter: xtables: make ip_tables reentrant) forgot to also compute the jumpstack size in the compat handlers. Result is that "iptables -I INPUT -j userchain" turns into -j DROP. Reported by Sebastian Roesner on #netfilter, closes http://bugzilla.netfilter.org/show_bug.cgi?id=669. Note: arptables change is compile-tested only. Signed-off-by: Florian Westphal Acked-by: Eric Dumazet Tested-by: Mikael Pettersson Signed-off-by: David S. Miller --- net/ipv4/netfilter/arp_tables.c | 3 +++ net/ipv4/netfilter/ip_tables.c | 3 +++ net/ipv6/netfilter/ip6_tables.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 51d6c3167975..e8f4f9a57f12 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1420,6 +1420,9 @@ static int translate_compat_table(const char *name, if (ret != 0) break; ++i; + if (strcmp(arpt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 97b64b22c412..d163f2e3b2e9 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1751,6 +1751,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ipt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 29a7bca29e3f..8e754be92c24 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1766,6 +1766,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ip6t_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* -- cgit v1.2.3-59-g8ed1b From 8488a38f4d2f43bd55a3e0db4cd57a5bef3af6d6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 11 Aug 2010 15:01:02 +0100 Subject: kobject: Break the kobject namespace defs into their own header Break the kobject namespace defs into their own header to avoid a header file inclusion ordering problem between linux/sysfs.h and linux/kobject.h. This fixes the build breakage on older versions of gcc. Signed-off-by: David Howells Cc: Eric Biederman Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 35 +---------------------------- include/linux/kobject_ns.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/sysfs.h | 1 + 3 files changed, 58 insertions(+), 34 deletions(-) create mode 100644 include/linux/kobject_ns.h diff --git a/include/linux/kobject.h b/include/linux/kobject.h index cf343a852534..7950a37a7146 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -136,42 +137,8 @@ struct kobj_attribute { extern const struct sysfs_ops kobj_sysfs_ops; -/* - * Namespace types which are used to tag kobjects and sysfs entries. - * Network namespace will likely be the first. - */ -enum kobj_ns_type { - KOBJ_NS_TYPE_NONE = 0, - KOBJ_NS_TYPE_NET, - KOBJ_NS_TYPES -}; - struct sock; -/* - * Callbacks so sysfs can determine namespaces - * @current_ns: return calling task's namespace - * @netlink_ns: return namespace to which a sock belongs (right?) - * @initial_ns: return the initial namespace (i.e. init_net_ns) - */ -struct kobj_ns_type_operations { - enum kobj_ns_type type; - const void *(*current_ns)(void); - const void *(*netlink_ns)(struct sock *sk); - const void *(*initial_ns)(void); -}; - -int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); -int kobj_ns_type_registered(enum kobj_ns_type type); -const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); -const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); - -const void *kobj_ns_current(enum kobj_ns_type type); -const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); -const void *kobj_ns_initial(enum kobj_ns_type type); -void kobj_ns_exit(enum kobj_ns_type type, const void *ns); - - /** * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. * diff --git a/include/linux/kobject_ns.h b/include/linux/kobject_ns.h new file mode 100644 index 000000000000..82cb5bf461fb --- /dev/null +++ b/include/linux/kobject_ns.h @@ -0,0 +1,56 @@ +/* Kernel object name space definitions + * + * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2002-2003 Open Source Development Labs + * Copyright (c) 2006-2008 Greg Kroah-Hartman + * Copyright (c) 2006-2008 Novell Inc. + * + * Split from kobject.h by David Howells (dhowells@redhat.com) + * + * This file is released under the GPLv2. + * + * Please read Documentation/kobject.txt before using the kobject + * interface, ESPECIALLY the parts about reference counts and object + * destructors. + */ + +#ifndef _LINUX_KOBJECT_NS_H +#define _LINUX_KOBJECT_NS_H + +struct sock; +struct kobject; + +/* + * Namespace types which are used to tag kobjects and sysfs entries. + * Network namespace will likely be the first. + */ +enum kobj_ns_type { + KOBJ_NS_TYPE_NONE = 0, + KOBJ_NS_TYPE_NET, + KOBJ_NS_TYPES +}; + +/* + * Callbacks so sysfs can determine namespaces + * @current_ns: return calling task's namespace + * @netlink_ns: return namespace to which a sock belongs (right?) + * @initial_ns: return the initial namespace (i.e. init_net_ns) + */ +struct kobj_ns_type_operations { + enum kobj_ns_type type; + const void *(*current_ns)(void); + const void *(*netlink_ns)(struct sock *sk); + const void *(*initial_ns)(void); +}; + +int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); +int kobj_ns_type_registered(enum kobj_ns_type type); +const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); +const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); + +const void *kobj_ns_current(enum kobj_ns_type type); +const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); +const void *kobj_ns_initial(enum kobj_ns_type type); +void kobj_ns_exit(enum kobj_ns_type type, const void *ns); + +#endif /* _LINUX_KOBJECT_NS_H */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 3c92121ba9af..96eb576d82fd 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -16,6 +16,7 @@ #include #include #include +#include #include struct kobject; -- cgit v1.2.3-59-g8ed1b From f45f3c1f3f616ca1d1e1eb5e7a720ca63cb59550 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Aug 2010 17:15:18 +0200 Subject: firmware_class: fix typo in error path In the error path, _request_firmware sets firmware_p to NULL rather than *firmware_p, which leads to passing a freed firmware struct to drivers when the firmware file cannot be found. Fix this. Broken by commit f8a4bd3456b988fc73b2c. Reported-by: Wey-Yi Guy Signed-off-by: Johannes Berg Acked-by: Dmitry Torokhov Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index c8a44f5e0584..40af43ebd92d 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -568,7 +568,7 @@ static int _request_firmware(const struct firmware **firmware_p, out: if (retval) { release_firmware(firmware); - firmware_p = NULL; + *firmware_p = NULL; } return retval; -- cgit v1.2.3-59-g8ed1b From f6e6e7799ebcad40fa15e4015beca2d776554302 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Fri, 13 Aug 2010 18:58:10 +0800 Subject: kobject_uevent: fix typo in comments s/ending/sending, s/kobject_uevent()/kobject_uevent_env() in the comments. Signed-off-by: Xiaotian Feng Signed-off-by: Greg Kroah-Hartman --- lib/kobject_uevent.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index b93579504dfa..70af0a7f97c0 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -123,7 +123,7 @@ static int kobj_usermode_filter(struct kobject *kobj) * @kobj: struct kobject that the action is happening to * @envp_ext: pointer to environmental data * - * Returns 0 if kobject_uevent() is completed with success or the + * Returns 0 if kobject_uevent_env() is completed with success or the * corresponding error when it fails. */ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, @@ -317,7 +317,7 @@ exit: EXPORT_SYMBOL_GPL(kobject_uevent_env); /** - * kobject_uevent - notify userspace by ending an uevent + * kobject_uevent - notify userspace by sending an uevent * * @action: action that is happening * @kobj: struct kobject that the action is happening to -- cgit v1.2.3-59-g8ed1b From 09e74c794fc9d5064e07c4bf6c9d5458586385c1 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 9 Jul 2010 23:25:12 -0400 Subject: Staging: spectra: removes q->prepare_flush_fn, fix build breakage This patch is the first one of a patchset that allows stagin/spectra driver to compile in linux-next. blk_queue_ordered doesn't receive a prepare flush function anymore Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/ffsport.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index d0c5c97eda3e..eca65363b23b 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -272,13 +272,6 @@ static int get_res_blk_num_os(void) return res_blks; } -static void SBD_prepare_flush(struct request_queue *q, struct request *rq) -{ - rq->cmd_type = REQ_TYPE_LINUX_BLOCK; - /* rq->timeout = 5 * HZ; */ - rq->cmd[0] = REQ_LB_OP_FLUSH; -} - /* Transfer a full request. */ static int do_transfer(struct spectra_nand_dev *tr, struct request *req) { @@ -650,8 +643,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); - blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH, - SBD_prepare_flush); + blk_queue_ordered(dev->queue, QUEUE_ORDERED_DRAIN_FLUSH); dev->thread = kthread_run(spectra_trans_thread, dev, "nand_thd"); if (IS_ERR(dev->thread)) { -- cgit v1.2.3-59-g8ed1b From 7b633f6624ce4ea6199a54c2cad6c9e84164f8f5 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 9 Jul 2010 23:28:13 -0400 Subject: Staging: use new REQ_FLUSH flag, fix build breakage REQ_TYPE_LINUX_BLOCK and REQ_LB_OP_FLUSH doesn't exist anymore. Using the new REQ_FLUSH flag instead Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/ffsport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index eca65363b23b..00a0ac03a49a 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -289,8 +289,7 @@ static int do_transfer(struct spectra_nand_dev *tr, struct request *req) IdentifyDeviceData.PagesPerBlock * res_blks_os; - if (req->cmd_type == REQ_TYPE_LINUX_BLOCK && - req->cmd[0] == REQ_LB_OP_FLUSH) { + if (req->cmd_type & REQ_FLUSH) { if (force_flush_cache()) /* Fail to flush cache */ return -EIO; else -- cgit v1.2.3-59-g8ed1b From 6e19d2db499b66aa7942bd36a7b55bb725379aae Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 10 Jul 2010 00:07:35 -0400 Subject: Staging: spectra: don't use locked_ioctl, fix build Last patch has a style problem. Sending the correct one. Sorry for the noise Since BKL was removed from block ioctl handling code, locked_ioctl doesn't exist anymore. Using ioctl instead and doing the locking manually. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/ffsport.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 00a0ac03a49a..7b3463514c38 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -27,6 +27,7 @@ #include #include #include +#include /**** Helper functions used for Div, Remainder operation on u64 ****/ @@ -589,11 +590,23 @@ int GLOB_SBD_ioctl(struct block_device *bdev, fmode_t mode, return -ENOTTY; } +int GLOB_SBD_unlocked_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + int ret; + + lock_kernel(); + ret = GLOB_SBD_ioctl(bdev, mode, cmd, arg); + unlock_kernel(); + + return ret; +} + static struct block_device_operations GLOB_SBD_ops = { .owner = THIS_MODULE, .open = GLOB_SBD_open, .release = GLOB_SBD_release, - .locked_ioctl = GLOB_SBD_ioctl, + .ioctl = GLOB_SBD_unlocked_ioctl, .getgeo = GLOB_SBD_getgeo, }; -- cgit v1.2.3-59-g8ed1b From c321da6dc53cd692dc2db82686d5dfd150a3b817 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:39:54 -0400 Subject: Staging: spectra: remove duplicate GLOB_VERSION definition This is the first patch of a patchset that removes all compilations warnings in staging/spectra. These patches are a delta from a previous patchset and it assumes that these three patches all already applied: Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/ffsport.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 7b3463514c38..44a7fbe7eccd 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -114,7 +114,6 @@ u64 GLOB_u64_Remainder(u64 addr, u32 divisor_type) #define GLOB_SBD_NAME "nd" #define GLOB_SBD_IRQ_NUM (29) -#define GLOB_VERSION "driver version 20091110" #define GLOB_SBD_IOCTL_GC (0x7701) #define GLOB_SBD_IOCTL_WL (0x7702) -- cgit v1.2.3-59-g8ed1b From 676cecaaddd09bbe41a38b1d15f190da10087294 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:42:19 -0400 Subject: Staging: spectra: removes unused variable Fix a compile warning by removing an unused variable int i. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index 134aa5166a8d..a0d60942fda5 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -775,7 +775,7 @@ static void dump_cache_l2_table(void) { struct list_head *p; struct spectra_l2_cache_list *pnd; - int n, i; + int n; n = 0; list_for_each(p, &cache_l2.table.list) { -- cgit v1.2.3-59-g8ed1b From fd484b86a22efeea06298c0dc3b1518473ff2fc4 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:45:27 -0400 Subject: Staging: spectra: initializa lblk variable Fix a compile warning by initializaing lblk. Since FTL_Get_Block_Index() returns BAD_BLOCK if it doesn't find the logical block number, lblk number is initizalized to BAD_BLOCK. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index a0d60942fda5..26733888fd0a 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -1698,7 +1698,7 @@ static int get_l2_cache_blks(void) static int erase_l2_cache_blocks(void) { int i, ret = PASS; - u32 pblk, lblk; + u32 pblk, lblk = BAD_BLOCK; u64 addr; u32 *pbt = (u32 *)g_pBlockTable; -- cgit v1.2.3-59-g8ed1b From 49b48547724eca062aec13a3bfd621194836513b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 17 Jul 2010 16:46:28 -0400 Subject: Staging: spectra: removes unused functions Fix compilation warning removing unused functions. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/flash.c | 416 ---------------------------------------- 1 file changed, 416 deletions(-) diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index 26733888fd0a..9b5218b6ada8 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -61,7 +61,6 @@ static void FTL_Cache_Read_Page(u8 *pData, u64 dwPageAddr, static void FTL_Cache_Write_Page(u8 *pData, u64 dwPageAddr, u8 cache_blk, u16 flag); static int FTL_Cache_Write(void); -static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr); static void FTL_Calculate_LRU(void); static u32 FTL_Get_Block_Index(u32 wBlockNum); @@ -86,8 +85,6 @@ static u32 FTL_Replace_MWBlock(void); static int FTL_Replace_Block(u64 blk_addr); static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX); -static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, u64 blk_addr); - struct device_info_tag DeviceInfo; struct flash_cache_tag Cache; static struct spectra_l2_cache_info cache_l2; @@ -1537,79 +1534,6 @@ static int FTL_Cache_Write_All(u8 *pData, u64 blk_addr) return wResult; } -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Update_Block -* Inputs: pointer to buffer,page address,block address -* Outputs: PASS=0 / FAIL=1 -* Description: It updates the cache -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Update_Block(u8 *pData, - u64 old_page_addr, u64 blk_addr) -{ - int i, j; - u8 *buf = pData; - int wResult = PASS; - int wFoundInCache; - u64 page_addr; - u64 addr; - u64 old_blk_addr; - u16 page_offset; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - old_blk_addr = (u64)(old_page_addr >> - DeviceInfo.nBitsInBlockDataSize) * DeviceInfo.wBlockDataSize; - page_offset = (u16)(GLOB_u64_Remainder(old_page_addr, 2) >> - DeviceInfo.nBitsInPageDataSize); - - for (i = 0; i < DeviceInfo.wPagesPerBlock; i += Cache.pages_per_item) { - page_addr = old_blk_addr + i * DeviceInfo.wPageDataSize; - if (i != page_offset) { - wFoundInCache = FAIL; - for (j = 0; j < CACHE_ITEM_NUM; j++) { - addr = Cache.array[j].address; - addr = FTL_Get_Physical_Block_Addr(addr) + - GLOB_u64_Remainder(addr, 2); - if ((addr >= page_addr) && addr < - (page_addr + Cache.cache_item_size)) { - wFoundInCache = PASS; - buf = Cache.array[j].buf; - Cache.array[j].changed = SET; -#if CMD_DMA -#if RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE - int_cache[ftl_cmd_cnt].item = j; - int_cache[ftl_cmd_cnt].cache.address = - Cache.array[j].address; - int_cache[ftl_cmd_cnt].cache.changed = - Cache.array[j].changed; -#endif -#endif - break; - } - } - if (FAIL == wFoundInCache) { - if (ERR == FTL_Cache_Read_All(g_pTempBuf, - page_addr)) { - wResult = FAIL; - break; - } - buf = g_pTempBuf; - } - } else { - buf = pData; - } - - if (FAIL == FTL_Cache_Write_All(buf, - blk_addr + (page_addr - old_blk_addr))) { - wResult = FAIL; - break; - } - } - - return wResult; -} - /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Copy_Block * Inputs: source block address @@ -2004,87 +1928,6 @@ static int search_l2_cache(u8 *buf, u64 logical_addr) return ret; } -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Cache_Write_Back -* Inputs: pointer to data cached in sys memory -* address of free block in flash -* Outputs: PASS=0 / FAIL=1 -* Description: writes all the pages of Cache Block to flash -* -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Cache_Write_Back(u8 *pData, u64 blk_addr) -{ - int i, j, iErase; - u64 old_page_addr, addr, phy_addr; - u32 *pbt = (u32 *)g_pBlockTable; - u32 lba; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - old_page_addr = FTL_Get_Physical_Block_Addr(blk_addr) + - GLOB_u64_Remainder(blk_addr, 2); - - iErase = (FAIL == FTL_Replace_Block(blk_addr)) ? PASS : FAIL; - - pbt[BLK_FROM_ADDR(blk_addr)] &= (~SPARE_BLOCK); - -#if CMD_DMA - p_BTableChangesDelta = (struct BTableChangesDelta *)g_pBTDelta_Free; - g_pBTDelta_Free += sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = (u32)(blk_addr >> - DeviceInfo.nBitsInBlockDataSize); - p_BTableChangesDelta->BT_Entry_Value = - pbt[(u32)(blk_addr >> DeviceInfo.nBitsInBlockDataSize)]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - for (i = 0; i < RETRY_TIMES; i++) { - if (PASS == iErase) { - phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); - if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) { - lba = BLK_FROM_ADDR(blk_addr); - MARK_BLOCK_AS_BAD(pbt[lba]); - i = RETRY_TIMES; - break; - } - } - - for (j = 0; j < CACHE_ITEM_NUM; j++) { - addr = Cache.array[j].address; - if ((addr <= blk_addr) && - ((addr + Cache.cache_item_size) > blk_addr)) - cache_block_to_write = j; - } - - phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); - if (PASS == FTL_Cache_Update_Block(pData, - old_page_addr, phy_addr)) { - cache_block_to_write = UNHIT_CACHE_ITEM; - break; - } else { - iErase = PASS; - } - } - - if (i >= RETRY_TIMES) { - if (ERR == FTL_Flash_Error_Handle(pData, - old_page_addr, blk_addr)) - return ERR; - else - return FAIL; - } - - return PASS; -} - /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Cache_Write_Page * Inputs: Pointer to buffer, page address, cache block number @@ -2370,159 +2213,6 @@ static int FTL_Write_Block_Table(int wForce) return 1; } -/****************************************************************** -* Function: GLOB_FTL_Flash_Format -* Inputs: none -* Outputs: PASS -* Description: The block table stores bad block info, including MDF+ -* blocks gone bad over the ages. Therefore, if we have a -* block table in place, then use it to scan for bad blocks -* If not, then scan for MDF. -* Now, a block table will only be found if spectra was already -* being used. For a fresh flash, we'll go thru scanning for -* MDF. If spectra was being used, then there is a chance that -* the MDF has been corrupted. Spectra avoids writing to the -* first 2 bytes of the spare area to all pages in a block. This -* covers all known flash devices. However, since flash -* manufacturers have no standard of where the MDF is stored, -* this cannot guarantee that the MDF is protected for future -* devices too. The initial scanning for the block table assures -* this. It is ok even if the block table is outdated, as all -* we're looking for are bad block markers. -* Use this when mounting a file system or starting a -* new flash. -* -*********************************************************************/ -static int FTL_Format_Flash(u8 valid_block_table) -{ - u32 i, j; - u32 *pbt = (u32 *)g_pBlockTable; - u32 tempNode; - int ret; - -#if CMD_DMA - u32 *pbtStartingCopy = (u32 *)g_pBTStartingCopy; - if (ftl_cmd_cnt) - return FAIL; -#endif - - if (FAIL == FTL_Check_Block_Table(FAIL)) - valid_block_table = 0; - - if (valid_block_table) { - u8 switched = 1; - u32 block, k; - - k = DeviceInfo.wSpectraStartBlock; - while (switched && (k < DeviceInfo.wSpectraEndBlock)) { - switched = 0; - k++; - for (j = DeviceInfo.wSpectraStartBlock, i = 0; - j <= DeviceInfo.wSpectraEndBlock; - j++, i++) { - block = (pbt[i] & ~BAD_BLOCK) - - DeviceInfo.wSpectraStartBlock; - if (block != i) { - switched = 1; - tempNode = pbt[i]; - pbt[i] = pbt[block]; - pbt[block] = tempNode; - } - } - } - if ((k == DeviceInfo.wSpectraEndBlock) && switched) - valid_block_table = 0; - } - - if (!valid_block_table) { - memset(g_pBlockTable, 0, - DeviceInfo.wDataBlockNum * sizeof(u32)); - memset(g_pWearCounter, 0, - DeviceInfo.wDataBlockNum * sizeof(u8)); - if (DeviceInfo.MLCDevice) - memset(g_pReadCounter, 0, - DeviceInfo.wDataBlockNum * sizeof(u16)); -#if CMD_DMA - memset(g_pBTStartingCopy, 0, - DeviceInfo.wDataBlockNum * sizeof(u32)); - memset(g_pWearCounterCopy, 0, - DeviceInfo.wDataBlockNum * sizeof(u8)); - if (DeviceInfo.MLCDevice) - memset(g_pReadCounterCopy, 0, - DeviceInfo.wDataBlockNum * sizeof(u16)); -#endif - for (j = DeviceInfo.wSpectraStartBlock, i = 0; - j <= DeviceInfo.wSpectraEndBlock; - j++, i++) { - if (GLOB_LLD_Get_Bad_Block((u32)j)) - pbt[i] = (u32)(BAD_BLOCK | j); - } - } - - nand_dbg_print(NAND_DBG_WARN, "Erasing all blocks in the NAND\n"); - - for (j = DeviceInfo.wSpectraStartBlock, i = 0; - j <= DeviceInfo.wSpectraEndBlock; - j++, i++) { - if ((pbt[i] & BAD_BLOCK) != BAD_BLOCK) { - ret = GLOB_LLD_Erase_Block(j); - if (FAIL == ret) { - pbt[i] = (u32)(j); - MARK_BLOCK_AS_BAD(pbt[i]); - nand_dbg_print(NAND_DBG_WARN, - "NAND Program fail in %s, Line %d, " - "Function: %s, new Bad Block %d generated!\n", - __FILE__, __LINE__, __func__, (int)j); - } else { - pbt[i] = (u32)(SPARE_BLOCK | j); - } - } -#if CMD_DMA - pbtStartingCopy[i] = pbt[i]; -#endif - } - - g_wBlockTableOffset = 0; - for (i = 0; (i <= (DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock)) - && ((pbt[i] & BAD_BLOCK) == BAD_BLOCK); i++) - ; - if (i > (DeviceInfo.wSpectraEndBlock - DeviceInfo.wSpectraStartBlock)) { - printk(KERN_ERR "All blocks bad!\n"); - return FAIL; - } else { - g_wBlockTableIndex = pbt[i] & ~BAD_BLOCK; - if (i != BLOCK_TABLE_INDEX) { - tempNode = pbt[i]; - pbt[i] = pbt[BLOCK_TABLE_INDEX]; - pbt[BLOCK_TABLE_INDEX] = tempNode; - } - } - pbt[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK); - -#if CMD_DMA - pbtStartingCopy[BLOCK_TABLE_INDEX] &= (~SPARE_BLOCK); -#endif - - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - memset(g_pBTBlocks, 0xFF, - (1 + LAST_BT_ID - FIRST_BT_ID) * sizeof(u32)); - g_pBTBlocks[FIRST_BT_ID-FIRST_BT_ID] = g_wBlockTableIndex; - FTL_Write_Block_Table(FAIL); - - for (i = 0; i < CACHE_ITEM_NUM; i++) { - Cache.array[i].address = NAND_CACHE_INIT_ADDR; - Cache.array[i].use_cnt = 0; - Cache.array[i].changed = CLEAR; - } - -#if (RESTORE_CACHE_ON_CDMA_CHAIN_FAILURE && CMD_DMA) - memcpy((void *)&cache_start_copy, (void *)&Cache, - sizeof(struct flash_cache_tag)); -#endif - return PASS; -} - static int force_format_nand(void) { u32 i; @@ -3031,112 +2721,6 @@ static int FTL_Read_Block_Table(void) return wResult; } - -/*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& -* Function: FTL_Flash_Error_Handle -* Inputs: Pointer to data -* Page address -* Block address -* Outputs: PASS=0 / FAIL=1 -* Description: It handles any error occured during Spectra operation -*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ -static int FTL_Flash_Error_Handle(u8 *pData, u64 old_page_addr, - u64 blk_addr) -{ - u32 i; - int j; - u32 tmp_node, blk_node = BLK_FROM_ADDR(blk_addr); - u64 phy_addr; - int wErase = FAIL; - int wResult = FAIL; - u32 *pbt = (u32 *)g_pBlockTable; - - nand_dbg_print(NAND_DBG_TRACE, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - - if (ERR == GLOB_FTL_Garbage_Collection()) - return ERR; - - do { - for (i = DeviceInfo.wSpectraEndBlock - - DeviceInfo.wSpectraStartBlock; - i > 0; i--) { - if (IS_SPARE_BLOCK(i)) { - tmp_node = (u32)(BAD_BLOCK | - pbt[blk_node]); - pbt[blk_node] = (u32)(pbt[i] & - (~SPARE_BLOCK)); - pbt[i] = tmp_node; -#if CMD_DMA - p_BTableChangesDelta = - (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = - blk_node; - p_BTableChangesDelta->BT_Entry_Value = - pbt[blk_node]; - p_BTableChangesDelta->ValidFields = 0x0C; - - p_BTableChangesDelta = - (struct BTableChangesDelta *) - g_pBTDelta_Free; - g_pBTDelta_Free += - sizeof(struct BTableChangesDelta); - - p_BTableChangesDelta->ftl_cmd_cnt = - ftl_cmd_cnt; - p_BTableChangesDelta->BT_Index = i; - p_BTableChangesDelta->BT_Entry_Value = pbt[i]; - p_BTableChangesDelta->ValidFields = 0x0C; -#endif - wResult = PASS; - break; - } - } - - if (FAIL == wResult) { - if (FAIL == GLOB_FTL_Garbage_Collection()) - break; - else - continue; - } - - if (IN_PROGRESS_BLOCK_TABLE != g_cBlockTableStatus) { - g_cBlockTableStatus = IN_PROGRESS_BLOCK_TABLE; - FTL_Write_IN_Progress_Block_Table_Page(); - } - - phy_addr = FTL_Get_Physical_Block_Addr(blk_addr); - - for (j = 0; j < RETRY_TIMES; j++) { - if (PASS == wErase) { - if (FAIL == GLOB_FTL_Block_Erase(phy_addr)) { - MARK_BLOCK_AS_BAD(pbt[blk_node]); - break; - } - } - if (PASS == FTL_Cache_Update_Block(pData, - old_page_addr, - phy_addr)) { - wResult = PASS; - break; - } else { - wResult = FAIL; - wErase = PASS; - } - } - } while (FAIL == wResult); - - FTL_Write_Block_Table(FAIL); - - return wResult; -} - /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& * Function: FTL_Get_Page_Num * Inputs: Size in bytes -- cgit v1.2.3-59-g8ed1b From 466122df80e447883588ffcf9d21b88152934819 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 9 Aug 2010 23:56:38 +0200 Subject: Staging: batman-adv: Fix merge of linus tree Greg Kroah-Hartman merged Linus 2.6.36 tree in e9563355ac1175dd3440dc2ea5c28b27ed51a283 with his staging tree. Different parts of the merge conflicts were resolved incorrectly and may result in an abnormal behavior. Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/bat_sysfs.c | 4 ++++ drivers/staging/batman-adv/hard-interface.c | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/staging/batman-adv/bat_sysfs.c b/drivers/staging/batman-adv/bat_sysfs.c index b4a8d5eb64fa..05ca15a6c9f8 100644 --- a/drivers/staging/batman-adv/bat_sysfs.c +++ b/drivers/staging/batman-adv/bat_sysfs.c @@ -267,6 +267,10 @@ static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr, if (atomic_read(&bat_priv->log_level) == log_level_tmp) return count; + bat_info(net_dev, "Changing log level from: %i to: %li\n", + atomic_read(&bat_priv->log_level), + log_level_tmp); + atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp); return count; } diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 92c216a56885..f6345c465eb3 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -442,8 +442,6 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct bat_priv *bat_priv = netdev_priv(soft_device); struct batman_packet *batman_packet; struct batman_if *batman_if; - struct net_device_stats *stats; - struct rtnl_link_stats64 temp; int ret; skb = skb_share_check(skb, GFP_ATOMIC); @@ -479,12 +477,6 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, if (batman_if->if_status != IF_ACTIVE) goto err_free; - stats = (struct net_device_stats *)dev_get_stats(skb->dev, &temp); - if (stats) { - stats->rx_packets++; - stats->rx_bytes += skb->len; - } - batman_packet = (struct batman_packet *)skb->data; if (batman_packet->version != COMPAT_VERSION) { -- cgit v1.2.3-59-g8ed1b From 9abc10238e1df7ce81c58a441f65efd5e905b9e8 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:39 +0200 Subject: Staging: batman-adv: unify orig_hash_lock spinlock handling to avoid deadlocks The orig_hash_lock spinlock always has to be locked with IRQs being disabled to avoid deadlocks between code that is being executed in IRQ context and code that is being executed in non-IRQ context. Reported-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/originator.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/staging/batman-adv/originator.c b/drivers/staging/batman-adv/originator.c index 28bb627ffa13..de5a8c1a8104 100644 --- a/drivers/staging/batman-adv/originator.c +++ b/drivers/staging/batman-adv/originator.c @@ -391,11 +391,12 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) { struct orig_node *orig_node; + unsigned long flags; HASHIT(hashit); /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); while (hash_iterate(orig_hash, &hashit)) { orig_node = hashit.bucket->data; @@ -404,11 +405,11 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) goto err; } - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return 0; err: - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return -ENOMEM; } @@ -468,12 +469,13 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) { struct batman_if *batman_if_tmp; struct orig_node *orig_node; + unsigned long flags; HASHIT(hashit); int ret; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock(&orig_hash_lock); + spin_lock_irqsave(&orig_hash_lock, flags); while (hash_iterate(orig_hash, &hashit)) { orig_node = hashit.bucket->data; @@ -500,10 +502,10 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) rcu_read_unlock(); batman_if->if_num = -1; - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return 0; err: - spin_unlock(&orig_hash_lock); + spin_unlock_irqrestore(&orig_hash_lock, flags); return -ENOMEM; } -- cgit v1.2.3-59-g8ed1b From 13334d4875dbaeeb44e7905463f07e236f80311f Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:40 +0200 Subject: Staging: batman-adv: fix batman icmp originating from secondary interface If a batman icmp packet had to be routed over a secondary interface at the first hop, the mac address of that secondary interface would be written in the 'orig' field of the icmp packet. A node which is more than one hop away is not aware of the mac address because secondary interfaces are not flooded through the whole mesh and therefore can't send a reply. This patch always sends the mac address of the primary interface in the 'orig' field of the icmp packet. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/icmp_socket.c | 12 ++++++++---- drivers/staging/batman-adv/types.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/staging/batman-adv/icmp_socket.c b/drivers/staging/batman-adv/icmp_socket.c index fc3d32c12729..3ae7dd2d2d4d 100644 --- a/drivers/staging/batman-adv/icmp_socket.c +++ b/drivers/staging/batman-adv/icmp_socket.c @@ -67,6 +67,7 @@ static int bat_socket_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&socket_client->queue_list); socket_client->queue_len = 0; socket_client->index = i; + socket_client->bat_priv = inode->i_private; spin_lock_init(&socket_client->lock); init_waitqueue_head(&socket_client->queue_wait); @@ -151,9 +152,8 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf, static ssize_t bat_socket_write(struct file *file, const char __user *buff, size_t len, loff_t *off) { - /* FIXME: each orig_node->batman_if will be attached to a softif */ - struct bat_priv *bat_priv = netdev_priv(soft_device); struct socket_client *socket_client = file->private_data; + struct bat_priv *bat_priv = socket_client->bat_priv; struct icmp_packet_rr icmp_packet; struct orig_node *orig_node; struct batman_if *batman_if; @@ -168,6 +168,9 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, return -EINVAL; } + if (!bat_priv->primary_if) + return -EFAULT; + if (len >= sizeof(struct icmp_packet_rr)) packet_len = sizeof(struct icmp_packet_rr); @@ -223,7 +226,8 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (batman_if->if_status != IF_ACTIVE) goto dst_unreach; - memcpy(icmp_packet.orig, batman_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet.orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); if (packet_len == sizeof(struct icmp_packet_rr)) memcpy(icmp_packet.rr, batman_if->net_dev->dev_addr, ETH_ALEN); @@ -271,7 +275,7 @@ int bat_socket_setup(struct bat_priv *bat_priv) goto err; d = debugfs_create_file(ICMP_SOCKET, S_IFREG | S_IWUSR | S_IRUSR, - bat_priv->debug_dir, NULL, &fops); + bat_priv->debug_dir, bat_priv, &fops); if (d) goto err; diff --git a/drivers/staging/batman-adv/types.h b/drivers/staging/batman-adv/types.h index 21d0717afb09..9aa9d369c752 100644 --- a/drivers/staging/batman-adv/types.h +++ b/drivers/staging/batman-adv/types.h @@ -126,6 +126,7 @@ struct socket_client { unsigned char index; spinlock_t lock; wait_queue_head_t queue_wait; + struct bat_priv *bat_priv; }; struct socket_packet { -- cgit v1.2.3-59-g8ed1b From b7a23bce7bc9cac85eab1b958e922b2c472ab8fd Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:41 +0200 Subject: Staging: batman-adv: always reply batman icmp packets with primary mac When receiving an batman icmp echo request or in case of a time-to-live exceeded batman would reply with the mac address of the outgoing interface which might be a secondary interface. Because secondary interfaces are not globally known this might lead to confusion. Now, replies are sent with the mac address of the primary interface. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/routing.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/staging/batman-adv/routing.c b/drivers/staging/batman-adv/routing.c index 066cc9149bf1..032195e6de94 100644 --- a/drivers/staging/batman-adv/routing.c +++ b/drivers/staging/batman-adv/routing.c @@ -783,6 +783,8 @@ int recv_bat_packet(struct sk_buff *skb, static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) { + /* FIXME: each batman_if will be attached to a softif */ + struct bat_priv *bat_priv = netdev_priv(soft_device); struct orig_node *orig_node; struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; @@ -801,6 +803,9 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) return NET_RX_DROP; } + if (!bat_priv->primary_if) + return NET_RX_DROP; + /* answer echo request (ping) */ /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); @@ -830,7 +835,8 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) } memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); + memcpy(icmp_packet->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = ECHO_REPLY; icmp_packet->ttl = TTL; @@ -845,6 +851,8 @@ static int recv_my_icmp_packet(struct sk_buff *skb, size_t icmp_len) static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) { + /* FIXME: each batman_if will be attached to a softif */ + struct bat_priv *bat_priv = netdev_priv(soft_device); struct orig_node *orig_node; struct icmp_packet *icmp_packet; struct ethhdr *ethhdr; @@ -865,6 +873,9 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) return NET_RX_DROP; } + if (!bat_priv->primary_if) + return NET_RX_DROP; + /* get routing information */ spin_lock_irqsave(&orig_hash_lock, flags); orig_node = ((struct orig_node *) @@ -892,7 +903,8 @@ static int recv_icmp_ttl_exceeded(struct sk_buff *skb, size_t icmp_len) } memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, ethhdr->h_dest, ETH_ALEN); + memcpy(icmp_packet->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->ttl = TTL; -- cgit v1.2.3-59-g8ed1b From 51e21ae3d79e608022271f91166c84bd0e9fb8b8 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 9 Aug 2010 23:56:42 +0200 Subject: Staging: batman-adv: fix own mac address detection Earlier batman-adv versions would only create a batman_if struct after a corresponding interface had been activated by a user. Now each existing system interface has a batman_if struct and has to be checked by verifying the IF_ACTIVE flag. Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c index 2686019fe4e1..ef7c20ae7979 100644 --- a/drivers/staging/batman-adv/main.c +++ b/drivers/staging/batman-adv/main.c @@ -250,10 +250,13 @@ int choose_orig(void *data, int32_t size) int is_my_mac(uint8_t *addr) { struct batman_if *batman_if; + rcu_read_lock(); list_for_each_entry_rcu(batman_if, &if_list, list) { - if ((batman_if->net_dev) && - (compare_orig(batman_if->net_dev->dev_addr, addr))) { + if (batman_if->if_status != IF_ACTIVE) + continue; + + if (compare_orig(batman_if->net_dev->dev_addr, addr)) { rcu_read_unlock(); return 1; } -- cgit v1.2.3-59-g8ed1b From 1189f130f89b73eecb6117c0fc5e90abbcb7faa0 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 21 Aug 2010 14:18:08 +0200 Subject: Staging: batman-adv: Create batman_if only on register event We try to get all events for all net_devices to be able to add special sysfs folders for the batman-adv configuration. This also includes such events like NETDEV_POST_INIT which has no valid kobject according to v2.6.32-rc3-13-g7ffbe3f. This would create an oops in that situation. It is enough to create the batman_if only on NETDEV_REGISTER events because we will also receive those events for devices which already existed when we registered the notifier call. Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hard-interface.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index f6345c465eb3..892166b86dd8 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -393,15 +393,13 @@ static int hard_if_event(struct notifier_block *this, /* FIXME: each batman_if will be attached to a softif */ struct bat_priv *bat_priv = netdev_priv(soft_device); - if (!batman_if) - batman_if = hardif_add_interface(net_dev); + if (!batman_if && event == NETDEV_REGISTER) + batman_if = hardif_add_interface(net_dev); if (!batman_if) goto out; switch (event) { - case NETDEV_REGISTER: - break; case NETDEV_UP: hardif_activate_interface(soft_device, bat_priv, batman_if); break; -- cgit v1.2.3-59-g8ed1b From 51a00eaf6e008b60943af6ab68c17ac3622208dc Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 21 Aug 2010 14:18:09 +0200 Subject: Staging: batman-adv: Don't use net_dev after dev_put dev_put allows a device to be freed when all its references are dropped. After that we are not allowed to access that information anymore. Access to the data structure of a net_device must be surrounded a dev_hold and ended using dev_put. batman-adv adds a device to its own management structure in hardif_add_interface and will release it in hardif_remove_interface. Thus it must hold a reference all the time between those functions to prevent any access to the already released net_device structure. Reported-by: Tim Glaremin Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hard-interface.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index 892166b86dd8..d08491ed5455 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -194,8 +194,6 @@ static void hardif_activate_interface(struct net_device *net_dev, if (batman_if->if_status != IF_INACTIVE) return; - dev_hold(batman_if->net_dev); - update_mac_addresses(batman_if); batman_if->if_status = IF_TO_BE_ACTIVATED; @@ -222,8 +220,6 @@ static void hardif_deactivate_interface(struct net_device *net_dev, (batman_if->if_status != IF_TO_BE_ACTIVATED)) return; - dev_put(batman_if->net_dev); - batman_if->if_status = IF_INACTIVE; bat_info(net_dev, "Interface deactivated: %s\n", batman_if->dev); @@ -318,11 +314,13 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) if (ret != 1) goto out; + dev_hold(net_dev); + batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC); if (!batman_if) { pr_err("Can't add interface (%s): out of memory\n", net_dev->name); - goto out; + goto release_dev; } batman_if->dev = kstrdup(net_dev->name, GFP_ATOMIC); @@ -346,6 +344,8 @@ free_dev: kfree(batman_if->dev); free_if: kfree(batman_if); +release_dev: + dev_put(net_dev); out: return NULL; } @@ -374,6 +374,7 @@ static void hardif_remove_interface(struct batman_if *batman_if) batman_if->if_status = IF_TO_BE_REMOVED; list_del_rcu(&batman_if->list); sysfs_del_hardif(&batman_if->hardif_obj); + dev_put(batman_if->net_dev); call_rcu(&batman_if->rcu, hardif_free_interface); } -- cgit v1.2.3-59-g8ed1b From f86b9984250fa2b71ce36d4693a939a58579583b Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sat, 21 Aug 2010 14:18:10 +0200 Subject: Staging: batman-adv: Don't write in not allocated packet_buff Each net_device in a system will automatically managed as a possible batman_if and holds different informations like a buffer with a prepared originator messages. To reduce the memory usage, the packet_buff will only be allocated when the interface is really added/enabled for batman-adv. The function to update the hw address information inside the packet_buff just assumes that the packet_buff is always initialised and thus the kernel will just oops when we try to change the hw address of a not already fully enabled interface. We must always check if the packet_buff is allocated before we try to change information inside of it. Reported-by: Tim Glaremin Reported-by: Kazuki Shimada Signed-off-by: Sven Eckelmann Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hard-interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index d08491ed5455..baa8b05b9e8d 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -129,6 +129,9 @@ static bool hardif_is_iface_up(struct batman_if *batman_if) static void update_mac_addresses(struct batman_if *batman_if) { + if (!batman_if || !batman_if->packet_buff) + return; + addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr); memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig, @@ -334,6 +337,7 @@ static struct batman_if *hardif_add_interface(struct net_device *net_dev) batman_if->if_num = -1; batman_if->net_dev = net_dev; batman_if->if_status = IF_NOT_IN_USE; + batman_if->packet_buff = NULL; INIT_LIST_HEAD(&batman_if->list); check_known_mac_addr(batman_if->net_dev->dev_addr); -- cgit v1.2.3-59-g8ed1b From d49824c06778830c82906884b94d94354c3bbdc8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 23 Aug 2010 10:28:31 -0700 Subject: Staging: sep: remove driver It's currently stalled and the original submitter recommended that it just be dropped at this point in time due. Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/sep/Kconfig | 10 - drivers/staging/sep/Makefile | 2 - drivers/staging/sep/TODO | 8 - drivers/staging/sep/sep_dev.h | 110 -- drivers/staging/sep/sep_driver.c | 2742 ------------------------------ drivers/staging/sep/sep_driver_api.h | 425 ----- drivers/staging/sep/sep_driver_config.h | 225 --- drivers/staging/sep/sep_driver_hw_defs.h | 232 --- 10 files changed, 3757 deletions(-) delete mode 100644 drivers/staging/sep/Kconfig delete mode 100644 drivers/staging/sep/Makefile delete mode 100644 drivers/staging/sep/TODO delete mode 100644 drivers/staging/sep/sep_dev.h delete mode 100644 drivers/staging/sep/sep_driver.c delete mode 100644 drivers/staging/sep/sep_driver_api.h delete mode 100644 drivers/staging/sep/sep_driver_config.h delete mode 100644 drivers/staging/sep/sep_driver_hw_defs.h diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 4a7a7a7f11b6..335311a98fdc 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -113,8 +113,6 @@ source "drivers/staging/vme/Kconfig" source "drivers/staging/memrar/Kconfig" -source "drivers/staging/sep/Kconfig" - source "drivers/staging/iio/Kconfig" source "drivers/staging/zram/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ca5c03eb3ce3..e3f1e1b6095e 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_FB_UDL) += udlfb/ obj-$(CONFIG_HYPERV) += hv/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ -obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig deleted file mode 100644 index 0a9c39c7f2bd..000000000000 --- a/drivers/staging/sep/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DX_SEP - tristate "Discretix SEP driver" -# depends on MRST - depends on RAR_REGISTER && PCI - default y - help - Discretix SEP driver - - If unsure say M. The compiled module will be - called sep_driver.ko diff --git a/drivers/staging/sep/Makefile b/drivers/staging/sep/Makefile deleted file mode 100644 index 628d5f919414..000000000000 --- a/drivers/staging/sep/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_DX_SEP) := sep_driver.o - diff --git a/drivers/staging/sep/TODO b/drivers/staging/sep/TODO deleted file mode 100644 index ff0e931dab64..000000000000 --- a/drivers/staging/sep/TODO +++ /dev/null @@ -1,8 +0,0 @@ -Todo's so far (from Alan Cox) -- Fix firmware loading -- Get firmware into firmware git tree -- Review and tidy each algorithm function -- Check whether it can be plugged into any of the kernel crypto API - interfaces -- Do something about the magic shared memory interface and replace it - with something saner (in Linux terms) diff --git a/drivers/staging/sep/sep_dev.h b/drivers/staging/sep/sep_dev.h deleted file mode 100644 index 9200524bb64d..000000000000 --- a/drivers/staging/sep/sep_dev.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef __SEP_DEV_H__ -#define __SEP_DEV_H__ - -/* - * - * sep_dev.h - Security Processor Device Structures - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * CONTACTS: - * - * Alan Cox alan@linux.intel.com - * - */ - -struct sep_device { - /* pointer to pci dev */ - struct pci_dev *pdev; - - unsigned long in_use; - - /* address of the shared memory allocated during init for SEP driver - (coherent alloc) */ - void *shared_addr; - /* the physical address of the shared area */ - dma_addr_t shared_bus; - - /* restricted access region (coherent alloc) */ - dma_addr_t rar_bus; - void *rar_addr; - /* firmware regions: cache is at rar_addr */ - unsigned long cache_size; - - /* follows the cache */ - dma_addr_t resident_bus; - unsigned long resident_size; - void *resident_addr; - - /* start address of the access to the SEP registers from driver */ - void __iomem *reg_addr; - /* transaction counter that coordinates the transactions between SEP and HOST */ - unsigned long send_ct; - /* counter for the messages from sep */ - unsigned long reply_ct; - /* counter for the number of bytes allocated in the pool for the current - transaction */ - unsigned long data_pool_bytes_allocated; - - /* array of pointers to the pages that represent input data for the synchronic - DMA action */ - struct page **in_page_array; - - /* array of pointers to the pages that represent out data for the synchronic - DMA action */ - struct page **out_page_array; - - /* number of pages in the sep_in_page_array */ - unsigned long in_num_pages; - - /* number of pages in the sep_out_page_array */ - unsigned long out_num_pages; - - /* global data for every flow */ - struct sep_flow_context_t flows[SEP_DRIVER_NUM_FLOWS]; - - /* pointer to the workqueue that handles the flow done interrupts */ - struct workqueue_struct *flow_wq; - -}; - -static struct sep_device *sep_dev; - -static inline void sep_write_reg(struct sep_device *dev, int reg, u32 value) -{ - void __iomem *addr = dev->reg_addr + reg; - writel(value, addr); -} - -static inline u32 sep_read_reg(struct sep_device *dev, int reg) -{ - void __iomem *addr = dev->reg_addr + reg; - return readl(addr); -} - -/* wait for SRAM write complete(indirect write */ -static inline void sep_wait_sram_write(struct sep_device *dev) -{ - u32 reg_val; - do - reg_val = sep_read_reg(dev, HW_SRAM_DATA_READY_REG_ADDR); - while (!(reg_val & 1)); -} - - -#endif diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c deleted file mode 100644 index ecbde3467b1b..000000000000 --- a/drivers/staging/sep/sep_driver.c +++ /dev/null @@ -1,2742 +0,0 @@ -/* - * - * sep_driver.c - Security Processor Driver main group of functions - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sep_driver_hw_defs.h" -#include "sep_driver_config.h" -#include "sep_driver_api.h" -#include "sep_dev.h" - -#if SEP_DRIVER_ARM_DEBUG_MODE - -#define CRYS_SEP_ROM_length 0x4000 -#define CRYS_SEP_ROM_start_address 0x8000C000UL -#define CRYS_SEP_ROM_start_address_offset 0xC000UL -#define SEP_ROM_BANK_register 0x80008420UL -#define SEP_ROM_BANK_register_offset 0x8420UL -#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0x82000000 - -/* - * THESE 2 definitions are specific to the board - must be - * defined during integration - */ -#define SEP_RAR_IO_MEM_REGION_START_ADDRESS 0xFF0D0000 - -/* 2M size */ - -static void sep_load_rom_code(struct sep_device *sep) -{ - /* Index variables */ - unsigned long i, k, j; - u32 reg; - u32 error; - u32 warning; - - /* Loading ROM from SEP_ROM_image.h file */ - k = sizeof(CRYS_SEP_ROM); - - edbg("SEP Driver: DX_CC_TST_SepRomLoader start\n"); - - edbg("SEP Driver: k is %lu\n", k); - edbg("SEP Driver: sep->reg_addr is %p\n", sep->reg_addr); - edbg("SEP Driver: CRYS_SEP_ROM_start_address_offset is %p\n", CRYS_SEP_ROM_start_address_offset); - - for (i = 0; i < 4; i++) { - /* write bank */ - sep_write_reg(sep, SEP_ROM_BANK_register_offset, i); - - for (j = 0; j < CRYS_SEP_ROM_length / 4; j++) { - sep_write_reg(sep, CRYS_SEP_ROM_start_address_offset + 4 * j, CRYS_SEP_ROM[i * 0x1000 + j]); - - k = k - 4; - - if (k == 0) { - j = CRYS_SEP_ROM_length; - i = 4; - } - } - } - - /* reset the SEP */ - sep_write_reg(sep, HW_HOST_SEP_SW_RST_REG_ADDR, 0x1); - - /* poll for SEP ROM boot finish */ - do - reg = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!reg); - - edbg("SEP Driver: ROM polling ended\n"); - - switch (reg) { - case 0x1: - /* fatal error - read erro status from GPRO */ - error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - edbg("SEP Driver: ROM polling case 1\n"); - break; - case 0x4: - /* Cold boot ended successfully */ - case 0x8: - /* Warmboot ended successfully */ - case 0x10: - /* ColdWarm boot ended successfully */ - error = 0; - case 0x2: - /* Boot First Phase ended */ - warning = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - case 0x20: - edbg("SEP Driver: ROM polling case %d\n", reg); - break; - } - -} - -#else -static void sep_load_rom_code(struct sep_device *sep) { } -#endif /* SEP_DRIVER_ARM_DEBUG_MODE */ - - - -/*---------------------------------------- - DEFINES ------------------------------------------*/ - -#define BASE_ADDRESS_FOR_SYSTEM 0xfffc0000 -#define SEP_RAR_IO_MEM_REGION_SIZE 0x40000 - -/*-------------------------------------------- - GLOBAL variables ---------------------------------------------*/ - -/* debug messages level */ -static int debug; -module_param(debug, int , 0); -MODULE_PARM_DESC(debug, "Flag to enable SEP debug messages"); - -/* Keep this a single static object for now to keep the conversion easy */ - -static struct sep_device sep_instance; -static struct sep_device *sep_dev = &sep_instance; - -/* - mutex for the access to the internals of the sep driver -*/ -static DEFINE_MUTEX(sep_mutex); - - -/* wait queue head (event) of the driver */ -static DECLARE_WAIT_QUEUE_HEAD(sep_event); - -/** - * sep_load_firmware - copy firmware cache/resident - * @sep: device we are loading - * - * This functions copies the cache and resident from their source - * location into destination shared memory. - */ - -static int sep_load_firmware(struct sep_device *sep) -{ - const struct firmware *fw; - char *cache_name = "sep/cache.image.bin"; - char *res_name = "sep/resident.image.bin"; - int error; - - edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); - edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus); - - /* load cache */ - error = request_firmware(&fw, cache_name, &sep->pdev->dev); - if (error) { - edbg("SEP Driver:cant request cache fw\n"); - return error; - } - edbg("SEP Driver:cache %08Zx@%p\n", fw->size, (void *) fw->data); - - memcpy(sep->rar_addr, (void *)fw->data, fw->size); - sep->cache_size = fw->size; - release_firmware(fw); - - sep->resident_bus = sep->rar_bus + sep->cache_size; - sep->resident_addr = sep->rar_addr + sep->cache_size; - - /* load resident */ - error = request_firmware(&fw, res_name, &sep->pdev->dev); - if (error) { - edbg("SEP Driver:cant request res fw\n"); - return error; - } - edbg("sep: res %08Zx@%p\n", fw->size, (void *)fw->data); - - memcpy(sep->resident_addr, (void *) fw->data, fw->size); - sep->resident_size = fw->size; - release_firmware(fw); - - edbg("sep: resident v %p b %08llx cache v %p b %08llx\n", - sep->resident_addr, (unsigned long long)sep->resident_bus, - sep->rar_addr, (unsigned long long)sep->rar_bus); - return 0; -} - -MODULE_FIRMWARE("sep/cache.image.bin"); -MODULE_FIRMWARE("sep/resident.image.bin"); - -/** - * sep_map_and_alloc_shared_area - allocate shared block - * @sep: security processor - * @size: size of shared area - * - * Allocate a shared buffer in host memory that can be used by both the - * kernel and also the hardware interface via DMA. - */ - -static int sep_map_and_alloc_shared_area(struct sep_device *sep, - unsigned long size) -{ - /* shared_addr = ioremap_nocache(0xda00000,shared_area_size); */ - sep->shared_addr = dma_alloc_coherent(&sep->pdev->dev, size, - &sep->shared_bus, GFP_KERNEL); - - if (!sep->shared_addr) { - edbg("sep_driver :shared memory dma_alloc_coherent failed\n"); - return -ENOMEM; - } - /* set the bus address of the shared area */ - edbg("sep: shared_addr %ld bytes @%p (bus %08llx)\n", - size, sep->shared_addr, (unsigned long long)sep->shared_bus); - return 0; -} - -/** - * sep_unmap_and_free_shared_area - free shared block - * @sep: security processor - * - * Free the shared area allocated to the security processor. The - * processor must have finished with this and any final posted - * writes cleared before we do so. - */ -static void sep_unmap_and_free_shared_area(struct sep_device *sep, int size) -{ - dma_free_coherent(&sep->pdev->dev, size, - sep->shared_addr, sep->shared_bus); -} - -/** - * sep_shared_virt_to_bus - convert bus/virt addresses - * - * Returns the bus address inside the shared area according - * to the virtual address. - */ - -static dma_addr_t sep_shared_virt_to_bus(struct sep_device *sep, - void *virt_address) -{ - dma_addr_t pa = sep->shared_bus + (virt_address - sep->shared_addr); - edbg("sep: virt to bus b %08llx v %p\n", (unsigned long long) pa, - virt_address); - return pa; -} - -/** - * sep_shared_bus_to_virt - convert bus/virt addresses - * - * Returns virtual address inside the shared area according - * to the bus address. - */ - -static void *sep_shared_bus_to_virt(struct sep_device *sep, - dma_addr_t bus_address) -{ - return sep->shared_addr + (bus_address - sep->shared_bus); -} - - -/** - * sep_try_open - attempt to open a SEP device - * @sep: device to attempt to open - * - * Atomically attempt to get ownership of a SEP device. - * Returns 1 if the device was opened, 0 on failure. - */ - -static int sep_try_open(struct sep_device *sep) -{ - if (!test_and_set_bit(0, &sep->in_use)) - return 1; - return 0; -} - -/** - * sep_open - device open method - * @inode: inode of sep device - * @filp: file handle to sep device - * - * Open method for the SEP device. Called when userspace opens - * the SEP device node. Must also release the memory data pool - * allocations. - * - * Returns zero on success otherwise an error code. - */ - -static int sep_open(struct inode *inode, struct file *filp) -{ - if (sep_dev == NULL) - return -ENODEV; - - /* check the blocking mode */ - if (filp->f_flags & O_NDELAY) { - if (sep_try_open(sep_dev) == 0) - return -EAGAIN; - } else - if (wait_event_interruptible(sep_event, sep_try_open(sep_dev)) < 0) - return -EINTR; - - /* Bind to the device, we only have one which makes it easy */ - filp->private_data = sep_dev; - /* release data pool allocations */ - sep_dev->data_pool_bytes_allocated = 0; - return 0; -} - - -/** - * sep_release - close a SEP device - * @inode: inode of SEP device - * @filp: file handle being closed - * - * Called on the final close of a SEP device. As the open protects against - * multiple simultaenous opens that means this method is called when the - * final reference to the open handle is dropped. - */ - -static int sep_release(struct inode *inode, struct file *filp) -{ - struct sep_device *sep = filp->private_data; -#if 0 /*!SEP_DRIVER_POLLING_MODE */ - /* close IMR */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF); - /* release IRQ line */ - free_irq(SEP_DIRVER_IRQ_NUM, sep); - -#endif - /* Ensure any blocked open progresses */ - clear_bit(0, &sep->in_use); - wake_up(&sep_event); - return 0; -} - -/*--------------------------------------------------------------- - map function - this functions maps the message shared area ------------------------------------------------------------------*/ -static int sep_mmap(struct file *filp, struct vm_area_struct *vma) -{ - dma_addr_t bus_addr; - struct sep_device *sep = filp->private_data; - - dbg("-------->SEP Driver: mmap start\n"); - - /* check that the size of the mapped range is as the size of the message - shared area */ - if ((vma->vm_end - vma->vm_start) > SEP_DRIVER_MMMAP_AREA_SIZE) { - edbg("SEP Driver mmap requested size is more than allowed\n"); - printk(KERN_WARNING "SEP Driver mmap requested size is more than allowed\n"); - printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_end); - printk(KERN_WARNING "SEP Driver vma->vm_end is %08lx\n", vma->vm_start); - return -EAGAIN; - } - - edbg("SEP Driver:sep->shared_addr is %p\n", sep->shared_addr); - - /* get bus address */ - bus_addr = sep->shared_bus; - - edbg("SEP Driver: phys_addr is %08llx\n", (unsigned long long)bus_addr); - - if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - edbg("SEP Driver remap_page_range failed\n"); - printk(KERN_WARNING "SEP Driver remap_page_range failed\n"); - return -EAGAIN; - } - - dbg("SEP Driver:<-------- mmap end\n"); - - return 0; -} - - -/*----------------------------------------------- - poll function -*----------------------------------------------*/ -static unsigned int sep_poll(struct file *filp, poll_table * wait) -{ - unsigned long count; - unsigned int mask = 0; - unsigned long retval = 0; /* flow id */ - struct sep_device *sep = filp->private_data; - - dbg("---------->SEP Driver poll: start\n"); - - -#if SEP_DRIVER_POLLING_MODE - - while (sep->send_ct != (retval & 0x7FFFFFFF)) { - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); - - for (count = 0; count < 10 * 4; count += 4) - edbg("Poll Debug Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + count))); - } - - sep->reply_ct++; -#else - /* add the event to the polling wait table */ - poll_wait(filp, &sep_event, wait); - -#endif - - edbg("sep->send_ct is %lu\n", sep->send_ct); - edbg("sep->reply_ct is %lu\n", sep->reply_ct); - - /* check if the data is ready */ - if (sep->send_ct == sep->reply_ct) { - for (count = 0; count < 12 * 4; count += 4) - edbg("Sep Mesg Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + count))); - - for (count = 0; count < 10 * 4; count += 4) - edbg("Debug Data Word %lu of the message is %lu\n", count, *((unsigned long *) (sep->shared_addr + 0x1800 + count))); - - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR2_REG_ADDR); - edbg("retval is %lu\n", retval); - /* check if the this is sep reply or request */ - if (retval >> 31) { - edbg("SEP Driver: sep request in\n"); - /* request */ - mask |= POLLOUT | POLLWRNORM; - } else { - edbg("SEP Driver: sep reply in\n"); - mask |= POLLIN | POLLRDNORM; - } - } - dbg("SEP Driver:<-------- poll exit\n"); - return mask; -} - -/** - * sep_time_address - address in SEP memory of time - * @sep: SEP device we want the address from - * - * Return the address of the two dwords in memory used for time - * setting. - */ - -static u32 *sep_time_address(struct sep_device *sep) -{ - return sep->shared_addr + SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES; -} - -/** - * sep_set_time - set the SEP time - * @sep: the SEP we are setting the time for - * - * Calculates time and sets it at the predefined address. - * Called with the sep mutex held. - */ -static unsigned long sep_set_time(struct sep_device *sep) -{ - struct timeval time; - u32 *time_addr; /* address of time as seen by the kernel */ - - - dbg("sep:sep_set_time start\n"); - - do_gettimeofday(&time); - - /* set value in the SYSTEM MEMORY offset */ - time_addr = sep_time_address(sep); - - time_addr[0] = SEP_TIME_VAL_TOKEN; - time_addr[1] = time.tv_sec; - - edbg("SEP Driver:time.tv_sec is %lu\n", time.tv_sec); - edbg("SEP Driver:time_addr is %p\n", time_addr); - edbg("SEP Driver:sep->shared_addr is %p\n", sep->shared_addr); - - return time.tv_sec; -} - -/** - * sep_dump_message - dump the message that is pending - * @sep: sep device - * - * Dump out the message pending in the shared message area - */ - -static void sep_dump_message(struct sep_device *sep) -{ - int count; - for (count = 0; count < 12 * 4; count += 4) - edbg("Word %d of the message is %u\n", count, *((u32 *) (sep->shared_addr + count))); -} - -/** - * sep_send_command_handler - kick off a command - * @sep: sep being signalled - * - * This function raises interrupt to SEP that signals that is has a new - * command from the host - */ - -static void sep_send_command_handler(struct sep_device *sep) -{ - dbg("sep:sep_send_command_handler start\n"); - - mutex_lock(&sep_mutex); - sep_set_time(sep); - - /* FIXME: flush cache */ - flush_cache_all(); - - sep_dump_message(sep); - /* update counter */ - sep->send_ct++; - /* send interrupt to SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); - dbg("SEP Driver:<-------- sep_send_command_handler end\n"); - mutex_unlock(&sep_mutex); - return; -} - -/** - * sep_send_reply_command_handler - kick off a command reply - * @sep: sep being signalled - * - * This function raises interrupt to SEP that signals that is has a new - * command from the host - */ - -static void sep_send_reply_command_handler(struct sep_device *sep) -{ - dbg("sep:sep_send_reply_command_handler start\n"); - - /* flash cache */ - flush_cache_all(); - - sep_dump_message(sep); - - mutex_lock(&sep_mutex); - sep->send_ct++; /* update counter */ - /* send the interrupt to SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, sep->send_ct); - /* update both counters */ - sep->send_ct++; - sep->reply_ct++; - mutex_unlock(&sep_mutex); - dbg("sep: sep_send_reply_command_handler end\n"); -} - -/* - This function handles the allocate data pool memory request - This function returns calculates the bus address of the - allocated memory, and the offset of this area from the mapped address. - Therefore, the FVOs in user space can calculate the exact virtual - address of this allocated memory -*/ -static int sep_allocate_data_pool_memory_handler(struct sep_device *sep, - unsigned long arg) -{ - int error; - struct sep_driver_alloc_t command_args; - - dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* allocate memory */ - if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { - error = -ENOMEM; - goto end_function; - } - - /* set the virtual and bus address */ - command_args.offset = SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated; - command_args.phys_address = sep->shared_bus + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + sep->data_pool_bytes_allocated; - - /* write the memory back to the user space */ - error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* set the allocation */ - sep->data_pool_bytes_allocated += command_args.num_bytes; - -end_function: - dbg("SEP Driver:<-------- sep_allocate_data_pool_memory_handler end\n"); - return error; -} - -/* - This function handles write into allocated data pool command -*/ -static int sep_write_into_data_pool_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - void *virt_address; - unsigned long va; - unsigned long app_in_address; - unsigned long num_bytes; - void *data_pool_area_addr; - - dbg("SEP Driver:--------> sep_write_into_data_pool_handler start\n"); - - /* get the application address */ - error = get_user(app_in_address, &(((struct sep_driver_write_t *) arg)->app_address)); - if (error) - goto end_function; - - /* get the virtual kernel address address */ - error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address)); - if (error) - goto end_function; - virt_address = (void *)va; - - /* get the number of bytes */ - error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); - if (error) - goto end_function; - - /* calculate the start of the data pool */ - data_pool_area_addr = sep->shared_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; - - - /* check that the range of the virtual kernel address is correct */ - if (virt_address < data_pool_area_addr || virt_address > (data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES)) { - error = -EINVAL; - goto end_function; - } - /* copy the application data */ - error = copy_from_user(virt_address, (void *) app_in_address, num_bytes); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n"); - return error; -} - -/* - this function handles the read from data pool command -*/ -static int sep_read_from_data_pool_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - /* virtual address of dest application buffer */ - unsigned long app_out_address; - /* virtual address of the data pool */ - unsigned long va; - void *virt_address; - unsigned long num_bytes; - void *data_pool_area_addr; - - dbg("SEP Driver:--------> sep_read_from_data_pool_handler start\n"); - - /* get the application address */ - error = get_user(app_out_address, &(((struct sep_driver_write_t *) arg)->app_address)); - if (error) - goto end_function; - - /* get the virtual kernel address address */ - error = get_user(va, &(((struct sep_driver_write_t *) arg)->datapool_address)); - if (error) - goto end_function; - virt_address = (void *)va; - - /* get the number of bytes */ - error = get_user(num_bytes, &(((struct sep_driver_write_t *) arg)->num_bytes)); - if (error) - goto end_function; - - /* calculate the start of the data pool */ - data_pool_area_addr = sep->shared_addr + SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES; - - /* FIXME: These are incomplete all over the driver: what about + len - and when doing that also overflows */ - /* check that the range of the virtual kernel address is correct */ - if (virt_address < data_pool_area_addr || virt_address > data_pool_area_addr + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) { - error = -EINVAL; - goto end_function; - } - - /* copy the application data */ - error = copy_to_user((void *) app_out_address, virt_address, num_bytes); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n"); - return error; -} - -/* - This function releases all the application virtual buffer physical pages, - that were previously locked -*/ -static int sep_free_dma_pages(struct page **page_array_ptr, unsigned long num_pages, unsigned long dirtyFlag) -{ - unsigned long count; - - if (dirtyFlag) { - for (count = 0; count < num_pages; count++) { - /* the out array was written, therefore the data was changed */ - if (!PageReserved(page_array_ptr[count])) - SetPageDirty(page_array_ptr[count]); - page_cache_release(page_array_ptr[count]); - } - } else { - /* free in pages - the data was only read, therefore no update was done - on those pages */ - for (count = 0; count < num_pages; count++) - page_cache_release(page_array_ptr[count]); - } - - if (page_array_ptr) - /* free the array */ - kfree(page_array_ptr); - - return 0; -} - -/* - This function locks all the physical pages of the kernel virtual buffer - and construct a basic lli array, where each entry holds the physical - page address and the size that application data holds in this physical pages -*/ -static int sep_lock_kernel_pages(struct sep_device *sep, - unsigned long kernel_virt_addr, - unsigned long data_size, - unsigned long *num_pages_ptr, - struct sep_lli_entry_t **lli_array_ptr, - struct page ***page_array_ptr) -{ - int error = 0; - /* the the page of the end address of the user space buffer */ - unsigned long end_page; - /* the page of the start address of the user space buffer */ - unsigned long start_page; - /* the range in pages */ - unsigned long num_pages; - struct sep_lli_entry_t *lli_array; - /* next kernel address to map */ - unsigned long next_kernel_address; - unsigned long count; - - dbg("SEP Driver:--------> sep_lock_kernel_pages start\n"); - - /* set start and end pages and num pages */ - end_page = (kernel_virt_addr + data_size - 1) >> PAGE_SHIFT; - start_page = kernel_virt_addr >> PAGE_SHIFT; - num_pages = end_page - start_page + 1; - - edbg("SEP Driver: kernel_virt_addr is %08lx\n", kernel_virt_addr); - edbg("SEP Driver: data_size is %lu\n", data_size); - edbg("SEP Driver: start_page is %lx\n", start_page); - edbg("SEP Driver: end_page is %lx\n", end_page); - edbg("SEP Driver: num_pages is %lu\n", num_pages); - - lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); - if (!lli_array) { - edbg("SEP Driver: kmalloc for lli_array failed\n"); - error = -ENOMEM; - goto end_function; - } - - /* set the start address of the first page - app data may start not at - the beginning of the page */ - lli_array[0].physical_address = (unsigned long) virt_to_phys((unsigned long *) kernel_virt_addr); - - /* check that not all the data is in the first page only */ - if ((PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK))) >= data_size) - lli_array[0].block_size = data_size; - else - lli_array[0].block_size = PAGE_SIZE - (kernel_virt_addr & (~PAGE_MASK)); - - /* debug print */ - dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size); - - /* advance the address to the start of the next page */ - next_kernel_address = (kernel_virt_addr & PAGE_MASK) + PAGE_SIZE; - - /* go from the second page to the prev before last */ - for (count = 1; count < (num_pages - 1); count++) { - lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); - lli_array[count].block_size = PAGE_SIZE; - - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); - next_kernel_address += PAGE_SIZE; - } - - /* if more then 1 pages locked - then update for the last page size needed */ - if (num_pages > 1) { - /* update the address of the last page */ - lli_array[count].physical_address = (unsigned long) virt_to_phys((unsigned long *) next_kernel_address); - - /* set the size of the last page */ - lli_array[count].block_size = (kernel_virt_addr + data_size) & (~PAGE_MASK); - - if (lli_array[count].block_size == 0) { - dbg("app_virt_addr is %08lx\n", kernel_virt_addr); - dbg("data_size is %lu\n", data_size); - while (1); - } - - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); - } - /* set output params */ - *lli_array_ptr = lli_array; - *num_pages_ptr = num_pages; - *page_array_ptr = 0; -end_function: - dbg("SEP Driver:<-------- sep_lock_kernel_pages end\n"); - return 0; -} - -/* - This function locks all the physical pages of the application virtual buffer - and construct a basic lli array, where each entry holds the physical page - address and the size that application data holds in this physical pages -*/ -static int sep_lock_user_pages(struct sep_device *sep, - unsigned long app_virt_addr, - unsigned long data_size, - unsigned long *num_pages_ptr, - struct sep_lli_entry_t **lli_array_ptr, - struct page ***page_array_ptr) -{ - int error = 0; - /* the the page of the end address of the user space buffer */ - unsigned long end_page; - /* the page of the start address of the user space buffer */ - unsigned long start_page; - /* the range in pages */ - unsigned long num_pages; - struct page **page_array; - struct sep_lli_entry_t *lli_array; - unsigned long count; - int result; - - dbg("SEP Driver:--------> sep_lock_user_pages start\n"); - - /* set start and end pages and num pages */ - end_page = (app_virt_addr + data_size - 1) >> PAGE_SHIFT; - start_page = app_virt_addr >> PAGE_SHIFT; - num_pages = end_page - start_page + 1; - - edbg("SEP Driver: app_virt_addr is %08lx\n", app_virt_addr); - edbg("SEP Driver: data_size is %lu\n", data_size); - edbg("SEP Driver: start_page is %lu\n", start_page); - edbg("SEP Driver: end_page is %lu\n", end_page); - edbg("SEP Driver: num_pages is %lu\n", num_pages); - - /* allocate array of pages structure pointers */ - page_array = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); - if (!page_array) { - edbg("SEP Driver: kmalloc for page_array failed\n"); - - error = -ENOMEM; - goto end_function; - } - - lli_array = kmalloc(sizeof(struct sep_lli_entry_t) * num_pages, GFP_ATOMIC); - if (!lli_array) { - edbg("SEP Driver: kmalloc for lli_array failed\n"); - - error = -ENOMEM; - goto end_function_with_error1; - } - - /* convert the application virtual address into a set of physical */ - down_read(¤t->mm->mmap_sem); - result = get_user_pages(current, current->mm, app_virt_addr, num_pages, 1, 0, page_array, 0); - up_read(¤t->mm->mmap_sem); - - /* check the number of pages locked - if not all then exit with error */ - if (result != num_pages) { - dbg("SEP Driver: not all pages locked by get_user_pages\n"); - - error = -ENOMEM; - goto end_function_with_error2; - } - - /* flush the cache */ - for (count = 0; count < num_pages; count++) - flush_dcache_page(page_array[count]); - - /* set the start address of the first page - app data may start not at - the beginning of the page */ - lli_array[0].physical_address = ((unsigned long) page_to_phys(page_array[0])) + (app_virt_addr & (~PAGE_MASK)); - - /* check that not all the data is in the first page only */ - if ((PAGE_SIZE - (app_virt_addr & (~PAGE_MASK))) >= data_size) - lli_array[0].block_size = data_size; - else - lli_array[0].block_size = PAGE_SIZE - (app_virt_addr & (~PAGE_MASK)); - - /* debug print */ - dbg("lli_array[0].physical_address is %08lx, lli_array[0].block_size is %lu\n", lli_array[0].physical_address, lli_array[0].block_size); - - /* go from the second page to the prev before last */ - for (count = 1; count < (num_pages - 1); count++) { - lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); - lli_array[count].block_size = PAGE_SIZE; - - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", count, lli_array[count].physical_address, count, lli_array[count].block_size); - } - - /* if more then 1 pages locked - then update for the last page size needed */ - if (num_pages > 1) { - /* update the address of the last page */ - lli_array[count].physical_address = (unsigned long) page_to_phys(page_array[count]); - - /* set the size of the last page */ - lli_array[count].block_size = (app_virt_addr + data_size) & (~PAGE_MASK); - - if (lli_array[count].block_size == 0) { - dbg("app_virt_addr is %08lx\n", app_virt_addr); - dbg("data_size is %lu\n", data_size); - while (1); - } - edbg("lli_array[%lu].physical_address is %08lx, lli_array[%lu].block_size is %lu\n", - count, lli_array[count].physical_address, - count, lli_array[count].block_size); - } - - /* set output params */ - *lli_array_ptr = lli_array; - *num_pages_ptr = num_pages; - *page_array_ptr = page_array; - goto end_function; - -end_function_with_error2: - /* release the cache */ - for (count = 0; count < num_pages; count++) - page_cache_release(page_array[count]); - kfree(lli_array); -end_function_with_error1: - kfree(page_array); -end_function: - dbg("SEP Driver:<-------- sep_lock_user_pages end\n"); - return 0; -} - - -/* - this function calculates the size of data that can be inserted into the lli - table from this array the condition is that either the table is full - (all etnries are entered), or there are no more entries in the lli array -*/ -static unsigned long sep_calculate_lli_table_max_size(struct sep_lli_entry_t *lli_in_array_ptr, unsigned long num_array_entries) -{ - unsigned long table_data_size = 0; - unsigned long counter; - - /* calculate the data in the out lli table if till we fill the whole - table or till the data has ended */ - for (counter = 0; (counter < (SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP - 1)) && (counter < num_array_entries); counter++) - table_data_size += lli_in_array_ptr[counter].block_size; - return table_data_size; -} - -/* - this functions builds ont lli table from the lli_array according to - the given size of data -*/ -static void sep_build_lli_table(struct sep_lli_entry_t *lli_array_ptr, struct sep_lli_entry_t *lli_table_ptr, unsigned long *num_processed_entries_ptr, unsigned long *num_table_entries_ptr, unsigned long table_data_size) -{ - unsigned long curr_table_data_size; - /* counter of lli array entry */ - unsigned long array_counter; - - dbg("SEP Driver:--------> sep_build_lli_table start\n"); - - /* init currrent table data size and lli array entry counter */ - curr_table_data_size = 0; - array_counter = 0; - *num_table_entries_ptr = 1; - - edbg("SEP Driver:table_data_size is %lu\n", table_data_size); - - /* fill the table till table size reaches the needed amount */ - while (curr_table_data_size < table_data_size) { - /* update the number of entries in table */ - (*num_table_entries_ptr)++; - - lli_table_ptr->physical_address = lli_array_ptr[array_counter].physical_address; - lli_table_ptr->block_size = lli_array_ptr[array_counter].block_size; - curr_table_data_size += lli_table_ptr->block_size; - - edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr); - edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - - /* check for overflow of the table data */ - if (curr_table_data_size > table_data_size) { - edbg("SEP Driver:curr_table_data_size > table_data_size\n"); - - /* update the size of block in the table */ - lli_table_ptr->block_size -= (curr_table_data_size - table_data_size); - - /* update the physical address in the lli array */ - lli_array_ptr[array_counter].physical_address += lli_table_ptr->block_size; - - /* update the block size left in the lli array */ - lli_array_ptr[array_counter].block_size = (curr_table_data_size - table_data_size); - } else - /* advance to the next entry in the lli_array */ - array_counter++; - - edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - - /* move to the next entry in table */ - lli_table_ptr++; - } - - /* set the info entry to default */ - lli_table_ptr->physical_address = 0xffffffff; - lli_table_ptr->block_size = 0; - - edbg("SEP Driver:lli_table_ptr is %08lx\n", (unsigned long) lli_table_ptr); - edbg("SEP Driver:lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - edbg("SEP Driver:lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - - /* set the output parameter */ - *num_processed_entries_ptr += array_counter; - - edbg("SEP Driver:*num_processed_entries_ptr is %lu\n", *num_processed_entries_ptr); - dbg("SEP Driver:<-------- sep_build_lli_table end\n"); - return; -} - -/* - this function goes over the list of the print created tables and - prints all the data -*/ -static void sep_debug_print_lli_tables(struct sep_device *sep, struct sep_lli_entry_t *lli_table_ptr, unsigned long num_table_entries, unsigned long table_data_size) -{ - unsigned long table_count; - unsigned long entries_count; - - dbg("SEP Driver:--------> sep_debug_print_lli_tables start\n"); - - table_count = 1; - while ((unsigned long) lli_table_ptr != 0xffffffff) { - edbg("SEP Driver: lli table %08lx, table_data_size is %lu\n", table_count, table_data_size); - edbg("SEP Driver: num_table_entries is %lu\n", num_table_entries); - - /* print entries of the table (without info entry) */ - for (entries_count = 0; entries_count < num_table_entries; entries_count++, lli_table_ptr++) { - edbg("SEP Driver:lli_table_ptr address is %08lx\n", (unsigned long) lli_table_ptr); - edbg("SEP Driver:phys address is %08lx block size is %lu\n", lli_table_ptr->physical_address, lli_table_ptr->block_size); - } - - /* point to the info entry */ - lli_table_ptr--; - - edbg("SEP Driver:phys lli_table_ptr->block_size is %lu\n", lli_table_ptr->block_size); - edbg("SEP Driver:phys lli_table_ptr->physical_address is %08lx\n", lli_table_ptr->physical_address); - - - table_data_size = lli_table_ptr->block_size & 0xffffff; - num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff; - lli_table_ptr = (struct sep_lli_entry_t *) - (lli_table_ptr->physical_address); - - edbg("SEP Driver:phys table_data_size is %lu num_table_entries is %lu lli_table_ptr is%lu\n", table_data_size, num_table_entries, (unsigned long) lli_table_ptr); - - if ((unsigned long) lli_table_ptr != 0xffffffff) - lli_table_ptr = (struct sep_lli_entry_t *) sep_shared_bus_to_virt(sep, (unsigned long) lli_table_ptr); - - table_count++; - } - dbg("SEP Driver:<-------- sep_debug_print_lli_tables end\n"); -} - - -/* - This function prepares only input DMA table for synhronic symmetric - operations (HASH) -*/ -static int sep_prepare_input_dma_table(struct sep_device *sep, - unsigned long app_virt_addr, - unsigned long data_size, - unsigned long block_size, - unsigned long *lli_table_ptr, - unsigned long *num_entries_ptr, - unsigned long *table_data_size_ptr, - bool isKernelVirtualAddress) -{ - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_entry_ptr; - /* array of pointers ot page */ - struct sep_lli_entry_t *lli_array_ptr; - /* points to the first entry to be processed in the lli_in_array */ - unsigned long current_entry; - /* num entries in the virtual buffer */ - unsigned long sep_lli_entries; - /* lli table pointer */ - struct sep_lli_entry_t *in_lli_table_ptr; - /* the total data in one table */ - unsigned long table_data_size; - /* number of entries in lli table */ - unsigned long num_entries_in_table; - /* next table address */ - void *lli_table_alloc_addr; - unsigned long result; - - dbg("SEP Driver:--------> sep_prepare_input_dma_table start\n"); - - edbg("SEP Driver:data_size is %lu\n", data_size); - edbg("SEP Driver:block_size is %lu\n", block_size); - - /* initialize the pages pointers */ - sep->in_page_array = 0; - sep->in_num_pages = 0; - - if (data_size == 0) { - /* special case - created 2 entries table with zero data */ - in_lli_table_ptr = (struct sep_lli_entry_t *) (sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES); - /* FIXME: Should the entry below not be for _bus */ - in_lli_table_ptr->physical_address = (unsigned long)sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - in_lli_table_ptr->block_size = 0; - - in_lli_table_ptr++; - in_lli_table_ptr->physical_address = 0xFFFFFFFF; - in_lli_table_ptr->block_size = 0; - - *lli_table_ptr = sep->shared_bus + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - *num_entries_ptr = 2; - *table_data_size_ptr = 0; - - goto end_function; - } - - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) - /* lock the pages of the kernel buffer and translate them to pages */ - result = sep_lock_kernel_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array); - else - /* lock the pages of the user buffer and translate them to pages */ - result = sep_lock_user_pages(sep, app_virt_addr, data_size, &sep->in_num_pages, &lli_array_ptr, &sep->in_page_array); - - if (result) - return result; - - edbg("SEP Driver:output sep->in_num_pages is %lu\n", sep->in_num_pages); - - current_entry = 0; - info_entry_ptr = 0; - sep_lli_entries = sep->in_num_pages; - - /* initiate to point after the message area */ - lli_table_alloc_addr = sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - - /* loop till all the entries in in array are not processed */ - while (current_entry < sep_lli_entries) { - /* set the new input and output tables */ - in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - - /* calculate the maximum size of data for input table */ - table_data_size = sep_calculate_lli_table_max_size(&lli_array_ptr[current_entry], (sep_lli_entries - current_entry)); - - /* now calculate the table size so that it will be module block size */ - table_data_size = (table_data_size / block_size) * block_size; - - edbg("SEP Driver:output table_data_size is %lu\n", table_data_size); - - /* construct input lli table */ - sep_build_lli_table(&lli_array_ptr[current_entry], in_lli_table_ptr, ¤t_entry, &num_entries_in_table, table_data_size); - - if (info_entry_ptr == 0) { - /* set the output parameters to physical addresses */ - *lli_table_ptr = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - *num_entries_ptr = num_entries_in_table; - *table_data_size_ptr = table_data_size; - - edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_ptr); - } else { - /* update the info entry of the previous in table */ - info_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - info_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); - } - - /* save the pointer to the info entry of the current tables */ - info_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; - } - - /* print input tables */ - sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) - sep_shared_bus_to_virt(sep, *lli_table_ptr), *num_entries_ptr, *table_data_size_ptr); - - /* the array of the pages */ - kfree(lli_array_ptr); -end_function: - dbg("SEP Driver:<-------- sep_prepare_input_dma_table end\n"); - return 0; - -} - -/* - This function creates the input and output dma tables for - symmetric operations (AES/DES) according to the block size from LLI arays -*/ -static int sep_construct_dma_tables_from_lli(struct sep_device *sep, - struct sep_lli_entry_t *lli_in_array, - unsigned long sep_in_lli_entries, - struct sep_lli_entry_t *lli_out_array, - unsigned long sep_out_lli_entries, - unsigned long block_size, unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr) -{ - /* points to the area where next lli table can be allocated: keep void * - as there is pointer scaling to fix otherwise */ - void *lli_table_alloc_addr; - /* input lli table */ - struct sep_lli_entry_t *in_lli_table_ptr; - /* output lli table */ - struct sep_lli_entry_t *out_lli_table_ptr; - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_in_entry_ptr; - /* pointer to the info entry of the table - the last entry */ - struct sep_lli_entry_t *info_out_entry_ptr; - /* points to the first entry to be processed in the lli_in_array */ - unsigned long current_in_entry; - /* points to the first entry to be processed in the lli_out_array */ - unsigned long current_out_entry; - /* max size of the input table */ - unsigned long in_table_data_size; - /* max size of the output table */ - unsigned long out_table_data_size; - /* flag te signifies if this is the first tables build from the arrays */ - unsigned long first_table_flag; - /* the data size that should be in table */ - unsigned long table_data_size; - /* number of etnries in the input table */ - unsigned long num_entries_in_table; - /* number of etnries in the output table */ - unsigned long num_entries_out_table; - - dbg("SEP Driver:--------> sep_construct_dma_tables_from_lli start\n"); - - /* initiate to pint after the message area */ - lli_table_alloc_addr = sep->shared_addr + SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES; - - current_in_entry = 0; - current_out_entry = 0; - first_table_flag = 1; - info_in_entry_ptr = 0; - info_out_entry_ptr = 0; - - /* loop till all the entries in in array are not processed */ - while (current_in_entry < sep_in_lli_entries) { - /* set the new input and output tables */ - in_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - - /* set the first output tables */ - out_lli_table_ptr = (struct sep_lli_entry_t *) lli_table_alloc_addr; - - lli_table_alloc_addr += sizeof(struct sep_lli_entry_t) * SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP; - - /* calculate the maximum size of data for input table */ - in_table_data_size = sep_calculate_lli_table_max_size(&lli_in_array[current_in_entry], (sep_in_lli_entries - current_in_entry)); - - /* calculate the maximum size of data for output table */ - out_table_data_size = sep_calculate_lli_table_max_size(&lli_out_array[current_out_entry], (sep_out_lli_entries - current_out_entry)); - - edbg("SEP Driver:in_table_data_size is %lu\n", in_table_data_size); - edbg("SEP Driver:out_table_data_size is %lu\n", out_table_data_size); - - /* check where the data is smallest */ - table_data_size = in_table_data_size; - if (table_data_size > out_table_data_size) - table_data_size = out_table_data_size; - - /* now calculate the table size so that it will be module block size */ - table_data_size = (table_data_size / block_size) * block_size; - - dbg("SEP Driver:table_data_size is %lu\n", table_data_size); - - /* construct input lli table */ - sep_build_lli_table(&lli_in_array[current_in_entry], in_lli_table_ptr, ¤t_in_entry, &num_entries_in_table, table_data_size); - - /* construct output lli table */ - sep_build_lli_table(&lli_out_array[current_out_entry], out_lli_table_ptr, ¤t_out_entry, &num_entries_out_table, table_data_size); - - /* if info entry is null - this is the first table built */ - if (info_in_entry_ptr == 0) { - /* set the output parameters to physical addresses */ - *lli_table_in_ptr = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - *in_num_entries_ptr = num_entries_in_table; - *lli_table_out_ptr = sep_shared_virt_to_bus(sep, out_lli_table_ptr); - *out_num_entries_ptr = num_entries_out_table; - *table_data_size_ptr = table_data_size; - - edbg("SEP Driver:output lli_table_in_ptr is %08lx\n", *lli_table_in_ptr); - edbg("SEP Driver:output lli_table_out_ptr is %08lx\n", *lli_table_out_ptr); - } else { - /* update the info entry of the previous in table */ - info_in_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, in_lli_table_ptr); - info_in_entry_ptr->block_size = ((num_entries_in_table) << 24) | (table_data_size); - - /* update the info entry of the previous in table */ - info_out_entry_ptr->physical_address = sep_shared_virt_to_bus(sep, out_lli_table_ptr); - info_out_entry_ptr->block_size = ((num_entries_out_table) << 24) | (table_data_size); - } - - /* save the pointer to the info entry of the current tables */ - info_in_entry_ptr = in_lli_table_ptr + num_entries_in_table - 1; - info_out_entry_ptr = out_lli_table_ptr + num_entries_out_table - 1; - - edbg("SEP Driver:output num_entries_out_table is %lu\n", (unsigned long) num_entries_out_table); - edbg("SEP Driver:output info_in_entry_ptr is %lu\n", (unsigned long) info_in_entry_ptr); - edbg("SEP Driver:output info_out_entry_ptr is %lu\n", (unsigned long) info_out_entry_ptr); - } - - /* print input tables */ - sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) - sep_shared_bus_to_virt(sep, *lli_table_in_ptr), *in_num_entries_ptr, *table_data_size_ptr); - /* print output tables */ - sep_debug_print_lli_tables(sep, (struct sep_lli_entry_t *) - sep_shared_bus_to_virt(sep, *lli_table_out_ptr), *out_num_entries_ptr, *table_data_size_ptr); - dbg("SEP Driver:<-------- sep_construct_dma_tables_from_lli end\n"); - return 0; -} - - -/* - This function builds input and output DMA tables for synhronic - symmetric operations (AES, DES). It also checks that each table - is of the modular block size -*/ -static int sep_prepare_input_output_dma_table(struct sep_device *sep, - unsigned long app_virt_in_addr, - unsigned long app_virt_out_addr, - unsigned long data_size, - unsigned long block_size, - unsigned long *lli_table_in_ptr, unsigned long *lli_table_out_ptr, unsigned long *in_num_entries_ptr, unsigned long *out_num_entries_ptr, unsigned long *table_data_size_ptr, bool isKernelVirtualAddress) -{ - /* array of pointers of page */ - struct sep_lli_entry_t *lli_in_array; - /* array of pointers of page */ - struct sep_lli_entry_t *lli_out_array; - int result = 0; - - dbg("SEP Driver:--------> sep_prepare_input_output_dma_table start\n"); - - /* initialize the pages pointers */ - sep->in_page_array = 0; - sep->out_page_array = 0; - - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) { - /* lock the pages of the kernel buffer and translate them to pages */ - result = sep_lock_kernel_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array); - if (result) { - edbg("SEP Driver: sep_lock_kernel_pages for input virtual buffer failed\n"); - goto end_function; - } - } else { - /* lock the pages of the user buffer and translate them to pages */ - result = sep_lock_user_pages(sep, app_virt_in_addr, data_size, &sep->in_num_pages, &lli_in_array, &sep->in_page_array); - if (result) { - edbg("SEP Driver: sep_lock_user_pages for input virtual buffer failed\n"); - goto end_function; - } - } - - if (isKernelVirtualAddress == true) { - result = sep_lock_kernel_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array); - if (result) { - edbg("SEP Driver: sep_lock_kernel_pages for output virtual buffer failed\n"); - goto end_function_with_error1; - } - } else { - result = sep_lock_user_pages(sep, app_virt_out_addr, data_size, &sep->out_num_pages, &lli_out_array, &sep->out_page_array); - if (result) { - edbg("SEP Driver: sep_lock_user_pages for output virtual buffer failed\n"); - goto end_function_with_error1; - } - } - edbg("sep->in_num_pages is %lu\n", sep->in_num_pages); - edbg("sep->out_num_pages is %lu\n", sep->out_num_pages); - edbg("SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); - - - /* call the fucntion that creates table from the lli arrays */ - result = sep_construct_dma_tables_from_lli(sep, lli_in_array, sep->in_num_pages, lli_out_array, sep->out_num_pages, block_size, lli_table_in_ptr, lli_table_out_ptr, in_num_entries_ptr, out_num_entries_ptr, table_data_size_ptr); - if (result) { - edbg("SEP Driver: sep_construct_dma_tables_from_lli failed\n"); - goto end_function_with_error2; - } - - /* fall through - free the lli entry arrays */ - dbg("in_num_entries_ptr is %08lx\n", *in_num_entries_ptr); - dbg("out_num_entries_ptr is %08lx\n", *out_num_entries_ptr); - dbg("table_data_size_ptr is %08lx\n", *table_data_size_ptr); -end_function_with_error2: - kfree(lli_out_array); -end_function_with_error1: - kfree(lli_in_array); -end_function: - dbg("SEP Driver:<-------- sep_prepare_input_output_dma_table end result = %d\n", (int) result); - return result; - -} - -/* - this function handles tha request for creation of the DMA table - for the synchronic symmetric operations (AES,DES) -*/ -static int sep_create_sync_dma_tables_handler(struct sep_device *sep, - unsigned long arg) -{ - int error; - /* command arguments */ - struct sep_driver_build_sync_table_t command_args; - - dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - edbg("app_in_address is %08lx\n", command_args.app_in_address); - edbg("app_out_address is %08lx\n", command_args.app_out_address); - edbg("data_size is %lu\n", command_args.data_in_size); - edbg("block_size is %lu\n", command_args.block_size); - - /* check if we need to build only input table or input/output */ - if (command_args.app_out_address) - /* prepare input and output tables */ - error = sep_prepare_input_output_dma_table(sep, - command_args.app_in_address, - command_args.app_out_address, - command_args.data_in_size, - command_args.block_size, - &command_args.in_table_address, - &command_args.out_table_address, &command_args.in_table_num_entries, &command_args.out_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress); - else - /* prepare input tables */ - error = sep_prepare_input_dma_table(sep, - command_args.app_in_address, - command_args.data_in_size, command_args.block_size, &command_args.in_table_address, &command_args.in_table_num_entries, &command_args.table_data_size, command_args.isKernelVirtualAddress); - - if (error) - goto end_function; - /* copy to user */ - if (copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_build_sync_table_t))) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_create_sync_dma_tables_handler end\n"); - return error; -} - -/* - this function handles the request for freeing dma table for synhronic actions -*/ -static int sep_free_dma_table_data_handler(struct sep_device *sep) -{ - dbg("SEP Driver:--------> sep_free_dma_table_data_handler start\n"); - - /* free input pages array */ - sep_free_dma_pages(sep->in_page_array, sep->in_num_pages, 0); - - /* free output pages array if needed */ - if (sep->out_page_array) - sep_free_dma_pages(sep->out_page_array, sep->out_num_pages, 1); - - /* reset all the values */ - sep->in_page_array = 0; - sep->out_page_array = 0; - sep->in_num_pages = 0; - sep->out_num_pages = 0; - dbg("SEP Driver:<-------- sep_free_dma_table_data_handler end\n"); - return 0; -} - -/* - this function find a space for the new flow dma table -*/ -static int sep_find_free_flow_dma_table_space(struct sep_device *sep, - unsigned long **table_address_ptr) -{ - int error = 0; - /* pointer to the id field of the flow dma table */ - unsigned long *start_table_ptr; - /* Do not make start_addr unsigned long * unless fixing the offset - computations ! */ - void *flow_dma_area_start_addr; - unsigned long *flow_dma_area_end_addr; - /* maximum table size in words */ - unsigned long table_size_in_words; - - /* find the start address of the flow DMA table area */ - flow_dma_area_start_addr = sep->shared_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES; - - /* set end address of the flow table area */ - flow_dma_area_end_addr = flow_dma_area_start_addr + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES; - - /* set table size in words */ - table_size_in_words = SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE * (sizeof(struct sep_lli_entry_t) / sizeof(long)) + 2; - - /* set the pointer to the start address of DMA area */ - start_table_ptr = flow_dma_area_start_addr; - - /* find the space for the next table */ - while (((*start_table_ptr & 0x7FFFFFFF) != 0) && start_table_ptr < flow_dma_area_end_addr) - start_table_ptr += table_size_in_words; - - /* check if we reached the end of floa tables area */ - if (start_table_ptr >= flow_dma_area_end_addr) - error = -1; - else - *table_address_ptr = start_table_ptr; - - return error; -} - -/* - This function creates one DMA table for flow and returns its data, - and pointer to its info entry -*/ -static int sep_prepare_one_flow_dma_table(struct sep_device *sep, - unsigned long virt_buff_addr, - unsigned long virt_buff_size, - struct sep_lli_entry_t *table_data, - struct sep_lli_entry_t **info_entry_ptr, - struct sep_flow_context_t *flow_data_ptr, - bool isKernelVirtualAddress) -{ - int error; - /* the range in pages */ - unsigned long lli_array_size; - struct sep_lli_entry_t *lli_array; - struct sep_lli_entry_t *flow_dma_table_entry_ptr; - unsigned long *start_dma_table_ptr; - /* total table data counter */ - unsigned long dma_table_data_count; - /* pointer that will keep the pointer to the pages of the virtual buffer */ - struct page **page_array_ptr; - unsigned long entry_count; - - /* find the space for the new table */ - error = sep_find_free_flow_dma_table_space(sep, &start_dma_table_ptr); - if (error) - goto end_function; - - /* check if the pages are in Kernel Virtual Address layout */ - if (isKernelVirtualAddress == true) - /* lock kernel buffer in the memory */ - error = sep_lock_kernel_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); - else - /* lock user buffer in the memory */ - error = sep_lock_user_pages(sep, virt_buff_addr, virt_buff_size, &lli_array_size, &lli_array, &page_array_ptr); - - if (error) - goto end_function; - - /* set the pointer to page array at the beginning of table - this table is - now considered taken */ - *start_dma_table_ptr = lli_array_size; - - /* point to the place of the pages pointers of the table */ - start_dma_table_ptr++; - - /* set the pages pointer */ - *start_dma_table_ptr = (unsigned long) page_array_ptr; - - /* set the pointer to the first entry */ - flow_dma_table_entry_ptr = (struct sep_lli_entry_t *) (++start_dma_table_ptr); - - /* now create the entries for table */ - for (dma_table_data_count = entry_count = 0; entry_count < lli_array_size; entry_count++) { - flow_dma_table_entry_ptr->physical_address = lli_array[entry_count].physical_address; - - flow_dma_table_entry_ptr->block_size = lli_array[entry_count].block_size; - - /* set the total data of a table */ - dma_table_data_count += lli_array[entry_count].block_size; - - flow_dma_table_entry_ptr++; - } - - /* set the physical address */ - table_data->physical_address = virt_to_phys(start_dma_table_ptr); - - /* set the num_entries and total data size */ - table_data->block_size = ((lli_array_size + 1) << SEP_NUM_ENTRIES_OFFSET_IN_BITS) | (dma_table_data_count); - - /* set the info entry */ - flow_dma_table_entry_ptr->physical_address = 0xffffffff; - flow_dma_table_entry_ptr->block_size = 0; - - /* set the pointer to info entry */ - *info_entry_ptr = flow_dma_table_entry_ptr; - - /* the array of the lli entries */ - kfree(lli_array); -end_function: - return error; -} - - - -/* - This function creates a list of tables for flow and returns the data for - the first and last tables of the list -*/ -static int sep_prepare_flow_dma_tables(struct sep_device *sep, - unsigned long num_virtual_buffers, - unsigned long first_buff_addr, struct sep_flow_context_t *flow_data_ptr, struct sep_lli_entry_t *first_table_data_ptr, struct sep_lli_entry_t *last_table_data_ptr, bool isKernelVirtualAddress) -{ - int error; - unsigned long virt_buff_addr; - unsigned long virt_buff_size; - struct sep_lli_entry_t table_data; - struct sep_lli_entry_t *info_entry_ptr; - struct sep_lli_entry_t *prev_info_entry_ptr; - unsigned long i; - - /* init vars */ - error = 0; - prev_info_entry_ptr = 0; - - /* init the first table to default */ - table_data.physical_address = 0xffffffff; - first_table_data_ptr->physical_address = 0xffffffff; - table_data.block_size = 0; - - for (i = 0; i < num_virtual_buffers; i++) { - /* get the virtual buffer address */ - error = get_user(virt_buff_addr, &first_buff_addr); - if (error) - goto end_function; - - /* get the virtual buffer size */ - first_buff_addr++; - error = get_user(virt_buff_size, &first_buff_addr); - if (error) - goto end_function; - - /* advance the address to point to the next pair of address|size */ - first_buff_addr++; - - /* now prepare the one flow LLI table from the data */ - error = sep_prepare_one_flow_dma_table(sep, virt_buff_addr, virt_buff_size, &table_data, &info_entry_ptr, flow_data_ptr, isKernelVirtualAddress); - if (error) - goto end_function; - - if (i == 0) { - /* if this is the first table - save it to return to the user - application */ - *first_table_data_ptr = table_data; - - /* set the pointer to info entry */ - prev_info_entry_ptr = info_entry_ptr; - } else { - /* not first table - the previous table info entry should - be updated */ - prev_info_entry_ptr->block_size = (0x1 << SEP_INT_FLAG_OFFSET_IN_BITS) | (table_data.block_size); - - /* set the pointer to info entry */ - prev_info_entry_ptr = info_entry_ptr; - } - } - - /* set the last table data */ - *last_table_data_ptr = table_data; -end_function: - return error; -} - -/* - this function goes over all the flow tables connected to the given - table and deallocate them -*/ -static void sep_deallocated_flow_tables(struct sep_lli_entry_t *first_table_ptr) -{ - /* id pointer */ - unsigned long *table_ptr; - /* end address of the flow dma area */ - unsigned long num_entries; - unsigned long num_pages; - struct page **pages_ptr; - /* maximum table size in words */ - struct sep_lli_entry_t *info_entry_ptr; - - /* set the pointer to the first table */ - table_ptr = (unsigned long *) first_table_ptr->physical_address; - - /* set the num of entries */ - num_entries = (first_table_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) - & SEP_NUM_ENTRIES_MASK; - - /* go over all the connected tables */ - while (*table_ptr != 0xffffffff) { - /* get number of pages */ - num_pages = *(table_ptr - 2); - - /* get the pointer to the pages */ - pages_ptr = (struct page **) (*(table_ptr - 1)); - - /* free the pages */ - sep_free_dma_pages(pages_ptr, num_pages, 1); - - /* goto to the info entry */ - info_entry_ptr = ((struct sep_lli_entry_t *) table_ptr) + (num_entries - 1); - - table_ptr = (unsigned long *) info_entry_ptr->physical_address; - num_entries = (info_entry_ptr->block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; - } - - return; -} - -/** - * sep_find_flow_context - find a flow - * @sep: the SEP we are working with - * @flow_id: flow identifier - * - * Returns a pointer the matching flow, or NULL if the flow does not - * exist. - */ - -static struct sep_flow_context_t *sep_find_flow_context(struct sep_device *sep, - unsigned long flow_id) -{ - int count; - /* - * always search for flow with id default first - in case we - * already started working on the flow there can be no situation - * when 2 flows are with default flag - */ - for (count = 0; count < SEP_DRIVER_NUM_FLOWS; count++) { - if (sep->flows[count].flow_id == flow_id) - return &sep->flows[count]; - } - return NULL; -} - - -/* - this function handles the request to create the DMA tables for flow -*/ -static int sep_create_flow_dma_tables_handler(struct sep_device *sep, - unsigned long arg) -{ - int error = -ENOENT; - struct sep_driver_build_flow_table_t command_args; - /* first table - output */ - struct sep_lli_entry_t first_table_data; - /* dma table data */ - struct sep_lli_entry_t last_table_data; - /* pointer to the info entry of the previuos DMA table */ - struct sep_lli_entry_t *prev_info_entry_ptr; - /* pointer to the flow data strucutre */ - struct sep_flow_context_t *flow_context_ptr; - - dbg("SEP Driver:--------> sep_create_flow_dma_tables_handler start\n"); - - /* init variables */ - prev_info_entry_ptr = 0; - first_table_data.physical_address = 0xffffffff; - - /* find the free structure for flow data */ - error = -EINVAL; - flow_context_ptr = sep_find_flow_context(sep, SEP_FREE_FLOW_ID); - if (flow_context_ptr == NULL) - goto end_function; - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* create flow tables */ - error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress); - if (error) - goto end_function_with_error; - - /* check if flow is static */ - if (!command_args.flow_type) - /* point the info entry of the last to the info entry of the first */ - last_table_data = first_table_data; - - /* set output params */ - command_args.first_table_addr = first_table_data.physical_address; - command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK); - command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t)); - if (error) { - error = -EFAULT; - goto end_function_with_error; - } - - /* all the flow created - update the flow entry with temp id */ - flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID; - - /* set the processing tables data in the context */ - if (command_args.input_output_flag == SEP_DRIVER_IN_FLAG) - flow_context_ptr->input_tables_in_process = first_table_data; - else - flow_context_ptr->output_tables_in_process = first_table_data; - - goto end_function; - -end_function_with_error: - /* free the allocated tables */ - sep_deallocated_flow_tables(&first_table_data); -end_function: - dbg("SEP Driver:<-------- sep_create_flow_dma_tables_handler end\n"); - return error; -} - -/* - this function handles add tables to flow -*/ -static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - unsigned long num_entries; - struct sep_driver_add_flow_table_t command_args; - struct sep_flow_context_t *flow_context_ptr; - /* first dma table data */ - struct sep_lli_entry_t first_table_data; - /* last dma table data */ - struct sep_lli_entry_t last_table_data; - /* pointer to the info entry of the current DMA table */ - struct sep_lli_entry_t *info_entry_ptr; - - dbg("SEP Driver:--------> sep_add_flow_tables_handler start\n"); - - /* get input parameters */ - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* find the flow structure for the flow id */ - flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id); - if (flow_context_ptr == NULL) - goto end_function; - - /* prepare the flow dma tables */ - error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress); - if (error) - goto end_function_with_error; - - /* now check if there is already an existing add table for this flow */ - if (command_args.inputOutputFlag == SEP_DRIVER_IN_FLAG) { - /* this buffer was for input buffers */ - if (flow_context_ptr->input_tables_flag) { - /* add table already exists - add the new tables to the end - of the previous */ - num_entries = (flow_context_ptr->last_input_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; - - info_entry_ptr = (struct sep_lli_entry_t *) - (flow_context_ptr->last_input_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1))); - - /* connect to list of tables */ - *info_entry_ptr = first_table_data; - - /* set the first table data */ - first_table_data = flow_context_ptr->first_input_table; - } else { - /* set the input flag */ - flow_context_ptr->input_tables_flag = 1; - - /* set the first table data */ - flow_context_ptr->first_input_table = first_table_data; - } - /* set the last table data */ - flow_context_ptr->last_input_table = last_table_data; - } else { /* this is output tables */ - - /* this buffer was for input buffers */ - if (flow_context_ptr->output_tables_flag) { - /* add table already exists - add the new tables to - the end of the previous */ - num_entries = (flow_context_ptr->last_output_table.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK; - - info_entry_ptr = (struct sep_lli_entry_t *) - (flow_context_ptr->last_output_table.physical_address + (sizeof(struct sep_lli_entry_t) * (num_entries - 1))); - - /* connect to list of tables */ - *info_entry_ptr = first_table_data; - - /* set the first table data */ - first_table_data = flow_context_ptr->first_output_table; - } else { - /* set the input flag */ - flow_context_ptr->output_tables_flag = 1; - - /* set the first table data */ - flow_context_ptr->first_output_table = first_table_data; - } - /* set the last table data */ - flow_context_ptr->last_output_table = last_table_data; - } - - /* set output params */ - command_args.first_table_addr = first_table_data.physical_address; - command_args.first_table_num_entries = ((first_table_data.block_size >> SEP_NUM_ENTRIES_OFFSET_IN_BITS) & SEP_NUM_ENTRIES_MASK); - command_args.first_table_data_size = (first_table_data.block_size & SEP_TABLE_DATA_SIZE_MASK); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t)); - if (error) - error = -EFAULT; -end_function_with_error: - /* free the allocated tables */ - sep_deallocated_flow_tables(&first_table_data); -end_function: - dbg("SEP Driver:<-------- sep_add_flow_tables_handler end\n"); - return error; -} - -/* - this function add the flow add message to the specific flow -*/ -static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - struct sep_driver_add_message_t command_args; - struct sep_flow_context_t *flow_context_ptr; - - dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - /* check input */ - if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) { - error = -ENOMEM; - goto end_function; - } - - /* find the flow context */ - flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id); - if (flow_context_ptr == NULL) - goto end_function; - - /* copy the message into context */ - flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes; - error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n"); - return error; -} - - -/* - this function returns the bus and virtual addresses of the static pool -*/ -static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - struct sep_driver_static_pool_addr_t command_args; - - dbg("SEP Driver:--------> sep_get_static_pool_addr_handler start\n"); - - /*prepare the output parameters in the struct */ - command_args.physical_static_address = sep->shared_bus + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; - command_args.virtual_static_address = (unsigned long)sep->shared_addr + SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES; - - edbg("SEP Driver:bus_static_address is %08lx, virtual_static_address %08lx\n", command_args.physical_static_address, command_args.virtual_static_address); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t)); - if (error) - error = -EFAULT; - dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n"); - return error; -} - -/* - this address gets the offset of the physical address from the start - of the mapped area -*/ -static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsigned long arg) -{ - int error; - struct sep_driver_get_mapped_offset_t command_args; - - dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n"); - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - - if (command_args.physical_address < sep->shared_bus) { - error = -EINVAL; - goto end_function; - } - - /*prepare the output parameters in the struct */ - command_args.offset = command_args.physical_address - sep->shared_bus; - - edbg("SEP Driver:bus_address is %08lx, offset is %lu\n", command_args.physical_address, command_args.offset); - - /* send the parameters to user application */ - error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t)); - if (error) - error = -EFAULT; -end_function: - dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n"); - return error; -} - - -/* - ? -*/ -static int sep_start_handler(struct sep_device *sep) -{ - unsigned long reg_val; - unsigned long error = 0; - - dbg("SEP Driver:--------> sep_start_handler start\n"); - - /* wait in polling for message from SEP */ - do - reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!reg_val); - - /* check the value */ - if (reg_val == 0x1) - /* fatal error - read error status from GPRO */ - error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - dbg("SEP Driver:<-------- sep_start_handler end\n"); - return error; -} - -/* - this function handles the request for SEP initialization -*/ -static int sep_init_handler(struct sep_device *sep, unsigned long arg) -{ - unsigned long message_word; - unsigned long *message_ptr; - struct sep_driver_init_t command_args; - unsigned long counter; - unsigned long error; - unsigned long reg_val; - - dbg("SEP Driver:--------> sep_init_handler start\n"); - error = 0; - - error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t)); - if (error) { - error = -EFAULT; - goto end_function; - } - dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user\n"); - - /* PATCH - configure the DMA to single -burst instead of multi-burst */ - /*sep_configure_dma_burst(); */ - - dbg("SEP Driver:--------> sep_init_handler - finished sep_configure_dma_burst \n"); - - message_ptr = (unsigned long *) command_args.message_addr; - - /* set the base address of the SRAM */ - sep_write_reg(sep, HW_SRAM_ADDR_REG_ADDR, HW_CC_SRAM_BASE_ADDRESS); - - for (counter = 0; counter < command_args.message_size_in_words; counter++, message_ptr++) { - get_user(message_word, message_ptr); - /* write data to SRAM */ - sep_write_reg(sep, HW_SRAM_DATA_REG_ADDR, message_word); - edbg("SEP Driver:message_word is %lu\n", message_word); - /* wait for write complete */ - sep_wait_sram_write(sep); - } - dbg("SEP Driver:--------> sep_init_handler - finished getting messages from user space\n"); - /* signal SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x1); - - do - reg_val = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); - while (!(reg_val & 0xFFFFFFFD)); - - dbg("SEP Driver:--------> sep_init_handler - finished waiting for reg_val & 0xFFFFFFFD \n"); - - /* check the value */ - if (reg_val == 0x1) { - edbg("SEP Driver:init failed\n"); - - error = sep_read_reg(sep, 0x8060); - edbg("SEP Driver:sw monitor is %lu\n", error); - - /* fatal error - read erro status from GPRO */ - error = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR0_REG_ADDR); - edbg("SEP Driver:error is %lu\n", error); - } -end_function: - dbg("SEP Driver:<-------- sep_init_handler end\n"); - return error; - -} - -/* - this function handles the request cache and resident reallocation -*/ -static int sep_realloc_cache_resident_handler(struct sep_device *sep, - unsigned long arg) -{ - struct sep_driver_realloc_cache_resident_t command_args; - int error; - - /* copy cache and resident to the their intended locations */ - error = sep_load_firmware(sep); - if (error) - return error; - - command_args.new_base_addr = sep->shared_bus; - - /* find the new base address according to the lowest address between - cache, resident and shared area */ - if (sep->resident_bus < command_args.new_base_addr) - command_args.new_base_addr = sep->resident_bus; - if (sep->rar_bus < command_args.new_base_addr) - command_args.new_base_addr = sep->rar_bus; - - /* set the return parameters */ - command_args.new_cache_addr = sep->rar_bus; - command_args.new_resident_addr = sep->resident_bus; - - /* set the new shared area */ - command_args.new_shared_area_addr = sep->shared_bus; - - edbg("SEP Driver:command_args.new_shared_addr is %08llx\n", command_args.new_shared_area_addr); - edbg("SEP Driver:command_args.new_base_addr is %08llx\n", command_args.new_base_addr); - edbg("SEP Driver:command_args.new_resident_addr is %08llx\n", command_args.new_resident_addr); - edbg("SEP Driver:command_args.new_rar_addr is %08llx\n", command_args.new_cache_addr); - - /* return to user */ - if (copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_realloc_cache_resident_t))) - return -EFAULT; - return 0; -} - -/** - * sep_get_time_handler - time request from user space - * @sep: sep we are to set the time for - * @arg: pointer to user space arg buffer - * - * This function reports back the time and the address in the SEP - * shared buffer at which it has been placed. (Do we really need this!!!) - */ - -static int sep_get_time_handler(struct sep_device *sep, unsigned long arg) -{ - struct sep_driver_get_time_t command_args; - - mutex_lock(&sep_mutex); - command_args.time_value = sep_set_time(sep); - command_args.time_physical_address = (unsigned long)sep_time_address(sep); - mutex_unlock(&sep_mutex); - if (copy_to_user((void __user *)arg, - &command_args, sizeof(struct sep_driver_get_time_t))) - return -EFAULT; - return 0; - -} - -/* - This API handles the end transaction request -*/ -static int sep_end_transaction_handler(struct sep_device *sep, unsigned long arg) -{ - dbg("SEP Driver:--------> sep_end_transaction_handler start\n"); - -#if 0 /*!SEP_DRIVER_POLLING_MODE */ - /* close IMR */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, 0x7FFF); - - /* release IRQ line */ - free_irq(SEP_DIRVER_IRQ_NUM, sep); - - /* lock the sep mutex */ - mutex_unlock(&sep_mutex); -#endif - - dbg("SEP Driver:<-------- sep_end_transaction_handler end\n"); - - return 0; -} - - -/** - * sep_set_flow_id_handler - handle flow setting - * @sep: the SEP we are configuring - * @flow_id: the flow we are setting - * - * This function handler the set flow id command - */ -static int sep_set_flow_id_handler(struct sep_device *sep, - unsigned long flow_id) -{ - int error = 0; - struct sep_flow_context_t *flow_data_ptr; - - /* find the flow data structure that was just used for creating new flow - - its id should be default */ - - mutex_lock(&sep_mutex); - flow_data_ptr = sep_find_flow_context(sep, SEP_TEMP_FLOW_ID); - if (flow_data_ptr) - flow_data_ptr->flow_id = flow_id; /* set flow id */ - else - error = -EINVAL; - mutex_unlock(&sep_mutex); - return error; -} - -static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - int error = 0; - struct sep_device *sep = filp->private_data; - - dbg("------------>SEP Driver: ioctl start\n"); - - edbg("SEP Driver: cmd is %x\n", cmd); - - switch (cmd) { - case SEP_IOCSENDSEPCOMMAND: - /* send command to SEP */ - sep_send_command_handler(sep); - edbg("SEP Driver: after sep_send_command_handler\n"); - break; - case SEP_IOCSENDSEPRPLYCOMMAND: - /* send reply command to SEP */ - sep_send_reply_command_handler(sep); - break; - case SEP_IOCALLOCDATAPOLL: - /* allocate data pool */ - error = sep_allocate_data_pool_memory_handler(sep, arg); - break; - case SEP_IOCWRITEDATAPOLL: - /* write data into memory pool */ - error = sep_write_into_data_pool_handler(sep, arg); - break; - case SEP_IOCREADDATAPOLL: - /* read data from data pool into application memory */ - error = sep_read_from_data_pool_handler(sep, arg); - break; - case SEP_IOCCREATESYMDMATABLE: - /* create dma table for synhronic operation */ - error = sep_create_sync_dma_tables_handler(sep, arg); - break; - case SEP_IOCCREATEFLOWDMATABLE: - /* create flow dma tables */ - error = sep_create_flow_dma_tables_handler(sep, arg); - break; - case SEP_IOCFREEDMATABLEDATA: - /* free the pages */ - error = sep_free_dma_table_data_handler(sep); - break; - case SEP_IOCSETFLOWID: - /* set flow id */ - error = sep_set_flow_id_handler(sep, (unsigned long)arg); - break; - case SEP_IOCADDFLOWTABLE: - /* add tables to the dynamic flow */ - error = sep_add_flow_tables_handler(sep, arg); - break; - case SEP_IOCADDFLOWMESSAGE: - /* add message of add tables to flow */ - error = sep_add_flow_tables_message_handler(sep, arg); - break; - case SEP_IOCSEPSTART: - /* start command to sep */ - error = sep_start_handler(sep); - break; - case SEP_IOCSEPINIT: - /* init command to sep */ - error = sep_init_handler(sep, arg); - break; - case SEP_IOCGETSTATICPOOLADDR: - /* get the physical and virtual addresses of the static pool */ - error = sep_get_static_pool_addr_handler(sep, arg); - break; - case SEP_IOCENDTRANSACTION: - error = sep_end_transaction_handler(sep, arg); - break; - case SEP_IOCREALLOCCACHERES: - error = sep_realloc_cache_resident_handler(sep, arg); - break; - case SEP_IOCGETMAPPEDADDROFFSET: - error = sep_get_physical_mapped_offset_handler(sep, arg); - break; - case SEP_IOCGETIME: - error = sep_get_time_handler(sep, arg); - break; - default: - error = -ENOTTY; - break; - } - dbg("SEP Driver:<-------- ioctl end\n"); - return error; -} - - - -#if !SEP_DRIVER_POLLING_MODE - -/* handler for flow done interrupt */ - -static void sep_flow_done_handler(struct work_struct *work) -{ - struct sep_flow_context_t *flow_data_ptr; - - /* obtain the mutex */ - mutex_lock(&sep_mutex); - - /* get the pointer to context */ - flow_data_ptr = (struct sep_flow_context_t *) work; - - /* free all the current input tables in sep */ - sep_deallocated_flow_tables(&flow_data_ptr->input_tables_in_process); - - /* free all the current tables output tables in SEP (if needed) */ - if (flow_data_ptr->output_tables_in_process.physical_address != 0xffffffff) - sep_deallocated_flow_tables(&flow_data_ptr->output_tables_in_process); - - /* check if we have additional tables to be sent to SEP only input - flag may be checked */ - if (flow_data_ptr->input_tables_flag) { - /* copy the message to the shared RAM and signal SEP */ - memcpy((void *) flow_data_ptr->message, (void *) sep->shared_addr, flow_data_ptr->message_size_in_bytes); - - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR2_REG_ADDR, 0x2); - } - mutex_unlock(&sep_mutex); -} -/* - interrupt handler function -*/ -static irqreturn_t sep_inthandler(int irq, void *dev_id) -{ - irqreturn_t int_error; - unsigned long reg_val; - unsigned long flow_id; - struct sep_flow_context_t *flow_context_ptr; - struct sep_device *sep = dev_id; - - int_error = IRQ_HANDLED; - - /* read the IRR register to check if this is SEP interrupt */ - reg_val = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); - edbg("SEP Interrupt - reg is %08lx\n", reg_val); - - /* check if this is the flow interrupt */ - if (0 /*reg_val & (0x1 << 11) */ ) { - /* read GPRO to find out the which flow is done */ - flow_id = sep_read_reg(sep, HW_HOST_IRR_REG_ADDR); - - /* find the contex of the flow */ - flow_context_ptr = sep_find_flow_context(sep, flow_id >> 28); - if (flow_context_ptr == NULL) - goto end_function_with_error; - - /* queue the work */ - INIT_WORK(&flow_context_ptr->flow_wq, sep_flow_done_handler); - queue_work(sep->flow_wq, &flow_context_ptr->flow_wq); - - } else { - /* check if this is reply interrupt from SEP */ - if (reg_val & (0x1 << 13)) { - /* update the counter of reply messages */ - sep->reply_ct++; - /* wake up the waiting process */ - wake_up(&sep_event); - } else { - int_error = IRQ_NONE; - goto end_function; - } - } -end_function_with_error: - /* clear the interrupt */ - sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, reg_val); -end_function: - return int_error; -} - -#endif - - - -#if 0 - -static void sep_wait_busy(struct sep_device *sep) -{ - u32 reg; - - do { - reg = sep_read_reg(sep, HW_HOST_SEP_BUSY_REG_ADDR); - } while (reg); -} - -/* - PATCH for configuring the DMA to single burst instead of multi-burst -*/ -static void sep_configure_dma_burst(struct sep_device *sep) -{ -#define HW_AHB_RD_WR_BURSTS_REG_ADDR 0x0E10UL - - dbg("SEP Driver:<-------- sep_configure_dma_burst start \n"); - - /* request access to registers from SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x2); - - dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (write reg) \n"); - - sep_wait_busy(sep); - - dbg("SEP Driver:<-------- sep_configure_dma_burst finished request access to registers from SEP (while(revVal) wait loop) \n"); - - /* set the DMA burst register to single burst */ - sep_write_reg(sep, HW_AHB_RD_WR_BURSTS_REG_ADDR, 0x0UL); - - /* release the sep busy */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR0_REG_ADDR, 0x0UL); - sep_wait_busy(sep); - - dbg("SEP Driver:<-------- sep_configure_dma_burst done \n"); - -} - -#endif - -/* - Function that is activated on the successful probe of the SEP device -*/ -static int __devinit sep_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int error = 0; - struct sep_device *sep; - int counter; - int size; /* size of memory for allocation */ - - edbg("Sep pci probe starting\n"); - if (sep_dev != NULL) { - dev_warn(&pdev->dev, "only one SEP supported.\n"); - return -EBUSY; - } - - /* enable the device */ - error = pci_enable_device(pdev); - if (error) { - edbg("error enabling pci device\n"); - goto end_function; - } - - /* set the pci dev pointer */ - sep_dev = &sep_instance; - sep = &sep_instance; - - edbg("sep->shared_addr = %p\n", sep->shared_addr); - /* transaction counter that coordinates the transactions between SEP - and HOST */ - sep->send_ct = 0; - /* counter for the messages from sep */ - sep->reply_ct = 0; - /* counter for the number of bytes allocated in the pool - for the current transaction */ - sep->data_pool_bytes_allocated = 0; - - /* calculate the total size for allocation */ - size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + - SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES; - - /* allocate the shared area */ - if (sep_map_and_alloc_shared_area(sep, size)) { - error = -ENOMEM; - /* allocation failed */ - goto end_function_error; - } - /* now set the memory regions */ -#if (SEP_DRIVER_RECONFIG_MESSAGE_AREA == 1) - /* Note: this test section will need moving before it could ever - work as the registers are not yet mapped ! */ - /* send the new SHARED MESSAGE AREA to the SEP */ - sep_write_reg(sep, HW_HOST_HOST_SEP_GPR1_REG_ADDR, sep->shared_bus); - - /* poll for SEP response */ - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - while (retval != 0xffffffff && retval != sep->shared_bus) - retval = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR1_REG_ADDR); - - /* check the return value (register) */ - if (retval != sep->shared_bus) { - error = -ENOMEM; - goto end_function_deallocate_sep_shared_area; - } -#endif - /* init the flow contextes */ - for (counter = 0; counter < SEP_DRIVER_NUM_FLOWS; counter++) - sep->flows[counter].flow_id = SEP_FREE_FLOW_ID; - - sep->flow_wq = create_singlethread_workqueue("sepflowwq"); - if (sep->flow_wq == NULL) { - error = -ENOMEM; - edbg("sep_driver:flow queue creation failed\n"); - goto end_function_deallocate_sep_shared_area; - } - edbg("SEP Driver: create flow workqueue \n"); - sep->pdev = pci_dev_get(pdev); - - sep->reg_addr = pci_ioremap_bar(pdev, 0); - if (!sep->reg_addr) { - edbg("sep: ioremap of registers failed.\n"); - goto end_function_deallocate_sep_shared_area; - } - edbg("SEP Driver:reg_addr is %p\n", sep->reg_addr); - - /* load the rom code */ - sep_load_rom_code(sep); - - /* set up system base address and shared memory location */ - sep->rar_addr = dma_alloc_coherent(&sep->pdev->dev, - 2 * SEP_RAR_IO_MEM_REGION_SIZE, - &sep->rar_bus, GFP_KERNEL); - - if (!sep->rar_addr) { - edbg("SEP Driver:can't allocate rar\n"); - goto end_function_uniomap; - } - - - edbg("SEP Driver:rar_bus is %08llx\n", (unsigned long long)sep->rar_bus); - edbg("SEP Driver:rar_virtual is %p\n", sep->rar_addr); - -#if !SEP_DRIVER_POLLING_MODE - - edbg("SEP Driver: about to write IMR and ICR REG_ADDR\n"); - - /* clear ICR register */ - sep_write_reg(sep, HW_HOST_ICR_REG_ADDR, 0xFFFFFFFF); - - /* set the IMR register - open only GPR 2 */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); - - edbg("SEP Driver: about to call request_irq\n"); - /* get the interrupt line */ - error = request_irq(pdev->irq, sep_inthandler, IRQF_SHARED, "sep_driver", sep); - if (error) - goto end_function_free_res; - return 0; - edbg("SEP Driver: about to write IMR REG_ADDR"); - - /* set the IMR register - open only GPR 2 */ - sep_write_reg(sep, HW_HOST_IMR_REG_ADDR, (~(0x1 << 13))); - -end_function_free_res: - dma_free_coherent(&sep->pdev->dev, 2 * SEP_RAR_IO_MEM_REGION_SIZE, - sep->rar_addr, sep->rar_bus); -#endif /* SEP_DRIVER_POLLING_MODE */ -end_function_uniomap: - iounmap(sep->reg_addr); -end_function_deallocate_sep_shared_area: - /* de-allocate shared area */ - sep_unmap_and_free_shared_area(sep, size); -end_function_error: - sep_dev = NULL; -end_function: - return error; -} - -static const struct pci_device_id sep_pci_id_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080c)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, sep_pci_id_tbl); - -/* field for registering driver to PCI device */ -static struct pci_driver sep_pci_driver = { - .name = "sep_sec_driver", - .id_table = sep_pci_id_tbl, - .probe = sep_probe - /* FIXME: remove handler */ -}; - -/* major and minor device numbers */ -static dev_t sep_devno; - -/* the files operations structure of the driver */ -static struct file_operations sep_file_operations = { - .owner = THIS_MODULE, - .unlocked_ioctl = sep_ioctl, - .poll = sep_poll, - .open = sep_open, - .release = sep_release, - .mmap = sep_mmap, -}; - - -/* cdev struct of the driver */ -static struct cdev sep_cdev; - -/* - this function registers the driver to the file system -*/ -static int sep_register_driver_to_fs(void) -{ - int ret_val = alloc_chrdev_region(&sep_devno, 0, 1, "sep_sec_driver"); - if (ret_val) { - edbg("sep: major number allocation failed, retval is %d\n", - ret_val); - return ret_val; - } - /* init cdev */ - cdev_init(&sep_cdev, &sep_file_operations); - sep_cdev.owner = THIS_MODULE; - - /* register the driver with the kernel */ - ret_val = cdev_add(&sep_cdev, sep_devno, 1); - if (ret_val) { - edbg("sep_driver:cdev_add failed, retval is %d\n", ret_val); - /* unregister dev numbers */ - unregister_chrdev_region(sep_devno, 1); - } - return ret_val; -} - - -/*-------------------------------------------------------------- - init function -----------------------------------------------------------------*/ -static int __init sep_init(void) -{ - int ret_val = 0; - dbg("SEP Driver:-------->Init start\n"); - /* FIXME: Probe can occur before we are ready to survive a probe */ - ret_val = pci_register_driver(&sep_pci_driver); - if (ret_val) { - edbg("sep_driver:sep_driver_to_device failed, ret_val is %d\n", ret_val); - goto end_function_unregister_from_fs; - } - /* register driver to fs */ - ret_val = sep_register_driver_to_fs(); - if (ret_val) - goto end_function_unregister_pci; - goto end_function; -end_function_unregister_pci: - pci_unregister_driver(&sep_pci_driver); -end_function_unregister_from_fs: - /* unregister from fs */ - cdev_del(&sep_cdev); - /* unregister dev numbers */ - unregister_chrdev_region(sep_devno, 1); -end_function: - dbg("SEP Driver:<-------- Init end\n"); - return ret_val; -} - - -/*------------------------------------------------------------- - exit function ---------------------------------------------------------------*/ -static void __exit sep_exit(void) -{ - int size; - - dbg("SEP Driver:--------> Exit start\n"); - - /* unregister from fs */ - cdev_del(&sep_cdev); - /* unregister dev numbers */ - unregister_chrdev_region(sep_devno, 1); - /* calculate the total size for de-allocation */ - size = SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES + - SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES + SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES + SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES + SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES; - /* FIXME: We need to do this in the unload for the device */ - /* free shared area */ - if (sep_dev) { - sep_unmap_and_free_shared_area(sep_dev, size); - edbg("SEP Driver: free pages SEP SHARED AREA \n"); - iounmap((void *) sep_dev->reg_addr); - edbg("SEP Driver: iounmap \n"); - } - edbg("SEP Driver: release_mem_region \n"); - dbg("SEP Driver:<-------- Exit end\n"); -} - - -module_init(sep_init); -module_exit(sep_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/sep/sep_driver_api.h b/drivers/staging/sep/sep_driver_api.h deleted file mode 100644 index 7ef16da7c4ef..000000000000 --- a/drivers/staging/sep/sep_driver_api.h +++ /dev/null @@ -1,425 +0,0 @@ -/* - * - * sep_driver_api.h - Security Processor Driver api definitions - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#ifndef __SEP_DRIVER_API_H__ -#define __SEP_DRIVER_API_H__ - - - -/*---------------------------------------------------------------- - IOCTL command defines - -----------------------------------------------------------------*/ - -/* magic number 1 of the sep IOCTL command */ -#define SEP_IOC_MAGIC_NUMBER 's' - -/* sends interrupt to sep that message is ready */ -#define SEP_IOCSENDSEPCOMMAND _IO(SEP_IOC_MAGIC_NUMBER , 0) - -/* sends interrupt to sep that message is ready */ -#define SEP_IOCSENDSEPRPLYCOMMAND _IO(SEP_IOC_MAGIC_NUMBER , 1) - -/* allocate memory in data pool */ -#define SEP_IOCALLOCDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 2) - -/* write to pre-allocated memory in data pool */ -#define SEP_IOCWRITEDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 3) - -/* read from pre-allocated memory in data pool */ -#define SEP_IOCREADDATAPOLL _IO(SEP_IOC_MAGIC_NUMBER , 4) - -/* create sym dma lli tables */ -#define SEP_IOCCREATESYMDMATABLE _IO(SEP_IOC_MAGIC_NUMBER , 5) - -/* create flow dma lli tables */ -#define SEP_IOCCREATEFLOWDMATABLE _IO(SEP_IOC_MAGIC_NUMBER , 6) - -/* free dynamic data aalocated during table creation */ -#define SEP_IOCFREEDMATABLEDATA _IO(SEP_IOC_MAGIC_NUMBER , 7) - -/* get the static pool area addresses (physical and virtual) */ -#define SEP_IOCGETSTATICPOOLADDR _IO(SEP_IOC_MAGIC_NUMBER , 8) - -/* set flow id command */ -#define SEP_IOCSETFLOWID _IO(SEP_IOC_MAGIC_NUMBER , 9) - -/* add tables to the dynamic flow */ -#define SEP_IOCADDFLOWTABLE _IO(SEP_IOC_MAGIC_NUMBER , 10) - -/* add flow add tables message */ -#define SEP_IOCADDFLOWMESSAGE _IO(SEP_IOC_MAGIC_NUMBER , 11) - -/* start sep command */ -#define SEP_IOCSEPSTART _IO(SEP_IOC_MAGIC_NUMBER , 12) - -/* init sep command */ -#define SEP_IOCSEPINIT _IO(SEP_IOC_MAGIC_NUMBER , 13) - -/* end transaction command */ -#define SEP_IOCENDTRANSACTION _IO(SEP_IOC_MAGIC_NUMBER , 15) - -/* reallocate cache and resident */ -#define SEP_IOCREALLOCCACHERES _IO(SEP_IOC_MAGIC_NUMBER , 16) - -/* get the offset of the address starting from the beginnnig of the map area */ -#define SEP_IOCGETMAPPEDADDROFFSET _IO(SEP_IOC_MAGIC_NUMBER , 17) - -/* get time address and value */ -#define SEP_IOCGETIME _IO(SEP_IOC_MAGIC_NUMBER , 19) - -/*------------------------------------------- - TYPEDEFS -----------------------------------------------*/ - -/* - init command struct -*/ -struct sep_driver_init_t { - /* start of the 1G of the host memory address that SEP can access */ - unsigned long message_addr; - - /* start address of resident */ - unsigned long message_size_in_words; - -}; - - -/* - realloc cache resident command -*/ -struct sep_driver_realloc_cache_resident_t { - /* new cache address */ - u64 new_cache_addr; - /* new resident address */ - u64 new_resident_addr; - /* new resident address */ - u64 new_shared_area_addr; - /* new base address */ - u64 new_base_addr; -}; - -struct sep_driver_alloc_t { - /* virtual address of allocated space */ - unsigned long offset; - - /* physical address of allocated space */ - unsigned long phys_address; - - /* number of bytes to allocate */ - unsigned long num_bytes; -}; - -/* - */ -struct sep_driver_write_t { - /* application space address */ - unsigned long app_address; - - /* address of the data pool */ - unsigned long datapool_address; - - /* number of bytes to write */ - unsigned long num_bytes; -}; - -/* - */ -struct sep_driver_read_t { - /* application space address */ - unsigned long app_address; - - /* address of the data pool */ - unsigned long datapool_address; - - /* number of bytes to read */ - unsigned long num_bytes; -}; - -/* -*/ -struct sep_driver_build_sync_table_t { - /* address value of the data in */ - unsigned long app_in_address; - - /* size of data in */ - unsigned long data_in_size; - - /* address of the data out */ - unsigned long app_out_address; - - /* the size of the block of the operation - if needed, - every table will be modulo this parameter */ - unsigned long block_size; - - /* the physical address of the first input DMA table */ - unsigned long in_table_address; - - /* number of entries in the first input DMA table */ - unsigned long in_table_num_entries; - - /* the physical address of the first output DMA table */ - unsigned long out_table_address; - - /* number of entries in the first output DMA table */ - unsigned long out_table_num_entries; - - /* data in the first input table */ - unsigned long table_data_size; - - /* distinct user/kernel layout */ - bool isKernelVirtualAddress; - -}; - -/* -*/ -struct sep_driver_build_flow_table_t { - /* flow type */ - unsigned long flow_type; - - /* flag for input output */ - unsigned long input_output_flag; - - /* address value of the data in */ - unsigned long virt_buff_data_addr; - - /* size of data in */ - unsigned long num_virtual_buffers; - - /* the physical address of the first input DMA table */ - unsigned long first_table_addr; - - /* number of entries in the first input DMA table */ - unsigned long first_table_num_entries; - - /* data in the first input table */ - unsigned long first_table_data_size; - - /* distinct user/kernel layout */ - bool isKernelVirtualAddress; -}; - - -struct sep_driver_add_flow_table_t { - /* flow id */ - unsigned long flow_id; - - /* flag for input output */ - unsigned long inputOutputFlag; - - /* address value of the data in */ - unsigned long virt_buff_data_addr; - - /* size of data in */ - unsigned long num_virtual_buffers; - - /* address of the first table */ - unsigned long first_table_addr; - - /* number of entries in the first table */ - unsigned long first_table_num_entries; - - /* data size of the first table */ - unsigned long first_table_data_size; - - /* distinct user/kernel layout */ - bool isKernelVirtualAddress; - -}; - -/* - command struct for set flow id -*/ -struct sep_driver_set_flow_id_t { - /* flow id to set */ - unsigned long flow_id; -}; - - -/* command struct for add tables message */ -struct sep_driver_add_message_t { - /* flow id to set */ - unsigned long flow_id; - - /* message size in bytes */ - unsigned long message_size_in_bytes; - - /* address of the message */ - unsigned long message_address; -}; - -/* command struct for static pool addresses */ -struct sep_driver_static_pool_addr_t { - /* physical address of the static pool */ - unsigned long physical_static_address; - - /* virtual address of the static pool */ - unsigned long virtual_static_address; -}; - -/* command struct for getiing offset of the physical address from - the start of the mapped area */ -struct sep_driver_get_mapped_offset_t { - /* physical address of the static pool */ - unsigned long physical_address; - - /* virtual address of the static pool */ - unsigned long offset; -}; - -/* command struct for getting time value and address */ -struct sep_driver_get_time_t { - /* physical address of stored time */ - unsigned long time_physical_address; - - /* value of the stored time */ - unsigned long time_value; -}; - - -/* - structure that represent one entry in the DMA LLI table -*/ -struct sep_lli_entry_t { - /* physical address */ - unsigned long physical_address; - - /* block size */ - unsigned long block_size; -}; - -/* - structure that reperesents data needed for lli table construction -*/ -struct sep_lli_prepare_table_data_t { - /* pointer to the memory where the first lli entry to be built */ - struct sep_lli_entry_t *lli_entry_ptr; - - /* pointer to the array of lli entries from which the table is to be built */ - struct sep_lli_entry_t *lli_array_ptr; - - /* number of elements in lli array */ - int lli_array_size; - - /* number of entries in the created table */ - int num_table_entries; - - /* number of array entries processed during table creation */ - int num_array_entries_processed; - - /* the totatl data size in the created table */ - int lli_table_total_data_size; -}; - -/* - structure that represent tone table - it is not used in code, jkust - to show what table looks like -*/ -struct sep_lli_table_t { - /* number of pages mapped in this tables. If 0 - means that the table - is not defined (used as a valid flag) */ - unsigned long num_pages; - /* - pointer to array of page pointers that represent the mapping of the - virtual buffer defined by the table to the physical memory. If this - pointer is NULL, it means that the table is not defined - (used as a valid flag) - */ - struct page **table_page_array_ptr; - - /* maximum flow entries in table */ - struct sep_lli_entry_t lli_entries[SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE]; -}; - - -/* - structure for keeping the mapping of the virtual buffer into physical pages -*/ -struct sep_flow_buffer_data { - /* pointer to the array of page structs pointers to the pages of the - virtual buffer */ - struct page **page_array_ptr; - - /* number of pages taken by the virtual buffer */ - unsigned long num_pages; - - /* this flag signals if this page_array is the last one among many that were - sent in one setting to SEP */ - unsigned long last_page_array_flag; -}; - -/* - struct that keeps all the data for one flow -*/ -struct sep_flow_context_t { - /* - work struct for handling the flow done interrupt in the workqueue - this structure must be in the first place, since it will be used - forcasting to the containing flow context - */ - struct work_struct flow_wq; - - /* flow id */ - unsigned long flow_id; - - /* additional input tables exists */ - unsigned long input_tables_flag; - - /* additional output tables exists */ - unsigned long output_tables_flag; - - /* data of the first input file */ - struct sep_lli_entry_t first_input_table; - - /* data of the first output table */ - struct sep_lli_entry_t first_output_table; - - /* last input table data */ - struct sep_lli_entry_t last_input_table; - - /* last output table data */ - struct sep_lli_entry_t last_output_table; - - /* first list of table */ - struct sep_lli_entry_t input_tables_in_process; - - /* output table in process (in sep) */ - struct sep_lli_entry_t output_tables_in_process; - - /* size of messages in bytes */ - unsigned long message_size_in_bytes; - - /* message */ - unsigned char message[SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES]; -}; - - -#endif diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h deleted file mode 100644 index 6008fe5eca09..000000000000 --- a/drivers/staging/sep/sep_driver_config.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * - * sep_driver_config.h - Security Processor Driver configuration - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#ifndef __SEP_DRIVER_CONFIG_H__ -#define __SEP_DRIVER_CONFIG_H__ - - -/*-------------------------------------- - DRIVER CONFIGURATION FLAGS - -------------------------------------*/ - -/* if flag is on , then the driver is running in polling and - not interrupt mode */ -#define SEP_DRIVER_POLLING_MODE 1 - -/* flag which defines if the shared area address should be - reconfiged (send to SEP anew) during init of the driver */ -#define SEP_DRIVER_RECONFIG_MESSAGE_AREA 0 - -/* the mode for running on the ARM1172 Evaluation platform (flag is 1) */ -#define SEP_DRIVER_ARM_DEBUG_MODE 0 - -/*------------------------------------------- - INTERNAL DATA CONFIGURATION - -------------------------------------------*/ - -/* flag for the input array */ -#define SEP_DRIVER_IN_FLAG 0 - -/* flag for output array */ -#define SEP_DRIVER_OUT_FLAG 1 - -/* maximum number of entries in one LLI tables */ -#define SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP 8 - - -/*-------------------------------------------------------- - SHARED AREA memory total size is 36K - it is divided is following: - - SHARED_MESSAGE_AREA 8K } - } - STATIC_POOL_AREA 4K } MAPPED AREA ( 24 K) - } - DATA_POOL_AREA 12K } - - SYNCHRONIC_DMA_TABLES_AREA 5K - - FLOW_DMA_TABLES_AREA 4K - - SYSTEM_MEMORY_AREA 3k - - SYSTEM_MEMORY total size is 3k - it is divided as following: - - TIME_MEMORY_AREA 8B ------------------------------------------------------------*/ - - - -/* - the maximum length of the message - the rest of the message shared - area will be dedicated to the dma lli tables -*/ -#define SEP_DRIVER_MAX_MESSAGE_SIZE_IN_BYTES (8 * 1024) - -/* the size of the message shared area in pages */ -#define SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES (8 * 1024) - -/* the size of the data pool static area in pages */ -#define SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES (4 * 1024) - -/* the size of the data pool shared area size in pages */ -#define SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES (12 * 1024) - -/* the size of the message shared area in pages */ -#define SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 5) - - -/* the size of the data pool shared area size in pages */ -#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES (1024 * 4) - -/* system data (time, caller id etc') pool */ -#define SEP_DRIVER_SYSTEM_DATA_MEMORY_SIZE_IN_BYTES 100 - - -/* area size that is mapped - we map the MESSAGE AREA, STATIC POOL and - DATA POOL areas. area must be module 4k */ -#define SEP_DRIVER_MMMAP_AREA_SIZE (1024 * 24) - - -/*----------------------------------------------- - offsets of the areas starting from the shared area start address -*/ - -/* message area offset */ -#define SEP_DRIVER_MESSAGE_AREA_OFFSET_IN_BYTES 0 - -/* static pool area offset */ -#define SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES) - -/* data pool area offset */ -#define SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_STATIC_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_STATIC_AREA_SIZE_IN_BYTES) - -/* synhronic dma tables area offset */ -#define SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_DATA_POOL_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) - -/* sep driver flow dma tables area offset */ -#define SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES \ - (SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_SYNCHRONIC_DMA_TABLES_AREA_SIZE_IN_BYTES) - -/* system memory offset in bytes */ -#define SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES \ - (SEP_DRIVER_FLOW_DMA_TABLES_AREA_OFFSET_IN_BYTES + \ - SEP_DRIVER_FLOW_DMA_TABLES_AREA_SIZE_IN_BYTES) - -/* offset of the time area */ -#define SEP_DRIVER_SYSTEM_TIME_MEMORY_OFFSET_IN_BYTES \ - (SEP_DRIVER_SYSTEM_DATA_MEMORY_OFFSET_IN_BYTES) - - - -/* start physical address of the SEP registers memory in HOST */ -#define SEP_IO_MEM_REGION_START_ADDRESS 0x80000000 - -/* size of the SEP registers memory region in HOST (for now 100 registers) */ -#define SEP_IO_MEM_REGION_SIZE (2 * 0x100000) - -/* define the number of IRQ for SEP interrupts */ -#define SEP_DIRVER_IRQ_NUM 1 - -/* maximum number of add buffers */ -#define SEP_MAX_NUM_ADD_BUFFERS 100 - -/* number of flows */ -#define SEP_DRIVER_NUM_FLOWS 4 - -/* maximum number of entries in flow table */ -#define SEP_DRIVER_MAX_FLOW_NUM_ENTRIES_IN_TABLE 25 - -/* offset of the num entries in the block length entry of the LLI */ -#define SEP_NUM_ENTRIES_OFFSET_IN_BITS 24 - -/* offset of the interrupt flag in the block length entry of the LLI */ -#define SEP_INT_FLAG_OFFSET_IN_BITS 31 - -/* mask for extracting data size from LLI */ -#define SEP_TABLE_DATA_SIZE_MASK 0xFFFFFF - -/* mask for entries after being shifted left */ -#define SEP_NUM_ENTRIES_MASK 0x7F - -/* default flow id */ -#define SEP_FREE_FLOW_ID 0xFFFFFFFF - -/* temp flow id used during cretiong of new flow until receiving - real flow id from sep */ -#define SEP_TEMP_FLOW_ID (SEP_DRIVER_NUM_FLOWS + 1) - -/* maximum add buffers message length in bytes */ -#define SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES (7 * 4) - -/* maximum number of concurrent virtual buffers */ -#define SEP_MAX_VIRT_BUFFERS_CONCURRENT 100 - -/* the token that defines the start of time address */ -#define SEP_TIME_VAL_TOKEN 0x12345678 - -/* DEBUG LEVEL MASKS */ -#define SEP_DEBUG_LEVEL_BASIC 0x1 - -#define SEP_DEBUG_LEVEL_EXTENDED 0x4 - - -/* Debug helpers */ - -#define dbg(fmt, args...) \ -do {\ - if (debug & SEP_DEBUG_LEVEL_BASIC) \ - printk(KERN_DEBUG fmt, ##args); \ -} while(0); - -#define edbg(fmt, args...) \ -do { \ - if (debug & SEP_DEBUG_LEVEL_EXTENDED) \ - printk(KERN_DEBUG fmt, ##args); \ -} while(0); - - - -#endif diff --git a/drivers/staging/sep/sep_driver_hw_defs.h b/drivers/staging/sep/sep_driver_hw_defs.h deleted file mode 100644 index ea6abd8a14b4..000000000000 --- a/drivers/staging/sep/sep_driver_hw_defs.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * - * sep_driver_hw_defs.h - Security Processor Driver hardware definitions - * - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * Copyright(c) 2009 Discretix. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * CONTACTS: - * - * Mark Allyn mark.a.allyn@intel.com - * - * CHANGES: - * - * 2009.06.26 Initial publish - * - */ - -#ifndef SEP_DRIVER_HW_DEFS__H -#define SEP_DRIVER_HW_DEFS__H - -/*--------------------------------------------------------------------------*/ -/* Abstract: HW Registers Defines. */ -/* */ -/* Note: This file was automatically created !!! */ -/* DO NOT EDIT THIS FILE !!! */ -/*--------------------------------------------------------------------------*/ - - -/* cf registers */ -#define HW_R0B_ADDR_0_REG_ADDR 0x0000UL -#define HW_R0B_ADDR_1_REG_ADDR 0x0004UL -#define HW_R0B_ADDR_2_REG_ADDR 0x0008UL -#define HW_R0B_ADDR_3_REG_ADDR 0x000cUL -#define HW_R0B_ADDR_4_REG_ADDR 0x0010UL -#define HW_R0B_ADDR_5_REG_ADDR 0x0014UL -#define HW_R0B_ADDR_6_REG_ADDR 0x0018UL -#define HW_R0B_ADDR_7_REG_ADDR 0x001cUL -#define HW_R0B_ADDR_8_REG_ADDR 0x0020UL -#define HW_R2B_ADDR_0_REG_ADDR 0x0080UL -#define HW_R2B_ADDR_1_REG_ADDR 0x0084UL -#define HW_R2B_ADDR_2_REG_ADDR 0x0088UL -#define HW_R2B_ADDR_3_REG_ADDR 0x008cUL -#define HW_R2B_ADDR_4_REG_ADDR 0x0090UL -#define HW_R2B_ADDR_5_REG_ADDR 0x0094UL -#define HW_R2B_ADDR_6_REG_ADDR 0x0098UL -#define HW_R2B_ADDR_7_REG_ADDR 0x009cUL -#define HW_R2B_ADDR_8_REG_ADDR 0x00a0UL -#define HW_R3B_REG_ADDR 0x00C0UL -#define HW_R4B_REG_ADDR 0x0100UL -#define HW_CSA_ADDR_0_REG_ADDR 0x0140UL -#define HW_CSA_ADDR_1_REG_ADDR 0x0144UL -#define HW_CSA_ADDR_2_REG_ADDR 0x0148UL -#define HW_CSA_ADDR_3_REG_ADDR 0x014cUL -#define HW_CSA_ADDR_4_REG_ADDR 0x0150UL -#define HW_CSA_ADDR_5_REG_ADDR 0x0154UL -#define HW_CSA_ADDR_6_REG_ADDR 0x0158UL -#define HW_CSA_ADDR_7_REG_ADDR 0x015cUL -#define HW_CSA_ADDR_8_REG_ADDR 0x0160UL -#define HW_CSA_REG_ADDR 0x0140UL -#define HW_SINB_REG_ADDR 0x0180UL -#define HW_SOUTB_REG_ADDR 0x0184UL -#define HW_PKI_CONTROL_REG_ADDR 0x01C0UL -#define HW_PKI_STATUS_REG_ADDR 0x01C4UL -#define HW_PKI_BUSY_REG_ADDR 0x01C8UL -#define HW_PKI_A_1025_REG_ADDR 0x01CCUL -#define HW_PKI_SDMA_CTL_REG_ADDR 0x01D0UL -#define HW_PKI_SDMA_OFFSET_REG_ADDR 0x01D4UL -#define HW_PKI_SDMA_POINTERS_REG_ADDR 0x01D8UL -#define HW_PKI_SDMA_DLENG_REG_ADDR 0x01DCUL -#define HW_PKI_SDMA_EXP_POINTERS_REG_ADDR 0x01E0UL -#define HW_PKI_SDMA_RES_POINTERS_REG_ADDR 0x01E4UL -#define HW_PKI_CLR_REG_ADDR 0x01E8UL -#define HW_PKI_SDMA_BUSY_REG_ADDR 0x01E8UL -#define HW_PKI_SDMA_FIRST_EXP_N_REG_ADDR 0x01ECUL -#define HW_PKI_SDMA_MUL_BY1_REG_ADDR 0x01F0UL -#define HW_PKI_SDMA_RMUL_SEL_REG_ADDR 0x01F4UL -#define HW_DES_KEY_0_REG_ADDR 0x0208UL -#define HW_DES_KEY_1_REG_ADDR 0x020CUL -#define HW_DES_KEY_2_REG_ADDR 0x0210UL -#define HW_DES_KEY_3_REG_ADDR 0x0214UL -#define HW_DES_KEY_4_REG_ADDR 0x0218UL -#define HW_DES_KEY_5_REG_ADDR 0x021CUL -#define HW_DES_CONTROL_0_REG_ADDR 0x0220UL -#define HW_DES_CONTROL_1_REG_ADDR 0x0224UL -#define HW_DES_IV_0_REG_ADDR 0x0228UL -#define HW_DES_IV_1_REG_ADDR 0x022CUL -#define HW_AES_KEY_0_ADDR_0_REG_ADDR 0x0400UL -#define HW_AES_KEY_0_ADDR_1_REG_ADDR 0x0404UL -#define HW_AES_KEY_0_ADDR_2_REG_ADDR 0x0408UL -#define HW_AES_KEY_0_ADDR_3_REG_ADDR 0x040cUL -#define HW_AES_KEY_0_ADDR_4_REG_ADDR 0x0410UL -#define HW_AES_KEY_0_ADDR_5_REG_ADDR 0x0414UL -#define HW_AES_KEY_0_ADDR_6_REG_ADDR 0x0418UL -#define HW_AES_KEY_0_ADDR_7_REG_ADDR 0x041cUL -#define HW_AES_KEY_0_REG_ADDR 0x0400UL -#define HW_AES_IV_0_ADDR_0_REG_ADDR 0x0440UL -#define HW_AES_IV_0_ADDR_1_REG_ADDR 0x0444UL -#define HW_AES_IV_0_ADDR_2_REG_ADDR 0x0448UL -#define HW_AES_IV_0_ADDR_3_REG_ADDR 0x044cUL -#define HW_AES_IV_0_REG_ADDR 0x0440UL -#define HW_AES_CTR1_ADDR_0_REG_ADDR 0x0460UL -#define HW_AES_CTR1_ADDR_1_REG_ADDR 0x0464UL -#define HW_AES_CTR1_ADDR_2_REG_ADDR 0x0468UL -#define HW_AES_CTR1_ADDR_3_REG_ADDR 0x046cUL -#define HW_AES_CTR1_REG_ADDR 0x0460UL -#define HW_AES_SK_REG_ADDR 0x0478UL -#define HW_AES_MAC_OK_REG_ADDR 0x0480UL -#define HW_AES_PREV_IV_0_ADDR_0_REG_ADDR 0x0490UL -#define HW_AES_PREV_IV_0_ADDR_1_REG_ADDR 0x0494UL -#define HW_AES_PREV_IV_0_ADDR_2_REG_ADDR 0x0498UL -#define HW_AES_PREV_IV_0_ADDR_3_REG_ADDR 0x049cUL -#define HW_AES_PREV_IV_0_REG_ADDR 0x0490UL -#define HW_AES_CONTROL_REG_ADDR 0x04C0UL -#define HW_HASH_H0_REG_ADDR 0x0640UL -#define HW_HASH_H1_REG_ADDR 0x0644UL -#define HW_HASH_H2_REG_ADDR 0x0648UL -#define HW_HASH_H3_REG_ADDR 0x064CUL -#define HW_HASH_H4_REG_ADDR 0x0650UL -#define HW_HASH_H5_REG_ADDR 0x0654UL -#define HW_HASH_H6_REG_ADDR 0x0658UL -#define HW_HASH_H7_REG_ADDR 0x065CUL -#define HW_HASH_H8_REG_ADDR 0x0660UL -#define HW_HASH_H9_REG_ADDR 0x0664UL -#define HW_HASH_H10_REG_ADDR 0x0668UL -#define HW_HASH_H11_REG_ADDR 0x066CUL -#define HW_HASH_H12_REG_ADDR 0x0670UL -#define HW_HASH_H13_REG_ADDR 0x0674UL -#define HW_HASH_H14_REG_ADDR 0x0678UL -#define HW_HASH_H15_REG_ADDR 0x067CUL -#define HW_HASH_CONTROL_REG_ADDR 0x07C0UL -#define HW_HASH_PAD_EN_REG_ADDR 0x07C4UL -#define HW_HASH_PAD_CFG_REG_ADDR 0x07C8UL -#define HW_HASH_CUR_LEN_0_REG_ADDR 0x07CCUL -#define HW_HASH_CUR_LEN_1_REG_ADDR 0x07D0UL -#define HW_HASH_CUR_LEN_2_REG_ADDR 0x07D4UL -#define HW_HASH_CUR_LEN_3_REG_ADDR 0x07D8UL -#define HW_HASH_PARAM_REG_ADDR 0x07DCUL -#define HW_HASH_INT_BUSY_REG_ADDR 0x07E0UL -#define HW_HASH_SW_RESET_REG_ADDR 0x07E4UL -#define HW_HASH_ENDIANESS_REG_ADDR 0x07E8UL -#define HW_HASH_DATA_REG_ADDR 0x07ECUL -#define HW_DRNG_CONTROL_REG_ADDR 0x0800UL -#define HW_DRNG_VALID_REG_ADDR 0x0804UL -#define HW_DRNG_DATA_REG_ADDR 0x0808UL -#define HW_RND_SRC_EN_REG_ADDR 0x080CUL -#define HW_AES_CLK_ENABLE_REG_ADDR 0x0810UL -#define HW_DES_CLK_ENABLE_REG_ADDR 0x0814UL -#define HW_HASH_CLK_ENABLE_REG_ADDR 0x0818UL -#define HW_PKI_CLK_ENABLE_REG_ADDR 0x081CUL -#define HW_CLK_STATUS_REG_ADDR 0x0824UL -#define HW_CLK_ENABLE_REG_ADDR 0x0828UL -#define HW_DRNG_SAMPLE_REG_ADDR 0x0850UL -#define HW_RND_SRC_CTL_REG_ADDR 0x0858UL -#define HW_CRYPTO_CTL_REG_ADDR 0x0900UL -#define HW_CRYPTO_STATUS_REG_ADDR 0x090CUL -#define HW_CRYPTO_BUSY_REG_ADDR 0x0910UL -#define HW_AES_BUSY_REG_ADDR 0x0914UL -#define HW_DES_BUSY_REG_ADDR 0x0918UL -#define HW_HASH_BUSY_REG_ADDR 0x091CUL -#define HW_CONTENT_REG_ADDR 0x0924UL -#define HW_VERSION_REG_ADDR 0x0928UL -#define HW_CONTEXT_ID_REG_ADDR 0x0930UL -#define HW_DIN_BUFFER_REG_ADDR 0x0C00UL -#define HW_DIN_MEM_DMA_BUSY_REG_ADDR 0x0c20UL -#define HW_SRC_LLI_MEM_ADDR_REG_ADDR 0x0c24UL -#define HW_SRC_LLI_WORD0_REG_ADDR 0x0C28UL -#define HW_SRC_LLI_WORD1_REG_ADDR 0x0C2CUL -#define HW_SRAM_SRC_ADDR_REG_ADDR 0x0c30UL -#define HW_DIN_SRAM_BYTES_LEN_REG_ADDR 0x0c34UL -#define HW_DIN_SRAM_DMA_BUSY_REG_ADDR 0x0C38UL -#define HW_WRITE_ALIGN_REG_ADDR 0x0C3CUL -#define HW_OLD_DATA_REG_ADDR 0x0C48UL -#define HW_WRITE_ALIGN_LAST_REG_ADDR 0x0C4CUL -#define HW_DOUT_BUFFER_REG_ADDR 0x0C00UL -#define HW_DST_LLI_WORD0_REG_ADDR 0x0D28UL -#define HW_DST_LLI_WORD1_REG_ADDR 0x0D2CUL -#define HW_DST_LLI_MEM_ADDR_REG_ADDR 0x0D24UL -#define HW_DOUT_MEM_DMA_BUSY_REG_ADDR 0x0D20UL -#define HW_SRAM_DEST_ADDR_REG_ADDR 0x0D30UL -#define HW_DOUT_SRAM_BYTES_LEN_REG_ADDR 0x0D34UL -#define HW_DOUT_SRAM_DMA_BUSY_REG_ADDR 0x0D38UL -#define HW_READ_ALIGN_REG_ADDR 0x0D3CUL -#define HW_READ_LAST_DATA_REG_ADDR 0x0D44UL -#define HW_RC4_THRU_CPU_REG_ADDR 0x0D4CUL -#define HW_AHB_SINGLE_REG_ADDR 0x0E00UL -#define HW_SRAM_DATA_REG_ADDR 0x0F00UL -#define HW_SRAM_ADDR_REG_ADDR 0x0F04UL -#define HW_SRAM_DATA_READY_REG_ADDR 0x0F08UL -#define HW_HOST_IRR_REG_ADDR 0x0A00UL -#define HW_HOST_IMR_REG_ADDR 0x0A04UL -#define HW_HOST_ICR_REG_ADDR 0x0A08UL -#define HW_HOST_SEP_SRAM_THRESHOLD_REG_ADDR 0x0A10UL -#define HW_HOST_SEP_BUSY_REG_ADDR 0x0A14UL -#define HW_HOST_SEP_LCS_REG_ADDR 0x0A18UL -#define HW_HOST_CC_SW_RST_REG_ADDR 0x0A40UL -#define HW_HOST_SEP_SW_RST_REG_ADDR 0x0A44UL -#define HW_HOST_FLOW_DMA_SW_INT0_REG_ADDR 0x0A80UL -#define HW_HOST_FLOW_DMA_SW_INT1_REG_ADDR 0x0A84UL -#define HW_HOST_FLOW_DMA_SW_INT2_REG_ADDR 0x0A88UL -#define HW_HOST_FLOW_DMA_SW_INT3_REG_ADDR 0x0A8cUL -#define HW_HOST_FLOW_DMA_SW_INT4_REG_ADDR 0x0A90UL -#define HW_HOST_FLOW_DMA_SW_INT5_REG_ADDR 0x0A94UL -#define HW_HOST_FLOW_DMA_SW_INT6_REG_ADDR 0x0A98UL -#define HW_HOST_FLOW_DMA_SW_INT7_REG_ADDR 0x0A9cUL -#define HW_HOST_SEP_HOST_GPR0_REG_ADDR 0x0B00UL -#define HW_HOST_SEP_HOST_GPR1_REG_ADDR 0x0B04UL -#define HW_HOST_SEP_HOST_GPR2_REG_ADDR 0x0B08UL -#define HW_HOST_SEP_HOST_GPR3_REG_ADDR 0x0B0CUL -#define HW_HOST_HOST_SEP_GPR0_REG_ADDR 0x0B80UL -#define HW_HOST_HOST_SEP_GPR1_REG_ADDR 0x0B84UL -#define HW_HOST_HOST_SEP_GPR2_REG_ADDR 0x0B88UL -#define HW_HOST_HOST_SEP_GPR3_REG_ADDR 0x0B8CUL -#define HW_HOST_HOST_ENDIAN_REG_ADDR 0x0B90UL -#define HW_HOST_HOST_COMM_CLK_EN_REG_ADDR 0x0B94UL -#define HW_CLR_SRAM_BUSY_REG_REG_ADDR 0x0F0CUL -#define HW_CC_SRAM_BASE_ADDRESS 0x5800UL - -#endif /* ifndef HW_DEFS */ -- cgit v1.2.3-59-g8ed1b From 07cda511c78db79974f56b277b3704bfc6bba711 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Thu, 12 Aug 2010 12:16:43 -0700 Subject: serial: print early console device address in hex Device addresses are usually printed in hex. Signed-off-by: Tony Luck Cc: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/serial/8250_early.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c index b745792ec25a..eaafb98debed 100644 --- a/drivers/serial/8250_early.c +++ b/drivers/serial/8250_early.c @@ -203,13 +203,13 @@ static int __init parse_options(struct early_serial8250_device *device, if (mmio || mmio32) printk(KERN_INFO - "Early serial console at MMIO%s 0x%llu (options '%s')\n", + "Early serial console at MMIO%s 0x%llx (options '%s')\n", mmio32 ? "32" : "", (unsigned long long)port->mapbase, device->options); else printk(KERN_INFO - "Early serial console at I/O port 0x%lu (options '%s')\n", + "Early serial console at I/O port 0x%lx (options '%s')\n", port->iobase, device->options); -- cgit v1.2.3-59-g8ed1b From f64ac9830b2a2455208ee023f6bac480ae159db4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Aug 2010 13:48:57 -0700 Subject: ip2: remove unneeded NULL check We don't pass NULL tty pointers to the close function, and anyway we already dereferenced it at this point. This check can be removed. Signed-off-by: Dan Carpenter Cc: "Michael H. Warfield" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/char/ip2/ip2main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 07f3ea38b582..8fa041eb8440 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1650,7 +1650,7 @@ ip2_close( PTTY tty, struct file *pFile ) /* disable DSS reporting */ i2QueueCommands(PTYPE_INLINE, pCh, 100, 4, CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); - if ( !tty || (tty->termios->c_cflag & HUPCL) ) { + if (tty->termios->c_cflag & HUPCL) { i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN); pCh->dataSetOut &= ~(I2_DTR | I2_RTS); i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); -- cgit v1.2.3-59-g8ed1b From 05254a207a255e1a76f9b349a783b5016b874d72 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Aug 2010 13:48:59 -0700 Subject: ip2: return -EFAULT on copy_to_user errors copy_to_user() returns the number of bytes remaining but we want to return a negative error code on errors. Signed-off-by: Dan Carpenter Cc: "Michael H. Warfield" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/char/ip2/ip2main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 8fa041eb8440..d4b71e8d0d23 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -2930,6 +2930,8 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) if ( pCh ) { rc = copy_to_user(argp, pCh, sizeof(i2ChanStr)); + if (rc) + rc = -EFAULT; } else { rc = -ENODEV; } -- cgit v1.2.3-59-g8ed1b From 49bf7eaffc0c252ab2a2cc8f1bf8c0077e778704 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Aug 2010 20:00:09 +0200 Subject: rocket: add a mutex_unlock() This path needs a mutex_unlock(). This is stuff from the bkl to mutex transition. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/rocket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 79c3bc69165a..7c79d243acc9 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -1244,6 +1244,7 @@ static int set_config(struct tty_struct *tty, struct r_port *info, } info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); configure_r_port(tty, info, NULL); + mutex_unlock(&info->port.mutex); return 0; } -- cgit v1.2.3-59-g8ed1b From 80d04f22b0869a1145b36a90a83a79603ac92be8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Aug 2010 20:01:46 +0200 Subject: synclink: add mutex_unlock() on error path There is a path which still holds its mutex here. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/synclink_gt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index fef80cfcab5c..e63b830c86cc 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -691,8 +691,10 @@ static int open(struct tty_struct *tty, struct file *filp) if (info->port.count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); - if (retval < 0) + if (retval < 0) { + mutex_unlock(&info->port.mutex); goto cleanup; + } } mutex_unlock(&info->port.mutex); retval = block_til_ready(tty, filp, info); -- cgit v1.2.3-59-g8ed1b From 5d56356a2c9f5e96efe7a095cbf9b6fee8265d22 Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sun, 1 Aug 2010 10:29:06 +0400 Subject: 68328serial: check return value of copy_*_user() instead of access_ok() As copy_*_user() calls access_ok() it should not be called explicitly. Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Kroah-Hartman --- drivers/serial/68328serial.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 7356a56ac458..be0ebce36e54 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -869,7 +869,9 @@ static int get_serial_info(struct m68k_serial * info, tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; - copy_to_user(retinfo,&tmp,sizeof(*retinfo)); + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; } @@ -882,7 +884,8 @@ static int set_serial_info(struct m68k_serial * info, if (!new_info) return -EFAULT; - copy_from_user(&new_serial,new_info,sizeof(new_serial)); + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) + return -EFAULT; old_info = *info; if (!capable(CAP_SYS_ADMIN)) { @@ -943,8 +946,7 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value) status = 0; #endif local_irq_restore(flags); - put_user(status,value); - return 0; + return put_user(status, value); } /* @@ -999,27 +1001,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, send_break(info, arg ? arg*(100) : 250); return 0; case TIOCGSERIAL: - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) - return get_serial_info(info, - (struct serial_struct *) arg); - return -EFAULT; + return get_serial_info(info, + (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int))) - return get_lsr_info(info, (unsigned int *) arg); - return -EFAULT; + return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - if (!access_ok(VERIFY_WRITE, (void *) arg, - sizeof(struct m68k_serial))) + if (copy_to_user((struct m68k_serial *) arg, + info, sizeof(struct m68k_serial))) return -EFAULT; - copy_to_user((struct m68k_serial *) arg, - info, sizeof(struct m68k_serial)); return 0; - default: return -ENOIOCTLCMD; } -- cgit v1.2.3-59-g8ed1b From d17c701ce6a548a92f7f8a3cec20299465f36ee3 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:42:52 +1000 Subject: xfs: unlock items before allowing the CIL to commit When we commit a transaction using delayed logging, we need to unlock the items in the transaciton before we unlock the CIL context and allow it to be checkpointed. If we unlock them after we release the CIl context lock, the CIL can checkpoint and complete before we free the log items. This breaks stale buffer item unlock and unpin processing as there is an implicit assumption that the unlock will occur before the unpin. Also, some log items need to store the LSN of the transaction commit in the item (inodes and EFIs) and so can race with other transaction completions if we don't prevent the CIL from checkpointing before the unlock occurs. Cc: Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_log_cil.c | 14 ++++++++++++++ fs/xfs/xfs_trans.c | 5 +---- fs/xfs/xfs_trans_priv.h | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 31e4ea2d19ac..ef8e7d9f445d 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -377,9 +377,23 @@ xfs_log_commit_cil( xfs_log_done(mp, tp->t_ticket, NULL, log_flags); xfs_trans_unreserve_and_mod_sb(tp); + /* + * Once all the items of the transaction have been copied to the CIL, + * the items can be unlocked and freed. + * + * This needs to be done before we drop the CIL context lock because we + * have to update state in the log items and unlock them before they go + * to disk. If we don't, then the CIL checkpoint can race with us and + * we can run checkpoint completion before we've updated and unlocked + * the log items. This affects (at least) processing of stale buffers, + * inodes and EFIs. + */ + xfs_trans_free_items(tp, *commit_lsn, 0); + /* check for background commit before unlock */ if (log->l_cilp->xc_ctx->space_used > XLOG_CIL_SPACE_LIMIT(log)) push = 1; + up_read(&log->l_cilp->xc_ctx_lock); /* diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index fdca7416c754..1c47edaea0d2 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -1167,7 +1167,7 @@ xfs_trans_del_item( * Unlock all of the items of a transaction and free all the descriptors * of that transaction. */ -STATIC void +void xfs_trans_free_items( struct xfs_trans *tp, xfs_lsn_t commit_lsn, @@ -1653,9 +1653,6 @@ xfs_trans_commit_cil( return error; current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); - - /* xfs_trans_free_items() unlocks them first */ - xfs_trans_free_items(tp, *commit_lsn, 0); xfs_trans_free(tp); return 0; } diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index e2d93d8ead7b..62da86c90de5 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h @@ -25,7 +25,8 @@ struct xfs_trans; void xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *); void xfs_trans_del_item(struct xfs_log_item *); - +void xfs_trans_free_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn, + int flags); void xfs_trans_item_committed(struct xfs_log_item *lip, xfs_lsn_t commit_lsn, int aborted); void xfs_trans_unreserve_and_mod_sb(struct xfs_trans *tp); -- cgit v1.2.3-59-g8ed1b From 5b3eed756cd37255cad1181bd86bfd0977e97953 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:42:41 +1000 Subject: xfs: ensure we mark all inodes in a freed cluster XFS_ISTALE Under heavy load parallel metadata loads (e.g. dbench), we can fail to mark all the inodes in a cluster being freed as XFS_ISTALE as we skip inodes we cannot get the XFS_ILOCK_EXCL or the flush lock on. When this happens and the inode cluster buffer has already been marked stale and freed, inode reclaim can try to write the inode out as it is dirty and not marked stale. This can result in writing th metadata to an freed extent, or in the case it has already been overwritten trigger a magic number check failure and return an EUCLEAN error such as: Filesystem "ram0": inode 0x442ba1 background reclaim flush failed with 117 Fix this by ensuring that we hoover up all in memory inodes in the cluster and mark them XFS_ISTALE when freeing the cluster. Cc: Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_inode.c | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 68415cb4f23c..34798f391c49 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1914,6 +1914,11 @@ xfs_iunlink_remove( return 0; } +/* + * A big issue when freeing the inode cluster is is that we _cannot_ skip any + * inodes that are in memory - they all must be marked stale and attached to + * the cluster buffer. + */ STATIC void xfs_ifree_cluster( xfs_inode_t *free_ip, @@ -1945,8 +1950,6 @@ xfs_ifree_cluster( } for (j = 0; j < nbufs; j++, inum += ninodes) { - int found = 0; - blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum), XFS_INO_TO_AGBNO(mp, inum)); @@ -1965,7 +1968,9 @@ xfs_ifree_cluster( /* * Walk the inodes already attached to the buffer and mark them * stale. These will all have the flush locks held, so an - * in-memory inode walk can't lock them. + * in-memory inode walk can't lock them. By marking them all + * stale first, we will not attempt to lock them in the loop + * below as the XFS_ISTALE flag will be set. */ lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); while (lip) { @@ -1977,11 +1982,11 @@ xfs_ifree_cluster( &iip->ili_flush_lsn, &iip->ili_item.li_lsn); xfs_iflags_set(iip->ili_inode, XFS_ISTALE); - found++; } lip = lip->li_bio_list; } + /* * For each inode in memory attempt to add it to the inode * buffer and set it up for being staled on buffer IO @@ -1993,6 +1998,7 @@ xfs_ifree_cluster( * even trying to lock them. */ for (i = 0; i < ninodes; i++) { +retry: read_lock(&pag->pag_ici_lock); ip = radix_tree_lookup(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, (inum + i))); @@ -2003,38 +2009,36 @@ xfs_ifree_cluster( continue; } - /* don't try to lock/unlock the current inode */ + /* + * Don't try to lock/unlock the current inode, but we + * _cannot_ skip the other inodes that we did not find + * in the list attached to the buffer and are not + * already marked stale. If we can't lock it, back off + * and retry. + */ if (ip != free_ip && !xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { read_unlock(&pag->pag_ici_lock); - continue; + delay(1); + goto retry; } read_unlock(&pag->pag_ici_lock); - if (!xfs_iflock_nowait(ip)) { - if (ip != free_ip) - xfs_iunlock(ip, XFS_ILOCK_EXCL); - continue; - } - + xfs_iflock(ip); xfs_iflags_set(ip, XFS_ISTALE); - if (xfs_inode_clean(ip)) { - ASSERT(ip != free_ip); - xfs_ifunlock(ip); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - continue; - } + /* + * we don't need to attach clean inodes or those only + * with unlogged changes (which we throw away, anyway). + */ iip = ip->i_itemp; - if (!iip) { - /* inode with unlogged changes only */ + if (!iip || xfs_inode_clean(ip)) { ASSERT(ip != free_ip); ip->i_update_core = 0; xfs_ifunlock(ip); xfs_iunlock(ip, XFS_ILOCK_EXCL); continue; } - found++; iip->ili_last_fields = iip->ili_format.ilf_fields; iip->ili_format.ilf_fields = 0; @@ -2049,8 +2053,7 @@ xfs_ifree_cluster( xfs_iunlock(ip, XFS_ILOCK_EXCL); } - if (found) - xfs_trans_stale_inode_buf(tp, bp); + xfs_trans_stale_inode_buf(tp, bp); xfs_trans_binval(tp, bp); } -- cgit v1.2.3-59-g8ed1b From 4536f2ad8b330453d7ebec0746c4374eadd649b1 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:42:30 +1000 Subject: xfs: fix untrusted inode number lookup Commit 7124fe0a5b619d65b739477b3b55a20bf805b06d ("xfs: validate untrusted inode numbers during lookup") changes the inode lookup code to do btree lookups for untrusted inode numbers. This change made an invalid assumption about the alignment of inodes and hence incorrectly calculated the first inode in the cluster. As a result, some inode numbers were being incorrectly considered invalid when they were actually valid. The issue was not picked up by the xfstests suite because it always runs fsr and dump (the two utilities that utilise the bulkstat interface) on cache hot inodes and hence the lookup code in the cold cache path was not sufficiently exercised to uncover this intermittent problem. Fix the issue by relaxing the btree lookup criteria and then checking if the record returned contains the inode number we are lookup for. If it we get an incorrect record, then the inode number is invalid. Cc: Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_ialloc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index abf80ae1e95b..5371d2dc360e 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -1213,7 +1213,6 @@ xfs_imap_lookup( struct xfs_inobt_rec_incore rec; struct xfs_btree_cur *cur; struct xfs_buf *agbp; - xfs_agino_t startino; int error; int i; @@ -1227,13 +1226,13 @@ xfs_imap_lookup( } /* - * derive and lookup the exact inode record for the given agino. If the - * record cannot be found, then it's an invalid inode number and we - * should abort. + * Lookup the inode record for the given agino. If the record cannot be + * found, then it's an invalid inode number and we should abort. Once + * we have a record, we need to ensure it contains the inode number + * we are looking up. */ cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); - startino = agino & ~(XFS_IALLOC_INODES(mp) - 1); - error = xfs_inobt_lookup(cur, startino, XFS_LOOKUP_EQ, &i); + error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); if (!error) { if (i) error = xfs_inobt_get_rec(cur, &rec, &i); @@ -1246,6 +1245,11 @@ xfs_imap_lookup( if (error) return error; + /* check that the returned record contains the required inode */ + if (rec.ir_startino > agino || + rec.ir_startino + XFS_IALLOC_INODES(mp) <= agino) + return EINVAL; + /* for untrusted inodes check it is allocated first */ if ((flags & XFS_IGET_UNTRUSTED) && (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))) -- cgit v1.2.3-59-g8ed1b From 546a1924224078c6f582e68f890b05b387b42653 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:44:34 +1000 Subject: writeback: write_cache_pages doesn't terminate at nr_to_write <= 0 I noticed XFS writeback in 2.6.36-rc1 was much slower than it should have been. Enabling writeback tracing showed: flush-253:16-8516 [007] 1342952.351608: wbc_writepage: bdi 253:16: towrt=1024 skip=0 mode=0 kupd=0 bgrd=1 reclm=0 cyclic=1 more=0 older=0x0 start=0x0 end=0x0 flush-253:16-8516 [007] 1342952.351654: wbc_writepage: bdi 253:16: towrt=1023 skip=0 mode=0 kupd=0 bgrd=1 reclm=0 cyclic=1 more=0 older=0x0 start=0x0 end=0x0 flush-253:16-8516 [000] 1342952.369520: wbc_writepage: bdi 253:16: towrt=0 skip=0 mode=0 kupd=0 bgrd=1 reclm=0 cyclic=1 more=0 older=0x0 start=0x0 end=0x0 flush-253:16-8516 [000] 1342952.369542: wbc_writepage: bdi 253:16: towrt=-1 skip=0 mode=0 kupd=0 bgrd=1 reclm=0 cyclic=1 more=0 older=0x0 start=0x0 end=0x0 flush-253:16-8516 [000] 1342952.369549: wbc_writepage: bdi 253:16: towrt=-2 skip=0 mode=0 kupd=0 bgrd=1 reclm=0 cyclic=1 more=0 older=0x0 start=0x0 end=0x0 Writeback is not terminating in background writeback if ->writepage is returning with wbc->nr_to_write == 0, resulting in sub-optimal single page writeback on XFS. Fix the write_cache_pages loop to terminate correctly when this situation occurs and so prevent this sub-optimal background writeback pattern. This improves sustained sequential buffered write performance from around 250MB/s to 750MB/s for a 100GB file on an XFS filesystem on my 8p test VM. Cc: Signed-off-by: Dave Chinner Reviewed-by: Wu Fengguang Reviewed-by: Christoph Hellwig --- mm/page-writeback.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index c09ef5219cbe..a803f5e33471 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -985,22 +985,16 @@ continue_unlock: } } - if (wbc->nr_to_write > 0) { - if (--wbc->nr_to_write == 0 && - wbc->sync_mode == WB_SYNC_NONE) { - /* - * We stop writing back only if we are - * not doing integrity sync. In case of - * integrity sync we have to keep going - * because someone may be concurrently - * dirtying pages, and we might have - * synced a lot of newly appeared dirty - * pages, but have not synced all of the - * old dirty pages. - */ - done = 1; - break; - } + /* + * We stop writing back only if we are not doing + * integrity sync. In case of integrity sync we have to + * keep going until we have written all the pages + * we tagged for writeback prior to entering this loop. + */ + if (--wbc->nr_to_write <= 0 && + wbc->sync_mode == WB_SYNC_NONE) { + done = 1; + break; } } pagevec_release(&pvec); -- cgit v1.2.3-59-g8ed1b From efceab1d563153a2b1a6e7d35376241a48126989 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:44:56 +1000 Subject: xfs: handle negative wbc->nr_to_write during sync writeback During data integrity (WB_SYNC_ALL) writeback, wbc->nr_to_write will go negative on inodes with more than 1024 dirty pages due to implementation details of write_cache_pages(). Currently XFS will abort page clustering in writeback once nr_to_write drops below zero, and so for data integrity writeback we will do very inefficient page at a time allocation and IO submission for inodes with large numbers of dirty pages. Fix this by only aborting the page clustering code when wbc->nr_to_write is negative and the sync mode is WB_SYNC_NONE. Cc: Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_aops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 15412fe15c3a..528be1ba1402 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -852,8 +852,8 @@ xfs_convert_page( SetPageUptodate(page); if (count) { - wbc->nr_to_write--; - if (wbc->nr_to_write <= 0) + if (--wbc->nr_to_write <= 0 && + wbc->sync_mode == WB_SYNC_NONE) done = 1; } xfs_start_page_writeback(page, !page_dirty, count); -- cgit v1.2.3-59-g8ed1b From 2fe33661fcd79d4c53022509f7223d526b5fa233 Mon Sep 17 00:00:00 2001 From: Stuart Brodsky Date: Tue, 24 Aug 2010 11:46:05 +1000 Subject: xfs: ensure f_ffree returned by statfs() is non-negative Because of delayed updates to sb_icount field in the super block, it is possible to allocate over maxicount number of inodes. This causes the arithmetic to calculate a negative number of free inodes in user commands like df or stat -f. Since maxicount is a somewhat arbitrary number, a slight over allocation is not critical but user commands should be displayed as 0 or greater and never go negative. To do this the value in the stats buffer f_ffree is capped to never go negative. [ Modified to use max_t as per Christoph's comment. ] Signed-off-by: Stu Brodsky Signed-off-by: Dave Chinner --- fs/xfs/linux-2.6/xfs_super.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 15c35b62ff14..c6b24e7c308a 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1226,6 +1226,7 @@ xfs_fs_statfs( struct xfs_inode *ip = XFS_I(dentry->d_inode); __uint64_t fakeinos, id; xfs_extlen_t lsize; + __int64_t ffree; statp->f_type = XFS_SB_MAGIC; statp->f_namelen = MAXNAMELEN - 1; @@ -1249,7 +1250,11 @@ xfs_fs_statfs( statp->f_files = min_t(typeof(statp->f_files), statp->f_files, mp->m_maxicount); - statp->f_ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree); + + /* make sure statp->f_ffree does not underflow */ + ffree = statp->f_files - (sbp->sb_icount - sbp->sb_ifree); + statp->f_ffree = max_t(__int64_t, ffree, 0); + spin_unlock(&mp->m_sb_lock); if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) || -- cgit v1.2.3-59-g8ed1b From 1a387d3be2b30c90f20d49a3497a8fc0693a9d18 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:46:31 +1000 Subject: xfs: dummy transactions should not dirty VFS state When we need to cover the log, we issue dummy transactions to ensure the current log tail is on disk. Unfortunately we currently use the root inode in the dummy transaction, and the act of committing the transaction dirties the inode at the VFS level. As a result, the VFS writeback of the dirty inode will prevent the filesystem from idling long enough for the log covering state machine to complete. The state machine gets stuck in a loop issuing new dummy transactions to cover the log and never makes progress. To avoid this problem, the dummy transactions should not cause externally visible state changes. To ensure this occurs, make sure that dummy transactions log an unchanging field in the superblock as it's state is never propagated outside the filesystem. This allows the log covering state machine to complete successfully and the filesystem now correctly enters a fully idle state about 90s after the last modification was made. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_super.c | 2 +- fs/xfs/linux-2.6/xfs_sync.c | 42 ++++++------------------------------------ fs/xfs/xfs_fsops.c | 31 ++++++++++++++++++------------- fs/xfs/xfs_fsops.h | 2 +- 4 files changed, 26 insertions(+), 51 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index c6b24e7c308a..a4e07974955b 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1407,7 +1407,7 @@ xfs_fs_freeze( xfs_save_resvblks(mp); xfs_quiesce_attr(mp); - return -xfs_fs_log_dummy(mp); + return -xfs_fs_log_dummy(mp, SYNC_WAIT); } STATIC int diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index dfcbd98d1599..d59c4a65d492 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -34,6 +34,7 @@ #include "xfs_inode_item.h" #include "xfs_quota.h" #include "xfs_trace.h" +#include "xfs_fsops.h" #include #include @@ -340,38 +341,6 @@ xfs_sync_attr( XFS_ICI_NO_TAG, 0, NULL); } -STATIC int -xfs_commit_dummy_trans( - struct xfs_mount *mp, - uint flags) -{ - struct xfs_inode *ip = mp->m_rootip; - struct xfs_trans *tp; - int error; - - /* - * Put a dummy transaction in the log to tell recovery - * that all others are OK. - */ - tp = xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); - error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); - if (error) { - xfs_trans_cancel(tp, 0); - return error; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL); - - xfs_trans_ijoin(tp, ip); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = xfs_trans_commit(tp, 0); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - /* the log force ensures this transaction is pushed to disk */ - xfs_log_force(mp, (flags & SYNC_WAIT) ? XFS_LOG_SYNC : 0); - return error; -} - STATIC int xfs_sync_fsdata( struct xfs_mount *mp) @@ -432,7 +401,7 @@ xfs_quiesce_data( /* mark the log as covered if needed */ if (xfs_log_need_covered(mp)) - error2 = xfs_commit_dummy_trans(mp, SYNC_WAIT); + error2 = xfs_fs_log_dummy(mp, SYNC_WAIT); /* flush data-only devices */ if (mp->m_rtdev_targp) @@ -563,7 +532,7 @@ xfs_flush_inodes( /* * Every sync period we need to unpin all items, reclaim inodes and sync * disk quotas. We might need to cover the log to indicate that the - * filesystem is idle. + * filesystem is idle and not frozen. */ STATIC void xfs_sync_worker( @@ -577,8 +546,9 @@ xfs_sync_worker( xfs_reclaim_inodes(mp, 0); /* dgc: errors ignored here */ error = xfs_qm_sync(mp, SYNC_TRYLOCK); - if (xfs_log_need_covered(mp)) - error = xfs_commit_dummy_trans(mp, 0); + if (mp->m_super->s_frozen == SB_UNFROZEN && + xfs_log_need_covered(mp)) + error = xfs_fs_log_dummy(mp, 0); } mp->m_sync_seq++; wake_up(&mp->m_wait_single_sync_task); diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index dbca5f5c37ba..43b1d5699335 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -604,31 +604,36 @@ out: return 0; } +/* + * Dump a transaction into the log that contains no real change. This is needed + * to be able to make the log dirty or stamp the current tail LSN into the log + * during the covering operation. + * + * We cannot use an inode here for this - that will push dirty state back up + * into the VFS and then periodic inode flushing will prevent log covering from + * making progress. Hence we log a field in the superblock instead. + */ int xfs_fs_log_dummy( - xfs_mount_t *mp) + xfs_mount_t *mp, + int flags) { xfs_trans_t *tp; - xfs_inode_t *ip; int error; tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1, KM_SLEEP); - error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); + error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, + XFS_DEFAULT_LOG_COUNT); if (error) { xfs_trans_cancel(tp, 0); return error; } - ip = mp->m_rootip; - xfs_ilock(ip, XFS_ILOCK_EXCL); - - xfs_trans_ijoin(tp, ip); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - xfs_trans_set_sync(tp); - error = xfs_trans_commit(tp, 0); - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; + /* log the UUID because it is an unchanging field */ + xfs_mod_sb(tp, XFS_SB_UUID); + if (flags & SYNC_WAIT) + xfs_trans_set_sync(tp); + return xfs_trans_commit(tp, 0); } int diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h index 88435e0a77c9..a786c5212c1e 100644 --- a/fs/xfs/xfs_fsops.h +++ b/fs/xfs/xfs_fsops.h @@ -25,6 +25,6 @@ extern int xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt); extern int xfs_reserve_blocks(xfs_mount_t *mp, __uint64_t *inval, xfs_fsop_resblks_t *outval); extern int xfs_fs_goingdown(xfs_mount_t *mp, __uint32_t inflags); -extern int xfs_fs_log_dummy(xfs_mount_t *mp); +extern int xfs_fs_log_dummy(xfs_mount_t *mp, int flags); #endif /* __XFS_FSOPS_H__ */ -- cgit v1.2.3-59-g8ed1b From a44f13edf0ebb4e41942d0f16ca80489dcf6659d Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:40:03 +1000 Subject: xfs: Reduce log force overhead for delayed logging Delayed logging adds some serialisation to the log force process to ensure that it does not deference a bad commit context structure when determining if a CIL push is necessary or not. It does this by grabing the CIL context lock exclusively, then dropping it before pushing the CIL if necessary. This causes serialisation of all log forces and pushes regardless of whether a force is necessary or not. As a result fsync heavy workloads (like dbench) can be significantly slower with delayed logging than without. To avoid this penalty, copy the current sequence from the context to the CIL structure when they are swapped. This allows us to do unlocked checks on the current sequence without having to worry about dereferencing context structures that may have already been freed. Hence we can remove the CIL context locking in the forcing code and only call into the push code if the current context matches the sequence we need to force. By passing the sequence into the push code, we can check the sequence again once we have the CIL lock held exclusive and abort if the sequence has already been pushed. This avoids a lock round-trip and unnecessary CIL pushes when we have racing push calls. The result is that the regression in dbench performance goes away - this change improves dbench performance on a ramdisk from ~2100MB/s to ~2500MB/s. This compares favourably to not using delayed logging which retuns ~2500MB/s for the same workload. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_log.c | 7 +- fs/xfs/xfs_log_cil.c | 245 +++++++++++++++++++++++++++----------------------- fs/xfs/xfs_log_priv.h | 13 ++- 3 files changed, 147 insertions(+), 118 deletions(-) diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 925d572bf0f4..33f718f92a48 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -3015,7 +3015,8 @@ _xfs_log_force( XFS_STATS_INC(xs_log_force); - xlog_cil_push(log, 1); + if (log->l_cilp) + xlog_cil_force(log); spin_lock(&log->l_icloglock); @@ -3167,7 +3168,7 @@ _xfs_log_force_lsn( XFS_STATS_INC(xs_log_force); if (log->l_cilp) { - lsn = xlog_cil_push_lsn(log, lsn); + lsn = xlog_cil_force_lsn(log, lsn); if (lsn == NULLCOMMITLSN) return 0; } @@ -3724,7 +3725,7 @@ xfs_log_force_umount( * call below. */ if (!logerror && (mp->m_flags & XFS_MOUNT_DELAYLOG)) - xlog_cil_push(log, 1); + xlog_cil_force(log); /* * We must hold both the GRANT lock and the LOG lock, diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index ef8e7d9f445d..9768f2437bb3 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -68,6 +68,7 @@ xlog_cil_init( ctx->sequence = 1; ctx->cil = cil; cil->xc_ctx = ctx; + cil->xc_current_sequence = ctx->sequence; cil->xc_log = log; log->l_cilp = cil; @@ -320,94 +321,6 @@ xlog_cil_free_logvec( } } -/* - * Commit a transaction with the given vector to the Committed Item List. - * - * To do this, we need to format the item, pin it in memory if required and - * account for the space used by the transaction. Once we have done that we - * need to release the unused reservation for the transaction, attach the - * transaction to the checkpoint context so we carry the busy extents through - * to checkpoint completion, and then unlock all the items in the transaction. - * - * For more specific information about the order of operations in - * xfs_log_commit_cil() please refer to the comments in - * xfs_trans_commit_iclog(). - * - * Called with the context lock already held in read mode to lock out - * background commit, returns without it held once background commits are - * allowed again. - */ -int -xfs_log_commit_cil( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_log_vec *log_vector, - xfs_lsn_t *commit_lsn, - int flags) -{ - struct log *log = mp->m_log; - int log_flags = 0; - int push = 0; - - if (flags & XFS_TRANS_RELEASE_LOG_RES) - log_flags = XFS_LOG_REL_PERM_RESERV; - - if (XLOG_FORCED_SHUTDOWN(log)) { - xlog_cil_free_logvec(log_vector); - return XFS_ERROR(EIO); - } - - /* lock out background commit */ - down_read(&log->l_cilp->xc_ctx_lock); - xlog_cil_format_items(log, log_vector, tp->t_ticket, commit_lsn); - - /* check we didn't blow the reservation */ - if (tp->t_ticket->t_curr_res < 0) - xlog_print_tic_res(log->l_mp, tp->t_ticket); - - /* attach the transaction to the CIL if it has any busy extents */ - if (!list_empty(&tp->t_busy)) { - spin_lock(&log->l_cilp->xc_cil_lock); - list_splice_init(&tp->t_busy, - &log->l_cilp->xc_ctx->busy_extents); - spin_unlock(&log->l_cilp->xc_cil_lock); - } - - tp->t_commit_lsn = *commit_lsn; - xfs_log_done(mp, tp->t_ticket, NULL, log_flags); - xfs_trans_unreserve_and_mod_sb(tp); - - /* - * Once all the items of the transaction have been copied to the CIL, - * the items can be unlocked and freed. - * - * This needs to be done before we drop the CIL context lock because we - * have to update state in the log items and unlock them before they go - * to disk. If we don't, then the CIL checkpoint can race with us and - * we can run checkpoint completion before we've updated and unlocked - * the log items. This affects (at least) processing of stale buffers, - * inodes and EFIs. - */ - xfs_trans_free_items(tp, *commit_lsn, 0); - - /* check for background commit before unlock */ - if (log->l_cilp->xc_ctx->space_used > XLOG_CIL_SPACE_LIMIT(log)) - push = 1; - - up_read(&log->l_cilp->xc_ctx_lock); - - /* - * We need to push CIL every so often so we don't cache more than we - * can fit in the log. The limit really is that a checkpoint can't be - * more than half the log (the current checkpoint is not allowed to - * overwrite the previous checkpoint), but commit latency and memory - * usage limit this to a smaller size in most cases. - */ - if (push) - xlog_cil_push(log, 0); - return 0; -} - /* * Mark all items committed and clear busy extents. We free the log vector * chains in a separate pass so that we unpin the log items as quickly as @@ -441,13 +354,23 @@ xlog_cil_committed( } /* - * Push the Committed Item List to the log. If the push_now flag is not set, - * then it is a background flush and so we can chose to ignore it. + * Push the Committed Item List to the log. If @push_seq flag is zero, then it + * is a background flush and so we can chose to ignore it. Otherwise, if the + * current sequence is the same as @push_seq we need to do a flush. If + * @push_seq is less than the current sequence, then it has already been + * flushed and we don't need to do anything - the caller will wait for it to + * complete if necessary. + * + * @push_seq is a value rather than a flag because that allows us to do an + * unlocked check of the sequence number for a match. Hence we can allows log + * forces to run racily and not issue pushes for the same sequence twice. If we + * get a race between multiple pushes for the same sequence they will block on + * the first one and then abort, hence avoiding needless pushes. */ -int +STATIC int xlog_cil_push( struct log *log, - int push_now) + xfs_lsn_t push_seq) { struct xfs_cil *cil = log->l_cilp; struct xfs_log_vec *lv; @@ -467,12 +390,14 @@ xlog_cil_push( if (!cil) return 0; + ASSERT(!push_seq || push_seq <= cil->xc_ctx->sequence); + new_ctx = kmem_zalloc(sizeof(*new_ctx), KM_SLEEP|KM_NOFS); new_ctx->ticket = xlog_cil_ticket_alloc(log); /* lock out transaction commit, but don't block on background push */ if (!down_write_trylock(&cil->xc_ctx_lock)) { - if (!push_now) + if (!push_seq) goto out_free_ticket; down_write(&cil->xc_ctx_lock); } @@ -483,7 +408,11 @@ xlog_cil_push( goto out_skip; /* check for spurious background flush */ - if (!push_now && cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log)) + if (!push_seq && cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log)) + goto out_skip; + + /* check for a previously pushed seqeunce */ + if (push_seq < cil->xc_ctx->sequence) goto out_skip; /* @@ -528,6 +457,13 @@ xlog_cil_push( new_ctx->cil = cil; cil->xc_ctx = new_ctx; + /* + * mirror the new sequence into the cil structure so that we can do + * unlocked checks against the current sequence in log forces without + * risking deferencing a freed context pointer. + */ + cil->xc_current_sequence = new_ctx->sequence; + /* * The switch is now done, so we can drop the context lock and move out * of a shared context. We can't just go straight to the commit record, @@ -639,6 +575,94 @@ out_abort: return XFS_ERROR(EIO); } +/* + * Commit a transaction with the given vector to the Committed Item List. + * + * To do this, we need to format the item, pin it in memory if required and + * account for the space used by the transaction. Once we have done that we + * need to release the unused reservation for the transaction, attach the + * transaction to the checkpoint context so we carry the busy extents through + * to checkpoint completion, and then unlock all the items in the transaction. + * + * For more specific information about the order of operations in + * xfs_log_commit_cil() please refer to the comments in + * xfs_trans_commit_iclog(). + * + * Called with the context lock already held in read mode to lock out + * background commit, returns without it held once background commits are + * allowed again. + */ +int +xfs_log_commit_cil( + struct xfs_mount *mp, + struct xfs_trans *tp, + struct xfs_log_vec *log_vector, + xfs_lsn_t *commit_lsn, + int flags) +{ + struct log *log = mp->m_log; + int log_flags = 0; + int push = 0; + + if (flags & XFS_TRANS_RELEASE_LOG_RES) + log_flags = XFS_LOG_REL_PERM_RESERV; + + if (XLOG_FORCED_SHUTDOWN(log)) { + xlog_cil_free_logvec(log_vector); + return XFS_ERROR(EIO); + } + + /* lock out background commit */ + down_read(&log->l_cilp->xc_ctx_lock); + xlog_cil_format_items(log, log_vector, tp->t_ticket, commit_lsn); + + /* check we didn't blow the reservation */ + if (tp->t_ticket->t_curr_res < 0) + xlog_print_tic_res(log->l_mp, tp->t_ticket); + + /* attach the transaction to the CIL if it has any busy extents */ + if (!list_empty(&tp->t_busy)) { + spin_lock(&log->l_cilp->xc_cil_lock); + list_splice_init(&tp->t_busy, + &log->l_cilp->xc_ctx->busy_extents); + spin_unlock(&log->l_cilp->xc_cil_lock); + } + + tp->t_commit_lsn = *commit_lsn; + xfs_log_done(mp, tp->t_ticket, NULL, log_flags); + xfs_trans_unreserve_and_mod_sb(tp); + + /* + * Once all the items of the transaction have been copied to the CIL, + * the items can be unlocked and freed. + * + * This needs to be done before we drop the CIL context lock because we + * have to update state in the log items and unlock them before they go + * to disk. If we don't, then the CIL checkpoint can race with us and + * we can run checkpoint completion before we've updated and unlocked + * the log items. This affects (at least) processing of stale buffers, + * inodes and EFIs. + */ + xfs_trans_free_items(tp, *commit_lsn, 0); + + /* check for background commit before unlock */ + if (log->l_cilp->xc_ctx->space_used > XLOG_CIL_SPACE_LIMIT(log)) + push = 1; + + up_read(&log->l_cilp->xc_ctx_lock); + + /* + * We need to push CIL every so often so we don't cache more than we + * can fit in the log. The limit really is that a checkpoint can't be + * more than half the log (the current checkpoint is not allowed to + * overwrite the previous checkpoint), but commit latency and memory + * usage limit this to a smaller size in most cases. + */ + if (push) + xlog_cil_push(log, 0); + return 0; +} + /* * Conditionally push the CIL based on the sequence passed in. * @@ -653,39 +677,34 @@ out_abort: * commit lsn is there. It'll be empty, so this is broken for now. */ xfs_lsn_t -xlog_cil_push_lsn( +xlog_cil_force_lsn( struct log *log, - xfs_lsn_t push_seq) + xfs_lsn_t sequence) { struct xfs_cil *cil = log->l_cilp; struct xfs_cil_ctx *ctx; xfs_lsn_t commit_lsn = NULLCOMMITLSN; -restart: - down_write(&cil->xc_ctx_lock); - ASSERT(push_seq <= cil->xc_ctx->sequence); - - /* check to see if we need to force out the current context */ - if (push_seq == cil->xc_ctx->sequence) { - up_write(&cil->xc_ctx_lock); - xlog_cil_push(log, 1); - goto restart; - } + ASSERT(sequence <= cil->xc_current_sequence); + + /* + * check to see if we need to force out the current context. + * xlog_cil_push() handles racing pushes for the same sequence, + * so no need to deal with it here. + */ + if (sequence == cil->xc_current_sequence) + xlog_cil_push(log, sequence); /* * See if we can find a previous sequence still committing. - * We can drop the flush lock as soon as we have the cil lock - * because we are now only comparing contexts protected by - * the cil lock. - * * We need to wait for all previous sequence commits to complete * before allowing the force of push_seq to go ahead. Hence block * on commits for those as well. */ +restart: spin_lock(&cil->xc_cil_lock); - up_write(&cil->xc_ctx_lock); list_for_each_entry(ctx, &cil->xc_committing, committing) { - if (ctx->sequence > push_seq) + if (ctx->sequence > sequence) continue; if (!ctx->commit_lsn) { /* @@ -695,7 +714,7 @@ restart: sv_wait(&cil->xc_commit_wait, 0, &cil->xc_cil_lock, 0); goto restart; } - if (ctx->sequence != push_seq) + if (ctx->sequence != sequence) continue; /* found it! */ commit_lsn = ctx->commit_lsn; diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 8c072618965c..ced52b98b322 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -422,6 +422,7 @@ struct xfs_cil { struct rw_semaphore xc_ctx_lock; struct list_head xc_committing; sv_t xc_commit_wait; + xfs_lsn_t xc_current_sequence; }; /* @@ -562,8 +563,16 @@ int xlog_cil_init(struct log *log); void xlog_cil_init_post_recovery(struct log *log); void xlog_cil_destroy(struct log *log); -int xlog_cil_push(struct log *log, int push_now); -xfs_lsn_t xlog_cil_push_lsn(struct log *log, xfs_lsn_t push_sequence); +/* + * CIL force routines + */ +xfs_lsn_t xlog_cil_force_lsn(struct log *log, xfs_lsn_t sequence); + +static inline void +xlog_cil_force(struct log *log) +{ + xlog_cil_force_lsn(log, log->l_cilp->xc_current_sequence); +} /* * Unmount record type is used as a pseudo transaction type for the ticket. -- cgit v1.2.3-59-g8ed1b From 3b93c7aaefc05ee2a75e2726929b01a321402984 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 24 Aug 2010 11:45:53 +1000 Subject: xfs: don't do memory allocation under the CIL context lock Formatting items requires memory allocation when using delayed logging. Currently that memory allocation is done while holding the CIL context lock in read mode. This means that if memory allocation takes some time (e.g. enters reclaim), we cannot push on the CIL until the allocation(s) required by formatting complete. This can stall CIL pushes for some time, and once a push is stalled so are all new transaction commits. Fix this splitting the item formatting into two steps. The first step which does the allocation and memcpy() into the allocated buffer is now done outside the CIL context lock, and only the CIL insert is done inside the CIL context lock. This avoids the stall issue. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_log_cil.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 9768f2437bb3..ed575fb4b495 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -270,15 +270,10 @@ xlog_cil_insert( static void xlog_cil_format_items( struct log *log, - struct xfs_log_vec *log_vector, - struct xlog_ticket *ticket, - xfs_lsn_t *start_lsn) + struct xfs_log_vec *log_vector) { struct xfs_log_vec *lv; - if (start_lsn) - *start_lsn = log->l_cilp->xc_ctx->sequence; - ASSERT(log_vector); for (lv = log_vector; lv; lv = lv->lv_next) { void *ptr; @@ -302,9 +297,24 @@ xlog_cil_format_items( ptr += vec->i_len; } ASSERT(ptr == lv->lv_buf + lv->lv_buf_len); + } +} +static void +xlog_cil_insert_items( + struct log *log, + struct xfs_log_vec *log_vector, + struct xlog_ticket *ticket, + xfs_lsn_t *start_lsn) +{ + struct xfs_log_vec *lv; + + if (start_lsn) + *start_lsn = log->l_cilp->xc_ctx->sequence; + + ASSERT(log_vector); + for (lv = log_vector; lv; lv = lv->lv_next) xlog_cil_insert(log, ticket, lv->lv_item, lv); - } } static void @@ -612,9 +622,17 @@ xfs_log_commit_cil( return XFS_ERROR(EIO); } + /* + * do all the hard work of formatting items (including memory + * allocation) outside the CIL context lock. This prevents stalling CIL + * pushes when we are low on memory and a transaction commit spends a + * lot of time in memory reclaim. + */ + xlog_cil_format_items(log, log_vector); + /* lock out background commit */ down_read(&log->l_cilp->xc_ctx_lock); - xlog_cil_format_items(log, log_vector, tp->t_ticket, commit_lsn); + xlog_cil_insert_items(log, log_vector, tp->t_ticket, commit_lsn); /* check we didn't blow the reservation */ if (tp->t_ticket->t_curr_res < 0) -- cgit v1.2.3-59-g8ed1b From b5420f235953448eeae615b3361584dc5e414f34 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 24 Aug 2010 11:47:51 +1000 Subject: xfs: do not discard page cache data on EAGAIN If xfs_map_blocks returns EAGAIN because of lock contention we must redirty the page and not disard the pagecache content and return an error from writepage. We used to do this correctly, but the logic got lost during the recent reshuffle of the writepage code. Signed-off-by: Christoph Hellwig Reported-by: Mike Gao Tested-by: Mike Gao Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/linux-2.6/xfs_aops.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 528be1ba1402..b552f816de15 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1068,7 +1068,7 @@ xfs_vm_writepage( * by themselves. */ if ((current->flags & (PF_MEMALLOC|PF_KSWAPD)) == PF_MEMALLOC) - goto out_fail; + goto redirty; /* * We need a transaction if there are delalloc or unwritten buffers @@ -1080,7 +1080,7 @@ xfs_vm_writepage( */ xfs_count_page_state(page, &delalloc, &unwritten); if ((current->flags & PF_FSTRANS) && (delalloc || unwritten)) - goto out_fail; + goto redirty; /* Is this page beyond the end of the file? */ offset = i_size_read(inode); @@ -1245,12 +1245,15 @@ error: if (iohead) xfs_cancel_ioend(iohead); + if (err == -EAGAIN) + goto redirty; + xfs_aops_discard_page(page); ClearPageUptodate(page); unlock_page(page); return err; -out_fail: +redirty: redirty_page_for_writepage(wbc, page); unlock_page(page); return 0; -- cgit v1.2.3-59-g8ed1b From 4c3a76abd379d9a4668b2d417baa991de9757dc2 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Sun, 22 Aug 2010 19:03:26 +0000 Subject: bridge: netfilter: fix a memory leak nf_bridge_alloc() always reset the skb->nf_bridge, so we should always put the old one. Signed-off-by: Changli Gao Signed-off-by: Bart De Schuymer Signed-off-by: David S. Miller --- net/bridge/br_netfilter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 2c911c0759c2..5ed00bd7009f 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -162,8 +162,8 @@ static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb) if (tmp) { memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info)); atomic_set(&tmp->use, 1); - nf_bridge_put(nf_bridge); } + nf_bridge_put(nf_bridge); nf_bridge = tmp; } return nf_bridge; -- cgit v1.2.3-59-g8ed1b From 7b589a35a1063b52f98c8b0f1b8f69afe91c3dba Mon Sep 17 00:00:00 2001 From: Yinglin Luan Date: Sun, 22 Aug 2010 21:56:19 +0000 Subject: netxen: fix poll implementation Function netxen_intr has pointer to nx_host_sds_ring as second parameter not pointer to netxen_adapter. Signed-off-by: Yinglin Luan Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index cb30df106a2c..73d314592230 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -2131,9 +2131,16 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) #ifdef CONFIG_NET_POLL_CONTROLLER static void netxen_nic_poll_controller(struct net_device *netdev) { + int ring; + struct nx_host_sds_ring *sds_ring; struct netxen_adapter *adapter = netdev_priv(netdev); + struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; + disable_irq(adapter->irq); - netxen_intr(adapter->irq, adapter); + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + netxen_intr(adapter->irq, sds_ring); + } enable_irq(adapter->irq); } #endif -- cgit v1.2.3-59-g8ed1b From bf82791ed667758a0f18a4b76be2d931d2c1b39d Mon Sep 17 00:00:00 2001 From: Yinglin Luan Date: Sun, 22 Aug 2010 21:57:56 +0000 Subject: qlcnic: fix poll implementation Function qlcnic_intr has pointer to qlcnic_host_sds_ring as second parameter not pointer to qlcnic_adapter. Signed-off-by: Yinglin Luan Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 213e3656d953..66eea5972020 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -2188,9 +2188,16 @@ static int qlcnic_rx_poll(struct napi_struct *napi, int budget) #ifdef CONFIG_NET_POLL_CONTROLLER static void qlcnic_poll_controller(struct net_device *netdev) { + int ring; + struct qlcnic_host_sds_ring *sds_ring; struct qlcnic_adapter *adapter = netdev_priv(netdev); + struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx; + disable_irq(adapter->irq); - qlcnic_intr(adapter->irq, adapter); + for (ring = 0; ring < adapter->max_sds_rings; ring++) { + sds_ring = &recv_ctx->sds_rings[ring]; + qlcnic_intr(adapter->irq, sds_ring); + } enable_irq(adapter->irq); } #endif -- cgit v1.2.3-59-g8ed1b From 9a887162be81bd21ea8495e0a57b46ab1d77d205 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 Aug 2010 09:59:58 +0200 Subject: USB: uvc_v4l2: cleanup test for end of loop We're trying to test for the the end of the loop here. "format" is never NULL. We don't know what "format->fcc" is because we're past the end of the loop and I think "fmt->fmt.pix.pixelformat" comes from the user so we don't know what that is either. It works, but it's cleaner to just test to see if (i == ARRAY_SIZE(uvc_formats). Signed-off-by: Dan Carpenter Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/uvc_v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c index 2dcffdac86d2..5e807f083bc8 100644 --- a/drivers/usb/gadget/uvc_v4l2.c +++ b/drivers/usb/gadget/uvc_v4l2.c @@ -94,7 +94,7 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) break; } - if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) { + if (i == ARRAY_SIZE(uvc_formats)) { printk(KERN_INFO "Unsupported format 0x%08x.\n", fmt->fmt.pix.pixelformat); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 76078dc4fc389185fe467d33428f259ea9e69807 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Fri, 6 Aug 2010 18:49:21 +0400 Subject: USB: option: add Celot CT-650 Signed-off-by: Michael Tokarev Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9fc6ea2c681f..adcbdb994de3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -365,6 +365,10 @@ static void option_instat_callback(struct urb *urb); #define OLIVETTI_VENDOR_ID 0x0b3c #define OLIVETTI_PRODUCT_OLICARD100 0xc000 +/* Celot products */ +#define CELOT_VENDOR_ID 0x211f +#define CELOT_PRODUCT_CT680M 0x6801 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -887,10 +891,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) }, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, - { USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) }, - { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, + { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.3-59-g8ed1b From ebb8a4e48722c8f5e04a6490b197d2fbc894a0f6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 5 Aug 2010 17:53:57 -0400 Subject: USB: isp1760: use a write barrier to ensure proper ndelay timing The ISP1760 has some timing requirements where it has to delay a short period after a write to a register has started. However, this delay is from the time the write hits the USB chip (the ISP1760), not from the time where the processor started processing the write. So on a quick enough processor, it is sometimes possible for the write to not hit the device before we start delaying, and we then violate the part's timing requirements, so things stop working. To avoid all this, insert a write barrier after the register write and before the timing delay/register read so we can guarantee we only start counting time after the write has hit the device. Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index d1a3dfc9a408..bdba8c5d844a 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -829,6 +829,7 @@ static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, * almost immediately. With ISP1761, this register requires a delay of * 195ns between a write and subsequent read (see section 15.1.1.3). */ + mmiowb(); ndelay(195); skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); @@ -870,6 +871,7 @@ static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, * almost immediately. With ISP1761, this register requires a delay of * 195ns between a write and subsequent read (see section 15.1.1.3). */ + mmiowb(); ndelay(195); skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); -- cgit v1.2.3-59-g8ed1b From 0eee6a2b2a52e17066a572d30ad2805d3ebc7508 Mon Sep 17 00:00:00 2001 From: Ross Burton Date: Fri, 6 Aug 2010 16:36:39 +0100 Subject: USB: add device IDs for igotu to navman I recently bought a i-gotU USB GPS, and whilst hunting around for linux support discovered this post by you back in 2009: http://kerneltrap.org/mailarchive/linux-usb/2009/3/12/5148644 >Try the navman driver instead. You can either add the device id to the > driver and rebuild it, or do this before you plug the device in: > modprobe navman > echo -n "0x0df7 0x0900" > /sys/bus/usb-serial/drivers/navman/new_id > > and then plug your device in and see if that works. I can confirm that the navman driver works with the right device IDs on my i-gotU GT-600, which has the same device IDs. Attached is a patch adding the IDs. From: Ross Burton Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/navman.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index a6b207c84917..1f00f243c26c 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -25,6 +25,7 @@ static int debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ + { USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit v1.2.3-59-g8ed1b From d92a3ca689257c6bec94e026538782c280afaaab Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 7 Aug 2010 16:20:35 +0800 Subject: USB: serial: fix leak of usb serial module refrence count The patch with title below makes reference count of usb serial module always more than one after driver is bound. USB-BKL: Remove BKL use for usb serial driver probing In fact, the patch above only replaces lock_kernel() with try_module_get() , and does not use module_put() to do what unlock_kernel() did, so casue leak of reference count of usb serial module and the module can not be unloaded after serial driver is bound with device. This patch fixes the issue, also simplifies such things: -only call try_module_get() once in the entry of usb_serial_probe() -only call module_put() once in the exit of usb_serial_probe Signed-off-by: Ming Lei Cc: Johan Hovold Cc: Andi Kleen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2a982e62963b..7a2177c79bde 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -736,6 +736,7 @@ int usb_serial_probe(struct usb_interface *interface, serial = create_serial(dev, interface, type); if (!serial) { + module_put(type->driver.owner); dev_err(&interface->dev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -746,11 +747,11 @@ int usb_serial_probe(struct usb_interface *interface, id = get_iface_id(type, interface); retval = type->probe(serial, id); - module_put(type->driver.owner); if (retval) { dbg("sub driver rejected device"); kfree(serial); + module_put(type->driver.owner); return retval; } } @@ -822,6 +823,7 @@ int usb_serial_probe(struct usb_interface *interface, if (num_bulk_in == 0 || num_bulk_out == 0) { dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree(serial); + module_put(type->driver.owner); return -ENODEV; } } @@ -835,22 +837,15 @@ int usb_serial_probe(struct usb_interface *interface, dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree(serial); + module_put(type->driver.owner); return -EIO; } } #endif if (!num_ports) { /* if this device type has a calc_num_ports function, call it */ - if (type->calc_num_ports) { - if (!try_module_get(type->driver.owner)) { - dev_err(&interface->dev, - "module get failed, exiting\n"); - kfree(serial); - return -EIO; - } + if (type->calc_num_ports) num_ports = type->calc_num_ports(serial); - module_put(type->driver.owner); - } if (!num_ports) num_ports = type->num_ports; } @@ -1039,13 +1034,7 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has an attach function, call it */ if (type->attach) { - if (!try_module_get(type->driver.owner)) { - dev_err(&interface->dev, - "module get failed, exiting\n"); - goto probe_error; - } retval = type->attach(serial); - module_put(type->driver.owner); if (retval < 0) goto probe_error; serial->attached = 1; @@ -1088,10 +1077,12 @@ int usb_serial_probe(struct usb_interface *interface, exit: /* success */ usb_set_intfdata(interface, serial); + module_put(type->driver.owner); return 0; probe_error: usb_serial_put(serial); + module_put(type->driver.owner); return -EIO; } EXPORT_SYMBOL_GPL(usb_serial_probe); -- cgit v1.2.3-59-g8ed1b From f36ecd5de93e4c85a9e3d25100c6e233155b12e5 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 9 Aug 2010 15:55:32 +0200 Subject: USB: pl2303: New vendor and product id Add support for the Zeagle N2iTiON3 dive computer interface. Since Zeagle devices are actually manufactured by Seiko, this patch will support other Seiko based models as well. Signed-off-by: Jef Driesen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 6b6001822279..c98f0fb675ba 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -86,6 +86,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, + { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index a871645389dd..43eb9bdad422 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -128,6 +128,10 @@ #define CRESSI_VENDOR_ID 0x04b8 #define CRESSI_EDY_PRODUCT_ID 0x0521 +/* Zeagle dive computer interface */ +#define ZEAGLE_VENDOR_ID 0x04b8 +#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 + /* Sony, USB data cable for CMD-Jxx mobile phones */ #define SONY_VENDOR_ID 0x054c #define SONY_QN3USB_PRODUCT_ID 0x0437 -- cgit v1.2.3-59-g8ed1b From 72916791cbeb9cc607ae620cfba207dea481cd76 Mon Sep 17 00:00:00 2001 From: Craig Shelley Date: Wed, 18 Aug 2010 22:13:39 +0100 Subject: USB: CP210x Fix Break On/Off The definitions for BREAK_ON and BREAK_OFF are inverted, causing break requests to fail. This patch sets BREAK_ON and BREAK_OFF to the correct values. Signed-off-by: Craig Shelley Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 2bef4415c19c..80bf8333bb03 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -222,8 +222,8 @@ static struct usb_serial_driver cp210x_device = { #define BITS_STOP_2 0x0002 /* CP210X_SET_BREAK */ -#define BREAK_ON 0x0000 -#define BREAK_OFF 0x0001 +#define BREAK_ON 0x0001 +#define BREAK_OFF 0x0000 /* CP210X_(SET_MHS|GET_MDMSTS) */ #define CONTROL_DTR 0x0001 -- cgit v1.2.3-59-g8ed1b From d1ab903d2552b2362339b19203c7f01c797cb316 Mon Sep 17 00:00:00 2001 From: Michael Wileczka Date: Wed, 18 Aug 2010 07:14:37 -0700 Subject: USB: ftdi_sio: fix endianess of max packet size The USB max packet size (always little-endian) was not being byte swapped on big-endian systems. Applicable since [USB: ftdi_sio: fix hi-speed device packet size calculation] approx 2.6.31 Signed-off-by: Michael Wileczka Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index eb12d9b096b4..e04a41613fbf 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1376,7 +1376,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port) } /* set max packet size based on descriptor */ - priv->max_packet_size = ep_desc->wMaxPacketSize; + priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize); dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } -- cgit v1.2.3-59-g8ed1b From 0827a9ff2bbcbb03c33f1a6eb283fe051059482c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 17 Aug 2010 15:15:37 -0700 Subject: USB: io_ti: check firmware version before updating If we can't read the firmware for a device from the disk, and yet the device already has a valid firmware image in it, we don't want to replace the firmware with something invalid. So check the version number to be less than the current one to verify this is the correct thing to do. Reported-by: Chris Beauchamp Tested-by: Chris Beauchamp Cc: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/io_ti.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index dc47f986df57..c3f27c316753 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1151,7 +1151,7 @@ static int download_fw(struct edgeport_serial *serial) /* Check if we have an old version in the I2C and update if necessary */ - if (download_cur_ver != download_new_ver) { + if (download_cur_ver < download_new_ver) { dbg("%s - Update I2C dld from %d.%d to %d.%d", __func__, firmware_version->Ver_Major, -- cgit v1.2.3-59-g8ed1b From 96f2a34d2cec71d59014be9ecd7a038435e88584 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 17 Aug 2010 09:41:29 +0800 Subject: USB: r8a66597-udc: return -ENOMEM if kzalloc() fails Signed-off-by: Axel Lin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/r8a66597-udc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 70a817842755..2456ccd9965e 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1557,6 +1557,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) /* initialize ucd */ r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); if (r8a66597 == NULL) { + ret = -ENOMEM; printk(KERN_ERR "kzalloc error\n"); goto clean_up; } -- cgit v1.2.3-59-g8ed1b From 175230587bcca6dee0a1d6832a8a2138e32ab6ab Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:05 -0400 Subject: USB: ssu100: add locking for port private data in ssu100 Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 6e82d4f54bc8..2826f013752d 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -99,6 +99,7 @@ static struct usb_driver ssu100_driver = { }; struct ssu100_port_private { + spinlock_t status_lock; u8 shadowLSR; u8 shadowMSR; wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ @@ -333,6 +334,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) struct ssu100_port_private *priv = usb_get_serial_port_data(port); u8 *data; int result; + unsigned long flags; dbg("%s - port %d", __func__, port->number); @@ -350,11 +352,13 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return result; } + spin_lock_irqsave(&priv->status_lock, flags); priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI); priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_CD); + spin_unlock_irqrestore(&priv->status_lock, flags); kfree(data); @@ -455,6 +459,7 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port) unsigned num_endpoints; int i; + unsigned long flags; num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); @@ -466,7 +471,9 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port) } /* set max packet size based on descriptor */ + spin_lock_irqsave(&priv->status_lock, flags); priv->max_packet_size = ep_desc->wMaxPacketSize; + spin_unlock_irqrestore(&priv->status_lock, flags); dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); } @@ -485,9 +492,9 @@ static int ssu100_attach(struct usb_serial *serial) return -ENOMEM; } + spin_lock_init(&priv->status_lock); init_waitqueue_head(&priv->delta_msr_wait); usb_set_serial_port_data(port, priv); - ssu100_set_max_packet_size(port); return ssu100_initdevice(serial->dev); -- cgit v1.2.3-59-g8ed1b From 9b2cef31f2823558eb92a35624d37439599f3f9f Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:06 -0400 Subject: USB: ssu100: refine process_packet in ssu100 The status information does not appear at the start of each incoming packet so the check for len < 4 at the start of ssu100_process_packet is wrong. Remove it. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 2826f013752d..c7193880a2b6 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -575,12 +575,8 @@ static int ssu100_process_packet(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); - if (len < 4) { - dbg("%s - malformed packet", __func__); - return 0; - } - - if ((packet[0] == 0x1b) && (packet[1] == 0x1b) && + if ((len >= 4) && + (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { if (packet[2] == 0x00) priv->shadowLSR = packet[3] & (SERIAL_LSR_OE | -- cgit v1.2.3-59-g8ed1b From 79f203a26a07a9d5701c404925e85eb161b72cde Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:07 -0400 Subject: USB: ssu100: remove duplicate #defines in ssu100 The ssu100 uses a TI16C550C UART so the SERIAL_ defines in this code are duplicates of those found in serial_reg.h. Remove the defines in ssu100.c and use the ones in the header file. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 86 ++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 55 deletions(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index c7193880a2b6..3c586b5790e1 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #define QT_OPEN_CLOSE_CHANNEL 0xca @@ -27,36 +28,11 @@ #define QT_HW_FLOW_CONTROL_MASK 0xc5 #define QT_SW_FLOW_CONTROL_MASK 0xc6 -#define MODEM_CTL_REGISTER 0x04 -#define MODEM_STATUS_REGISTER 0x06 - - -#define SERIAL_LSR_OE 0x02 -#define SERIAL_LSR_PE 0x04 -#define SERIAL_LSR_FE 0x08 -#define SERIAL_LSR_BI 0x10 - -#define SERIAL_LSR_TEMT 0x40 - -#define SERIAL_MCR_DTR 0x01 -#define SERIAL_MCR_RTS 0x02 -#define SERIAL_MCR_LOOP 0x10 - -#define SERIAL_MSR_CTS 0x10 -#define SERIAL_MSR_CD 0x80 -#define SERIAL_MSR_RI 0x40 -#define SERIAL_MSR_DSR 0x20 #define SERIAL_MSR_MASK 0xf0 -#define SERIAL_CRTSCTS ((SERIAL_MCR_RTS << 8) | SERIAL_MSR_CTS) - -#define SERIAL_8_DATA 0x03 -#define SERIAL_7_DATA 0x02 -#define SERIAL_6_DATA 0x01 -#define SERIAL_5_DATA 0x00 +#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) -#define SERIAL_ODD_PARITY 0X08 -#define SERIAL_EVEN_PARITY 0X18 +#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) #define MAX_BAUD_RATE 460800 @@ -153,7 +129,7 @@ static inline int ssu100_setregister(struct usb_device *dev, unsigned short uart, u16 data) { - u16 value = (data << 8) | MODEM_CTL_REGISTER; + u16 value = (data << 8) | UART_MCR; return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), QT_SET_GET_REGISTER, 0x40, value, uart, @@ -179,9 +155,9 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, clear &= ~set; /* 'set' takes precedence over 'clear' */ urb_value = 0; if (set & TIOCM_DTR) - urb_value |= SERIAL_MCR_DTR; + urb_value |= UART_MCR_DTR; if (set & TIOCM_RTS) - urb_value |= SERIAL_MCR_RTS; + urb_value |= UART_MCR_RTS; result = ssu100_setregister(dev, 0, urb_value); if (result < 0) @@ -265,24 +241,24 @@ static void ssu100_set_termios(struct tty_struct *tty, if (cflag & PARENB) { if (cflag & PARODD) - urb_value |= SERIAL_ODD_PARITY; + urb_value |= UART_LCR_PARITY; else urb_value |= SERIAL_EVEN_PARITY; } switch (cflag & CSIZE) { case CS5: - urb_value |= SERIAL_5_DATA; + urb_value |= UART_LCR_WLEN5; break; case CS6: - urb_value |= SERIAL_6_DATA; + urb_value |= UART_LCR_WLEN6; break; case CS7: - urb_value |= SERIAL_7_DATA; + urb_value |= UART_LCR_WLEN7; break; default: case CS8: - urb_value |= SERIAL_8_DATA; + urb_value |= UART_LCR_WLEN8; break; } @@ -353,11 +329,11 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) } spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE | - SERIAL_LSR_FE | SERIAL_LSR_BI); + priv->shadowLSR = data[0] & (UART_LSR_OE | UART_LSR_PE | + UART_LSR_FE | UART_LSR_BI); - priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR | - SERIAL_MSR_RI | SERIAL_MSR_CD); + priv->shadowMSR = data[1] & (UART_MSR_CTS | UART_MSR_DSR | + UART_MSR_RI | UART_MSR_DCD); spin_unlock_irqrestore(&priv->status_lock, flags); kfree(data); @@ -430,10 +406,10 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file, /* Return 0 if caller wanted to know about these bits */ - if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) || - ((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) || - ((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) || - ((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS))) + if (((arg & TIOCM_RNG) && (diff & UART_MSR_RI)) || + ((arg & TIOCM_DSR) && (diff & UART_MSR_DSR)) || + ((arg & TIOCM_CD) && (diff & UART_MSR_DCD)) || + ((arg & TIOCM_CTS) && (diff & UART_MSR_CTS))) return 0; } } @@ -513,20 +489,20 @@ static int ssu100_tiocmget(struct tty_struct *tty, struct file *file) if (!d) return -ENOMEM; - r = ssu100_getregister(dev, 0, MODEM_CTL_REGISTER, d); + r = ssu100_getregister(dev, 0, UART_MCR, d); if (r < 0) goto mget_out; - r = ssu100_getregister(dev, 0, MODEM_STATUS_REGISTER, d+1); + r = ssu100_getregister(dev, 0, UART_MSR, d+1); if (r < 0) goto mget_out; - r = (d[0] & SERIAL_MCR_DTR ? TIOCM_DTR : 0) | - (d[0] & SERIAL_MCR_RTS ? TIOCM_RTS : 0) | - (d[1] & SERIAL_MSR_CTS ? TIOCM_CTS : 0) | - (d[1] & SERIAL_MSR_CD ? TIOCM_CAR : 0) | - (d[1] & SERIAL_MSR_RI ? TIOCM_RI : 0) | - (d[1] & SERIAL_MSR_DSR ? TIOCM_DSR : 0); + r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | + (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | + (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | + (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | + (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | + (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); mget_out: kfree(d); @@ -579,10 +555,10 @@ static int ssu100_process_packet(struct tty_struct *tty, (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { if (packet[2] == 0x00) - priv->shadowLSR = packet[3] & (SERIAL_LSR_OE | - SERIAL_LSR_PE | - SERIAL_LSR_FE | - SERIAL_LSR_BI); + priv->shadowLSR = packet[3] & (UART_LSR_OE | + UART_LSR_PE | + UART_LSR_FE | + UART_LSR_BI); if (packet[2] == 0x01) { priv->shadowMSR = packet[3]; -- cgit v1.2.3-59-g8ed1b From 556f1a0e9c178193e584209b47cf1cb9f669bd51 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:08 -0400 Subject: USB: ssu100: add register parameter to ssu100_setregister The function ssu100_setregister was hard coded to only set the MCR register. Add a register parameter so that other registers can be set. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 3c586b5790e1..ad5f9ae40687 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -127,9 +127,10 @@ static inline int ssu100_getregister(struct usb_device *dev, static inline int ssu100_setregister(struct usb_device *dev, unsigned short uart, + unsigned short reg, u16 data) { - u16 value = (data << 8) | UART_MCR; + u16 value = (data << 8) | reg; return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), QT_SET_GET_REGISTER, 0x40, value, uart, @@ -159,7 +160,7 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set, if (set & TIOCM_RTS) urb_value |= UART_MCR_RTS; - result = ssu100_setregister(dev, 0, urb_value); + result = ssu100_setregister(dev, 0, UART_MCR, urb_value); if (result < 0) dbg("%s Error from MODEM_CTRL urb", __func__); @@ -529,7 +530,7 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) if (!port->serial->disconnected) { /* Disable flow control */ if (!on && - ssu100_setregister(dev, 0, 0) < 0) + ssu100_setregister(dev, 0, UART_MCR, 0) < 0) dev_err(&port->dev, "error from flowcontrol urb\n"); /* drop RTS and DTR */ if (on) -- cgit v1.2.3-59-g8ed1b From f81c83db563334d8377b26ad45585261f604605a Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:09 -0400 Subject: USB: ssu100: rework logic for TIOCMIWAIT Rework the logic for TIOCMIWAIT to use wait_event_interruptible. This also adds support for TIOCGICOUNT. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 146 +++++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 35 deletions(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index ad5f9ae40687..e244491b1a0d 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -80,6 +80,7 @@ struct ssu100_port_private { u8 shadowMSR; wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ unsigned short max_packet_size; + struct async_icount icount; }; static void ssu100_release(struct usb_serial *serial) @@ -330,11 +331,8 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) } spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = data[0] & (UART_LSR_OE | UART_LSR_PE | - UART_LSR_FE | UART_LSR_BI); - - priv->shadowMSR = data[1] & (UART_MSR_CTS | UART_MSR_DSR | - UART_MSR_RI | UART_MSR_DCD); + priv->shadowLSR = data[0]; + priv->shadowMSR = data[1]; spin_unlock_irqrestore(&priv->status_lock, flags); kfree(data); @@ -379,11 +377,51 @@ static int get_serial_info(struct usb_serial_port *port, return 0; } +static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +{ + struct ssu100_port_private *priv = usb_get_serial_port_data(port); + struct async_icount prev, cur; + unsigned long flags; + + spin_lock_irqsave(&priv->status_lock, flags); + prev = priv->icount; + spin_unlock_irqrestore(&priv->status_lock, flags); + + while (1) { + wait_event_interruptible(priv->delta_msr_wait, + ((priv->icount.rng != prev.rng) || + (priv->icount.dsr != prev.dsr) || + (priv->icount.dcd != prev.dcd) || + (priv->icount.cts != prev.cts))); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&priv->status_lock, flags); + cur = priv->icount; + spin_unlock_irqrestore(&priv->status_lock, flags); + + if ((prev.rng == cur.rng) && + (prev.dsr == cur.dsr) && + (prev.dcd == cur.dcd) && + (prev.cts == cur.cts)) + return -EIO; + + if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || + (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || + (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || + (arg & TIOCM_CTS && (prev.cts != cur.cts))) + return 0; + } + return 0; +} + static int ssu100_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct ssu100_port_private *priv = usb_get_serial_port_data(port); + void __user *user_arg = (void __user *)arg; dbg("%s cmd 0x%04x", __func__, cmd); @@ -393,28 +431,28 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file, (struct serial_struct __user *) arg); case TIOCMIWAIT: - while (priv != NULL) { - u8 prevMSR = priv->shadowMSR & SERIAL_MSR_MASK; - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - else { - u8 diff = (priv->shadowMSR & SERIAL_MSR_MASK) ^ prevMSR; - if (!diff) - return -EIO; /* no change => error */ - - /* Return 0 if caller wanted to know about - these bits */ - - if (((arg & TIOCM_RNG) && (diff & UART_MSR_RI)) || - ((arg & TIOCM_DSR) && (diff & UART_MSR_DSR)) || - ((arg & TIOCM_CD) && (diff & UART_MSR_DCD)) || - ((arg & TIOCM_CTS) && (diff & UART_MSR_CTS))) - return 0; - } - } + return wait_modem_info(port, arg); + + case TIOCGICOUNT: + { + struct serial_icounter_struct icount; + struct async_icount cnow = priv->icount; + memset(&icount, 0, sizeof(icount)); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + if (copy_to_user(user_arg, &icount, sizeof(icount))) + return -EFAULT; return 0; + } default: break; @@ -541,6 +579,50 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) mutex_unlock(&port->serial->disc_mutex); } +static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) +{ + struct ssu100_port_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + spin_lock_irqsave(&priv->status_lock, flags); + priv->shadowMSR = msr; + spin_unlock_irqrestore(&priv->status_lock, flags); + + if (msr & UART_MSR_ANY_DELTA) { + /* update input line counters */ + if (msr & UART_MSR_DCTS) + priv->icount.cts++; + if (msr & UART_MSR_DDSR) + priv->icount.dsr++; + if (msr & UART_MSR_DDCD) + priv->icount.dcd++; + if (msr & UART_MSR_TERI) + priv->icount.rng++; + wake_up_interruptible(&priv->delta_msr_wait); + } +} + +static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr) +{ + struct ssu100_port_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + spin_lock_irqsave(&priv->status_lock, flags); + priv->shadowLSR = lsr; + spin_unlock_irqrestore(&priv->status_lock, flags); + + if (lsr & UART_LSR_BRK_ERROR_BITS) { + if (lsr & UART_LSR_BI) + priv->icount.brk++; + if (lsr & UART_LSR_FE) + priv->icount.frame++; + if (lsr & UART_LSR_PE) + priv->icount.parity++; + if (lsr & UART_LSR_OE) + priv->icount.overrun++; + } +} + static int ssu100_process_packet(struct tty_struct *tty, struct usb_serial_port *port, struct ssu100_port_private *priv, @@ -556,15 +638,9 @@ static int ssu100_process_packet(struct tty_struct *tty, (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { if (packet[2] == 0x00) - priv->shadowLSR = packet[3] & (UART_LSR_OE | - UART_LSR_PE | - UART_LSR_FE | - UART_LSR_BI); - - if (packet[2] == 0x01) { - priv->shadowMSR = packet[3]; - wake_up_interruptible(&priv->delta_msr_wait); - } + ssu100_update_lsr(port, packet[3]); + if (packet[2] == 0x01) + ssu100_update_msr(port, packet[3]); len -= 4; ch = packet + 4; -- cgit v1.2.3-59-g8ed1b From 5c7efeb76e7dc5145b467657fa049f3c1bd9cf58 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:10 -0400 Subject: USB: serial: export symbol usb_serial_generic_disconnect This is needed by the ssu100 driver to use this function. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/generic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index ca92f67747cc..0b1a13384c6d 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -518,6 +518,7 @@ void usb_serial_generic_disconnect(struct usb_serial *serial) for (i = 0; i < serial->num_ports; ++i) generic_cleanup(serial->port[i]); } +EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); void usb_serial_generic_release(struct usb_serial *serial) { -- cgit v1.2.3-59-g8ed1b From 85dee135b84f1c7cad252fa4a619ea692077a7fc Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Thu, 5 Aug 2010 17:01:11 -0400 Subject: USB: ssu100: add disconnect function for ssu100 Add a disconnect function to the functions of this device. The disconnect is a call to usb_serial_generic_disconnect() so it requires that symbol to be exported from generic.c. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index e244491b1a0d..55e9672d286a 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -687,7 +687,6 @@ static void ssu100_process_read_urb(struct urb *urb) tty_kref_put(tty); } - static struct usb_serial_driver ssu100_device = { .driver = { .owner = THIS_MODULE, @@ -709,6 +708,7 @@ static struct usb_serial_driver ssu100_device = { .tiocmset = ssu100_tiocmset, .ioctl = ssu100_ioctl, .set_termios = ssu100_set_termios, + .disconnect = usb_serial_generic_disconnect, }; static int __init ssu100_init(void) -- cgit v1.2.3-59-g8ed1b From 6b8f1ca5581bf9783069cd6bde65ba7a3a470aab Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Fri, 13 Aug 2010 09:59:31 -0400 Subject: USB: ssu100: set tty_flags in ssu100_process_packet flag was never set in ssu100_process_packet. Add logic to set it before calling tty_insert_flip_* Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 55e9672d286a..660c31f14999 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -602,7 +602,8 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) } } -static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr) +static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, + char *tty_flag) { struct ssu100_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; @@ -611,16 +612,32 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr) priv->shadowLSR = lsr; spin_unlock_irqrestore(&priv->status_lock, flags); + *tty_flag = TTY_NORMAL; if (lsr & UART_LSR_BRK_ERROR_BITS) { - if (lsr & UART_LSR_BI) + /* we always want to update icount, but we only want to + * update tty_flag for one case */ + if (lsr & UART_LSR_BI) { priv->icount.brk++; - if (lsr & UART_LSR_FE) - priv->icount.frame++; - if (lsr & UART_LSR_PE) + *tty_flag = TTY_BREAK; + usb_serial_handle_break(port); + } + if (lsr & UART_LSR_PE) { priv->icount.parity++; - if (lsr & UART_LSR_OE) + if (*tty_flag == TTY_NORMAL) + *tty_flag = TTY_PARITY; + } + if (lsr & UART_LSR_FE) { + priv->icount.frame++; + if (*tty_flag == TTY_NORMAL) + *tty_flag = TTY_FRAME; + } + if (lsr & UART_LSR_OE){ priv->icount.overrun++; + if (*tty_flag == TTY_NORMAL) + *tty_flag = TTY_OVERRUN; + } } + } static int ssu100_process_packet(struct tty_struct *tty, @@ -629,7 +646,7 @@ static int ssu100_process_packet(struct tty_struct *tty, char *packet, int len) { int i; - char flag; + char flag = TTY_NORMAL; char *ch; dbg("%s - port %d", __func__, port->number); @@ -637,8 +654,11 @@ static int ssu100_process_packet(struct tty_struct *tty, if ((len >= 4) && (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { - if (packet[2] == 0x00) - ssu100_update_lsr(port, packet[3]); + if (packet[2] == 0x00) { + ssu100_update_lsr(port, packet[3], &flag); + if (flag == TTY_OVERRUN) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } if (packet[2] == 0x01) ssu100_update_msr(port, packet[3]); -- cgit v1.2.3-59-g8ed1b From d187abb9a83e6c6b6e9f2ca17962bdeafb4bc903 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 11 Aug 2010 12:07:13 -0700 Subject: USB: gadget: fix composite kernel-doc warnings Warning(include/linux/usb/composite.h:284): No description found for parameter 'disconnect' Warning(drivers/usb/gadget/composite.c:744): No description found for parameter 'c' Warning(drivers/usb/gadget/composite.c:744): Excess function parameter 'cdev' description in 'usb_string_ids_n' Signed-off-by: Randy Dunlap Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/composite.c | 4 ++-- include/linux/usb/composite.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index e483f80822d2..1160c55de7f2 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -723,12 +723,12 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) /** * usb_string_ids_n() - allocate unused string IDs in batch - * @cdev: the device whose string descriptor IDs are being allocated + * @c: the device whose string descriptor IDs are being allocated * @n: number of string IDs to allocate * Context: single threaded during gadget setup * * Returns the first requested ID. This ID and next @n-1 IDs are now - * valid IDs. At least providind that @n is non zore because if it + * valid IDs. At least provided that @n is non-zero because if it * is, returns last requested ID which is now very useful information. * * @usb_string_ids_n() is called from bind() callbacks to allocate diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 890bc1472190..617068134ae8 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -247,6 +247,7 @@ int usb_add_config(struct usb_composite_dev *, * value; it should return zero on successful initialization. * @unbind: Reverses @bind(); called as a side effect of unregistering * this driver. + * @disconnect: optional driver disconnect method * @suspend: Notifies when the host stops sending USB traffic, * after function notifications * @resume: Notifies configuration when the host restarts USB traffic, -- cgit v1.2.3-59-g8ed1b From 7c81aafaf059b81ead2330bc13db78269ef62612 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 11 Aug 2010 12:10:48 +0200 Subject: USB: gadget: Return -ENOMEM on memory allocation failure In this code, 0 is returned on memory allocation failure, even though other failures return -ENOMEM or other similar values. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression ret; expression x,e1,e2,e3; @@ ret = 0 ... when != ret = e1 *x = \(kmalloc\|kcalloc\|kzalloc\)(...) ... when != ret = e2 if (x == NULL) { ... when != ret = e3 return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/m66592-udc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 166bf71fd348..e03058fe23cb 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1609,6 +1609,7 @@ static int __init m66592_probe(struct platform_device *pdev) /* initialize ucd */ m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); if (m66592 == NULL) { + ret = -ENOMEM; pr_err("kzalloc error\n"); goto clean_up; } -- cgit v1.2.3-59-g8ed1b From 461c317705eca5cac09a360f488715927fd0a927 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 11 Aug 2010 13:02:32 +0300 Subject: USB: otg: twl4030: fix wrong assumption of starting state The reset state of twl4030-usb is not sleeping, it starts up awaken and we need to disable it if we have booted with a disconnected cable to avoid over consumption on the default state. To avoid problems later, we read the current state of the transceiver from the PHY_PWR_CTRL register. The bootloader can, anyways, put the device to sleep before us. Tested on a custom OMAP board. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/otg/twl4030-usb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 0e8888588d4e..05aaac1c3861 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -550,6 +550,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) struct twl4030_usb_data *pdata = pdev->dev.platform_data; struct twl4030_usb *twl; int status, err; + u8 pwr; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); @@ -568,7 +569,10 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) twl->otg.set_peripheral = twl4030_set_peripheral; twl->otg.set_suspend = twl4030_set_suspend; twl->usb_mode = pdata->usb_mode; - twl->asleep = 1; + + pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); + + twl->asleep = (pwr & PHY_PWR_PHYPWD); /* init spinlock for workqueue */ spin_lock_init(&twl->lock); -- cgit v1.2.3-59-g8ed1b From fd6e5bbb241720715cee737f534496d7c0ae9022 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Aug 2010 14:29:19 -0700 Subject: USB: serial: io_ti.c: don't return 0 if writing the download record failed If the write download record failed we shouldn't return 0. Signed-off-by: Roel Kluin Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/io_ti.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index c3f27c316753..a7cfc5952937 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1284,7 +1284,7 @@ static int download_fw(struct edgeport_serial *serial) kfree(header); kfree(rom_desc); kfree(ti_manuf_desc); - return status; + return -EINVAL; } /* Update I2C with type 0xf2 record with correct -- cgit v1.2.3-59-g8ed1b From 666cc076d284e32d11bfc5ea2fbfc50434cff051 Mon Sep 17 00:00:00 2001 From: Martin Michlmayr Date: Tue, 10 Aug 2010 20:31:21 +0100 Subject: USB: ftdi_sio: Add ID for Ionics PlugComputer Add the ID for the Ionics PlugComputer (). Signed-off-by: Martin Michlmayr Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index e04a41613fbf..aeb93316791a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -750,6 +750,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, + { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 6e612c52e763..aa37cc511282 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -988,6 +988,12 @@ #define ALTI2_VID 0x1BC9 #define ALTI2_N3_PID 0x6001 /* Neptune 3 */ +/* + * Ionics PlugComputer + */ +#define IONICS_VID 0x1c0c +#define IONICS_PLUGCOMPUTER_PID 0x0102 + /* * Dresden Elektronik Sensor Terminal Board */ -- cgit v1.2.3-59-g8ed1b From a1669b2c64a9c8b031e0ac5cbf2692337a577f7c Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 9 Aug 2010 13:56:11 -0700 Subject: USB: xhci: Remove buggy assignment in next_trb() The code to increment the TRB pointer has a slight ambiguity that could lead to a bug on different compilers. The ANSI C specification does not specify the precedence of the assignment operator over the postfix operator. gcc 4.4 produced the correct code (increment the pointer and assign the value), but a MIPS compiler that one of John's clients used assigned the old (unincremented) value. Remove the unnecessary assignment to make all compilers produce the correct assembly. Signed-off-by: John Youn Signed-off-by: Sarah Sharp Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index bc3f4f427065..2f19f3a817c2 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -131,7 +131,7 @@ static void next_trb(struct xhci_hcd *xhci, *seg = (*seg)->next; *trb = ((*seg)->trbs); } else { - *trb = (*trb)++; + (*trb)++; } } -- cgit v1.2.3-59-g8ed1b From 14184f9b8047026f1812f49df074e89dad3a09bc Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 9 Aug 2010 13:56:15 -0700 Subject: USB: xHCI: update ring dequeue pointer when process missed tds This patch fixes a isoc transfer bug reported by Sander Eikelenboom. When ep->skip is set, endpoint ring dequeue pointer should be updated when processed every missed td. Although ring dequeue pointer will also be updated when ep->skip is clear, leave it intact during missed tds processing may cause two issues: 1). If the very next valid transfer following missed tds is a short transfer, its actual_length will be miscalculated; 2). If there are too many missed tds during transfer, new inserted tds may found the transfer ring full and urb enqueue fails. Reported-by: Sander Eikelenboom Tested-by: Sander Eikelenboom Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 2f19f3a817c2..48e60d166ff0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1551,6 +1551,10 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* calc actual length */ if (ep->skip) { td->urb->iso_frame_desc[idx].actual_length = 0; + /* Update ring dequeue pointer */ + while (ep_ring->dequeue != td->last_trb) + inc_deq(xhci, ep_ring, false); + inc_deq(xhci, ep_ring, false); return finish_td(xhci, td, event_trb, event, ep, status, true); } -- cgit v1.2.3-59-g8ed1b From 6d4d4554863b7897f2bc9cd9085f54c819152825 Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sat, 31 Jul 2010 21:39:46 +0400 Subject: USB: iowarrior: fix misuse of return value of copy_to_user() copy_to_user() returns number of not copied bytes, not error code. Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 2de49c8887c5..bc88c79875a1 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -542,7 +542,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, retval = io_res; else { io_res = copy_to_user(user_buffer, buffer, dev->report_size); - if (io_res < 0) + if (io_res) retval = -EFAULT; } break; @@ -574,7 +574,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, } io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, sizeof(struct iowarrior_info)); - if (io_res < 0) + if (io_res) retval = -EFAULT; break; } -- cgit v1.2.3-59-g8ed1b From 1865a9c382ede507065cf1575308b53495814c7d Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Sat, 31 Jul 2010 21:40:07 +0400 Subject: USB: adutux: fix misuse of return value of copy_to_user() copy_to_user() returns number of not copied bytes, not error code. Signed-off-by: Kulikov Vasiliy Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index d240de097c62..801324af9470 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -439,7 +439,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, /* drain secondary buffer */ int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary; i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount); - if (i < 0) { + if (i) { retval = -EFAULT; goto exit; } -- cgit v1.2.3-59-g8ed1b From ea233f805537f5da16c2b34d85b6c5cf88a0f9aa Mon Sep 17 00:00:00 2001 From: Galen Seitz Date: Thu, 19 Aug 2010 11:15:20 -0700 Subject: USB: ftdi_sio: add product ID for Lenz LI-USB Add ftdi product ID for Lenz LI-USB, a model train interface. This was NOT tested against 2.6.35, but a similar patch was tested with the CentOS 2.6.18-194.11.1.el5 kernel. It wasn't clear to me what ordering is being used in ftdi_sio.c, so I inserted the ID after another model train entry(SPROG_II). Signed-off-by: Galen Seitz Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index aeb93316791a..63ddb2f65cee 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -180,6 +180,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index aa37cc511282..2e95857c9633 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -110,6 +110,9 @@ /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +/* Lenz LI-USB Computer Interface. */ +#define FTDI_LENZ_LIUSB_PID 0xD780 + /* * Xsens Technologies BV products (http://www.xsens.com). */ -- cgit v1.2.3-59-g8ed1b From 70ddd47f7d56f17b40f78d21d6f653c84617e450 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 13 Aug 2010 14:06:50 +0200 Subject: ARM: imx: fix build failure concerning otg/ulpi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build failure was introduced by 13dd0c9 (USB: otg/ulpi: extend the generic ulpi driver.) Signed-off-by: Uwe Kleine-König Acked-by: Igor Grinberg Cc: Mike Rapoport Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-imx/mach-cpuimx27.c | 4 ++-- arch/arm/mach-imx/mach-pca100.c | 4 ++-- arch/arm/mach-mx25/mach-cpuimx25.c | 2 +- arch/arm/mach-mx3/mach-cpuimx35.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c index 575ff1ae85a7..339150ab0ea5 100644 --- a/arch/arm/mach-imx/mach-cpuimx27.c +++ b/arch/arm/mach-imx/mach-cpuimx27.c @@ -279,13 +279,13 @@ static void __init eukrea_cpuimx27_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c index a389d1148f18..23c9e1f37b9c 100644 --- a/arch/arm/mach-imx/mach-pca100.c +++ b/arch/arm/mach-imx/mach-pca100.c @@ -419,13 +419,13 @@ static void __init pca100_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_usbh2, &usbh2_pdata); #endif diff --git a/arch/arm/mach-mx25/mach-cpuimx25.c b/arch/arm/mach-mx25/mach-cpuimx25.c index 56b2e26d23b4..a5f0174290b4 100644 --- a/arch/arm/mach-mx25/mach-cpuimx25.c +++ b/arch/arm/mach-mx25/mach-cpuimx25.c @@ -138,7 +138,7 @@ static void __init eukrea_cpuimx25_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg, &otg_pdata); } diff --git a/arch/arm/mach-mx3/mach-cpuimx35.c b/arch/arm/mach-mx3/mach-cpuimx35.c index 63f970f340a2..9770a6a973be 100644 --- a/arch/arm/mach-mx3/mach-cpuimx35.c +++ b/arch/arm/mach-mx3/mach-cpuimx35.c @@ -192,7 +192,7 @@ static void __init mxc_board_init(void) #if defined(CONFIG_USB_ULPI) if (otg_mode_host) { otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, - USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT); + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); mxc_register_device(&mxc_otg_host, &otg_pdata); } -- cgit v1.2.3-59-g8ed1b From 529b7307d804f649839b5b65b303442140266d26 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 24 Aug 2010 14:41:48 +1000 Subject: powerpc: Make rwsem use "long" type This makes the 64-bit kernel use 64-bit signed integers for the counter (effectively supporting 32-bit of active count in the semaphore), thus avoiding things like overflow of the mmap_sem if you use a really crazy number of threads Note: Ideally the type in the structure should be atomic_long_t rather than "long". However, there's some nasty issues with that. It needs to be initialized statically -and- lib/rwsem.c does things like sem->count = RWSEM_UNLOCKED_VALUE; Now, if you mix in the fact that atomic_* types are actually structures with one member and note typedefs of a scalar, it makes its really nasty. So I stuck to what we did before using a long and casts for now. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/rwsem.h | 64 +++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/arch/powerpc/include/asm/rwsem.h b/arch/powerpc/include/asm/rwsem.h index 24cd9281ec37..8447d89fbe72 100644 --- a/arch/powerpc/include/asm/rwsem.h +++ b/arch/powerpc/include/asm/rwsem.h @@ -21,15 +21,20 @@ /* * the semaphore definition */ -struct rw_semaphore { - /* XXX this should be able to be an atomic_t -- paulus */ - signed int count; -#define RWSEM_UNLOCKED_VALUE 0x00000000 -#define RWSEM_ACTIVE_BIAS 0x00000001 -#define RWSEM_ACTIVE_MASK 0x0000ffff -#define RWSEM_WAITING_BIAS (-0x00010000) +#ifdef CONFIG_PPC64 +# define RWSEM_ACTIVE_MASK 0xffffffffL +#else +# define RWSEM_ACTIVE_MASK 0x0000ffffL +#endif + +#define RWSEM_UNLOCKED_VALUE 0x00000000L +#define RWSEM_ACTIVE_BIAS 0x00000001L +#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + +struct rw_semaphore { + long count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_LOCK_ALLOC @@ -43,9 +48,13 @@ struct rw_semaphore { # define __RWSEM_DEP_MAP_INIT(lockname) #endif -#define __RWSEM_INITIALIZER(name) \ - { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \ - LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) } +#define __RWSEM_INITIALIZER(name) \ +{ \ + RWSEM_UNLOCKED_VALUE, \ + __SPIN_LOCK_UNLOCKED((name).wait_lock), \ + LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) \ +} #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) @@ -70,13 +79,13 @@ extern void __init_rwsem(struct rw_semaphore *sem, const char *name, */ static inline void __down_read(struct rw_semaphore *sem) { - if (unlikely(atomic_inc_return((atomic_t *)(&sem->count)) <= 0)) + if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0)) rwsem_down_read_failed(sem); } static inline int __down_read_trylock(struct rw_semaphore *sem) { - int tmp; + long tmp; while ((tmp = sem->count) >= 0) { if (tmp == cmpxchg(&sem->count, tmp, @@ -92,10 +101,10 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) */ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) { - int tmp; + long tmp; - tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_t *)(&sem->count)); + tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_long_t *)&sem->count); if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) rwsem_down_write_failed(sem); } @@ -107,7 +116,7 @@ static inline void __down_write(struct rw_semaphore *sem) static inline int __down_write_trylock(struct rw_semaphore *sem) { - int tmp; + long tmp; tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, RWSEM_ACTIVE_WRITE_BIAS); @@ -119,9 +128,9 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) */ static inline void __up_read(struct rw_semaphore *sem) { - int tmp; + long tmp; - tmp = atomic_dec_return((atomic_t *)(&sem->count)); + tmp = atomic_long_dec_return((atomic_long_t *)&sem->count); if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)) rwsem_wake(sem); } @@ -131,17 +140,17 @@ static inline void __up_read(struct rw_semaphore *sem) */ static inline void __up_write(struct rw_semaphore *sem) { - if (unlikely(atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, - (atomic_t *)(&sem->count)) < 0)) + if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_long_t *)&sem->count) < 0)) rwsem_wake(sem); } /* * implement atomic add functionality */ -static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) +static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) { - atomic_add(delta, (atomic_t *)(&sem->count)); + atomic_long_add(delta, (atomic_long_t *)&sem->count); } /* @@ -149,9 +158,10 @@ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) */ static inline void __downgrade_write(struct rw_semaphore *sem) { - int tmp; + long tmp; - tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count)); + tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS, + (atomic_long_t *)&sem->count); if (tmp < 0) rwsem_downgrade_wake(sem); } @@ -159,14 +169,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem) /* * implement exchange and add functionality */ -static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) { - return atomic_add_return(delta, (atomic_t *)(&sem->count)); + return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); } static inline int rwsem_is_locked(struct rw_semaphore *sem) { - return (sem->count != 0); + return sem->count != 0; } #endif /* __KERNEL__ */ -- cgit v1.2.3-59-g8ed1b From 79c3095fb39964d0d44368cbbb4eff5b52c43d2c Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Thu, 19 Aug 2010 18:08:09 +0000 Subject: powerpc: Export memstart_addr and kernstart_addr on ppc64 Some modules (like eHCA) want to map all of kernel memory, for this to work with a relocated kernel, we need to export kernstart_addr so modules can use PHYSICAL_START and memstart_addr so they could use MEMORY_START. Note that the 32bit code already exports these symbols. Signed-off-By: Sonny Rao Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/mm/init_64.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 71f1415e2472..ace85fa74b29 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -79,7 +79,9 @@ #endif /* CONFIG_PPC_STD_MMU_64 */ phys_addr_t memstart_addr = ~0; +EXPORT_SYMBOL_GPL(memstart_addr); phys_addr_t kernstart_addr; +EXPORT_SYMBOL_GPL(kernstart_addr); void free_initmem(void) { -- cgit v1.2.3-59-g8ed1b From 9904b00593f548156962764f67b1bb23f4da56fc Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Thu, 29 Jul 2010 22:04:39 +0000 Subject: powerpc: Use is_32bit_task() helper to test 32 bit binary Use is_32bit_task() helper to test 32 bit binary. Signed-off-by: Denis Kirjanov Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/process.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 91356ffda2ca..986fedf7e278 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -728,7 +728,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, p->thread.regs = childregs; if (clone_flags & CLONE_SETTLS) { #ifdef CONFIG_PPC64 - if (!test_thread_flag(TIF_32BIT)) + if (!is_32bit_task()) childregs->gpr[13] = childregs->gpr[6]; else #endif @@ -823,7 +823,7 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) regs->nip = start; regs->msr = MSR_USER; #else - if (!test_thread_flag(TIF_32BIT)) { + if (!is_32bit_task()) { unsigned long entry, toc; /* start is a relocated pointer to the function descriptor for @@ -995,7 +995,7 @@ int sys_clone(unsigned long clone_flags, unsigned long usp, if (usp == 0) usp = regs->gpr[1]; /* stack pointer for child */ #ifdef CONFIG_PPC64 - if (test_thread_flag(TIF_32BIT)) { + if (is_32bit_task()) { parent_tidp = TRUNC_PTR(parent_tidp); child_tidp = TRUNC_PTR(child_tidp); } -- cgit v1.2.3-59-g8ed1b From 3469270807ffde921ad36f90d7b8c8e095d3e4e8 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 2 Aug 2010 20:35:18 +0000 Subject: powerpc/mm: Fix vsid_scrample typo The code is wrapped in an #if 0, but it's wrong so we may as well fix it. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/mmu-hash64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index 0e398cfee2c8..acac35d5b382 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h @@ -433,7 +433,7 @@ typedef struct { * with. However gcc is not clever enough to compute the * modulus (2^n-1) without a second multiply. */ -#define vsid_scrample(protovsid, size) \ +#define vsid_scramble(protovsid, size) \ ((((protovsid) * VSID_MULTIPLIER_##size) % VSID_MODULUS_##size)) #else /* 1 */ -- cgit v1.2.3-59-g8ed1b From 249ec2287579d578ea72593dc3b30a00121c4075 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 2 Aug 2010 20:39:41 +0000 Subject: powerpc/kdump: Stop all other CPUs before running crash handlers During kdump we run the crash handlers first then stop all other CPUs. We really want to stop all CPUs as close to the fail as possible and also have a very controlled environment for running the crash handlers, so it makes sense to reverse the order. Signed-off-by: Anton Blanchard Acked-by: Matt Evans Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/crash.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 417f7b05a9ce..4457382f8667 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c @@ -402,6 +402,18 @@ void default_machine_crash_shutdown(struct pt_regs *regs) */ hard_irq_disable(); + /* + * Make a note of crashing cpu. Will be used in machine_kexec + * such that another IPI will not be sent. + */ + crashing_cpu = smp_processor_id(); + crash_save_cpu(regs, crashing_cpu); + crash_kexec_prepare_cpus(crashing_cpu); + cpu_set(crashing_cpu, cpus_in_crash); +#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) + crash_kexec_wait_realmode(crashing_cpu); +#endif + for_each_irq(i) { struct irq_desc *desc = irq_to_desc(i); @@ -438,18 +450,8 @@ void default_machine_crash_shutdown(struct pt_regs *regs) crash_shutdown_cpu = -1; __debugger_fault_handler = old_handler; - /* - * Make a note of crashing cpu. Will be used in machine_kexec - * such that another IPI will not be sent. - */ - crashing_cpu = smp_processor_id(); - crash_save_cpu(regs, crashing_cpu); - crash_kexec_prepare_cpus(crashing_cpu); - cpu_set(crashing_cpu, cpus_in_crash); crash_kexec_stop_spus(); -#if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) - crash_kexec_wait_realmode(crashing_cpu); -#endif + if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(1, 0); } -- cgit v1.2.3-59-g8ed1b From d1efa2a7551a10006055e0ac2870b4b6077df8ef Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 3 Aug 2010 09:50:32 +0000 Subject: powerpc/powermac: Drop unnecessary of_node_put for_each_node_by_name only exits when its first argument is NULL, and a subsequent call to of_node_put on that argument is unnecessary. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ iterator name for_each_node_by_name; expression np,E; identifier l; @@ for_each_node_by_name(np,...) { ... when != break; when != goto l; } ... when != np = E - of_node_put(np); // Signed-off-by: Julia Lawall Reviewed-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powermac/feature.c | 1 - arch/powerpc/platforms/powermac/pci.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 39df6ab1735a..6e26068a27c2 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2878,7 +2878,6 @@ set_initial_features(void) core99_airport_enable(np, 0, 0); } } - of_node_put(np); } /* On all machines that support sound PM, switch sound off */ diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index ab2027cdf893..3bc075c788ef 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1155,13 +1155,11 @@ void __init pmac_pcibios_after_init(void) pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0); } } - of_node_put(nd); for_each_node_by_name(nd, "ethernet") { if (nd->parent && of_device_is_compatible(nd, "gmac") && of_device_is_compatible(nd->parent, "uni-north")) pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0); } - of_node_put(nd); } void pmac_pci_fixup_cardbus(struct pci_dev* dev) -- cgit v1.2.3-59-g8ed1b From 5fba610ec94a1290fc299ea051e47d55da9059ba Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 3 Aug 2010 11:33:43 +0000 Subject: powerpc/powermac: Drop unnecessary null test for_each_node_by_name binds its first argument to a non-null value, and thus any null test on the value of that argument is superfluous. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ iterator I; expression x,E; @@ I(x,...) { <... ( - (x != NULL) && E ...> } // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powermac/feature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index 6e26068a27c2..df423993f175 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2873,7 +2873,7 @@ set_initial_features(void) /* Switch airport off */ for_each_node_by_name(np, "radio") { - if (np && np->parent == macio_chips[0].of_node) { + if (np->parent == macio_chips[0].of_node) { macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; core99_airport_enable(np, 0, 0); } -- cgit v1.2.3-59-g8ed1b From da9bef6735d3c5c1c0cd16717acee18d56dd59f5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 3 Aug 2010 11:35:17 +0000 Subject: powerpc/pci: Drop unnecessary null test list_for_each_entry binds its first argument to a non-null value, and thus any null test on the value of that argument is superfluous. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ iterator I; expression x,E,E1,E2; statement S,S1,S2; @@ I(x,...) { <... - if (x != NULL || ...) S ...> } // Signed-off-by: Julia Lawall Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/pci_of_scan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 6ddb795f83e8..62dd363a9762 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -336,8 +336,7 @@ static void __devinit __of_scan_bus(struct device_node *node, if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { struct device_node *child = pci_device_to_OF_node(dev); - if (dev) - of_scan_pci_bridge(child, dev); + of_scan_pci_bridge(child, dev); } } } -- cgit v1.2.3-59-g8ed1b From a7c2bb8279d20d853e43c34584eaf2b039de8026 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: Darren Hart" Date: Wed, 4 Aug 2010 18:28:33 +0000 Subject: powerpc: Re-enable preemption before cpu_die() start_secondary() is called shortly after _start and also via cpu_idle()->cpu_die()->pseries_mach_cpu_die() start_secondary() expects a preempt_count() of 0. pseries_mach_cpu_die() is called via the cpu_idle() routine with preemption disabled, resulting in the following repeating message during rapid cpu offline/online tests with CONFIG_PREEMPT=y: BUG: scheduling while atomic: swapper/0/0x00000002 Modules linked in: autofs4 binfmt_misc dm_mirror dm_region_hash dm_log [last unloaded: scsi_wait_scan] Call Trace: [c00000010e7079c0] [c0000000000133ec] .show_stack+0xd8/0x218 (unreliable) [c00000010e707aa0] [c0000000006a47f0] .dump_stack+0x28/0x3c [c00000010e707b20] [c00000000006e7a4] .__schedule_bug+0x7c/0x9c [c00000010e707bb0] [c000000000699d9c] .schedule+0x104/0x800 [c00000010e707cd0] [c000000000015b24] .cpu_idle+0x1c4/0x1d8 [c00000010e707d70] [c0000000006aa1b4] .start_secondary+0x398/0x3d4 [c00000010e707e30] [c000000000008278] .start_secondary_resume+0x10/0x14 Move the cpu_die() call inside the existing preemption enabled block of cpu_idle(). This is safe as the idle task is affined to a single CPU so the debug_smp_processor_id() tests (from cpu_should_die()) won't trigger as we are in a "migration disabled" region. Signed-off-by: Darren Hart Acked-by: Will Schmidt Cc: Thomas Gleixner Cc: Nathan Fontenot Cc: Robert Jennings Cc: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/idle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 049dda60e475..39a2baa6ad58 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -94,9 +94,9 @@ void cpu_idle(void) HMT_medium(); ppc64_runlatch_on(); tick_nohz_restart_sched_tick(); + preempt_enable_no_resched(); if (cpu_should_die()) cpu_die(); - preempt_enable_no_resched(); schedule(); preempt_disable(); } -- cgit v1.2.3-59-g8ed1b From 6685a477494ceb063c10300891e48895bb1843c9 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: Darren Hart" Date: Wed, 4 Aug 2010 18:28:34 +0000 Subject: powerpc: Silence __cpu_up() under normal operation During CPU offline/online tests __cpu_up would flood the logs with the following message: Processor 0 found. This provides no useful information to the user as there is no context provided, and since the operation was a success (to this point) it is expected that the CPU will come back online, providing all the feedback necessary. Change the "Processor found" message to DBG() similar to other such messages in the same function. Also, add an appropriate log level for the "Processor is stuck" message. Signed-off-by: Darren Hart Acked-by: Will Schmidt Cc: Thomas Gleixner Cc: Nathan Fontenot Cc: Robert Jennings Cc: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/smp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index a61b3ddd7bb3..0008bc58e826 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -427,11 +427,11 @@ int __cpuinit __cpu_up(unsigned int cpu) #endif if (!cpu_callin_map[cpu]) { - printk("Processor %u is stuck.\n", cpu); + printk(KERN_ERR "Processor %u is stuck.\n", cpu); return -ENOENT; } - printk("Processor %u found.\n", cpu); + DBG("Processor %u found.\n", cpu); if (smp_ops->give_timebase) smp_ops->give_timebase(); -- cgit v1.2.3-59-g8ed1b From 1afb56cf977ab41bff4fc6bf9e5864770b19b880 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: Darren Hart" Date: Wed, 4 Aug 2010 18:28:35 +0000 Subject: powerpc: Silence xics_migrate_irqs_away() during cpu offline All IRQs are migrated away from a CPU that is being offlined so the following messages suggest a problem when the system is behaving as designed: IRQ 262 affinity broken off cpu 1 IRQ 17 affinity broken off cpu 0 IRQ 18 affinity broken off cpu 0 IRQ 19 affinity broken off cpu 0 IRQ 256 affinity broken off cpu 0 IRQ 261 affinity broken off cpu 0 IRQ 262 affinity broken off cpu 0 Don't print these messages when the CPU is not online. Signed-off-by: Darren Hart Acked-by: Will Schmidt Cc: Thomas Gleixner Cc: Nathan Fontenot Cc: Robert Jennings Cc: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/xics.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 5b22b07c8f67..93834b0d8272 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -928,8 +928,10 @@ void xics_migrate_irqs_away(void) if (xics_status[0] != hw_cpu) goto unlock; - printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", - virq, cpu); + /* This is expected during cpu offline. */ + if (cpu_online(cpu)) + printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", + virq, cpu); /* Reset affinity to all cpus */ cpumask_setall(irq_to_desc(virq)->affinity); -- cgit v1.2.3-59-g8ed1b From 954e6da54b2f3a5e2634312db800bc1395c509ee Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 5 Aug 2010 07:42:11 +0000 Subject: powerpc: Correct smt_enabled=X boot option for > 2 threads per core The 'smt_enabled=X' boot option does not handle values of X > 2. For Power 7 processors with smt modes of 0,1,2,3, and 4 this does not work. This patch allows the smt_enabled option to be set to any value limited to a max equal to the number of threads per core. Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/setup_64.c | 63 ++++++++++++++++++++---------------- arch/powerpc/platforms/pseries/smp.c | 11 ++++--- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 1bee4b68fa45..e72690ec9b87 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -95,7 +95,7 @@ int ucache_bsize; #ifdef CONFIG_SMP -static int smt_enabled_cmdline; +static char *smt_enabled_cmdline; /* Look for ibm,smt-enabled OF option */ static void check_smt_enabled(void) @@ -103,37 +103,46 @@ static void check_smt_enabled(void) struct device_node *dn; const char *smt_option; - /* Allow the command line to overrule the OF option */ - if (smt_enabled_cmdline) - return; - - dn = of_find_node_by_path("/options"); - - if (dn) { - smt_option = of_get_property(dn, "ibm,smt-enabled", NULL); + /* Default to enabling all threads */ + smt_enabled_at_boot = threads_per_core; - if (smt_option) { - if (!strcmp(smt_option, "on")) - smt_enabled_at_boot = 1; - else if (!strcmp(smt_option, "off")) - smt_enabled_at_boot = 0; - } - } + /* Allow the command line to overrule the OF option */ + if (smt_enabled_cmdline) { + if (!strcmp(smt_enabled_cmdline, "on")) + smt_enabled_at_boot = threads_per_core; + else if (!strcmp(smt_enabled_cmdline, "off")) + smt_enabled_at_boot = 0; + else { + long smt; + int rc; + + rc = strict_strtol(smt_enabled_cmdline, 10, &smt); + if (!rc) + smt_enabled_at_boot = + min(threads_per_core, (int)smt); + } + } else { + dn = of_find_node_by_path("/options"); + if (dn) { + smt_option = of_get_property(dn, "ibm,smt-enabled", + NULL); + + if (smt_option) { + if (!strcmp(smt_option, "on")) + smt_enabled_at_boot = threads_per_core; + else if (!strcmp(smt_option, "off")) + smt_enabled_at_boot = 0; + } + + of_node_put(dn); + } + } } /* Look for smt-enabled= cmdline option */ static int __init early_smt_enabled(char *p) { - smt_enabled_cmdline = 1; - - if (!p) - return 0; - - if (!strcmp(p, "on") || !strcmp(p, "1")) - smt_enabled_at_boot = 1; - else if (!strcmp(p, "off") || !strcmp(p, "0")) - smt_enabled_at_boot = 0; - + smt_enabled_cmdline = p; return 0; } early_param("smt-enabled", early_smt_enabled); @@ -380,8 +389,8 @@ void __init setup_system(void) */ xmon_setup(); - check_smt_enabled(); smp_setup_cpu_maps(); + check_smt_enabled(); #ifdef CONFIG_SMP /* Release secondary cpus out of their spinloops at 0x60 now that diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 3b1bf61c45be..0317cce877c6 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -182,10 +182,13 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) /* Special case - we inhibit secondary thread startup * during boot if the user requests it. */ - if (system_state < SYSTEM_RUNNING && - cpu_has_feature(CPU_FTR_SMT) && - !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) - return 0; + if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) { + if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) + return 0; + if (smt_enabled_at_boot + && cpu_thread_in_core(nr) >= smt_enabled_at_boot) + return 0; + } return 1; } -- cgit v1.2.3-59-g8ed1b From 4138d65333fa8961714441ed40229ea8cbeaf7e5 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 6 Aug 2010 03:28:19 +0000 Subject: powerpc: Inline ppc64_runlatch_off I'm sick of seeing ppc64_runlatch_off in our profiles, so inline it into the callers. To avoid a mess of circular includes I didn't add it as an inline function. Signed-off-by: Anton Blanchard Acked-by: Olof Johansson Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/reg.h | 9 ++++++++- arch/powerpc/kernel/process.c | 14 ++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index d8be016d2ede..ff0005eec7dd 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -951,7 +951,14 @@ #ifdef CONFIG_PPC64 extern void ppc64_runlatch_on(void); -extern void ppc64_runlatch_off(void); +extern void __ppc64_runlatch_off(void); + +#define ppc64_runlatch_off() \ + do { \ + if (cpu_has_feature(CPU_FTR_CTRL) && \ + test_thread_flag(TIF_RUNLATCH)) \ + __ppc64_runlatch_off(); \ + } while (0) extern unsigned long scom970_read(unsigned int address); extern void scom970_write(unsigned int address, unsigned long value); diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 986fedf7e278..b1c648a36b03 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1199,19 +1199,17 @@ void ppc64_runlatch_on(void) } } -void ppc64_runlatch_off(void) +void __ppc64_runlatch_off(void) { unsigned long ctrl; - if (cpu_has_feature(CPU_FTR_CTRL) && test_thread_flag(TIF_RUNLATCH)) { - HMT_medium(); + HMT_medium(); - clear_thread_flag(TIF_RUNLATCH); + clear_thread_flag(TIF_RUNLATCH); - ctrl = mfspr(SPRN_CTRLF); - ctrl &= ~CTRL_RUNLATCH; - mtspr(SPRN_CTRLT, ctrl); - } + ctrl = mfspr(SPRN_CTRLF); + ctrl &= ~CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); } #endif -- cgit v1.2.3-59-g8ed1b From 7aa241fdcef2a1d6587fe4c390e9fdbfc767af28 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 11 Aug 2010 16:42:48 +0000 Subject: powerpc: Fix bogus it_blocksize in VIO iommu code When looking at some issues with the virtual ethernet driver I noticed that TCE allocation was following a very strange pattern: address 00e9000 length 2048 address 0409000 length 2048 <----- address 0429000 length 2048 address 0449000 length 2048 address 0469000 length 2048 address 0489000 length 2048 address 04a9000 length 2048 address 04c9000 length 2048 address 04e9000 length 2048 address 4009000 length 2048 <----- address 4029000 length 2048 Huge unexplained gaps in what should be an empty TCE table. It turns out it_blocksize, the amount we want to align the next allocation to, was c0000000fe903b20. Completely bogus. Initialise it to something reasonable in the VIO IOMMU code, and use kzalloc everywhere to protect against this when we next add a non compulsary field to iommu code and forget to initialise it. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/vio.c | 3 ++- arch/powerpc/platforms/cell/iommu.c | 2 +- arch/powerpc/platforms/iseries/iommu.c | 2 +- arch/powerpc/platforms/pseries/iommu.c | 8 ++++---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 00b9436f7652..fa3469ddaef8 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -1059,7 +1059,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) if (!dma_window) return NULL; - tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); if (tbl == NULL) return NULL; @@ -1072,6 +1072,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; tbl->it_busno = 0; tbl->it_type = TCE_VB; + tbl->it_blocksize = 16; return iommu_init_table(tbl, -1); } diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 58b13ce3847e..26a067122a54 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -477,7 +477,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, ioid = cell_iommu_get_ioid(np); - window = kmalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); + window = kzalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); BUG_ON(window == NULL); window->offset = offset; diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index ce61cea0afb5..d8b76335bd13 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -184,7 +184,7 @@ static void pci_dma_dev_setup_iseries(struct pci_dev *pdev) BUG_ON(lsn == NULL); - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL); iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 395848e30c52..a77bcaed80af 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -403,7 +403,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus) pci->phb->dma_window_size = 0x8000000ul; pci->phb->dma_window_base_cur = 0x8000000ul; - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, pci->phb->node); iommu_table_setparms(pci->phb, dn, tbl); @@ -448,7 +448,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) pdn->full_name, ppci->iommu_table); if (!ppci->iommu_table) { - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, ppci->phb->node); iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window, bus->number); @@ -478,7 +478,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev) struct pci_controller *phb = PCI_DN(dn)->phb; pr_debug(" --> first child, no bridge. Allocating iommu table.\n"); - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, phb->node); iommu_table_setparms(phb, dn, tbl); PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node); @@ -544,7 +544,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) pci = PCI_DN(pdn); if (!pci->iommu_table) { - tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, + tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL, pci->phb->node); iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window, pci->phb->bus->number); -- cgit v1.2.3-59-g8ed1b From f761622e59433130bc33ad086ce219feee9eb961 Mon Sep 17 00:00:00 2001 From: Matt Evans Date: Thu, 12 Aug 2010 20:58:28 +0000 Subject: powerpc: Initialise paca->kstack before early_setup_secondary As early setup calls down to slb_initialize(), we must have kstack initialised before checking "should we add a bolted SLB entry for our kstack?" Failing to do so means stack access requires an SLB miss exception to refill an entry dynamically, if the stack isn't accessible via SLB(0) (kernel text & static data). It's not always allowable to take such a miss, and intermittent crashes will result. Primary CPUs don't have this issue; an SLB entry is not bolted for their stack anyway (as that lives within SLB(0)). This patch therefore only affects the init of secondaries. Signed-off-by: Matt Evans Cc: stable Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/head_64.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 844a44b64472..4d6681dce816 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -572,9 +572,6 @@ __secondary_start: /* Set thread priority to MEDIUM */ HMT_MEDIUM - /* Do early setup for that CPU (stab, slb, hash table pointer) */ - bl .early_setup_secondary - /* Initialize the kernel stack. Just a repeat for iSeries. */ LOAD_REG_ADDR(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ @@ -582,6 +579,9 @@ __secondary_start: addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD std r1,PACAKSAVE(r13) + /* Do early setup for that CPU (stab, slb, hash table pointer) */ + bl .early_setup_secondary + /* Clear backchain so we get nice backtraces */ li r7,0 mtlr r7 -- cgit v1.2.3-59-g8ed1b From c686ecf5040d287a68d4fca7f1948472f556a6d3 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 15 Aug 2010 22:26:56 +0000 Subject: powerpc: Fix typo in uImage target Commit e32e78c5ee8aadef020fbaecbe6fb741ed9029fd (powerpc: fix build with make 3.82) introduced a typo in uImage target and broke building uImage: make: *** No rule to make target `uImage'. Stop. Signed-off-by: Anatolij Gustschin Cc: stable Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index e3ea151c9597..b7212b619c52 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -164,7 +164,7 @@ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ all: zImage # With make 3.82 we cannot mix normal and wildcard targets -BOOT_TARGETS1 := zImage zImage.initrd uImaged +BOOT_TARGETS1 := zImage zImage.initrd uImage BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.% PHONY += $(BOOT_TARGETS1) $(BOOT_TARGETS2) -- cgit v1.2.3-59-g8ed1b From 76ec01dbb70353928a9cee826502073ae928bbba Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 18 Aug 2010 08:27:55 +0000 Subject: powerpc/pci: Fix checking for child bridges in PCI code. pci_device_to_OF_node() can return null, and list_for_each_entry will never enter the loop when dev is NULL, so it looks like this test is a typo. Reported-by: Julia Lawall Signed-off-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/pci_of_scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 62dd363a9762..e751506323b4 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -336,7 +336,8 @@ static void __devinit __of_scan_bus(struct device_node *node, if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { struct device_node *child = pci_device_to_OF_node(dev); - of_scan_pci_bridge(child, dev); + if (child) + of_scan_pci_bridge(child, dev); } } } -- cgit v1.2.3-59-g8ed1b From bcc30d37582b3822ae24712e894379ccd8298e8f Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 19 Aug 2010 05:15:37 +0000 Subject: powerpc: Wire up fanotify_init, fanotify_mark, prlimit64 syscalls Signed-off-by: Andreas Schwab Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/systbl.h | 3 +++ arch/powerpc/include/asm/unistd.h | 5 ++++- arch/powerpc/kernel/sys_ppc32.c | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index a5ee345b6a5c..3d212669a130 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -326,3 +326,6 @@ SYSCALL_SPU(perf_event_open) COMPAT_SYS_SPU(preadv) COMPAT_SYS_SPU(pwritev) COMPAT_SYS(rt_tgsigqueueinfo) +SYSCALL(fanotify_init) +COMPAT_SYS(fanotify_mark) +SYSCALL_SPU(prlimit64) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index f0a10266e7f7..597e6f9d094a 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -345,10 +345,13 @@ #define __NR_preadv 320 #define __NR_pwritev 321 #define __NR_rt_tgsigqueueinfo 322 +#define __NR_fanotify_init 323 +#define __NR_fanotify_mark 324 +#define __NR_prlimit64 325 #ifdef __KERNEL__ -#define __NR_syscalls 323 +#define __NR_syscalls 326 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 20fd701a686a..b1b6043a56c4 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -616,3 +616,11 @@ asmlinkage long compat_sys_sync_file_range2(int fd, unsigned int flags, return sys_sync_file_range(fd, offset, nbytes, flags); } + +asmlinkage long compat_sys_fanotify_mark(int fanotify_fd, unsigned int flags, + unsigned mask_hi, unsigned mask_lo, + int dfd, const char __user *pathname) +{ + u64 mask = ((u64)mask_hi << 32) | mask_lo; + return sys_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname); +} -- cgit v1.2.3-59-g8ed1b From 4cc4587fb14bb04fbc68096cc3780b4e6aa88fe7 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sun, 22 Aug 2010 06:23:17 +0000 Subject: via-pmu: Add compat_pmu_ioctl The ioctls are actually compatible, but due to historical mistake the numbers differ between 32bit and 64bit. Signed-off-by: Andreas Schwab Acked-by: Arnd Bergmann Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/via-pmu.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 35bc2737412f..2d17e76066bd 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -2349,11 +2350,52 @@ static long pmu_unlocked_ioctl(struct file *filp, return ret; } +#ifdef CONFIG_COMPAT +#define PMU_IOC_GET_BACKLIGHT32 _IOR('B', 1, compat_size_t) +#define PMU_IOC_SET_BACKLIGHT32 _IOW('B', 2, compat_size_t) +#define PMU_IOC_GET_MODEL32 _IOR('B', 3, compat_size_t) +#define PMU_IOC_HAS_ADB32 _IOR('B', 4, compat_size_t) +#define PMU_IOC_CAN_SLEEP32 _IOR('B', 5, compat_size_t) +#define PMU_IOC_GRAB_BACKLIGHT32 _IOR('B', 6, compat_size_t) + +static long compat_pmu_ioctl (struct file *filp, u_int cmd, u_long arg) +{ + switch (cmd) { + case PMU_IOC_SLEEP: + break; + case PMU_IOC_GET_BACKLIGHT32: + cmd = PMU_IOC_GET_BACKLIGHT; + break; + case PMU_IOC_SET_BACKLIGHT32: + cmd = PMU_IOC_SET_BACKLIGHT; + break; + case PMU_IOC_GET_MODEL32: + cmd = PMU_IOC_GET_MODEL; + break; + case PMU_IOC_HAS_ADB32: + cmd = PMU_IOC_HAS_ADB; + break; + case PMU_IOC_CAN_SLEEP32: + cmd = PMU_IOC_CAN_SLEEP; + break; + case PMU_IOC_GRAB_BACKLIGHT32: + cmd = PMU_IOC_GRAB_BACKLIGHT; + break; + default: + return -ENOIOCTLCMD; + } + return pmu_unlocked_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static const struct file_operations pmu_device_fops = { .read = pmu_read, .write = pmu_write, .poll = pmu_fpoll, .unlocked_ioctl = pmu_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_pmu_ioctl, +#endif .open = pmu_open, .release = pmu_release, }; -- cgit v1.2.3-59-g8ed1b From 314b389b1795286400f109a25e9c2f02ab3b9b15 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 23 Aug 2010 07:36:41 +0000 Subject: powerpc: Fix config dependency problem with MPIC_U3_HT_IRQS MPIC_U3_HT_IRQS is selected both by PPC_PMAC64 and PPC_MAPLE, but depends on PPC_MAPLE, so a PPC_PMAC64-only config gets this warning: warning: (PPC_PMAC64 && PPC_PMAC && POWER4 || PPC_MAPLE && PPC64 && PPC_BOOK3S) selects MPIC_U3_HT_IRQS which has unmet direct dependencies (PPC_MAPLE) Fix that by removing the dependency on PPC_MAPLE. Signed-off-by: Andreas Schwab Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index d1663db7810f..81c9208025fa 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -106,8 +106,7 @@ config MMIO_NVRAM config MPIC_U3_HT_IRQS bool - depends on PPC_MAPLE - default y + default n config MPIC_BROKEN_REGREAD bool -- cgit v1.2.3-59-g8ed1b From 25edd6946a1d74e5e77813c2324a0908c68bcf9e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 23 Aug 2010 23:10:57 -0700 Subject: sparc64: Get rid of indirect p1275 PROM call buffer. This is based upon a report by Meelis Roos showing that it's possible that we'll try to fetch a property that is 32K in size with some devices. With the current fixed 3K buffer we use for moving data in and out of the firmware during PROM calls, that simply won't work. In fact, it will scramble random kernel data during bootup. The reasoning behind the temporary buffer is entirely historical. It used to be the case that we had problems referencing dynamic kernel memory (including the stack) early in the boot process before we explicitly told the firwmare to switch us over to the kernel trap table. So what we did was always give the firmware buffers that were locked into the main kernel image. But we no longer have problems like that, so get rid of all of this indirect bounce buffering. Besides fixing Meelis's bug, this also makes the kernel data about 3K smaller. It was also discovered during these conversions that the implementation of prom_retain() was completely wrong, so that was fixed here as well. Currently that interface is not in use. Reported-by: Meelis Roos Tested-by: Meelis Roos Signed-off-by: David S. Miller --- arch/sparc/include/asm/oplib_64.h | 27 +--- arch/sparc/prom/cif.S | 16 +- arch/sparc/prom/console_64.c | 48 ++++-- arch/sparc/prom/devops_64.c | 36 ++++- arch/sparc/prom/misc_64.c | 314 ++++++++++++++++++++++++++------------ arch/sparc/prom/p1275.c | 102 +------------ arch/sparc/prom/tree_64.c | 210 ++++++++++++++++++------- 7 files changed, 456 insertions(+), 297 deletions(-) diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h index a5db0317b5fb..3e0b2d62303d 100644 --- a/arch/sparc/include/asm/oplib_64.h +++ b/arch/sparc/include/asm/oplib_64.h @@ -185,9 +185,8 @@ extern int prom_getunumber(int syndrome_code, char *buf, int buflen); /* Retain physical memory to the caller across soft resets. */ -extern unsigned long prom_retain(const char *name, - unsigned long pa_low, unsigned long pa_high, - long size, long align); +extern int prom_retain(const char *name, unsigned long size, + unsigned long align, unsigned long *paddr); /* Load explicit I/D TLB entries into the calling processor. */ extern long prom_itlb_load(unsigned long index, @@ -287,26 +286,6 @@ extern void prom_sun4v_guest_soft_state(void); extern int prom_ihandle2path(int handle, char *buffer, int bufsize); /* Client interface level routines. */ -extern long p1275_cmd(const char *, long, ...); - -#if 0 -#define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x)) -#else -#define P1275_SIZE(x) x -#endif - -/* We support at most 16 input and 1 output argument */ -#define P1275_ARG_NUMBER 0 -#define P1275_ARG_IN_STRING 1 -#define P1275_ARG_OUT_BUF 2 -#define P1275_ARG_OUT_32B 3 -#define P1275_ARG_IN_FUNCTION 4 -#define P1275_ARG_IN_BUF 5 -#define P1275_ARG_IN_64B 6 - -#define P1275_IN(x) ((x) & 0xf) -#define P1275_OUT(x) (((x) << 4) & 0xf0) -#define P1275_INOUT(i,o) (P1275_IN(i)|P1275_OUT(o)) -#define P1275_ARG(n,x) ((x) << ((n)*3 + 8)) +extern void p1275_cmd_direct(unsigned long *); #endif /* !(__SPARC64_OPLIB_H) */ diff --git a/arch/sparc/prom/cif.S b/arch/sparc/prom/cif.S index 5f27ad779c0c..9c86b4b7d429 100644 --- a/arch/sparc/prom/cif.S +++ b/arch/sparc/prom/cif.S @@ -9,18 +9,18 @@ #include .text - .globl prom_cif_interface -prom_cif_interface: - sethi %hi(p1275buf), %o0 - or %o0, %lo(p1275buf), %o0 - ldx [%o0 + 0x010], %o1 ! prom_cif_stack - save %o1, -192, %sp - ldx [%i0 + 0x008], %l2 ! prom_cif_handler + .globl prom_cif_direct +prom_cif_direct: + sethi %hi(p1275buf), %o1 + or %o1, %lo(p1275buf), %o1 + ldx [%o1 + 0x0010], %o2 ! prom_cif_stack + save %o2, -192, %sp + ldx [%i1 + 0x0008], %l2 ! prom_cif_handler mov %g4, %l0 mov %g5, %l1 mov %g6, %l3 call %l2 - add %i0, 0x018, %o0 ! prom_args + mov %i0, %o0 ! prom_args mov %l0, %g4 mov %l1, %g5 mov %l3, %g6 diff --git a/arch/sparc/prom/console_64.c b/arch/sparc/prom/console_64.c index f55d58a8a156..10322dc2f557 100644 --- a/arch/sparc/prom/console_64.c +++ b/arch/sparc/prom/console_64.c @@ -21,14 +21,22 @@ extern int prom_stdin, prom_stdout; inline int prom_nbgetchar(void) { + unsigned long args[7]; char inc; - if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)| - P1275_INOUT(3,1), - prom_stdin, &inc, P1275_SIZE(1)) == 1) + args[0] = (unsigned long) "read"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) prom_stdin; + args[4] = (unsigned long) &inc; + args[5] = 1; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[6] == 1) return inc; - else - return -1; + return -1; } /* Non blocking put character to console device, returns -1 if @@ -37,12 +45,22 @@ prom_nbgetchar(void) inline int prom_nbputchar(char c) { + unsigned long args[7]; char outc; outc = c; - if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| - P1275_INOUT(3,1), - prom_stdout, &outc, P1275_SIZE(1)) == 1) + + args[0] = (unsigned long) "write"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) prom_stdout; + args[4] = (unsigned long) &outc; + args[5] = 1; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[6] == 1) return 0; else return -1; @@ -67,7 +85,15 @@ prom_putchar(char c) void prom_puts(const char *s, int len) { - p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)| - P1275_INOUT(3,1), - prom_stdout, s, P1275_SIZE(len)); + unsigned long args[7]; + + args[0] = (unsigned long) "write"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) prom_stdout; + args[4] = (unsigned long) s; + args[5] = len; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); } diff --git a/arch/sparc/prom/devops_64.c b/arch/sparc/prom/devops_64.c index 9dbd803e46e1..a017119e7ef1 100644 --- a/arch/sparc/prom/devops_64.c +++ b/arch/sparc/prom/devops_64.c @@ -18,16 +18,32 @@ int prom_devopen(const char *dstr) { - return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1,1), - dstr); + unsigned long args[5]; + + args[0] = (unsigned long) "open"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) dstr; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[4]; } /* Close the device described by device handle 'dhandle'. */ int prom_devclose(int dhandle) { - p1275_cmd ("close", P1275_INOUT(1,0), dhandle); + unsigned long args[4]; + + args[0] = (unsigned long) "close"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned int) dhandle; + + p1275_cmd_direct(args); + return 0; } @@ -37,5 +53,15 @@ prom_devclose(int dhandle) void prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) { - p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo); + unsigned long args[7]; + + args[0] = (unsigned long) "seek"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) dhandle; + args[4] = seekhi; + args[5] = seeklo; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); } diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c index 39fc6af21b7c..6cb1581d6aef 100644 --- a/arch/sparc/prom/misc_64.c +++ b/arch/sparc/prom/misc_64.c @@ -20,10 +20,17 @@ int prom_service_exists(const char *service_name) { - int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_INOUT(1, 1), service_name); + unsigned long args[5]; - if (err) + args[0] = (unsigned long) "test"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) service_name; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[4]) return 0; return 1; } @@ -31,30 +38,47 @@ int prom_service_exists(const char *service_name) void prom_sun4v_guest_soft_state(void) { const char *svc = "SUNW,soft-state-supported"; + unsigned long args[3]; if (!prom_service_exists(svc)) return; - p1275_cmd(svc, P1275_INOUT(0, 0)); + args[0] = (unsigned long) svc; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(const char *bcommand) { + unsigned long args[4]; + #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_reboot(bcommand); #endif - p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_INOUT(1, 0), bcommand); + args[0] = (unsigned long) "boot"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned long) bcommand; + + p1275_cmd_direct(args); } /* Forth evaluate the expression contained in 'fstring'. */ void prom_feval(const char *fstring) { + unsigned long args[5]; + if (!fstring || fstring[0] == 0) return; - p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_INOUT(1, 1), fstring); + args[0] = (unsigned long) "interpret"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) fstring; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); } EXPORT_SYMBOL(prom_feval); @@ -68,6 +92,7 @@ extern void smp_release(void); */ void prom_cmdline(void) { + unsigned long args[3]; unsigned long flags; local_irq_save(flags); @@ -76,7 +101,11 @@ void prom_cmdline(void) smp_capture(); #endif - p1275_cmd("enter", P1275_INOUT(0, 0)); + args[0] = (unsigned long) "enter"; + args[1] = 0; + args[2] = 0; + + p1275_cmd_direct(args); #ifdef CONFIG_SMP smp_release(); @@ -90,22 +119,32 @@ void prom_cmdline(void) */ void notrace prom_halt(void) { + unsigned long args[3]; + #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_power_off(); #endif again: - p1275_cmd("exit", P1275_INOUT(0, 0)); + args[0] = (unsigned long) "exit"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); goto again; /* PROM is out to get me -DaveM */ } void prom_halt_power_off(void) { + unsigned long args[3]; + #ifdef CONFIG_SUN_LDOMS if (ldom_domaining_enabled) ldom_power_off(); #endif - p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); + args[0] = (unsigned long) "SUNW,power-off"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); /* if nothing else helps, we just halt */ prom_halt(); @@ -114,10 +153,15 @@ void prom_halt_power_off(void) /* Set prom sync handler to call function 'funcp'. */ void prom_setcallback(callback_func_t funcp) { + unsigned long args[5]; if (!funcp) return; - p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) | - P1275_INOUT(1, 1), funcp); + args[0] = (unsigned long) "set-callback"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) funcp; + args[4] = (unsigned long) -1; + p1275_cmd_direct(args); } /* Get the idprom and stuff it into buffer 'idbuf'. Returns the @@ -173,57 +217,61 @@ static int prom_get_memory_ihandle(void) } /* Load explicit I/D TLB entries. */ +static long tlb_load(const char *type, unsigned long index, + unsigned long tte_data, unsigned long vaddr) +{ + unsigned long args[9]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 5; + args[2] = 1; + args[3] = (unsigned long) type; + args[4] = (unsigned int) prom_get_mmu_ihandle(); + args[5] = vaddr; + args[6] = tte_data; + args[7] = index; + args[8] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (long) args[8]; +} + long prom_itlb_load(unsigned long index, unsigned long tte_data, unsigned long vaddr) { - return p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(2, P1275_ARG_IN_64B) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_INOUT(5, 1)), - "SUNW,itlb-load", - prom_get_mmu_ihandle(), - /* And then our actual args are pushed backwards. */ - vaddr, - tte_data, - index); + return tlb_load("SUNW,itlb-load", index, tte_data, vaddr); } long prom_dtlb_load(unsigned long index, unsigned long tte_data, unsigned long vaddr) { - return p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(2, P1275_ARG_IN_64B) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_INOUT(5, 1)), - "SUNW,dtlb-load", - prom_get_mmu_ihandle(), - /* And then our actual args are pushed backwards. */ - vaddr, - tte_data, - index); + return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr); } int prom_map(int mode, unsigned long size, unsigned long vaddr, unsigned long paddr) { - int ret = p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_ARG(4, P1275_ARG_IN_64B) | - P1275_ARG(6, P1275_ARG_IN_64B) | - P1275_INOUT(7, 1)), - prom_map_name, - prom_get_mmu_ihandle(), - mode, - size, - vaddr, - 0, - paddr); - + unsigned long args[11]; + int ret; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 7; + args[2] = 1; + args[3] = (unsigned long) prom_map_name; + args[4] = (unsigned int) prom_get_mmu_ihandle(); + args[5] = (unsigned int) mode; + args[6] = size; + args[7] = vaddr; + args[8] = 0; + args[9] = paddr; + args[10] = (unsigned long) -1; + + p1275_cmd_direct(args); + + ret = (int) args[10]; if (ret == 0) ret = -1; return ret; @@ -231,40 +279,51 @@ int prom_map(int mode, unsigned long size, void prom_unmap(unsigned long size, unsigned long vaddr) { - p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(2, P1275_ARG_IN_64B) | - P1275_ARG(3, P1275_ARG_IN_64B) | - P1275_INOUT(4, 0)), - prom_unmap_name, - prom_get_mmu_ihandle(), - size, - vaddr); + unsigned long args[7]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 4; + args[2] = 0; + args[3] = (unsigned long) prom_unmap_name; + args[4] = (unsigned int) prom_get_mmu_ihandle(); + args[5] = size; + args[6] = vaddr; + + p1275_cmd_direct(args); } /* Set aside physical memory which is not touched or modified * across soft resets. */ -unsigned long prom_retain(const char *name, - unsigned long pa_low, unsigned long pa_high, - long size, long align) +int prom_retain(const char *name, unsigned long size, + unsigned long align, unsigned long *paddr) { - /* XXX I don't think we return multiple values correctly. - * XXX OBP supposedly returns pa_low/pa_high here, how does - * XXX it work? + unsigned long args[11]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 5; + args[2] = 3; + args[3] = (unsigned long) "SUNW,retain"; + args[4] = (unsigned int) prom_get_memory_ihandle(); + args[5] = align; + args[6] = size; + args[7] = (unsigned long) name; + args[8] = (unsigned long) -1; + args[9] = (unsigned long) -1; + args[10] = (unsigned long) -1; + + p1275_cmd_direct(args); + + if (args[8]) + return (int) args[8]; + + /* Next we get "phys_high" then "phys_low". On 64-bit + * the phys_high cell is don't care since the phys_low + * cell has the full value. */ + *paddr = args[10]; - /* If align is zero, the pa_low/pa_high args are passed, - * else they are not. - */ - if (align == 0) - return p1275_cmd("SUNW,retain", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), - name, pa_low, pa_high, size, align); - else - return p1275_cmd("SUNW,retain", - (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), - name, size, align); + return 0; } /* Get "Unumber" string for the SIMM at the given @@ -277,62 +336,129 @@ int prom_getunumber(int syndrome_code, unsigned long phys_addr, char *buf, int buflen) { - return p1275_cmd(prom_callmethod_name, - (P1275_ARG(0, P1275_ARG_IN_STRING) | - P1275_ARG(3, P1275_ARG_OUT_BUF) | - P1275_ARG(6, P1275_ARG_IN_64B) | - P1275_INOUT(8, 2)), - "SUNW,get-unumber", prom_get_memory_ihandle(), - buflen, buf, P1275_SIZE(buflen), - 0, phys_addr, syndrome_code); + unsigned long args[12]; + + args[0] = (unsigned long) prom_callmethod_name; + args[1] = 7; + args[2] = 2; + args[3] = (unsigned long) "SUNW,get-unumber"; + args[4] = (unsigned int) prom_get_memory_ihandle(); + args[5] = buflen; + args[6] = (unsigned long) buf; + args[7] = 0; + args[8] = phys_addr; + args[9] = (unsigned int) syndrome_code; + args[10] = (unsigned long) -1; + args[11] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[10]; } /* Power management extensions. */ void prom_sleepself(void) { - p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); + unsigned long args[3]; + + args[0] = (unsigned long) "SUNW,sleep-self"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } int prom_sleepsystem(void) { - return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,sleep-system"; + args[1] = 0; + args[2] = 1; + args[3] = (unsigned long) -1; + p1275_cmd_direct(args); + + return (int) args[3]; } int prom_wakeupsystem(void) { - return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,wakeup-system"; + args[1] = 0; + args[2] = 1; + args[3] = (unsigned long) -1; + p1275_cmd_direct(args); + + return (int) args[3]; } #ifdef CONFIG_SMP void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) { - p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg); + unsigned long args[6]; + + args[0] = (unsigned long) "SUNW,start-cpu"; + args[1] = 3; + args[2] = 0; + args[3] = (unsigned int) cpunode; + args[4] = pc; + args[5] = arg; + p1275_cmd_direct(args); } void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) { - p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0), - cpuid, pc, arg); + unsigned long args[6]; + + args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid"; + args[1] = 3; + args[2] = 0; + args[3] = (unsigned int) cpuid; + args[4] = pc; + args[5] = arg; + p1275_cmd_direct(args); } void prom_stopcpu_cpuid(int cpuid) { - p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0), - cpuid); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned int) cpuid; + p1275_cmd_direct(args); } void prom_stopself(void) { - p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); + unsigned long args[3]; + + args[0] = (unsigned long) "SUNW,stop-self"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } void prom_idleself(void) { - p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); + unsigned long args[3]; + + args[0] = (unsigned long) "SUNW,idle-self"; + args[1] = 0; + args[2] = 0; + p1275_cmd_direct(args); } void prom_resumecpu(int cpunode) { - p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); + unsigned long args[4]; + + args[0] = (unsigned long) "SUNW,resume-cpu"; + args[1] = 1; + args[2] = 0; + args[3] = (unsigned int) cpunode; + p1275_cmd_direct(args); } #endif diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c index 2d8b70d397f1..fa6e4e219b9c 100644 --- a/arch/sparc/prom/p1275.c +++ b/arch/sparc/prom/p1275.c @@ -22,13 +22,11 @@ struct { long prom_callback; /* 0x00 */ void (*prom_cif_handler)(long *); /* 0x08 */ unsigned long prom_cif_stack; /* 0x10 */ - unsigned long prom_args [23]; /* 0x18 */ - char prom_buffer [3000]; } p1275buf; extern void prom_world(int); -extern void prom_cif_interface(void); +extern void prom_cif_direct(unsigned long *args); extern void prom_cif_callback(void); /* @@ -36,114 +34,20 @@ extern void prom_cif_callback(void); */ DEFINE_RAW_SPINLOCK(prom_entry_lock); -long p1275_cmd(const char *service, long fmt, ...) +void p1275_cmd_direct(unsigned long *args) { - char *p, *q; unsigned long flags; - int nargs, nrets, i; - va_list list; - long attrs, x; - - p = p1275buf.prom_buffer; raw_local_save_flags(flags); raw_local_irq_restore(PIL_NMI); raw_spin_lock(&prom_entry_lock); - p1275buf.prom_args[0] = (unsigned long)p; /* service */ - strcpy (p, service); - p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); - p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ - p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ - attrs = fmt >> 8; - va_start(list, fmt); - for (i = 0; i < nargs; i++, attrs >>= 3) { - switch (attrs & 0x7) { - case P1275_ARG_NUMBER: - p1275buf.prom_args[i + 3] = - (unsigned)va_arg(list, long); - break; - case P1275_ARG_IN_64B: - p1275buf.prom_args[i + 3] = - va_arg(list, unsigned long); - break; - case P1275_ARG_IN_STRING: - strcpy (p, va_arg(list, char *)); - p1275buf.prom_args[i + 3] = (unsigned long)p; - p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); - break; - case P1275_ARG_OUT_BUF: - (void) va_arg(list, char *); - p1275buf.prom_args[i + 3] = (unsigned long)p; - x = va_arg(list, long); - i++; attrs >>= 3; - p = (char *)(((long)(p + (int)x + 7)) & ~7); - p1275buf.prom_args[i + 3] = x; - break; - case P1275_ARG_IN_BUF: - q = va_arg(list, char *); - p1275buf.prom_args[i + 3] = (unsigned long)p; - x = va_arg(list, long); - i++; attrs >>= 3; - memcpy (p, q, (int)x); - p = (char *)(((long)(p + (int)x + 7)) & ~7); - p1275buf.prom_args[i + 3] = x; - break; - case P1275_ARG_OUT_32B: - (void) va_arg(list, char *); - p1275buf.prom_args[i + 3] = (unsigned long)p; - p += 32; - break; - case P1275_ARG_IN_FUNCTION: - p1275buf.prom_args[i + 3] = - (unsigned long)prom_cif_callback; - p1275buf.prom_callback = va_arg(list, long); - break; - } - } - va_end(list); - prom_world(1); - prom_cif_interface(); + prom_cif_direct(args); prom_world(0); - attrs = fmt >> 8; - va_start(list, fmt); - for (i = 0; i < nargs; i++, attrs >>= 3) { - switch (attrs & 0x7) { - case P1275_ARG_NUMBER: - (void) va_arg(list, long); - break; - case P1275_ARG_IN_STRING: - (void) va_arg(list, char *); - break; - case P1275_ARG_IN_FUNCTION: - (void) va_arg(list, long); - break; - case P1275_ARG_IN_BUF: - (void) va_arg(list, char *); - (void) va_arg(list, long); - i++; attrs >>= 3; - break; - case P1275_ARG_OUT_BUF: - p = va_arg(list, char *); - x = va_arg(list, long); - memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); - i++; attrs >>= 3; - break; - case P1275_ARG_OUT_32B: - p = va_arg(list, char *); - memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); - break; - } - } - va_end(list); - x = p1275buf.prom_args [nargs + 3]; - raw_spin_unlock(&prom_entry_lock); raw_local_irq_restore(flags); - - return x; } void prom_cif_init(void *cif_handler, void *cif_stack) diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c index 3c0d2dd9f693..9d3f9137a43a 100644 --- a/arch/sparc/prom/tree_64.c +++ b/arch/sparc/prom/tree_64.c @@ -16,22 +16,39 @@ #include #include +static int prom_node_to_node(const char *type, int node) +{ + unsigned long args[5]; + + args[0] = (unsigned long) type; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[4]; +} + /* Return the child of node 'node' or zero if no this node has no * direct descendent. */ inline int __prom_getchild(int node) { - return p1275_cmd ("child", P1275_INOUT(1, 1), node); + return prom_node_to_node("child", node); } inline int prom_getchild(int node) { int cnode; - if(node == -1) return 0; + if (node == -1) + return 0; cnode = __prom_getchild(node); - if(cnode == -1) return 0; - return (int)cnode; + if (cnode == -1) + return 0; + return cnode; } EXPORT_SYMBOL(prom_getchild); @@ -39,10 +56,12 @@ inline int prom_getparent(int node) { int cnode; - if(node == -1) return 0; - cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); - if(cnode == -1) return 0; - return (int)cnode; + if (node == -1) + return 0; + cnode = prom_node_to_node("parent", node); + if (cnode == -1) + return 0; + return cnode; } /* Return the next sibling of node 'node' or zero if no more siblings @@ -50,7 +69,7 @@ inline int prom_getparent(int node) */ inline int __prom_getsibling(int node) { - return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node); + return prom_node_to_node(prom_peer_name, node); } inline int prom_getsibling(int node) @@ -72,11 +91,21 @@ EXPORT_SYMBOL(prom_getsibling); */ inline int prom_getproplen(int node, const char *prop) { - if((!node) || (!prop)) return -1; - return p1275_cmd ("getproplen", - P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_INOUT(2, 1), - node, prop); + unsigned long args[6]; + + if (!node || !prop) + return -1; + + args[0] = (unsigned long) "getproplen"; + args[1] = 2; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) prop; + args[5] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[5]; } EXPORT_SYMBOL(prom_getproplen); @@ -87,19 +116,25 @@ EXPORT_SYMBOL(prom_getproplen); inline int prom_getproperty(int node, const char *prop, char *buffer, int bufsize) { + unsigned long args[8]; int plen; plen = prom_getproplen(node, prop); - if ((plen > bufsize) || (plen == 0) || (plen == -1)) { + if ((plen > bufsize) || (plen == 0) || (plen == -1)) return -1; - } else { - /* Ok, things seem all right. */ - return p1275_cmd(prom_getprop_name, - P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_OUT_BUF)| - P1275_INOUT(4, 1), - node, prop, buffer, P1275_SIZE(plen)); - } + + args[0] = (unsigned long) prom_getprop_name; + args[1] = 4; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) prop; + args[5] = (unsigned long) buffer; + args[6] = bufsize; + args[7] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[7]; } EXPORT_SYMBOL(prom_getproperty); @@ -110,7 +145,7 @@ inline int prom_getint(int node, const char *prop) { int intprop; - if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) + if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) return intprop; return -1; @@ -126,7 +161,8 @@ int prom_getintdefault(int node, const char *property, int deflt) int retval; retval = prom_getint(node, property); - if(retval == -1) return deflt; + if (retval == -1) + return deflt; return retval; } @@ -138,7 +174,8 @@ int prom_getbool(int node, const char *prop) int retval; retval = prom_getproplen(node, prop); - if(retval == -1) return 0; + if (retval == -1) + return 0; return 1; } EXPORT_SYMBOL(prom_getbool); @@ -152,7 +189,8 @@ void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size) int len; len = prom_getproperty(node, prop, user_buf, ubuf_size); - if(len != -1) return; + if (len != -1) + return; user_buf[0] = 0; } EXPORT_SYMBOL(prom_getstring); @@ -164,7 +202,8 @@ int prom_nodematch(int node, const char *name) { char namebuf[128]; prom_getproperty(node, "name", namebuf, sizeof(namebuf)); - if(strcmp(namebuf, name) == 0) return 1; + if (strcmp(namebuf, name) == 0) + return 1; return 0; } @@ -190,16 +229,29 @@ int prom_searchsiblings(int node_start, const char *nodename) } EXPORT_SYMBOL(prom_searchsiblings); +static const char *prom_nextprop_name = "nextprop"; + /* Return the first property type for node 'node'. * buffer should be at least 32B in length */ inline char *prom_firstprop(int node, char *buffer) { + unsigned long args[7]; + *buffer = 0; - if(node == -1) return buffer; - p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| - P1275_INOUT(3, 0), - node, (char *) 0x0, buffer); + if (node == -1) + return buffer; + + args[0] = (unsigned long) prom_nextprop_name; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = 0; + args[5] = (unsigned long) buffer; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + return buffer; } EXPORT_SYMBOL(prom_firstprop); @@ -210,9 +262,10 @@ EXPORT_SYMBOL(prom_firstprop); */ inline char *prom_nextprop(int node, const char *oprop, char *buffer) { + unsigned long args[7]; char buf[32]; - if(node == -1) { + if (node == -1) { *buffer = 0; return buffer; } @@ -220,10 +273,17 @@ inline char *prom_nextprop(int node, const char *oprop, char *buffer) strcpy (buf, oprop); oprop = buf; } - p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_OUT_32B)| - P1275_INOUT(3, 0), - node, oprop, buffer); + + args[0] = (unsigned long) prom_nextprop_name; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) oprop; + args[5] = (unsigned long) buffer; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + return buffer; } EXPORT_SYMBOL(prom_nextprop); @@ -231,12 +291,19 @@ EXPORT_SYMBOL(prom_nextprop); int prom_finddevice(const char *name) { + unsigned long args[5]; + if (!name) return 0; - return p1275_cmd(prom_finddev_name, - P1275_ARG(0,P1275_ARG_IN_STRING)| - P1275_INOUT(1, 1), - name); + args[0] = (unsigned long) "finddevice"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned long) name; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[4]; } EXPORT_SYMBOL(prom_finddevice); @@ -247,7 +314,7 @@ int prom_node_has_property(int node, const char *prop) *buf = 0; do { prom_nextprop(node, buf, buf); - if(!strcmp(buf, prop)) + if (!strcmp(buf, prop)) return 1; } while (*buf); return 0; @@ -260,6 +327,8 @@ EXPORT_SYMBOL(prom_node_has_property); int prom_setprop(int node, const char *pname, char *value, int size) { + unsigned long args[8]; + if (size == 0) return 0; if ((pname == 0) || (value == 0)) @@ -271,19 +340,37 @@ prom_setprop(int node, const char *pname, char *value, int size) return 0; } #endif - return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| - P1275_ARG(2,P1275_ARG_IN_BUF)| - P1275_INOUT(4, 1), - node, pname, value, P1275_SIZE(size)); + args[0] = (unsigned long) "setprop"; + args[1] = 4; + args[2] = 1; + args[3] = (unsigned int) node; + args[4] = (unsigned long) pname; + args[5] = (unsigned long) value; + args[6] = size; + args[7] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[7]; } EXPORT_SYMBOL(prom_setprop); inline int prom_inst2pkg(int inst) { + unsigned long args[5]; int node; - node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst); - if (node == -1) return 0; + args[0] = (unsigned long) "instance-to-package"; + args[1] = 1; + args[2] = 1; + args[3] = (unsigned int) inst; + args[4] = (unsigned long) -1; + + p1275_cmd_direct(args); + + node = (int) args[4]; + if (node == -1) + return 0; return node; } @@ -296,17 +383,28 @@ prom_pathtoinode(const char *path) int node, inst; inst = prom_devopen (path); - if (inst == 0) return 0; - node = prom_inst2pkg (inst); - prom_devclose (inst); - if (node == -1) return 0; + if (inst == 0) + return 0; + node = prom_inst2pkg(inst); + prom_devclose(inst); + if (node == -1) + return 0; return node; } int prom_ihandle2path(int handle, char *buffer, int bufsize) { - return p1275_cmd("instance-to-path", - P1275_ARG(1,P1275_ARG_OUT_BUF)| - P1275_INOUT(3, 1), - handle, buffer, P1275_SIZE(bufsize)); + unsigned long args[7]; + + args[0] = (unsigned long) "instance-to-path"; + args[1] = 3; + args[2] = 1; + args[3] = (unsigned int) handle; + args[4] = (unsigned long) buffer; + args[5] = bufsize; + args[6] = (unsigned long) -1; + + p1275_cmd_direct(args); + + return (int) args[6]; } -- cgit v1.2.3-59-g8ed1b From 7af048dc7639db5202c56fecf2346c310647a218 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 24 Aug 2010 09:26:20 +0200 Subject: [S390] s390: fix build error (sys_execve) fix this build error: arch/s390/kernel/process.c:272: error: conflicting types for 'sys_execve' arch/s390/kernel/entry.h:45: error: previous declaration of 'sys_execve' was here make[1]: *** [arch/s390/kernel/process.o] Error 1 make: *** [arch/s390/kernel] Error 2 introduced by d7627467b7a8dd6944885290a03a07ceb28c10eb Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/entry.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 403fb430a896..ff579b6bde06 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -42,8 +42,8 @@ long sys_clone(unsigned long newsp, unsigned long clone_flags, int __user *parent_tidptr, int __user *child_tidptr); long sys_vfork(void); void execve_tail(void); -long sys_execve(const char __user *name, char __user * __user *argv, - char __user * __user *envp); +long sys_execve(const char __user *name, const char __user *const __user *argv, + const char __user *const __user *envp); long sys_sigsuspend(int history0, int history1, old_sigset_t mask); long sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact); -- cgit v1.2.3-59-g8ed1b From 050eef364ad700590a605a0749f825cab4834b1e Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 24 Aug 2010 09:26:21 +0200 Subject: [S390] fix tlb flushing vs. concurrent /proc accesses The tlb flushing code uses the mm_users field of the mm_struct to decide if each page table entry needs to be flushed individually with IPTE or if a global flush for the mm_struct is sufficient after all page table updates have been done. The comment for mm_users says "How many users with user space?" but the /proc code increases mm_users after it found the process structure by pid without creating a new user process. Which makes mm_users useless for the decision between the two tlb flusing methods. The current code can be confused to not flush tlb entries by a concurrent access to /proc files if e.g. a fork is in progres. The solution for this problem is to make the tlb flushing logic independent from the mm_users field. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/hugetlb.h | 4 +++- arch/s390/include/asm/mmu.h | 2 ++ arch/s390/include/asm/mmu_context.h | 9 +++++++++ arch/s390/include/asm/pgtable.h | 6 ++++-- arch/s390/include/asm/tlb.h | 3 +-- arch/s390/include/asm/tlbflush.h | 6 +++++- arch/s390/kernel/smp.c | 2 ++ arch/s390/mm/init.c | 2 ++ 8 files changed, 28 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index 670a1d1745d2..bb8343d157bc 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h @@ -97,6 +97,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, { pte_t pte = huge_ptep_get(ptep); + mm->context.flush_mm = 1; pmd_clear((pmd_t *) ptep); return pte; } @@ -167,7 +168,8 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm, ({ \ pte_t __pte = huge_ptep_get(__ptep); \ if (pte_write(__pte)) { \ - if (atomic_read(&(__mm)->mm_users) > 1 || \ + (__mm)->context.flush_mm = 1; \ + if (atomic_read(&(__mm)->context.attach_count) > 1 || \ (__mm) != current->active_mm) \ huge_ptep_invalidate(__mm, __addr, __ptep); \ set_huge_pte_at(__mm, __addr, __ptep, \ diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 99e3409102b9..78522cdefdd4 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -2,6 +2,8 @@ #define __MMU_H typedef struct { + atomic_t attach_count; + unsigned int flush_mm; spinlock_t list_lock; struct list_head crst_list; struct list_head pgtable_list; diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 976e273988c2..a6f0e7cc9cde 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -11,11 +11,14 @@ #include #include +#include #include static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { + atomic_set(&mm->context.attach_count, 0); + mm->context.flush_mm = 0; mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; #ifdef CONFIG_64BIT mm->context.asce_bits |= _ASCE_TYPE_REGION3; @@ -76,6 +79,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, { cpumask_set_cpu(smp_processor_id(), mm_cpumask(next)); update_mm(next, tsk); + atomic_dec(&prev->context.attach_count); + WARN_ON(atomic_read(&prev->context.attach_count) < 0); + atomic_inc(&next->context.attach_count); + /* Check for TLBs not flushed yet */ + if (next->context.flush_mm) + __tlb_flush_mm(next); } #define enter_lazy_tlb(mm,tsk) do { } while (0) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 89a504c3f12e..3157441ee1da 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -880,7 +880,8 @@ static inline void ptep_invalidate(struct mm_struct *mm, #define ptep_get_and_clear(__mm, __address, __ptep) \ ({ \ pte_t __pte = *(__ptep); \ - if (atomic_read(&(__mm)->mm_users) > 1 || \ + (__mm)->context.flush_mm = 1; \ + if (atomic_read(&(__mm)->context.attach_count) > 1 || \ (__mm) != current->active_mm) \ ptep_invalidate(__mm, __address, __ptep); \ else \ @@ -923,7 +924,8 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, ({ \ pte_t __pte = *(__ptep); \ if (pte_write(__pte)) { \ - if (atomic_read(&(__mm)->mm_users) > 1 || \ + (__mm)->context.flush_mm = 1; \ + if (atomic_read(&(__mm)->context.attach_count) > 1 || \ (__mm) != current->active_mm) \ ptep_invalidate(__mm, __addr, __ptep); \ set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h index 81150b053689..fd1c00d08bf5 100644 --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h @@ -50,8 +50,7 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, struct mmu_gather *tlb = &get_cpu_var(mmu_gathers); tlb->mm = mm; - tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) || - (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm); + tlb->fullmm = full_mm_flush; tlb->nr_ptes = 0; tlb->nr_pxds = TLB_NR_PTRS; if (tlb->fullmm) diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index 304cffa623e1..29d5d6d4becc 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h @@ -94,8 +94,12 @@ static inline void __tlb_flush_mm(struct mm_struct * mm) static inline void __tlb_flush_mm_cond(struct mm_struct * mm) { - if (atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm) + spin_lock(&mm->page_table_lock); + if (mm->context.flush_mm) { __tlb_flush_mm(mm); + mm->context.flush_mm = 0; + } + spin_unlock(&mm->page_table_lock); } /* diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 541053ed234e..8127ebd59c4d 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -583,6 +583,7 @@ int __cpuinit __cpu_up(unsigned int cpu) sf->gprs[9] = (unsigned long) sf; cpu_lowcore->save_area[15] = (unsigned long) sf; __ctl_store(cpu_lowcore->cregs_save_area, 0, 15); + atomic_inc(&init_mm.context.attach_count); asm volatile( " stam 0,15,0(%0)" : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); @@ -659,6 +660,7 @@ void __cpu_die(unsigned int cpu) while (sigp_p(0, cpu, sigp_set_prefix) == sigp_busy) udelay(10); smp_free_lowcore(cpu); + atomic_dec(&init_mm.context.attach_count); pr_info("Processor %d stopped\n", cpu); } diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index acc91c75bc94..30eb6d02ddb8 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -74,6 +74,8 @@ void __init paging_init(void) __ctl_load(S390_lowcore.kernel_asce, 13, 13); __raw_local_irq_ssm(ssm_mask); + atomic_set(&init_mm.context.attach_count, 1); + sparse_memory_present_with_active_regions(MAX_NUMNODES); sparse_init(); memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); -- cgit v1.2.3-59-g8ed1b From aa25ab7d943a5e1e6bcc2a65ff6669144f5b5d60 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 11 Aug 2010 05:12:57 +0000 Subject: 3c59x: Fix deadlock between boomerang_interrupt and boomerang_start_tx If netconsole is in use, there is a possibility for deadlock in 3c59x between boomerang_interrupt and boomerang_start_xmit. Both routines take the vp->lock, and if netconsole is in use, a pr_* call from the boomerang_interrupt routine will result in the netconsole code attempting to trnasmit an skb, which can try to take the same spin lock, resulting in deadlock. The fix is pretty straightforward. This patch allocats a bit in the 3c59x private structure to indicate that its handling an interrupt. If we get into the transmit routine and that bit is set, we can be sure that we have recursed and will deadlock if we continue, so instead we just return NETDEV_TX_BUSY, so the stack requeues the skb to try again later. Signed-off-by: Neil Horman Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c754d88e5ec9..c685a55fc2f4 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -633,7 +633,8 @@ struct vortex_private { open:1, medialock:1, must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ - large_frames:1; /* accept large frames */ + large_frames:1, /* accept large frames */ + handling_irq:1; /* private in_irq indicator */ int drv_flags; u16 status_enable; u16 intr_enable; @@ -2133,6 +2134,15 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) dev->name, vp->cur_tx); } + /* + * We can't allow a recursion from our interrupt handler back into the + * tx routine, as they take the same spin lock, and that causes + * deadlock. Just return NETDEV_TX_BUSY and let the stack try again in + * a bit + */ + if (vp->handling_irq) + return NETDEV_TX_BUSY; + if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { if (vortex_debug > 0) pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", @@ -2335,11 +2345,13 @@ boomerang_interrupt(int irq, void *dev_id) ioaddr = vp->ioaddr; + /* * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout * and boomerang_start_xmit */ spin_lock(&vp->lock); + vp->handling_irq = 1; status = ioread16(ioaddr + EL3_STATUS); @@ -2447,6 +2459,7 @@ boomerang_interrupt(int irq, void *dev_id) pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status); handler_exit: + vp->handling_irq = 0; spin_unlock(&vp->lock); return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From 77f4b9fe050d59a30c3b11e267289630bb13f56a Mon Sep 17 00:00:00 2001 From: Shuduo Sang Date: Tue, 24 Aug 2010 14:35:17 +0100 Subject: intel_pmic_battery: Fix battery charging status on mrst The arguments got swapped on some functions which produces undefined results. The main one got fixed before submit but the other two were missed. Signed-off-by: Shuduo Sang Signed-off-by: Alan Cox Signed-off-by: Anton Vorontsov --- drivers/power/intel_mid_battery.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c index c61ffec2ff10..2a10cd361181 100644 --- a/drivers/power/intel_mid_battery.c +++ b/drivers/power/intel_mid_battery.c @@ -185,8 +185,8 @@ static int pmic_scu_ipc_battery_property_get(struct battery_property *prop) { u32 data[3]; u8 *p = (u8 *)&data[1]; - int err = intel_scu_ipc_command(IPC_CMD_BATTERY_PROPERTY, - IPCMSG_BATTERY, NULL, 0, data, 3); + int err = intel_scu_ipc_command(IPCMSG_BATTERY, + IPC_CMD_BATTERY_PROPERTY, NULL, 0, data, 3); prop->capacity = data[0]; prop->crnt = *p++; @@ -207,7 +207,7 @@ static int pmic_scu_ipc_battery_property_get(struct battery_property *prop) static int pmic_scu_ipc_set_charger(int charger) { - return intel_scu_ipc_simple_command(charger, IPCMSG_BATTERY); + return intel_scu_ipc_simple_command(IPCMSG_BATTERY, charger); } /** -- cgit v1.2.3-59-g8ed1b From 426409b1edcd7db922dd326911eba23d5a06d098 Mon Sep 17 00:00:00 2001 From: Decio Fonini Date: Tue, 24 Aug 2010 17:45:49 +0200 Subject: HID: Kanvus Note A5 tablet needs HID_QUIRK_MULTI_INPUT The Kanvus Note A5 tablet (with USB ID 5543:6001, USB vendor UC_Logic) needs the HID_QUIRK_MULTI_INPUT in order to work out of the box; otherwise, we get the usual "cursor stuck at the upper left corner of the screen". Signed-off-by: Decio Fonini Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 29051425ca0f..b309525ae280 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -508,6 +508,7 @@ #define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 +#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 #define USB_VENDOR_ID_VERNIER 0x08f7 #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 1b222398ff54..89fa4ac989f9 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -69,6 +69,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.3-59-g8ed1b From c29771c2d8ceb907ed45eb8c7fc0450308140aca Mon Sep 17 00:00:00 2001 From: Alan Ott Date: Tue, 17 Aug 2010 00:44:04 -0400 Subject: HID: Set Report ID properly for Output reports on the Control endpoint. When I made commit 29129a98e6fc89 ("HID: Send Report ID when numbered reports are sent over the control endpoint"), I didn't account for *buf not being the report ID anymore, as buf is incremented. Signed-off-by: Alan Ott Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index b729c0286679..ffd6899d4ba0 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -828,6 +828,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co } } else { int skipped_report_id = 0; + int report_id = buf[0]; if (buf[0] == 0x0) { /* Don't send the Report ID */ buf++; @@ -837,7 +838,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), HID_REQ_SET_REPORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - ((report_type + 1) << 8) | *buf, + ((report_type + 1) << 8) | report_id, interface->desc.bInterfaceNumber, buf, count, USB_CTRL_SET_TIMEOUT); /* count also the report id, if this was a numbered report. */ -- cgit v1.2.3-59-g8ed1b From e41e704bc4f49057fc68b643108366e6e6781aa3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 24 Aug 2010 14:22:47 +0200 Subject: workqueue: improve destroy_workqueue() debuggability Now that the worklist is global, having works pending after wq destruction can easily lead to oops and destroy_workqueue() have several BUG_ON()s to catch these cases. Unfortunately, BUG_ON() doesn't tell much about how the work became pending after the final flush_workqueue(). This patch adds WQ_DYING which is set before the final flush begins. If a work is requested to be queued on a dying workqueue, WARN_ON_ONCE() is triggered and the request is ignored. This clearly indicates which caller is trying to queue a work on a dying workqueue and keeps the system working in most cases. Locking rule comment is updated such that the 'I' rule includes modifying the field from destruction path. Signed-off-by: Tejun Heo --- include/linux/workqueue.h | 2 ++ kernel/workqueue.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 4f9d277bcd9a..c959666eafca 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -241,6 +241,8 @@ enum { WQ_HIGHPRI = 1 << 4, /* high priority */ WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */ + WQ_DYING = 1 << 6, /* internal: workqueue is dying */ + WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */ WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2, diff --git a/kernel/workqueue.c b/kernel/workqueue.c index cc3456f96c56..362b50d092e2 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -87,7 +87,8 @@ enum { /* * Structure fields follow one of the following exclusion rules. * - * I: Set during initialization and read-only afterwards. + * I: Modifiable by initialization/destruction paths and read-only for + * everyone else. * * P: Preemption protected. Disabling preemption is enough and should * only be modified and accessed from the local cpu. @@ -944,6 +945,9 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, debug_work_activate(work); + if (WARN_ON_ONCE(wq->flags & WQ_DYING)) + return; + /* determine gcwq to use */ if (!(wq->flags & WQ_UNBOUND)) { struct global_cwq *last_gcwq; @@ -2828,6 +2832,7 @@ void destroy_workqueue(struct workqueue_struct *wq) { unsigned int cpu; + wq->flags |= WQ_DYING; flush_workqueue(wq); /* -- cgit v1.2.3-59-g8ed1b From e045c29126eae3a8cfdf8507baa75b5c70fd4f53 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 6 Aug 2010 18:55:45 +0200 Subject: MCE, AMD: Limit MCE decoding to current families for now Limit MCE error decoding to current and older families only (K8-F11h). Signed-off-by: Borislav Petkov --- drivers/edac/edac_mce_amd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index bae9351e9473..352dcc6c8971 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -426,11 +426,15 @@ static struct notifier_block amd_mce_dec_nb = { static int __init mce_amd_init(void) { /* - * We can decode MCEs for Opteron and later CPUs: + * We can decode MCEs for K8, F10h and F11h CPUs: */ - if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && - (boot_cpu_data.x86 >= 0xf)) - atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb); + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return 0; + + if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11) + return 0; + + atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb); return 0; } -- cgit v1.2.3-59-g8ed1b From 577ba406e1cceac4776b095c83ee2896074a0327 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 24 Aug 2010 10:41:33 +0200 Subject: V4L/DVB: mantis: Fix IR_CORE dependency This build bug triggers: drivers/built-in.o: In function `mantis_exit': (.text+0x377413): undefined reference to `ir_input_unregister' drivers/built-in.o: In function `mantis_input_init': (.text+0x3774ff): undefined reference to `__ir_input_register' If MANTIS_CORE is enabled but IR_CORE is not. Add the correct dependency. Signed-off-by: Ingo Molnar Acked-by: Randy Dunlap Signed-off-by: Linus Torvalds --- drivers/media/dvb/mantis/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig index decdeda840d0..fd0830ed10d8 100644 --- a/drivers/media/dvb/mantis/Kconfig +++ b/drivers/media/dvb/mantis/Kconfig @@ -1,6 +1,6 @@ config MANTIS_CORE tristate "Mantis/Hopper PCI bridge based devices" - depends on PCI && I2C && INPUT + depends on PCI && I2C && INPUT && IR_CORE help Support for PCI cards based on the Mantis and Hopper PCi bridge. -- cgit v1.2.3-59-g8ed1b From a9728c9a31524ef927260096411ee85c8ee6b163 Mon Sep 17 00:00:00 2001 From: Ossama Othman Date: Tue, 24 Aug 2010 12:55:14 +0100 Subject: rar: Fix off by one error It looks like there is an off-by-one error in one of your changes to drivers/staging/rar_register/rar_register.c: Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/platform/x86/intel_rar_register.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c index 73f8e6d72669..2b11a33325e6 100644 --- a/drivers/platform/x86/intel_rar_register.c +++ b/drivers/platform/x86/intel_rar_register.c @@ -145,7 +145,7 @@ static void free_rar_device(struct rar_device *rar) */ static struct rar_device *_rar_to_device(int rar, int *off) { - if (rar >= 0 && rar <= 3) { + if (rar >= 0 && rar < MRST_NUM_RAR) { *off = rar; return &my_rar_device; } -- cgit v1.2.3-59-g8ed1b From 32e2f63bcc8903487975506d8db5931a8c4bbb1f Mon Sep 17 00:00:00 2001 From: Jianwei Yang Date: Tue, 24 Aug 2010 14:32:38 +0100 Subject: intel_scu_ipc: fix IPC i2c write bug We should pass the data to the data register. Signed-off-by: Jianwei Yang Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/platform/x86/intel_scu_ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 943f9084dcb1..6abe18e638e9 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -487,7 +487,7 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) mdelay(1); *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR); } else if (cmd == IPC_I2C_WRITE) { - writel(addr, ipcdev.i2c_base + I2C_DATA_ADDR); + writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR); mdelay(1); writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); } else { -- cgit v1.2.3-59-g8ed1b From 2d20ca835867d93ead6ce61780d883a4b128106d Mon Sep 17 00:00:00 2001 From: "shirishpargaonkar@gmail.com" Date: Tue, 24 Aug 2010 11:53:48 -0500 Subject: Eliminate sparse warning - bad constant expression Eliminiate sparse warning during usage of crypto_shash_* APIs error: bad constant expression Allocate memory for shash descriptors once, so that we do not kmalloc/kfree it for every signature generation (shash descriptor for md5 hash). From ed7538619817777decc44b5660b52268077b74f3 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Tue, 24 Aug 2010 11:47:43 -0500 Subject: [PATCH] eliminate sparse warnings during crypto_shash_* APis usage Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 193 +++++++++++++++++++++++++++++++------------------- fs/cifs/cifsglob.h | 7 ++ 2 files changed, 128 insertions(+), 72 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index eef78c24e0cc..709f2296bdb4 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -45,39 +45,38 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, char *signature) { - int rc = 0; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; - } sdesc; + int rc; if (cifs_pdu == NULL || server == NULL || signature == NULL) return -EINVAL; - sdesc.shash.tfm = server->ntlmssp.md5; - sdesc.shash.flags = 0x0; + if (!server->ntlmssp.sdescmd5) { + cERROR(1, + "cifs_calculate_signature: can't generate signature\n"); + return -1; + } - rc = crypto_shash_init(&sdesc.shash); + rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash); if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); + cERROR(1, "cifs_calculate_signature: oould not init md5\n"); return rc; } if (server->secType == RawNTLMSSP) - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdescmd5->shash, server->session_key.data.ntlmv2.key, CIFS_NTLMV2_SESSKEY_SIZE); else - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdescmd5->shash, (char *)&server->session_key.data, server->session_key.len); - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdescmd5->shash, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); - rc = crypto_shash_final(&sdesc.shash, signature); + rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature); - return 0; + return rc; } @@ -115,30 +114,28 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, struct TCP_Server_Info *server, char *signature) { int i; - int rc = 0; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; - } sdesc; + int rc; if (iov == NULL || server == NULL || signature == NULL) return -EINVAL; - sdesc.shash.tfm = server->ntlmssp.md5; - sdesc.shash.flags = 0x0; + if (!server->ntlmssp.sdescmd5) { + cERROR(1, "cifs_calc_signature2: can't generate signature\n"); + return -1; + } - rc = crypto_shash_init(&sdesc.shash); + rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash); if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); + cERROR(1, "cifs_calc_signature2: oould not init md5\n"); return rc; } if (server->secType == RawNTLMSSP) - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdescmd5->shash, server->session_key.data.ntlmv2.key, CIFS_NTLMV2_SESSKEY_SIZE); else - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdescmd5->shash, (char *)&server->session_key.data, server->session_key.len); @@ -146,7 +143,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, if (iov[i].iov_len == 0) continue; if (iov[i].iov_base == NULL) { - cERROR(1, "null iovec entry"); + cERROR(1, "cifs_calc_signature2: null iovec entry"); return -EIO; } /* The first entry includes a length field (which does not get @@ -154,16 +151,16 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, if (i == 0) { if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ break; /* nothing to sign or corrupt header */ - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdescmd5->shash, iov[i].iov_base + 4, iov[i].iov_len - 4); } else - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdescmd5->shash, iov[i].iov_base, iov[i].iov_len); } - rc = crypto_shash_final(&sdesc.shash, signature); + rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature); - return 0; + return rc; } int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, @@ -313,43 +310,48 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, wchar_t *user; wchar_t *domain; wchar_t *server; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; - } sdesc; + + if (!ses->server->ntlmssp.sdeschmacmd5) { + cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); + return -1; + } /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); - sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; - sdesc.shash.flags = 0x0; - crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, nt_hash, CIFS_NTHASH_SIZE); - rc = crypto_shash_init(&sdesc.shash); + rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash); if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); + cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); return rc; } /* convert ses->userName to unicode and uppercase */ len = strlen(ses->userName); user = kmalloc(2 + (len * 2), GFP_KERNEL); - if (user == NULL) + if (user == NULL) { + cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); + rc = -ENOMEM; goto calc_exit_2; + } len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); - crypto_shash_update(&sdesc.shash, (char *)user, 2 * len); + crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, + (char *)user, 2 * len); /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { len = strlen(ses->domainName); domain = kmalloc(2 + (len * 2), GFP_KERNEL); - if (domain == NULL) + if (domain == NULL) { + cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); + rc = -ENOMEM; goto calc_exit_1; + } len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, nls_cp); /* the following line was removed since it didn't work well @@ -357,15 +359,19 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, Maybe converting the domain name earlier makes sense */ /* UniStrupr(domain); */ - crypto_shash_update(&sdesc.shash, (char *)domain, 2 * len); + crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, + (char *)domain, 2 * len); kfree(domain); } else if (ses->serverName) { len = strlen(ses->serverName); server = kmalloc(2 + (len * 2), GFP_KERNEL); - if (server == NULL) + if (server == NULL) { + cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); + rc = -ENOMEM; goto calc_exit_1; + } len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, nls_cp); /* the following line was removed since it didn't work well @@ -373,16 +379,20 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, Maybe converting the domain name earlier makes sense */ /* UniStrupr(domain); */ - crypto_shash_update(&sdesc.shash, (char *)server, 2 * len); + crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, + (char *)server, 2 * len); kfree(server); } + + rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash, + ses->server->ntlmv2_hash); + calc_exit_1: kfree(user); calc_exit_2: /* BB FIXME what about bytes 24 through 40 of the signing key? compare with the NTLM example */ - rc = crypto_shash_final(&sdesc.shash, ses->server->ntlmv2_hash); return rc; } @@ -442,34 +452,33 @@ CalcNTLMv2_response(const struct TCP_Server_Info *server, char *v2_session_response) { int rc; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(server->ntlmssp.hmacmd5)]; - } sdesc; - sdesc.shash.tfm = server->ntlmssp.hmacmd5; - sdesc.shash.flags = 0x0; + if (!server->ntlmssp.sdeschmacmd5) { + cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); + return -1; + } crypto_shash_setkey(server->ntlmssp.hmacmd5, server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - rc = crypto_shash_init(&sdesc.shash); + rc = crypto_shash_init(&server->ntlmssp.sdeschmacmd5->shash); if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); + cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); return rc; } memcpy(v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, server->cryptKey, CIFS_SERVER_CHALLENGE_SIZE); - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash, v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, sizeof(struct ntlmv2_resp) - CIFS_SERVER_CHALLENGE_SIZE); if (server->tilen) - crypto_shash_update(&sdesc.shash, + crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash, server->tiblob, server->tilen); - rc = crypto_shash_final(&sdesc.shash, v2_session_response); + rc = crypto_shash_final(&server->ntlmssp.sdeschmacmd5->shash, + v2_session_response); return rc; } @@ -480,10 +489,6 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, { int rc = 0; struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; - } sdesc; buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; @@ -511,21 +516,24 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, return rc; } + if (!ses->server->ntlmssp.sdeschmacmd5) { + cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); + return -1; + } + crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, ses->server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; - sdesc.shash.flags = 0x0; - - rc = crypto_shash_init(&sdesc.shash); + rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash); if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); + cERROR(1, "setup_ntlmv2_rsp: could not init hmacmd5\n"); return rc; } - crypto_shash_update(&sdesc.shash, resp_buf, CIFS_HMAC_MD5_HASH_SIZE); + crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, + resp_buf, CIFS_HMAC_MD5_HASH_SIZE); - rc = crypto_shash_final(&sdesc.shash, + rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash, ses->server->session_key.data.ntlmv2.key); memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, @@ -578,24 +586,65 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server) if (server->ntlmssp.hmacmd5) crypto_free_shash(server->ntlmssp.hmacmd5); + + kfree(server->ntlmssp.sdeschmacmd5); + + kfree(server->ntlmssp.sdescmd5); } int cifs_crypto_shash_allocate(struct TCP_Server_Info *server) { + int rc; + unsigned int size; + server->ntlmssp.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); if (!server->ntlmssp.hmacmd5 || IS_ERR(server->ntlmssp.hmacmd5)) { - cERROR(1, "could not allocate master crypto API hmacmd5\n"); + cERROR(1, "could not allocate crypto hmacmd5\n"); return 1; } server->ntlmssp.md5 = crypto_alloc_shash("md5", 0, 0); if (!server->ntlmssp.md5 || IS_ERR(server->ntlmssp.md5)) { - crypto_free_shash(server->ntlmssp.hmacmd5); - cERROR(1, "could not allocate master crypto API md5\n"); - return 1; + cERROR(1, "could not allocate crypto md5\n"); + rc = 1; + goto cifs_crypto_shash_allocate_ret1; } + size = sizeof(struct shash_desc) + + crypto_shash_descsize(server->ntlmssp.hmacmd5); + server->ntlmssp.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); + if (!server->ntlmssp.sdeschmacmd5) { + cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); + rc = -ENOMEM; + goto cifs_crypto_shash_allocate_ret2; + } + server->ntlmssp.sdeschmacmd5->shash.tfm = server->ntlmssp.hmacmd5; + server->ntlmssp.sdeschmacmd5->shash.flags = 0x0; + + + size = sizeof(struct shash_desc) + + crypto_shash_descsize(server->ntlmssp.md5); + server->ntlmssp.sdescmd5 = kmalloc(size, GFP_KERNEL); + if (!server->ntlmssp.sdescmd5) { + cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); + rc = -ENOMEM; + goto cifs_crypto_shash_allocate_ret3; + } + server->ntlmssp.sdescmd5->shash.tfm = server->ntlmssp.md5; + server->ntlmssp.sdescmd5->shash.flags = 0x0; + return 0; + +cifs_crypto_shash_allocate_ret3: + kfree(server->ntlmssp.sdeschmacmd5); + +cifs_crypto_shash_allocate_ret2: + crypto_free_shash(server->ntlmssp.md5); + +cifs_crypto_shash_allocate_ret1: + crypto_free_shash(server->ntlmssp.hmacmd5); + + return rc; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 49563e0c1725..c9d0cfc086eb 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -123,12 +123,19 @@ struct cifs_cred { struct cifs_ace *aces; }; +struct sdesc { + struct shash_desc shash; + char ctx[]; +}; + struct ntlmssp_auth { __u32 client_flags; __u32 server_flags; unsigned char ciphertext[CIFS_CPHTXT_SIZE]; struct crypto_shash *hmacmd5; struct crypto_shash *md5; + struct sdesc *sdeschmacmd5; + struct sdesc *sdescmd5; }; /* -- cgit v1.2.3-59-g8ed1b From aaca49642b92c8a57d3ca5029a5a94019c7af69f Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 20 Aug 2010 18:57:53 -0700 Subject: xen: use percpu interrupts for IPIs and VIRQs IPIs and VIRQs are inherently per-cpu event types, so treat them as such: - use a specific percpu irq_chip implementation, and - handle them with handle_percpu_irq This makes the path for delivering these interrupts more efficient (no masking/unmasking, no locks), and it avoid problems with attempts to migrate them. Signed-off-by: Jeremy Fitzhardinge Cc: Stable Kernel --- drivers/xen/events.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 72f91bff29c7..0923ccb26121 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -112,6 +112,7 @@ static inline unsigned long *cpu_evtchn_mask(int cpu) #define VALID_EVTCHN(chn) ((chn) != 0) static struct irq_chip xen_dynamic_chip; +static struct irq_chip xen_percpu_chip; /* Constructor for packed IRQ information. */ static struct irq_info mk_unbound_info(void) @@ -403,8 +404,8 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) if (irq < 0) goto out; - set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, - handle_level_irq, "ipi"); + set_irq_chip_and_handler_name(irq, &xen_percpu_chip, + handle_percpu_irq, "ipi"); bind_ipi.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, @@ -444,8 +445,8 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) irq = find_unbound_irq(); - set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, - handle_level_irq, "virq"); + set_irq_chip_and_handler_name(irq, &xen_percpu_chip, + handle_percpu_irq, "virq"); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_virq_info(evtchn, virq); @@ -964,6 +965,16 @@ static struct irq_chip xen_dynamic_chip __read_mostly = { .retrigger = retrigger_dynirq, }; +static struct irq_chip xen_percpu_chip __read_mostly = { + .name = "xen-percpu", + + .disable = disable_dynirq, + .mask = disable_dynirq, + .unmask = enable_dynirq, + + .ack = ack_dynirq, +}; + int xen_set_callback_via(uint64_t via) { struct xen_hvm_param a; -- cgit v1.2.3-59-g8ed1b From dffe2e1e1a1ddb566a76266136c312801c66dcf7 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Fri, 20 Aug 2010 19:10:01 -0700 Subject: xen: handle events as edge-triggered Xen events are logically edge triggered, as Xen only calls the event upcall when an event is newly set, but not continuously as it remains set. As a result, use handle_edge_irq rather than handle_level_irq. This has the important side-effect of fixing a long-standing bug of events getting lost if: - an event's interrupt handler is running - the event is migrated to a different vcpu - the event is re-triggered The most noticable symptom of these lost events is occasional lockups of blkfront. Many thanks to Tom Kopec and Daniel Stodden in tracking this down. Signed-off-by: Jeremy Fitzhardinge Cc: Tom Kopec Cc: Daniel Stodden Cc: Stable Kernel --- drivers/xen/events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0923ccb26121..13365ba35218 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -378,7 +378,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) irq = find_unbound_irq(); set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, - handle_level_irq, "event"); + handle_edge_irq, "event"); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_evtchn_info(evtchn); -- cgit v1.2.3-59-g8ed1b From bac1e74dba9755128748b872a0f304dad4d198c6 Mon Sep 17 00:00:00 2001 From: David Alan Gilbert Date: Tue, 24 Aug 2010 20:22:18 +0200 Subject: PM QoS: Fix kzalloc() parameters swapped in pm_qos_power_open() sparse spotted that the kzalloc() in pm_qos_power_open() in the current Linus' git tree had its parameters swapped. Fix this. Signed-off-by: David Alan Gilbert Acked-by: mark gross Signed-off-by: Rafael J. Wysocki --- kernel/pm_qos_params.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c index 996a4dec5f96..9da439b419aa 100644 --- a/kernel/pm_qos_params.c +++ b/kernel/pm_qos_params.c @@ -348,7 +348,7 @@ static int pm_qos_power_open(struct inode *inode, struct file *filp) pm_qos_class = find_pm_qos_object_by_minor(iminor(inode)); if (pm_qos_class >= 0) { - struct pm_qos_request_list *req = kzalloc(GFP_KERNEL, sizeof(*req)); + struct pm_qos_request_list *req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 9559fcdbff4f93d29af04478bbc48294519424f5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 24 Aug 2010 11:31:16 -0700 Subject: drm/i915: fix vblank wait test condition When converting this to the new wait_for macro I inverted the wait condition, which causes all sorts of problems. So correct it to fix several failures caused by the bad wait (flickering, bad output detection, tearing, etc.). Reviewed-by: Chris Wilson Tested-by: Sitsofe Wheeler Signed-off-by: Jesse Barnes Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 23157e1de3be..11a3394f5fe1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -992,7 +992,7 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) /* Wait for vblank interrupt bit to set */ if (wait_for((I915_READ(pipestat_reg) & - PIPE_VBLANK_INTERRUPT_STATUS) == 0, + PIPE_VBLANK_INTERRUPT_STATUS), 50, 0)) DRM_DEBUG_KMS("vblank wait timed out\n"); } -- cgit v1.2.3-59-g8ed1b From 8ca3eb08097f6839b2206e2242db4179aee3cfb3 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Tue, 24 Aug 2010 11:44:18 -0700 Subject: guard page for stacks that grow upwards pa-risc and ia64 have stacks that grow upwards. Check that they do not run into other mappings. By making VM_GROWSUP 0x0 on architectures that do not ever use it, we can avoid some unpleasant #ifdefs in check_stack_guard_page(). Signed-off-by: Tony Luck Signed-off-by: Linus Torvalds --- include/linux/mm.h | 8 +++++++- mm/memory.c | 15 +++++++++++---- mm/mmap.c | 3 --- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 709f6728fc90..831c693416b2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -78,7 +78,11 @@ extern unsigned int kobjsize(const void *objp); #define VM_MAYSHARE 0x00000080 #define VM_GROWSDOWN 0x00000100 /* general info on the segment */ +#if defined(CONFIG_STACK_GROWSUP) || defined(CONFIG_IA64) #define VM_GROWSUP 0x00000200 +#else +#define VM_GROWSUP 0x00000000 +#endif #define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */ #define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */ @@ -1330,8 +1334,10 @@ unsigned long ra_submit(struct file_ra_state *ra, /* Do stack extension */ extern int expand_stack(struct vm_area_struct *vma, unsigned long address); -#ifdef CONFIG_IA64 +#if VM_GROWSUP extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); +#else + #define expand_upwards(vma, address) do { } while (0) #endif extern int expand_stack_downwards(struct vm_area_struct *vma, unsigned long address); diff --git a/mm/memory.c b/mm/memory.c index 2ed2267439df..6b2ab1051851 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2760,11 +2760,9 @@ out_release: } /* - * This is like a special single-page "expand_downwards()", - * except we must first make sure that 'address-PAGE_SIZE' + * This is like a special single-page "expand_{down|up}wards()", + * except we must first make sure that 'address{-|+}PAGE_SIZE' * doesn't hit another vma. - * - * The "find_vma()" will do the right thing even if we wrap */ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address) { @@ -2783,6 +2781,15 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo expand_stack(vma, address - PAGE_SIZE); } + if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { + struct vm_area_struct *next = vma->vm_next; + + /* As VM_GROWSDOWN but s/below/above/ */ + if (next && next->vm_start == address + PAGE_SIZE) + return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; + + expand_upwards(vma, address + PAGE_SIZE); + } return 0; } diff --git a/mm/mmap.c b/mm/mmap.c index 331e51af38c9..6128dc8e5ede 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1716,9 +1716,6 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns * PA-RISC uses this for its stack; IA64 for its Register Backing Store. * vma is the last one with address > vma->vm_end. Have to extend vma. */ -#ifndef CONFIG_IA64 -static -#endif int expand_upwards(struct vm_area_struct *vma, unsigned long address) { int error; -- cgit v1.2.3-59-g8ed1b From 9dc002d8d9c2af837e789b5bb88c61a8b32c1be8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 24 Aug 2010 12:21:13 -0700 Subject: caif-driver: add HAS_DMA dependency Fix this error on an s390 allyesconfig build: linux-2.6/drivers/net/caif/caif_spi.c:98: undefined reference to `dma_free_coherent' Cc: Sjur Braendeland Signed-off-by: Heiko Carstens Signed-off-by: David S. Miller --- drivers/net/caif/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index 631a6242b011..75bfc3a9d95f 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -15,7 +15,7 @@ config CAIF_TTY config CAIF_SPI_SLAVE tristate "CAIF SPI transport driver for slave interface" - depends on CAIF + depends on CAIF && HAS_DMA default n ---help--- The CAIF Link layer SPI Protocol driver for Slave SPI interface. -- cgit v1.2.3-59-g8ed1b From f1a7bfaf6bb9cb195577e674c0ab2fd0a55d9014 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 01:50:52 +0200 Subject: PCI: PCIe AER: Introduce pci_aer_available() Introduce a function allowing the caller to check whether to try to enable PCIe AER. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pci.h | 2 ++ drivers/pci/pcie/aer/aerdrv.c | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 679c39de6a89..7754a678ab15 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -140,8 +140,10 @@ static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } #ifdef CONFIG_PCIEAER void pci_no_aer(void); +bool pci_aer_available(void); #else static inline void pci_no_aer(void) { } +static inline bool pci_aer_available(void) { return false; } #endif static inline int pci_no_d1d2(struct pci_dev *dev) diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 484cc55194b8..f409948e1a9b 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -72,6 +72,11 @@ void pci_no_aer(void) pcie_aer_disable = 1; /* has priority over 'forceload' */ } +bool pci_aer_available(void) +{ + return !pcie_aer_disable && pci_msi_enabled(); +} + static int set_device_error_reporting(struct pci_dev *dev, void *data) { bool enable = *((bool *)data); @@ -411,9 +416,7 @@ static void aer_error_resume(struct pci_dev *dev) */ static int __init aer_service_init(void) { - if (pcie_aer_disable) - return -ENXIO; - if (!pci_msi_enabled()) + if (!pci_aer_available()) return -ENXIO; return pcie_port_service_register(&aerdriver); } -- cgit v1.2.3-59-g8ed1b From 79dd9182db2072d63ccf160bb9a3463b1c952723 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 01:51:44 +0200 Subject: PCI: PCIe: Introduce commad line switch for disabling port services Introduce kernel command line switch pcie_ports= allowing one to disable all of the native PCIe port services, so that PCIe ports are treated like PCI-to-PCI bridges. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- Documentation/kernel-parameters.txt | 4 ++++ drivers/pci/pcie/portdrv.h | 2 ++ drivers/pci/pcie/portdrv_core.c | 3 +++ drivers/pci/pcie/portdrv_pci.c | 15 +++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 873b68090098..b9008fc3a53d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2042,6 +2042,10 @@ and is between 256 and 4096 characters. It is defined in the file force Enable ASPM even on devices that claim not to support it. WARNING: Forcing ASPM on may cause system lockups. + pcie_ports= [PCIE] PCIe ports handling: + compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe + ports driver. + pcie_pme= [PCIE,PM] Native PCIe PME signaling options: Format: {auto|force}[,nomsi] auto Use native PCIe PME signaling if the BIOS allows the diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 813a5c3427b6..966f6e9761c8 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -20,6 +20,8 @@ #define get_descriptor_id(type, service) (((type - 4) << 4) | service) +extern bool pcie_ports_disabled; + extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_register(struct pci_dev *dev); #ifdef CONFIG_PM diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index e73effbe402c..2bf2fe510e15 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -494,6 +494,9 @@ static void pcie_port_shutdown_service(struct device *dev) {} */ int pcie_port_service_register(struct pcie_port_service_driver *new) { + if (pcie_ports_disabled) + return -ENODEV; + new->driver.name = (char *)new->name; new->driver.bus = &pcie_port_bus_type; new->driver.probe = pcie_port_probe_service; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 3debed25e46b..a04392da6ce1 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -29,6 +29,18 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +/* If this switch is set, PCIe port native services should not be enabled. */ +bool pcie_ports_disabled; + +static int __init pcie_port_setup(char *str) +{ + if (!strncmp(str, "compat", 6)) + pcie_ports_disabled = true; + + return 1; +} +__setup("pcie_ports=", pcie_port_setup); + /* global data */ static int pcie_portdrv_restore_config(struct pci_dev *dev) @@ -301,6 +313,9 @@ static int __init pcie_portdrv_init(void) { int retval; + if (pcie_ports_disabled) + return -EACCES; + dmi_check_system(pcie_portdrv_dmi_table); retval = pcie_port_bus_register(); -- cgit v1.2.3-59-g8ed1b From b879dc4b3e81069e3f715b7569bb0f43eed76c76 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 01:52:37 +0200 Subject: ACPI/PCI: Reorder checks in acpi_pci_osc_control_set() Make acpi_pci_osc_control_set() attempt to find the handle of the _OSC object under the given PCI root bridge object after verifying that its second argument is correct and that there is a struct acpi_pci_root object for the given root bridge handle, which is more logical than the old code. Signed-off-by: Rafael J. Wysocki Reviewed-by: Hidetoshi Seto Signed-off-by: Jesse Barnes --- drivers/acpi/pci_root.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1f67057af2a5..e10dbafa0569 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -378,10 +378,6 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) acpi_handle tmp; struct acpi_pci_root *root; - status = acpi_get_handle(handle, "_OSC", &tmp); - if (ACPI_FAILURE(status)) - return status; - control_req = (flags & OSC_PCI_CONTROL_MASKS); if (!control_req) return AE_TYPE; @@ -390,6 +386,10 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) if (!root) return AE_NOT_EXIST; + status = acpi_get_handle(handle, "_OSC", &tmp); + if (ACPI_FAILURE(status)) + return status; + mutex_lock(&osc_lock); /* No need to evaluate _OSC if the control was already granted. */ if ((root->osc_control_set & control_req) == control_req) -- cgit v1.2.3-59-g8ed1b From ab8e8957a2ae21c0f036476c6db13e949be730ac Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 01:53:27 +0200 Subject: ACPI/PCI: Make acpi_pci_query_osc() return control bits Make acpi_pci_query_osc() use an additional pointer argument to return the mask of control bits obtained from the BIOS to the caller. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/acpi/pci_root.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e10dbafa0569..d2ae816df0f5 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -226,22 +226,35 @@ static acpi_status acpi_pci_run_osc(acpi_handle handle, return status; } -static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags) +static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, + u32 support, + u32 *control) { acpi_status status; - u32 support_set, result, capbuf[3]; + u32 result, capbuf[3]; + + support &= OSC_PCI_SUPPORT_MASKS; + support |= root->osc_support_set; - /* do _OSC query for all possible controls */ - support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS); capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; - capbuf[OSC_SUPPORT_TYPE] = support_set; - capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; + capbuf[OSC_SUPPORT_TYPE] = support; + if (control) { + *control &= OSC_PCI_CONTROL_MASKS; + capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set; + } else { + /* Run _OSC query for all possible controls. */ + capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; + } status = acpi_pci_run_osc(root->device->handle, capbuf, &result); if (ACPI_SUCCESS(status)) { - root->osc_support_set = support_set; - root->osc_control_qry = result; - root->osc_queried = 1; + root->osc_support_set = support; + if (control) { + *control = result; + } else { + root->osc_control_qry = result; + root->osc_queried = 1; + } } return status; } @@ -255,7 +268,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) if (ACPI_FAILURE(status)) return status; mutex_lock(&osc_lock); - status = acpi_pci_query_osc(root, flags); + status = acpi_pci_query_osc(root, flags, NULL); mutex_unlock(&osc_lock); return status; } @@ -397,7 +410,7 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) /* Need to query controls first before requesting them */ if (!root->osc_queried) { - status = acpi_pci_query_osc(root, root->osc_support_set); + status = acpi_pci_query_osc(root, root->osc_support_set, NULL); if (ACPI_FAILURE(status)) goto out; } -- cgit v1.2.3-59-g8ed1b From 2b8fd9186d9275b07aef43e5bb4e98cd571f9a7d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 23 Aug 2010 23:55:59 +0200 Subject: ACPI/PCI: Do not preserve _OSC control bits returned by a query There is the assumption in acpi_pci_osc_control_set() that it is always sufficient to compare the mask of _OSC control bits to be requested with the result of an _OSC query where all of the known control bits have been checked. However, in general, that need not be the case. For example, if an _OSC feature A depends on an _OSC feature B and control of A, B plus another _OSC feature C is requested simultaneously, the BIOS may return A, B, C, while it would only return C if A and C were requested without B. That may result in passing a wrong mask of _OSC control bits to an _OSC control request, in which case the BIOS may only grant control of a subset of the requested features. Moreover, acpi_pci_run_osc() will return error code if that happens and the caller of acpi_pci_osc_control_set() will not know that it's been granted control of some _OSC features. Consequently, the system will generally not work as expected. Apart from this acpi_pci_osc_control_set() always uses the mask of _OSC control bits returned by the very first invocation of acpi_pci_query_osc(), but that is done with the second argument equal to OSC_PCI_SEGMENT_GROUPS_SUPPORT which generally happens to affect the returned _OSC control bits. For these reasons, make acpi_pci_osc_control_set() always check if control of the requested _OSC features will be granted before making the final control request. As a result, the osc_control_qry and osc_queried members of struct acpi_pci_root are not necessary any more, so drop them and remove the remaining code referring to them. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/acpi/pci_root.c | 20 +++++++------------- include/acpi/acpi_bus.h | 3 --- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d2ae816df0f5..77cd19697b1e 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -249,12 +249,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, status = acpi_pci_run_osc(root->device->handle, capbuf, &result); if (ACPI_SUCCESS(status)) { root->osc_support_set = support; - if (control) { + if (control) *control = result; - } else { - root->osc_control_qry = result; - root->osc_queried = 1; - } } return status; } @@ -409,14 +405,12 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) goto out; /* Need to query controls first before requesting them */ - if (!root->osc_queried) { - status = acpi_pci_query_osc(root, root->osc_support_set, NULL); - if (ACPI_FAILURE(status)) - goto out; - } - if ((root->osc_control_qry & control_req) != control_req) { - printk(KERN_DEBUG - "Firmware did not grant requested _OSC control\n"); + flags = control_req; + status = acpi_pci_query_osc(root, root->osc_support_set, &flags); + if (ACPI_FAILURE(status)) + goto out; + + if (flags != control_req) { status = AE_SUPPORT; goto out; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index baacd98e7cc6..4de84ce3a927 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -377,9 +377,6 @@ struct acpi_pci_root { u32 osc_support_set; /* _OSC state of support bits */ u32 osc_control_set; /* _OSC state of control bits */ - u32 osc_control_qry; /* the latest _OSC query result */ - - u32 osc_queried:1; /* has _OSC control been queried? */ }; /* helper */ -- cgit v1.2.3-59-g8ed1b From 75fb60f26befb59dbfa05cb122972642b7bdd219 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 23 Aug 2010 23:53:11 +0200 Subject: ACPI/PCI: Negotiate _OSC control bits before requesting them It is possible that the BIOS will not grant control of all _OSC features requested via acpi_pci_osc_control_set(), so it is recommended to negotiate the final set of _OSC features with the query flag set before calling _OSC to request control of these features. To implement it, rework acpi_pci_osc_control_set() so that the caller can specify the mask of _OSC control bits to negotiate and the mask of _OSC control bits that are absolutely necessary to it. Then, acpi_pci_osc_control_set() will run _OSC queries in a loop until the mask of _OSC control bits returned by the BIOS is equal to the mask passed to it. Also, before running the _OSC request acpi_pci_osc_control_set() will check if the caller's required control bits are present in the final mask. Using this mechanism we will be able to avoid situations in which the BIOS doesn't grant control of certain _OSC features, because they depend on some other _OSC features that have not been requested. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/acpi/pci_root.c | 59 +++++++++++++++++++++++------------- drivers/pci/hotplug/acpi_pcihp.c | 2 +- drivers/pci/pcie/aer/aerdrv_acpi.c | 6 ++-- drivers/pci/pcie/pme/pcie_pme_acpi.c | 8 +++-- include/linux/acpi.h | 4 +-- 5 files changed, 49 insertions(+), 30 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 77cd19697b1e..c34713112520 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -374,21 +374,32 @@ out: EXPORT_SYMBOL_GPL(acpi_get_pci_dev); /** - * acpi_pci_osc_control_set - commit requested control to Firmware - * @handle: acpi_handle for the target ACPI object - * @flags: driver's requested control bits + * acpi_pci_osc_control_set - Request control of PCI root _OSC features. + * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex). + * @mask: Mask of _OSC bits to request control of, place to store control mask. + * @req: Mask of _OSC bits the control of is essential to the caller. * - * Attempt to take control from Firmware on requested control bits. + * Run _OSC query for @mask and if that is successful, compare the returned + * mask of control bits with @req. If all of the @req bits are set in the + * returned mask, run _OSC request for it. + * + * The variable at the @mask address may be modified regardless of whether or + * not the function returns success. On success it will contain the mask of + * _OSC bits the BIOS has granted control of, but its contents are meaningless + * on failure. **/ -acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) +acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) { + struct acpi_pci_root *root; acpi_status status; - u32 control_req, result, capbuf[3]; + u32 ctrl, capbuf[3]; acpi_handle tmp; - struct acpi_pci_root *root; - control_req = (flags & OSC_PCI_CONTROL_MASKS); - if (!control_req) + if (!mask) + return AE_BAD_PARAMETER; + + ctrl = *mask & OSC_PCI_CONTROL_MASKS; + if ((ctrl & req) != req) return AE_TYPE; root = acpi_pci_find_root(handle); @@ -400,27 +411,33 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) return status; mutex_lock(&osc_lock); + + *mask = ctrl | root->osc_control_set; /* No need to evaluate _OSC if the control was already granted. */ - if ((root->osc_control_set & control_req) == control_req) + if ((root->osc_control_set & ctrl) == ctrl) goto out; - /* Need to query controls first before requesting them */ - flags = control_req; - status = acpi_pci_query_osc(root, root->osc_support_set, &flags); - if (ACPI_FAILURE(status)) - goto out; + /* Need to check the available controls bits before requesting them. */ + while (*mask) { + status = acpi_pci_query_osc(root, root->osc_support_set, mask); + if (ACPI_FAILURE(status)) + goto out; + if (ctrl == *mask) + break; + ctrl = *mask; + } - if (flags != control_req) { + if ((ctrl & req) != req) { status = AE_SUPPORT; goto out; } capbuf[OSC_QUERY_TYPE] = 0; capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set; - capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req; - status = acpi_pci_run_osc(handle, capbuf, &result); + capbuf[OSC_CONTROL_TYPE] = ctrl; + status = acpi_pci_run_osc(handle, capbuf, mask); if (ACPI_SUCCESS(status)) - root->osc_control_set = result; + root->osc_control_set = *mask; out: mutex_unlock(&osc_lock); return status; @@ -551,8 +568,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (flags != base_flags) acpi_pci_osc_support(root, flags); - status = acpi_pci_osc_control_set(root->device->handle, - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; + status = acpi_pci_osc_control_set(root->device->handle, &flags, flags); if (ACPI_FAILURE(status)) { printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n"); diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 45fcc1e96df9..3d93d529a7bd 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -360,7 +360,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); dbg("Trying to get hotplug control for %s\n", (char *)string.pointer); - status = acpi_pci_osc_control_set(handle, flags); + status = acpi_pci_osc_control_set(handle, &flags, flags); if (ACPI_SUCCESS(status)) goto got_one; if (status == AE_SUPPORT) diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index f278d7b0d95d..3a276a0cea93 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -39,9 +39,9 @@ int aer_osc_setup(struct pcie_device *pciedev) handle = acpi_find_root_bridge_handle(pdev); if (handle) { - status = acpi_pci_osc_control_set(handle, - OSC_PCI_EXPRESS_AER_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + u32 flags = OSC_PCI_EXPRESS_AER_CONTROL | + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; + status = acpi_pci_osc_control_set(handle, &flags, flags); } if (ACPI_FAILURE(status)) { diff --git a/drivers/pci/pcie/pme/pcie_pme_acpi.c b/drivers/pci/pcie/pme/pcie_pme_acpi.c index 83ab2287ae3f..be20222b12d3 100644 --- a/drivers/pci/pcie/pme/pcie_pme_acpi.c +++ b/drivers/pci/pcie/pme/pcie_pme_acpi.c @@ -28,6 +28,7 @@ int pcie_pme_acpi_setup(struct pcie_device *srv) acpi_status status = AE_NOT_FOUND; struct pci_dev *port = srv->port; acpi_handle handle; + u32 flags; int error = 0; if (acpi_pci_disabled) @@ -39,9 +40,10 @@ int pcie_pme_acpi_setup(struct pcie_device *srv) if (!handle) return -EINVAL; - status = acpi_pci_osc_control_set(handle, - OSC_PCI_EXPRESS_PME_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + flags = OSC_PCI_EXPRESS_PME_CONTROL | + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; + + status = acpi_pci_osc_control_set(handle, &flags, flags); if (ACPI_FAILURE(status)) { dev_info(&port->dev, "Failed to receive control of PCIe PME service: %s\n", diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ccf94dc5acdf..c227757feb06 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -304,8 +304,8 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); OSC_PCI_EXPRESS_PME_CONTROL | \ OSC_PCI_EXPRESS_AER_CONTROL | \ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL) - -extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags); +extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, + u32 *mask, u32 req); extern void acpi_early_init(void); #else /* !CONFIG_ACPI */ -- cgit v1.2.3-59-g8ed1b From 28eb5f274a305bf3a13b2c80c4804d4515d05c64 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 22:02:38 +0200 Subject: PCI: PCIe: Ask BIOS for control of all native services at once After commit 852972acff8f10f3a15679be2059bb94916cba5d (ACPI: Disable ASPM if the platform won't provide _OSC control for PCIe) control of the PCIe Capability Structure is unconditionally requested by acpi_pci_root_add(), which in principle may cause problems to happen in two ways. First, the BIOS may refuse to give control of the PCIe Capability Structure if it is not asked for any of the _OSC features depending on it at the same time. Second, the BIOS may assume that control of the _OSC features depending on the PCIe Capability Structure will be requested in the future and may behave incorrectly if that doesn't happen. For this reason, control of the PCIe Capability Structure should always be requested along with control of any other _OSC features that may depend on it (ie. PCIe native PME, PCIe native hot-plug, PCIe AER). Rework the PCIe port driver so that (1) it checks which native PCIe port services can be enabled, according to the BIOS, and (2) it requests control of all these services simultaneously. In particular, this causes pcie_portdrv_probe() to fail if the BIOS refuses to grant control of the PCIe Capability Structure, which means that no native PCIe port services can be enabled for the PCIe Root Complex the given port belongs to. If that happens, ASPM is disabled to avoid problems with mishandling it by the part of the PCIe hierarchy for which control of the PCIe Capability Structure has not been received. Make it possible to override this behavior using 'pcie_ports=native' (use the PCIe native services regardless of the BIOS response to the control request), or 'pcie_ports=compat' (do not use the PCIe native services at all). Accordingly, rework the existing PCIe port service drivers so that they don't request control of the services directly. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- Documentation/kernel-parameters.txt | 13 +++--- drivers/acpi/pci_root.c | 9 ----- drivers/pci/hotplug/acpi_pcihp.c | 4 +- drivers/pci/hotplug/pciehp.h | 12 ------ drivers/pci/hotplug/pciehp_acpi.c | 4 +- drivers/pci/hotplug/pciehp_core.c | 4 +- drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer/aerdrv_acpi.c | 36 ----------------- drivers/pci/pcie/aer/aerdrv_core.c | 14 +------ drivers/pci/pcie/pme/Makefile | 5 +-- drivers/pci/pcie/pme/pcie_pme.c | 64 +++--------------------------- drivers/pci/pcie/pme/pcie_pme.h | 28 ------------- drivers/pci/pcie/pme/pcie_pme_acpi.c | 56 -------------------------- drivers/pci/pcie/portdrv.h | 20 ++++++++++ drivers/pci/pcie/portdrv_acpi.c | 77 ++++++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv_core.c | 25 ++++++++++-- drivers/pci/pcie/portdrv_pci.c | 20 +++++++++- 17 files changed, 155 insertions(+), 237 deletions(-) delete mode 100644 drivers/pci/pcie/pme/pcie_pme.h delete mode 100644 drivers/pci/pcie/pme/pcie_pme_acpi.c create mode 100644 drivers/pci/pcie/portdrv_acpi.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index b9008fc3a53d..8f126e878dbe 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2043,18 +2043,17 @@ and is between 256 and 4096 characters. It is defined in the file WARNING: Forcing ASPM on may cause system lockups. pcie_ports= [PCIE] PCIe ports handling: + auto Ask the BIOS whether or not to use native PCIe services + associated with PCIe ports (PME, hot-plug, AER). Use + them only if that is allowed by the BIOS. + native Use native PCIe services associated with PCIe ports + unconditionally. compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe ports driver. pcie_pme= [PCIE,PM] Native PCIe PME signaling options: - Format: {auto|force}[,nomsi] - auto Use native PCIe PME signaling if the BIOS allows the - kernel to control PCIe config registers of root ports. - force Use native PCIe PME signaling even if the BIOS refuses - to allow the kernel to control the relevant PCIe config - registers. nomsi Do not use MSI for native PCIe PME signaling (this makes - all PCIe root ports use INTx for everything). + all PCIe root ports use INTx for all services). pcmv= [HW,PCMCIA] BadgePAD 4 diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c34713112520..3ba8d1f44a73 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -568,14 +567,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (flags != base_flags) acpi_pci_osc_support(root, flags); - flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; - status = acpi_pci_osc_control_set(root->device->handle, &flags, flags); - - if (ACPI_FAILURE(status)) { - printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n"); - pcie_no_aspm(); - } - pci_acpi_add_bus_pm_notifier(device, root->bus); if (device->wakeup.flags.run_wake) device_set_run_wake(root->bus->bridge, true); diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 3d93d529a7bd..3bc72d18b121 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) acpi_handle chandle, handle; struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; - flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | - OSC_SHPC_NATIVE_HP_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + flags &= OSC_SHPC_NATIVE_HP_CONTROL; if (!flags) { err("Invalid flags %u specified!\n", flags); return -EINVAL; diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4ed76b47b6dc..653de6ff8ac6 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(void) { pciehp_acpi_slot_detection_init(); } - -static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) -{ - int retval; - u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); - retval = acpi_get_hp_hw_control_from_firmware(dev, flags); - if (retval) - return retval; - return pciehp_acpi_slot_detection_check(dev); -} #else #define pciehp_firmware_init() do {} while (0) -#define pciehp_get_hp_hw_control_from_firmware(dev) 0 #endif /* CONFIG_ACPI */ #endif /* _PCIEHP_H */ diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 1f4000a5a108..2574700db461 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -85,9 +85,7 @@ static int __init dummy_probe(struct pcie_device *dev) acpi_handle handle; struct dummy_slot *slot, *tmp; struct pci_dev *pdev = dev->port; - /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ - if (pciehp_get_hp_hw_control_from_firmware(pdev)) - return -ENODEV; + pos = pci_pcie_cap(pdev); if (!pos) return -ENODEV; diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 3588ea61b0dd..aa5f3ff629ff 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644); MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); -MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); +MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing"); #define PCIE_MODULE_NAME "pciehp" @@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_device *dev) dev_info(&dev->device, "Bypassing BIOS check for pciehp use on %s\n", pci_name(dev->port)); - else if (pciehp_get_hp_hw_control_from_firmware(dev->port)) + else if (pciehp_acpi_slot_detection_check(dev->port)) goto err_out_none; ctrl = pcie_init(dev); diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index ea654545e7c4..4d2b18704c47 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_PCIEASPM) += aspm.o pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o +pcieportdrv-$(CONFIG_ACPI) += portdrv_acpi.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 3a276a0cea93..2bb9b8972211 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -19,42 +19,6 @@ #include #include "aerdrv.h" -/** - * aer_osc_setup - run ACPI _OSC method - * @pciedev: pcie_device which AER is being enabled on - * - * @return: Zero on success. Nonzero otherwise. - * - * Invoked when PCIe bus loads AER service driver. To avoid conflict with - * BIOS AER support requires BIOS to yield AER control to OS native driver. - **/ -int aer_osc_setup(struct pcie_device *pciedev) -{ - acpi_status status = AE_NOT_FOUND; - struct pci_dev *pdev = pciedev->port; - acpi_handle handle = NULL; - - if (acpi_pci_disabled) - return -1; - - handle = acpi_find_root_bridge_handle(pdev); - if (handle) { - u32 flags = OSC_PCI_EXPRESS_AER_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; - status = acpi_pci_osc_control_set(handle, &flags, flags); - } - - if (ACPI_FAILURE(status)) { - dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't " - "init device: %s\n", - (status == AE_SUPPORT || status == AE_NOT_FOUND) ? - "no _OSC support" : "_OSC failed"); - return -1; - } - - return 0; -} - #ifdef CONFIG_ACPI_APEI static inline int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index fc0b5a93e1de..29e268fadf14 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -772,22 +772,10 @@ void aer_isr(struct work_struct *work) */ int aer_init(struct pcie_device *dev) { - if (pcie_aer_get_firmware_first(dev->port)) { - dev_printk(KERN_DEBUG, &dev->device, - "PCIe errors handled by platform firmware.\n"); - goto out; - } - - if (aer_osc_setup(dev)) - goto out; - - return 0; -out: if (forceload) { dev_printk(KERN_DEBUG, &dev->device, "aerdrv forceload requested.\n"); pcie_aer_force_firmware_first(dev->port, 0); - return 0; } - return -ENXIO; + return 0; } diff --git a/drivers/pci/pcie/pme/Makefile b/drivers/pci/pcie/pme/Makefile index 8b9238053080..3c67bf4d26cf 100644 --- a/drivers/pci/pcie/pme/Makefile +++ b/drivers/pci/pcie/pme/Makefile @@ -2,7 +2,4 @@ # Makefile for PCI-Express Root Port PME signaling driver # -obj-$(CONFIG_PCIE_PME) += pmedriver.o - -pmedriver-objs := pcie_pme.o -pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o +obj-$(CONFIG_PCIE_PME) += pcie_pme.o diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c index bbdea18693d9..9d1361e1a776 100644 --- a/drivers/pci/pcie/pme/pcie_pme.c +++ b/drivers/pci/pcie/pme/pcie_pme.c @@ -24,36 +24,11 @@ #include #include "../../pci.h" -#include "pcie_pme.h" +#include "../portdrv.h" #define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ -/* - * If set, this switch will prevent the PCIe root port PME service driver from - * being registered. Consequently, the interrupt-based PCIe PME signaling will - * not be used by any PCIe root ports in that case. - */ -static bool pcie_pme_disabled = true; - -/* - * The PCI Express Base Specification 2.0, Section 6.1.8, states the following: - * "In order to maintain compatibility with non-PCI Express-aware system - * software, system power management logic must be configured by firmware to use - * the legacy mechanism of signaling PME by default. PCI Express-aware system - * software must notify the firmware prior to enabling native, interrupt-based - * PME signaling." However, if the platform doesn't provide us with a suitable - * notification mechanism or the notification fails, it is not clear whether or - * not we are supposed to use the interrupt-based PCIe PME signaling. The - * switch below can be used to indicate the desired behaviour. When set, it - * will make the kernel use the interrupt-based PCIe PME signaling regardless of - * the platform notification status, although the kernel will attempt to notify - * the platform anyway. When unset, it will prevent the kernel from using the - * the interrupt-based PCIe PME signaling if the platform notification fails, - * which is the default. - */ -static bool pcie_pme_force_enable; - /* * If this switch is set, MSI will not be used for PCIe PME signaling. This * causes the PCIe port driver to use INTx interrupts only, but it turns out @@ -64,38 +39,13 @@ bool pcie_pme_msi_disabled; static int __init pcie_pme_setup(char *str) { - if (!strncmp(str, "auto", 4)) - pcie_pme_disabled = false; - else if (!strncmp(str, "force", 5)) - pcie_pme_force_enable = true; - - str = strchr(str, ','); - if (str) { - str++; - str += strspn(str, " \t"); - if (*str && !strcmp(str, "nomsi")) - pcie_pme_msi_disabled = true; - } + if (!strncmp(str, "nomsi", 5)) + pcie_pme_msi_disabled = true; return 1; } __setup("pcie_pme=", pcie_pme_setup); -/** - * pcie_pme_platform_setup - Ensure that the kernel controls the PCIe PME. - * @srv: PCIe PME root port service to use for carrying out the check. - * - * Notify the platform that the native PCIe PME is going to be used and return - * 'true' if the control of the PCIe PME registers has been acquired from the - * platform. - */ -static bool pcie_pme_platform_setup(struct pcie_device *srv) -{ - if (!pcie_pme_platform_notify(srv)) - return true; - return pcie_pme_force_enable; -} - struct pcie_pme_service_data { spinlock_t lock; struct pcie_device *srv; @@ -108,7 +58,7 @@ struct pcie_pme_service_data { * @dev: PCIe root port or event collector. * @enable: Enable or disable the interrupt. */ -static void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) +void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) { int rtctl_pos; u16 rtctl; @@ -417,9 +367,6 @@ static int pcie_pme_probe(struct pcie_device *srv) struct pcie_pme_service_data *data; int ret; - if (!pcie_pme_platform_setup(srv)) - return -EACCES; - data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -509,8 +456,7 @@ static struct pcie_port_service_driver pcie_pme_driver = { */ static int __init pcie_pme_service_init(void) { - return pcie_pme_disabled ? - -ENODEV : pcie_port_service_register(&pcie_pme_driver); + return pcie_port_service_register(&pcie_pme_driver); } module_init(pcie_pme_service_init); diff --git a/drivers/pci/pcie/pme/pcie_pme.h b/drivers/pci/pcie/pme/pcie_pme.h deleted file mode 100644 index b30d2b7c9775..000000000000 --- a/drivers/pci/pcie/pme/pcie_pme.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * drivers/pci/pcie/pme/pcie_pme.h - * - * PCI Express Root Port PME signaling support - * - * Copyright (C) 2009 Rafael J. Wysocki , Novell Inc. - */ - -#ifndef _PCIE_PME_H_ -#define _PCIE_PME_H_ - -struct pcie_device; - -#ifdef CONFIG_ACPI -extern int pcie_pme_acpi_setup(struct pcie_device *srv); - -static inline int pcie_pme_platform_notify(struct pcie_device *srv) -{ - return pcie_pme_acpi_setup(srv); -} -#else /* !CONFIG_ACPI */ -static inline int pcie_pme_platform_notify(struct pcie_device *srv) -{ - return 0; -} -#endif /* !CONFIG_ACPI */ - -#endif diff --git a/drivers/pci/pcie/pme/pcie_pme_acpi.c b/drivers/pci/pcie/pme/pcie_pme_acpi.c deleted file mode 100644 index be20222b12d3..000000000000 --- a/drivers/pci/pcie/pme/pcie_pme_acpi.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * PCIe Native PME support, ACPI-related part - * - * Copyright (C) 2009 Rafael J. Wysocki , Novell Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License V2. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include - -/** - * pcie_pme_acpi_setup - Request the ACPI BIOS to release control over PCIe PME. - * @srv - PCIe PME service for a root port or event collector. - * - * Invoked when the PCIe bus type loads PCIe PME service driver. To avoid - * conflict with the BIOS PCIe support requires the BIOS to yield PCIe PME - * control to the kernel. - */ -int pcie_pme_acpi_setup(struct pcie_device *srv) -{ - acpi_status status = AE_NOT_FOUND; - struct pci_dev *port = srv->port; - acpi_handle handle; - u32 flags; - int error = 0; - - if (acpi_pci_disabled) - return -ENOSYS; - - dev_info(&port->dev, "Requesting control of PCIe PME from ACPI BIOS\n"); - - handle = acpi_find_root_bridge_handle(port); - if (!handle) - return -EINVAL; - - flags = OSC_PCI_EXPRESS_PME_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; - - status = acpi_pci_osc_control_set(handle, &flags, flags); - if (ACPI_FAILURE(status)) { - dev_info(&port->dev, - "Failed to receive control of PCIe PME service: %s\n", - (status == AE_SUPPORT || status == AE_NOT_FOUND) ? - "no _OSC support" : "ACPI _OSC failed"); - error = -ENODEV; - } - - return error; -} diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 966f6e9761c8..7b5aba0a3291 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -21,6 +21,7 @@ #define get_descriptor_id(type, service) (((type - 4) << 4) | service) extern bool pcie_ports_disabled; +extern bool pcie_ports_auto; extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_register(struct pci_dev *dev); @@ -32,6 +33,8 @@ extern void pcie_port_device_remove(struct pci_dev *dev); extern int __must_check pcie_port_bus_register(void); extern void pcie_port_bus_unregister(void); +struct pci_dev; + #ifdef CONFIG_PCIE_PME extern bool pcie_pme_msi_disabled; @@ -44,9 +47,26 @@ static inline bool pcie_pme_no_msi(void) { return pcie_pme_msi_disabled; } + +extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable); #else /* !CONFIG_PCIE_PME */ static inline void pcie_pme_disable_msi(void) {} static inline bool pcie_pme_no_msi(void) { return false; } +static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {} #endif /* !CONFIG_PCIE_PME */ +#ifdef CONFIG_ACPI +extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask); + +static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask) +{ + return pcie_port_acpi_setup(port, mask); +} +#else /* !CONFIG_ACPI */ +static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask) +{ + return 0; +} +#endif /* !CONFIG_ACPI */ + #endif /* _PORTDRV_H_ */ diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c new file mode 100644 index 000000000000..b7c4cb1ccb23 --- /dev/null +++ b/drivers/pci/pcie/portdrv_acpi.c @@ -0,0 +1,77 @@ +/* + * PCIe Port Native Services Support, ACPI-Related Part + * + * Copyright (C) 2010 Rafael J. Wysocki , Novell Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License V2. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "aer/aerdrv.h" +#include "../pci.h" + +/** + * pcie_port_acpi_setup - Request the BIOS to release control of PCIe services. + * @port: PCIe Port service for a root port or event collector. + * @srv_mask: Bit mask of services that can be enabled for @port. + * + * Invoked when @port is identified as a PCIe port device. To avoid conflicts + * with the BIOS PCIe port native services support requires the BIOS to yield + * control of these services to the kernel. The mask of services that the BIOS + * allows to be enabled for @port is written to @srv_mask. + * + * NOTE: It turns out that we cannot do that for individual port services + * separately, because that would make some systems work incorrectly. + */ +int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) +{ + acpi_status status; + acpi_handle handle; + u32 flags; + + if (acpi_pci_disabled) + return 0; + + handle = acpi_find_root_bridge_handle(port); + if (!handle) + return -EINVAL; + + flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL + | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL + | OSC_PCI_EXPRESS_PME_CONTROL; + + if (pci_aer_available()) { + if (pcie_aer_get_firmware_first(port)) + dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n"); + else + flags |= OSC_PCI_EXPRESS_AER_CONTROL; + } + + status = acpi_pci_osc_control_set(handle, &flags, + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + if (ACPI_FAILURE(status)) { + dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n", + status); + return -ENODEV; + } + + dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags); + + *srv_mask = PCIE_PORT_SERVICE_VC; + if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) + *srv_mask |= PCIE_PORT_SERVICE_HP; + if (flags & OSC_PCI_EXPRESS_PME_CONTROL) + *srv_mask |= PCIE_PORT_SERVICE_PME; + if (flags & OSC_PCI_EXPRESS_AER_CONTROL) + *srv_mask |= PCIE_PORT_SERVICE_AER; + + return 0; +} diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 2bf2fe510e15..d0245c83b621 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "../pci.h" #include "portdrv.h" @@ -236,23 +238,40 @@ static int get_port_device_capability(struct pci_dev *dev) int services = 0, pos; u16 reg16; u32 reg32; + int cap_mask; + int err; + + err = pcie_port_platform_notify(dev, &cap_mask); + if (pcie_ports_auto) { + if (err) { + pcie_no_aspm(); + return 0; + } + } else { + cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP + | PCIE_PORT_SERVICE_VC; + if (pci_aer_available()) + cap_mask |= PCIE_PORT_SERVICE_AER; + } pos = pci_pcie_cap(dev); pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); /* Hot-Plug Capable */ - if (reg16 & PCI_EXP_FLAGS_SLOT) { + if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) { pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, ®32); if (reg32 & PCI_EXP_SLTCAP_HPC) services |= PCIE_PORT_SERVICE_HP; } /* AER capable */ - if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) + if ((cap_mask & PCIE_PORT_SERVICE_AER) + && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) services |= PCIE_PORT_SERVICE_AER; /* VC support */ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) services |= PCIE_PORT_SERVICE_VC; /* Root ports are capable of generating PME too */ - if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + if ((cap_mask & PCIE_PORT_SERVICE_PME) + && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) services |= PCIE_PORT_SERVICE_PME; return services; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index a04392da6ce1..8f1338d1c53f 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "portdrv.h" #include "aer/aerdrv.h" @@ -32,10 +33,23 @@ MODULE_LICENSE("GPL"); /* If this switch is set, PCIe port native services should not be enabled. */ bool pcie_ports_disabled; +/* + * If this switch is set, ACPI _OSC will be used to determine whether or not to + * enable PCIe port native services. + */ +bool pcie_ports_auto = true; + static int __init pcie_port_setup(char *str) { - if (!strncmp(str, "compat", 6)) + if (!strncmp(str, "compat", 6)) { pcie_ports_disabled = true; + } else if (!strncmp(str, "native", 6)) { + pcie_ports_disabled = false; + pcie_ports_auto = false; + } else if (!strncmp(str, "auto", 4)) { + pcie_ports_disabled = false; + pcie_ports_auto = true; + } return 1; } @@ -313,8 +327,10 @@ static int __init pcie_portdrv_init(void) { int retval; - if (pcie_ports_disabled) + if (pcie_ports_disabled) { + pcie_no_aspm(); return -EACCES; + } dmi_check_system(pcie_portdrv_dmi_table); -- cgit v1.2.3-59-g8ed1b From 2bd50dd800b52245294cfceb56be62020cdc7515 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 01:57:39 +0200 Subject: PCI: PCIe: Disable PCIe port services during port initialization In principle PCIe port services may be enabled by the BIOS, so it's better to disable them during port initialization to avoid spurious events from being generated. Signed-off-by: Rafael J. Wysocki Reviewed-by: Hidetoshi Seto Signed-off-by: Jesse Barnes --- drivers/pci/pcie/portdrv_core.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index d0245c83b621..a9c222d79ebc 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -259,20 +259,43 @@ static int get_port_device_capability(struct pci_dev *dev) /* Hot-Plug Capable */ if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) { pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, ®32); - if (reg32 & PCI_EXP_SLTCAP_HPC) + if (reg32 & PCI_EXP_SLTCAP_HPC) { services |= PCIE_PORT_SERVICE_HP; + /* + * Disable hot-plug interrupts in case they have been + * enabled by the BIOS and the hot-plug service driver + * is not loaded. + */ + pos += PCI_EXP_SLTCTL; + pci_read_config_word(dev, pos, ®16); + reg16 &= ~(PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE); + pci_write_config_word(dev, pos, reg16); + } } /* AER capable */ if ((cap_mask & PCIE_PORT_SERVICE_AER) - && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) + && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) { services |= PCIE_PORT_SERVICE_AER; + /* + * Disable AER on this port in case it's been enabled by the + * BIOS (the AER service driver will enable it when necessary). + */ + pci_disable_pcie_error_reporting(dev); + } /* VC support */ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) services |= PCIE_PORT_SERVICE_VC; /* Root ports are capable of generating PME too */ if ((cap_mask & PCIE_PORT_SERVICE_PME) - && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) { services |= PCIE_PORT_SERVICE_PME; + /* + * Disable PME interrupt on this port in case it's been enabled + * by the BIOS (the PME service driver will enable it when + * necessary). + */ + pcie_pme_interrupt_enable(dev, false); + } return services; } -- cgit v1.2.3-59-g8ed1b From 271fb719cc472af3b1e96d8c527bb0da7060a172 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 01:58:22 +0200 Subject: PCI: PCIe: Move PCIe PME code to the pcie directory The PCIe PME code only consists of one file, so it doesn't need to occupy its own directory. Move it to drivers/pci/pcie/pme.c and remove the contents of drivers/pci/pcie/pme . Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/pcie/Makefile | 2 +- drivers/pci/pcie/pme.c | 462 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/pcie/pme/Makefile | 5 - drivers/pci/pcie/pme/pcie_pme.c | 462 ---------------------------------------- 4 files changed, 463 insertions(+), 468 deletions(-) create mode 100644 drivers/pci/pcie/pme.c delete mode 100644 drivers/pci/pcie/pme/Makefile delete mode 100644 drivers/pci/pcie/pme/pcie_pme.c diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index 4d2b18704c47..00c62df5a9fc 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -13,4 +13,4 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o # Build PCI Express AER if needed obj-$(CONFIG_PCIEAER) += aer/ -obj-$(CONFIG_PCIE_PME) += pme/ +obj-$(CONFIG_PCIE_PME) += pme.o diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c new file mode 100644 index 000000000000..2f3c90407227 --- /dev/null +++ b/drivers/pci/pcie/pme.c @@ -0,0 +1,462 @@ +/* + * PCIe Native PME support + * + * Copyright (C) 2007 - 2009 Intel Corp + * Copyright (C) 2007 - 2009 Shaohua Li + * Copyright (C) 2009 Rafael J. Wysocki , Novell Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License V2. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" +#include "portdrv.h" + +#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ +#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ + +/* + * If this switch is set, MSI will not be used for PCIe PME signaling. This + * causes the PCIe port driver to use INTx interrupts only, but it turns out + * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based + * wake-up from system sleep states. + */ +bool pcie_pme_msi_disabled; + +static int __init pcie_pme_setup(char *str) +{ + if (!strncmp(str, "nomsi", 5)) + pcie_pme_msi_disabled = true; + + return 1; +} +__setup("pcie_pme=", pcie_pme_setup); + +struct pcie_pme_service_data { + spinlock_t lock; + struct pcie_device *srv; + struct work_struct work; + bool noirq; /* Don't enable the PME interrupt used by this service. */ +}; + +/** + * pcie_pme_interrupt_enable - Enable/disable PCIe PME interrupt generation. + * @dev: PCIe root port or event collector. + * @enable: Enable or disable the interrupt. + */ +void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) +{ + int rtctl_pos; + u16 rtctl; + + rtctl_pos = pci_pcie_cap(dev) + PCI_EXP_RTCTL; + + pci_read_config_word(dev, rtctl_pos, &rtctl); + if (enable) + rtctl |= PCI_EXP_RTCTL_PMEIE; + else + rtctl &= ~PCI_EXP_RTCTL_PMEIE; + pci_write_config_word(dev, rtctl_pos, rtctl); +} + +/** + * pcie_pme_clear_status - Clear root port PME interrupt status. + * @dev: PCIe root port or event collector. + */ +static void pcie_pme_clear_status(struct pci_dev *dev) +{ + int rtsta_pos; + u32 rtsta; + + rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; + + pci_read_config_dword(dev, rtsta_pos, &rtsta); + rtsta |= PCI_EXP_RTSTA_PME; + pci_write_config_dword(dev, rtsta_pos, rtsta); +} + +/** + * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. + * @bus: PCI bus to scan. + * + * Scan given PCI bus and all buses under it for devices asserting PME#. + */ +static bool pcie_pme_walk_bus(struct pci_bus *bus) +{ + struct pci_dev *dev; + bool ret = false; + + list_for_each_entry(dev, &bus->devices, bus_list) { + /* Skip PCIe devices in case we started from a root port. */ + if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { + pm_request_resume(&dev->dev); + pci_wakeup_event(dev); + ret = true; + } + + if (dev->subordinate && pcie_pme_walk_bus(dev->subordinate)) + ret = true; + } + + return ret; +} + +/** + * pcie_pme_from_pci_bridge - Check if PCIe-PCI bridge generated a PME. + * @bus: Secondary bus of the bridge. + * @devfn: Device/function number to check. + * + * PME from PCI devices under a PCIe-PCI bridge may be converted to an in-band + * PCIe PME message. In such that case the bridge should use the Requester ID + * of device/function number 0 on its secondary bus. + */ +static bool pcie_pme_from_pci_bridge(struct pci_bus *bus, u8 devfn) +{ + struct pci_dev *dev; + bool found = false; + + if (devfn) + return false; + + dev = pci_dev_get(bus->self); + if (!dev) + return false; + + if (pci_is_pcie(dev) && dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { + down_read(&pci_bus_sem); + if (pcie_pme_walk_bus(bus)) + found = true; + up_read(&pci_bus_sem); + } + + pci_dev_put(dev); + return found; +} + +/** + * pcie_pme_handle_request - Find device that generated PME and handle it. + * @port: Root port or event collector that generated the PME interrupt. + * @req_id: PCIe Requester ID of the device that generated the PME. + */ +static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) +{ + u8 busnr = req_id >> 8, devfn = req_id & 0xff; + struct pci_bus *bus; + struct pci_dev *dev; + bool found = false; + + /* First, check if the PME is from the root port itself. */ + if (port->devfn == devfn && port->bus->number == busnr) { + if (pci_check_pme_status(port)) { + pm_request_resume(&port->dev); + found = true; + } else { + /* + * Apparently, the root port generated the PME on behalf + * of a non-PCIe device downstream. If this is done by + * a root port, the Requester ID field in its status + * register may contain either the root port's, or the + * source device's information (PCI Express Base + * Specification, Rev. 2.0, Section 6.1.9). + */ + down_read(&pci_bus_sem); + found = pcie_pme_walk_bus(port->subordinate); + up_read(&pci_bus_sem); + } + goto out; + } + + /* Second, find the bus the source device is on. */ + bus = pci_find_bus(pci_domain_nr(port->bus), busnr); + if (!bus) + goto out; + + /* Next, check if the PME is from a PCIe-PCI bridge. */ + found = pcie_pme_from_pci_bridge(bus, devfn); + if (found) + goto out; + + /* Finally, try to find the PME source on the bus. */ + down_read(&pci_bus_sem); + list_for_each_entry(dev, &bus->devices, bus_list) { + pci_dev_get(dev); + if (dev->devfn == devfn) { + found = true; + break; + } + pci_dev_put(dev); + } + up_read(&pci_bus_sem); + + if (found) { + /* The device is there, but we have to check its PME status. */ + found = pci_check_pme_status(dev); + if (found) { + pm_request_resume(&dev->dev); + pci_wakeup_event(dev); + } + pci_dev_put(dev); + } else if (devfn) { + /* + * The device is not there, but we can still try to recover by + * assuming that the PME was reported by a PCIe-PCI bridge that + * used devfn different from zero. + */ + dev_dbg(&port->dev, "PME interrupt generated for " + "non-existent device %02x:%02x.%d\n", + busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); + found = pcie_pme_from_pci_bridge(bus, 0); + } + + out: + if (!found) + dev_dbg(&port->dev, "Spurious native PME interrupt!\n"); +} + +/** + * pcie_pme_work_fn - Work handler for PCIe PME interrupt. + * @work: Work structure giving access to service data. + */ +static void pcie_pme_work_fn(struct work_struct *work) +{ + struct pcie_pme_service_data *data = + container_of(work, struct pcie_pme_service_data, work); + struct pci_dev *port = data->srv->port; + int rtsta_pos; + u32 rtsta; + + rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; + + spin_lock_irq(&data->lock); + + for (;;) { + if (data->noirq) + break; + + pci_read_config_dword(port, rtsta_pos, &rtsta); + if (rtsta & PCI_EXP_RTSTA_PME) { + /* + * Clear PME status of the port. If there are other + * pending PMEs, the status will be set again. + */ + pcie_pme_clear_status(port); + + spin_unlock_irq(&data->lock); + pcie_pme_handle_request(port, rtsta & 0xffff); + spin_lock_irq(&data->lock); + + continue; + } + + /* No need to loop if there are no more PMEs pending. */ + if (!(rtsta & PCI_EXP_RTSTA_PENDING)) + break; + + spin_unlock_irq(&data->lock); + cpu_relax(); + spin_lock_irq(&data->lock); + } + + if (!data->noirq) + pcie_pme_interrupt_enable(port, true); + + spin_unlock_irq(&data->lock); +} + +/** + * pcie_pme_irq - Interrupt handler for PCIe root port PME interrupt. + * @irq: Interrupt vector. + * @context: Interrupt context pointer. + */ +static irqreturn_t pcie_pme_irq(int irq, void *context) +{ + struct pci_dev *port; + struct pcie_pme_service_data *data; + int rtsta_pos; + u32 rtsta; + unsigned long flags; + + port = ((struct pcie_device *)context)->port; + data = get_service_data((struct pcie_device *)context); + + rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; + + spin_lock_irqsave(&data->lock, flags); + pci_read_config_dword(port, rtsta_pos, &rtsta); + + if (!(rtsta & PCI_EXP_RTSTA_PME)) { + spin_unlock_irqrestore(&data->lock, flags); + return IRQ_NONE; + } + + pcie_pme_interrupt_enable(port, false); + spin_unlock_irqrestore(&data->lock, flags); + + /* We don't use pm_wq, because it's freezable. */ + schedule_work(&data->work); + + return IRQ_HANDLED; +} + +/** + * pcie_pme_set_native - Set the PME interrupt flag for given device. + * @dev: PCI device to handle. + * @ign: Ignored. + */ +static int pcie_pme_set_native(struct pci_dev *dev, void *ign) +{ + dev_info(&dev->dev, "Signaling PME through PCIe PME interrupt\n"); + + device_set_run_wake(&dev->dev, true); + dev->pme_interrupt = true; + return 0; +} + +/** + * pcie_pme_mark_devices - Set the PME interrupt flag for devices below a port. + * @port: PCIe root port or event collector to handle. + * + * For each device below given root port, including the port itself (or for each + * root complex integrated endpoint if @port is a root complex event collector) + * set the flag indicating that it can signal run-time wake-up events via PCIe + * PME interrupts. + */ +static void pcie_pme_mark_devices(struct pci_dev *port) +{ + pcie_pme_set_native(port, NULL); + if (port->subordinate) { + pci_walk_bus(port->subordinate, pcie_pme_set_native, NULL); + } else { + struct pci_bus *bus = port->bus; + struct pci_dev *dev; + + /* Check if this is a root port event collector. */ + if (port->pcie_type != PCI_EXP_TYPE_RC_EC || !bus) + return; + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &bus->devices, bus_list) + if (pci_is_pcie(dev) + && dev->pcie_type == PCI_EXP_TYPE_RC_END) + pcie_pme_set_native(dev, NULL); + up_read(&pci_bus_sem); + } +} + +/** + * pcie_pme_probe - Initialize PCIe PME service for given root port. + * @srv: PCIe service to initialize. + */ +static int pcie_pme_probe(struct pcie_device *srv) +{ + struct pci_dev *port; + struct pcie_pme_service_data *data; + int ret; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&data->lock); + INIT_WORK(&data->work, pcie_pme_work_fn); + data->srv = srv; + set_service_data(srv, data); + + port = srv->port; + pcie_pme_interrupt_enable(port, false); + pcie_pme_clear_status(port); + + ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); + if (ret) { + kfree(data); + } else { + pcie_pme_mark_devices(port); + pcie_pme_interrupt_enable(port, true); + } + + return ret; +} + +/** + * pcie_pme_suspend - Suspend PCIe PME service device. + * @srv: PCIe service device to suspend. + */ +static int pcie_pme_suspend(struct pcie_device *srv) +{ + struct pcie_pme_service_data *data = get_service_data(srv); + struct pci_dev *port = srv->port; + + spin_lock_irq(&data->lock); + pcie_pme_interrupt_enable(port, false); + pcie_pme_clear_status(port); + data->noirq = true; + spin_unlock_irq(&data->lock); + + synchronize_irq(srv->irq); + + return 0; +} + +/** + * pcie_pme_resume - Resume PCIe PME service device. + * @srv - PCIe service device to resume. + */ +static int pcie_pme_resume(struct pcie_device *srv) +{ + struct pcie_pme_service_data *data = get_service_data(srv); + struct pci_dev *port = srv->port; + + spin_lock_irq(&data->lock); + data->noirq = false; + pcie_pme_clear_status(port); + pcie_pme_interrupt_enable(port, true); + spin_unlock_irq(&data->lock); + + return 0; +} + +/** + * pcie_pme_remove - Prepare PCIe PME service device for removal. + * @srv - PCIe service device to resume. + */ +static void pcie_pme_remove(struct pcie_device *srv) +{ + pcie_pme_suspend(srv); + free_irq(srv->irq, srv); + kfree(get_service_data(srv)); +} + +static struct pcie_port_service_driver pcie_pme_driver = { + .name = "pcie_pme", + .port_type = PCI_EXP_TYPE_ROOT_PORT, + .service = PCIE_PORT_SERVICE_PME, + + .probe = pcie_pme_probe, + .suspend = pcie_pme_suspend, + .resume = pcie_pme_resume, + .remove = pcie_pme_remove, +}; + +/** + * pcie_pme_service_init - Register the PCIe PME service driver. + */ +static int __init pcie_pme_service_init(void) +{ + return pcie_port_service_register(&pcie_pme_driver); +} + +module_init(pcie_pme_service_init); diff --git a/drivers/pci/pcie/pme/Makefile b/drivers/pci/pcie/pme/Makefile deleted file mode 100644 index 3c67bf4d26cf..000000000000 --- a/drivers/pci/pcie/pme/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for PCI-Express Root Port PME signaling driver -# - -obj-$(CONFIG_PCIE_PME) += pcie_pme.o diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c deleted file mode 100644 index 9d1361e1a776..000000000000 --- a/drivers/pci/pcie/pme/pcie_pme.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * PCIe Native PME support - * - * Copyright (C) 2007 - 2009 Intel Corp - * Copyright (C) 2007 - 2009 Shaohua Li - * Copyright (C) 2009 Rafael J. Wysocki , Novell Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License V2. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../pci.h" -#include "../portdrv.h" - -#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ -#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ - -/* - * If this switch is set, MSI will not be used for PCIe PME signaling. This - * causes the PCIe port driver to use INTx interrupts only, but it turns out - * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based - * wake-up from system sleep states. - */ -bool pcie_pme_msi_disabled; - -static int __init pcie_pme_setup(char *str) -{ - if (!strncmp(str, "nomsi", 5)) - pcie_pme_msi_disabled = true; - - return 1; -} -__setup("pcie_pme=", pcie_pme_setup); - -struct pcie_pme_service_data { - spinlock_t lock; - struct pcie_device *srv; - struct work_struct work; - bool noirq; /* Don't enable the PME interrupt used by this service. */ -}; - -/** - * pcie_pme_interrupt_enable - Enable/disable PCIe PME interrupt generation. - * @dev: PCIe root port or event collector. - * @enable: Enable or disable the interrupt. - */ -void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) -{ - int rtctl_pos; - u16 rtctl; - - rtctl_pos = pci_pcie_cap(dev) + PCI_EXP_RTCTL; - - pci_read_config_word(dev, rtctl_pos, &rtctl); - if (enable) - rtctl |= PCI_EXP_RTCTL_PMEIE; - else - rtctl &= ~PCI_EXP_RTCTL_PMEIE; - pci_write_config_word(dev, rtctl_pos, rtctl); -} - -/** - * pcie_pme_clear_status - Clear root port PME interrupt status. - * @dev: PCIe root port or event collector. - */ -static void pcie_pme_clear_status(struct pci_dev *dev) -{ - int rtsta_pos; - u32 rtsta; - - rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; - - pci_read_config_dword(dev, rtsta_pos, &rtsta); - rtsta |= PCI_EXP_RTSTA_PME; - pci_write_config_dword(dev, rtsta_pos, rtsta); -} - -/** - * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. - * @bus: PCI bus to scan. - * - * Scan given PCI bus and all buses under it for devices asserting PME#. - */ -static bool pcie_pme_walk_bus(struct pci_bus *bus) -{ - struct pci_dev *dev; - bool ret = false; - - list_for_each_entry(dev, &bus->devices, bus_list) { - /* Skip PCIe devices in case we started from a root port. */ - if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { - pm_request_resume(&dev->dev); - pci_wakeup_event(dev); - ret = true; - } - - if (dev->subordinate && pcie_pme_walk_bus(dev->subordinate)) - ret = true; - } - - return ret; -} - -/** - * pcie_pme_from_pci_bridge - Check if PCIe-PCI bridge generated a PME. - * @bus: Secondary bus of the bridge. - * @devfn: Device/function number to check. - * - * PME from PCI devices under a PCIe-PCI bridge may be converted to an in-band - * PCIe PME message. In such that case the bridge should use the Requester ID - * of device/function number 0 on its secondary bus. - */ -static bool pcie_pme_from_pci_bridge(struct pci_bus *bus, u8 devfn) -{ - struct pci_dev *dev; - bool found = false; - - if (devfn) - return false; - - dev = pci_dev_get(bus->self); - if (!dev) - return false; - - if (pci_is_pcie(dev) && dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { - down_read(&pci_bus_sem); - if (pcie_pme_walk_bus(bus)) - found = true; - up_read(&pci_bus_sem); - } - - pci_dev_put(dev); - return found; -} - -/** - * pcie_pme_handle_request - Find device that generated PME and handle it. - * @port: Root port or event collector that generated the PME interrupt. - * @req_id: PCIe Requester ID of the device that generated the PME. - */ -static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) -{ - u8 busnr = req_id >> 8, devfn = req_id & 0xff; - struct pci_bus *bus; - struct pci_dev *dev; - bool found = false; - - /* First, check if the PME is from the root port itself. */ - if (port->devfn == devfn && port->bus->number == busnr) { - if (pci_check_pme_status(port)) { - pm_request_resume(&port->dev); - found = true; - } else { - /* - * Apparently, the root port generated the PME on behalf - * of a non-PCIe device downstream. If this is done by - * a root port, the Requester ID field in its status - * register may contain either the root port's, or the - * source device's information (PCI Express Base - * Specification, Rev. 2.0, Section 6.1.9). - */ - down_read(&pci_bus_sem); - found = pcie_pme_walk_bus(port->subordinate); - up_read(&pci_bus_sem); - } - goto out; - } - - /* Second, find the bus the source device is on. */ - bus = pci_find_bus(pci_domain_nr(port->bus), busnr); - if (!bus) - goto out; - - /* Next, check if the PME is from a PCIe-PCI bridge. */ - found = pcie_pme_from_pci_bridge(bus, devfn); - if (found) - goto out; - - /* Finally, try to find the PME source on the bus. */ - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) { - pci_dev_get(dev); - if (dev->devfn == devfn) { - found = true; - break; - } - pci_dev_put(dev); - } - up_read(&pci_bus_sem); - - if (found) { - /* The device is there, but we have to check its PME status. */ - found = pci_check_pme_status(dev); - if (found) { - pm_request_resume(&dev->dev); - pci_wakeup_event(dev); - } - pci_dev_put(dev); - } else if (devfn) { - /* - * The device is not there, but we can still try to recover by - * assuming that the PME was reported by a PCIe-PCI bridge that - * used devfn different from zero. - */ - dev_dbg(&port->dev, "PME interrupt generated for " - "non-existent device %02x:%02x.%d\n", - busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); - found = pcie_pme_from_pci_bridge(bus, 0); - } - - out: - if (!found) - dev_dbg(&port->dev, "Spurious native PME interrupt!\n"); -} - -/** - * pcie_pme_work_fn - Work handler for PCIe PME interrupt. - * @work: Work structure giving access to service data. - */ -static void pcie_pme_work_fn(struct work_struct *work) -{ - struct pcie_pme_service_data *data = - container_of(work, struct pcie_pme_service_data, work); - struct pci_dev *port = data->srv->port; - int rtsta_pos; - u32 rtsta; - - rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; - - spin_lock_irq(&data->lock); - - for (;;) { - if (data->noirq) - break; - - pci_read_config_dword(port, rtsta_pos, &rtsta); - if (rtsta & PCI_EXP_RTSTA_PME) { - /* - * Clear PME status of the port. If there are other - * pending PMEs, the status will be set again. - */ - pcie_pme_clear_status(port); - - spin_unlock_irq(&data->lock); - pcie_pme_handle_request(port, rtsta & 0xffff); - spin_lock_irq(&data->lock); - - continue; - } - - /* No need to loop if there are no more PMEs pending. */ - if (!(rtsta & PCI_EXP_RTSTA_PENDING)) - break; - - spin_unlock_irq(&data->lock); - cpu_relax(); - spin_lock_irq(&data->lock); - } - - if (!data->noirq) - pcie_pme_interrupt_enable(port, true); - - spin_unlock_irq(&data->lock); -} - -/** - * pcie_pme_irq - Interrupt handler for PCIe root port PME interrupt. - * @irq: Interrupt vector. - * @context: Interrupt context pointer. - */ -static irqreturn_t pcie_pme_irq(int irq, void *context) -{ - struct pci_dev *port; - struct pcie_pme_service_data *data; - int rtsta_pos; - u32 rtsta; - unsigned long flags; - - port = ((struct pcie_device *)context)->port; - data = get_service_data((struct pcie_device *)context); - - rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; - - spin_lock_irqsave(&data->lock, flags); - pci_read_config_dword(port, rtsta_pos, &rtsta); - - if (!(rtsta & PCI_EXP_RTSTA_PME)) { - spin_unlock_irqrestore(&data->lock, flags); - return IRQ_NONE; - } - - pcie_pme_interrupt_enable(port, false); - spin_unlock_irqrestore(&data->lock, flags); - - /* We don't use pm_wq, because it's freezable. */ - schedule_work(&data->work); - - return IRQ_HANDLED; -} - -/** - * pcie_pme_set_native - Set the PME interrupt flag for given device. - * @dev: PCI device to handle. - * @ign: Ignored. - */ -static int pcie_pme_set_native(struct pci_dev *dev, void *ign) -{ - dev_info(&dev->dev, "Signaling PME through PCIe PME interrupt\n"); - - device_set_run_wake(&dev->dev, true); - dev->pme_interrupt = true; - return 0; -} - -/** - * pcie_pme_mark_devices - Set the PME interrupt flag for devices below a port. - * @port: PCIe root port or event collector to handle. - * - * For each device below given root port, including the port itself (or for each - * root complex integrated endpoint if @port is a root complex event collector) - * set the flag indicating that it can signal run-time wake-up events via PCIe - * PME interrupts. - */ -static void pcie_pme_mark_devices(struct pci_dev *port) -{ - pcie_pme_set_native(port, NULL); - if (port->subordinate) { - pci_walk_bus(port->subordinate, pcie_pme_set_native, NULL); - } else { - struct pci_bus *bus = port->bus; - struct pci_dev *dev; - - /* Check if this is a root port event collector. */ - if (port->pcie_type != PCI_EXP_TYPE_RC_EC || !bus) - return; - - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) - if (pci_is_pcie(dev) - && dev->pcie_type == PCI_EXP_TYPE_RC_END) - pcie_pme_set_native(dev, NULL); - up_read(&pci_bus_sem); - } -} - -/** - * pcie_pme_probe - Initialize PCIe PME service for given root port. - * @srv: PCIe service to initialize. - */ -static int pcie_pme_probe(struct pcie_device *srv) -{ - struct pci_dev *port; - struct pcie_pme_service_data *data; - int ret; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - spin_lock_init(&data->lock); - INIT_WORK(&data->work, pcie_pme_work_fn); - data->srv = srv; - set_service_data(srv, data); - - port = srv->port; - pcie_pme_interrupt_enable(port, false); - pcie_pme_clear_status(port); - - ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); - if (ret) { - kfree(data); - } else { - pcie_pme_mark_devices(port); - pcie_pme_interrupt_enable(port, true); - } - - return ret; -} - -/** - * pcie_pme_suspend - Suspend PCIe PME service device. - * @srv: PCIe service device to suspend. - */ -static int pcie_pme_suspend(struct pcie_device *srv) -{ - struct pcie_pme_service_data *data = get_service_data(srv); - struct pci_dev *port = srv->port; - - spin_lock_irq(&data->lock); - pcie_pme_interrupt_enable(port, false); - pcie_pme_clear_status(port); - data->noirq = true; - spin_unlock_irq(&data->lock); - - synchronize_irq(srv->irq); - - return 0; -} - -/** - * pcie_pme_resume - Resume PCIe PME service device. - * @srv - PCIe service device to resume. - */ -static int pcie_pme_resume(struct pcie_device *srv) -{ - struct pcie_pme_service_data *data = get_service_data(srv); - struct pci_dev *port = srv->port; - - spin_lock_irq(&data->lock); - data->noirq = false; - pcie_pme_clear_status(port); - pcie_pme_interrupt_enable(port, true); - spin_unlock_irq(&data->lock); - - return 0; -} - -/** - * pcie_pme_remove - Prepare PCIe PME service device for removal. - * @srv - PCIe service device to resume. - */ -static void pcie_pme_remove(struct pcie_device *srv) -{ - pcie_pme_suspend(srv); - free_irq(srv->irq, srv); - kfree(get_service_data(srv)); -} - -static struct pcie_port_service_driver pcie_pme_driver = { - .name = "pcie_pme", - .port_type = PCI_EXP_TYPE_ROOT_PORT, - .service = PCIE_PORT_SERVICE_PME, - - .probe = pcie_pme_probe, - .suspend = pcie_pme_suspend, - .resume = pcie_pme_resume, - .remove = pcie_pme_remove, -}; - -/** - * pcie_pme_service_init - Register the PCIe PME service driver. - */ -static int __init pcie_pme_service_init(void) -{ - return pcie_port_service_register(&pcie_pme_driver); -} - -module_init(pcie_pme_service_init); -- cgit v1.2.3-59-g8ed1b From a9d2a6df11f5b9dc19ad4147374e8b67c4438158 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Sat, 21 Aug 2010 01:59:10 +0200 Subject: PCI: PCIe: Remove the port driver module exit routine The PCIe port driver's module exit routine is never used, so drop it. Signed-off-by: Kenji Kaneshige Signed-off-by: Rafael J. Wysocki Reviewed-by: Hidetoshi Seto Signed-off-by: Jesse Barnes --- drivers/pci/pcie/portdrv_pci.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 8f1338d1c53f..f9033e190fb6 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -346,11 +346,4 @@ static int __init pcie_portdrv_init(void) return retval; } -static void __exit pcie_portdrv_exit(void) -{ - pci_unregister_driver(&pcie_portdriver); - pcie_port_bus_unregister(); -} - module_init(pcie_portdrv_init); -module_exit(pcie_portdrv_exit); -- cgit v1.2.3-59-g8ed1b From ef24b16b5d67c815874ed2d0e2581db629661ba3 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 24 Aug 2010 14:46:12 -0700 Subject: phylib: Fix race between returning phydev and calling adjust_link It is possible that phylib will call adjust_link before returning from {,of_}phy_connect(), which may cause the following [very rare, though] oops upon reopening the device: Unable to handle kernel paging request for data at address 0x0000024c Oops: Kernel access of bad area, sig: 11 [#1] PREEMPT SMP NR_CPUS=2 LTT NESTING LEVEL : 0 P1021 RDB Modules linked in: NIP: c0345dac LR: c0345dac CTR: c0345d84 TASK = dffab6b0[30] 'events/0' THREAD: c0d24000 CPU: 0 [...] NIP [c0345dac] adjust_link+0x28/0x19c LR [c0345dac] adjust_link+0x28/0x19c Call Trace: [c0d25f00] [000045e1] 0x45e1 (unreliable) [c0d25f30] [c036c158] phy_state_machine+0x3ac/0x554 [...] Here is why. Drivers store phydev in their private structures, e.g. gianfar driver: static int init_phy(struct net_device *dev) { ... priv->phydev = of_phy_connect(...); ... } So that adjust_link could retrieve it back: static void adjust_link(struct net_device *dev) { ... struct phy_device *phydev = priv->phydev; ... } If the device has been opened before, then phydev->state is set to PHY_HALTED (or undefined if the driver didn't call phy_stop()). Now, phy_connect starts the PHY state machine before returning phydev to the driver: phy_start_machine(phydev, NULL); if (phydev->irq > 0) phy_start_interrupts(phydev); return phydev; The time between 'phy_start_machine()' and 'return phydev' is undefined. The start machine routine delays execution for 1 second, which is enough for most cases. But under heavy load, or if you're unlucky, it is quite possible that PHY state machine will execute before phy_connect() returns, and so adjust_link callback will try to dereference phydev, which is not yet ready. To fix the issue, simply initialize the PHY's state to PHY_READY during phy_attach(). This will ensure that phylib won't call adjust_link before phy_start(). Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index c0761197c07e..16ddc77313cb 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -466,6 +466,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev->interface = interface; + phydev->state = PHY_READY; + /* Do initial configuration here, now that * we have certain key parameters * (dev_flags and interface) */ -- cgit v1.2.3-59-g8ed1b From 4169591fd7c260b2b0b4e8f4d51f63f5b15ad78a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Aug 2010 06:52:46 +0000 Subject: pxa168_eth: remove unneeded null check "pep->pd" isn't checked consistently in this function. For example it's dereferenced unconditionally on the next line after the end of the if condition. This function is only called from pxa168_eth_probe() and pep->pd is always non-NULL so I removed the check. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/pxa168_eth.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index ecc64d750cce..857a68115a5c 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -1414,10 +1414,8 @@ static int ethernet_phy_setup(struct net_device *dev) { struct pxa168_eth_private *pep = netdev_priv(dev); - if (pep->pd != NULL) { - if (pep->pd->init) - pep->pd->init(); - } + if (pep->pd->init) + pep->pd->init(); pep->phy = phy_scan(pep, pep->pd->phy_addr & 0x1f); if (pep->phy != NULL) phy_init(pep, pep->pd->speed, pep->pd->duplex); -- cgit v1.2.3-59-g8ed1b From 945c7c73e2e81d68e3e2970afd95254e8f153fc9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Aug 2010 06:53:33 +0000 Subject: pxa168_eth: fix error handling in prope A couple issues here: * Some resources weren't released. * If alloc_etherdev() failed it would have caused a NULL dereference because "pep" would be null when we checked "if (pep->clk)". * Also it's better to propagate the error codes from mdiobus_register() instead of just returning -ENOMEM. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/pxa168_eth.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index 857a68115a5c..302fb480374b 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -1497,7 +1497,7 @@ static int pxa168_eth_probe(struct platform_device *pdev) dev = alloc_etherdev(sizeof(struct pxa168_eth_private)); if (!dev) { err = -ENOMEM; - goto out; + goto err_clk; } platform_set_drvdata(pdev, dev); @@ -1507,12 +1507,12 @@ static int pxa168_eth_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { err = -ENODEV; - goto out; + goto err_netdev; } pep->base = ioremap(res->start, res->end - res->start + 1); if (pep->base == NULL) { err = -ENOMEM; - goto out; + goto err_netdev; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); BUG_ON(!res); @@ -1549,7 +1549,7 @@ static int pxa168_eth_probe(struct platform_device *pdev) pep->smi_bus = mdiobus_alloc(); if (pep->smi_bus == NULL) { err = -ENOMEM; - goto out; + goto err_base; } pep->smi_bus->priv = pep; pep->smi_bus->name = "pxa168_eth smi"; @@ -1558,31 +1558,31 @@ static int pxa168_eth_probe(struct platform_device *pdev) snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id); pep->smi_bus->parent = &pdev->dev; pep->smi_bus->phy_mask = 0xffffffff; - if (mdiobus_register(pep->smi_bus) < 0) { - err = -ENOMEM; - goto out; - } + err = mdiobus_register(pep->smi_bus); + if (err) + goto err_free_mdio; + pxa168_init_hw(pep); err = ethernet_phy_setup(dev); if (err) - goto out; + goto err_mdiobus; SET_NETDEV_DEV(dev, &pdev->dev); err = register_netdev(dev); if (err) - goto out; + goto err_mdiobus; return 0; -out: - if (pep->clk) { - clk_disable(pep->clk); - clk_put(pep->clk); - pep->clk = NULL; - } - if (pep->base) { - iounmap(pep->base); - pep->base = NULL; - } - if (dev) - free_netdev(dev); + +err_mdiobus: + mdiobus_unregister(pep->smi_bus); +err_free_mdio: + mdiobus_free(pep->smi_bus); +err_base: + iounmap(pep->base); +err_netdev: + free_netdev(dev); +err_clk: + clk_disable(clk); + clk_put(clk); return err; } -- cgit v1.2.3-59-g8ed1b From 4f2c85106883bada5167e1d42a0409e063da8895 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Aug 2010 06:54:20 +0000 Subject: pxa168_eth: update call to phy_mii_ioctl() The phy_mii_ioctl() function changed recently. It now takes a struct ifreq pointer directly. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/pxa168_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index 302fb480374b..f324b767f685 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -1350,7 +1350,7 @@ static int pxa168_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, { struct pxa168_eth_private *pep = netdev_priv(dev); if (pep->phy != NULL) - return phy_mii_ioctl(pep->phy, if_mii(ifr), cmd); + return phy_mii_ioctl(pep->phy, ifr, cmd); return -EOPNOTSUPP; } -- cgit v1.2.3-59-g8ed1b From b2bc85631e72485b984bcd202a104591874babba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Aug 2010 06:55:05 +0000 Subject: pxa168_eth: silence gcc warnings Casting "pep->tx_desc_dma" to to a struct tx_desc pointer makes gcc complain: drivers/net/pxa168_eth.c:657: warning: cast to pointer from integer of different size Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/pxa168_eth.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index f324b767f685..410ea0a61371 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -654,15 +654,15 @@ static void eth_port_start(struct net_device *dev) /* Assignment of Tx CTRP of given queue */ tx_curr_desc = pep->tx_curr_desc_q; wrl(pep, ETH_C_TX_DESC_1, - (u32) ((struct tx_desc *)pep->tx_desc_dma + tx_curr_desc)); + (u32) (pep->tx_desc_dma + tx_curr_desc * sizeof(struct tx_desc))); /* Assignment of Rx CRDP of given queue */ rx_curr_desc = pep->rx_curr_desc_q; wrl(pep, ETH_C_RX_DESC_0, - (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc)); + (u32) (pep->rx_desc_dma + rx_curr_desc * sizeof(struct rx_desc))); wrl(pep, ETH_F_RX_DESC_0, - (u32) ((struct rx_desc *)pep->rx_desc_dma + rx_curr_desc)); + (u32) (pep->rx_desc_dma + rx_curr_desc * sizeof(struct rx_desc))); /* Clear all interrupts */ wrl(pep, INT_CAUSE, 0); -- cgit v1.2.3-59-g8ed1b From 7d8cb26d7dcb911f110b7762bd5941e8f009d6c3 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 24 Aug 2010 08:44:16 -0700 Subject: ceph: maintain i_head_snapc when any caps are dirty, not just for data We used to use i_head_snapc to keep track of which snapc the current epoch of dirty data was dirtied under. It is used by queue_cap_snap to set up the cap_snap. However, since we queue cap snaps for any dirty caps, not just for dirty file data, we need to keep a valid i_head_snapc anytime we have dirty|flushing caps. This fixes a NULL pointer deref in queue_cap_snap when writing back dirty caps without data (e.g., snaptest-authwb.sh). Signed-off-by: Sage Weil --- fs/ceph/addr.c | 4 ++-- fs/ceph/caps.c | 20 +++++++++++++++++--- fs/ceph/snap.c | 6 +++++- fs/ceph/super.h | 3 ++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 420d46974ec8..4cfce1ee31fa 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -87,7 +87,7 @@ static int ceph_set_page_dirty(struct page *page) /* dirty the head */ spin_lock(&inode->i_lock); - if (ci->i_wrbuffer_ref_head == 0) + if (ci->i_head_snapc == NULL) ci->i_head_snapc = ceph_get_snap_context(snapc); ++ci->i_wrbuffer_ref_head; if (ci->i_wrbuffer_ref == 0) @@ -346,7 +346,7 @@ static struct ceph_snap_context *get_oldest_context(struct inode *inode, break; } } - if (!snapc && ci->i_head_snapc) { + if (!snapc && ci->i_wrbuffer_ref_head) { snapc = ceph_get_snap_context(ci->i_head_snapc); dout(" head snapc %p has %d dirty pages\n", snapc, ci->i_wrbuffer_ref_head); diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index ba5bbf318fe1..a2069b6680ae 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1143,6 +1143,10 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, for (i = 0; i < CEPH_CAP_BITS; i++) if (flushing & (1 << i)) ci->i_cap_flush_tid[i] = flush_tid; + + follows = ci->i_head_snapc->seq; + } else { + follows = 0; } keep = cap->implemented; @@ -1156,7 +1160,6 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, mtime = inode->i_mtime; atime = inode->i_atime; time_warp_seq = ci->i_time_warp_seq; - follows = ci->i_snap_realm->cached_context->seq; uid = inode->i_uid; gid = inode->i_gid; mode = inode->i_mode; @@ -1332,7 +1335,11 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) ceph_cap_string(was | mask)); ci->i_dirty_caps |= mask; if (was == 0) { - dout(" inode %p now dirty\n", &ci->vfs_inode); + if (!ci->i_head_snapc) + ci->i_head_snapc = ceph_get_snap_context( + ci->i_snap_realm->cached_context); + dout(" inode %p now dirty snapc %p\n", &ci->vfs_inode, + ci->i_head_snapc); BUG_ON(!list_empty(&ci->i_dirty_item)); spin_lock(&mdsc->cap_dirty_lock); list_add(&ci->i_dirty_item, &mdsc->cap_dirty); @@ -2190,7 +2197,9 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, if (ci->i_head_snapc == snapc) { ci->i_wrbuffer_ref_head -= nr; - if (!ci->i_wrbuffer_ref_head) { + if (ci->i_wrbuffer_ref_head == 0 && + ci->i_dirty_caps == 0 && ci->i_flushing_caps == 0) { + BUG_ON(!ci->i_head_snapc); ceph_put_snap_context(ci->i_head_snapc); ci->i_head_snapc = NULL; } @@ -2483,6 +2492,11 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, dout(" inode %p now clean\n", inode); BUG_ON(!list_empty(&ci->i_dirty_item)); drop = 1; + if (ci->i_wrbuffer_ref_head == 0) { + BUG_ON(!ci->i_head_snapc); + ceph_put_snap_context(ci->i_head_snapc); + ci->i_head_snapc = NULL; + } } else { BUG_ON(list_empty(&ci->i_dirty_item)); } diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 6bdbf3ae7082..4868b9dcac5a 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -458,6 +458,8 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR))) { struct ceph_snap_context *snapc = ci->i_head_snapc; + dout("queue_cap_snap %p cap_snap %p queuing under %p\n", inode, + capsnap, snapc); igrab(inode); atomic_set(&capsnap->nref, 1); @@ -489,7 +491,9 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) capsnap->dirty_pages = ci->i_wrbuffer_ref_head; ci->i_wrbuffer_ref_head = 0; capsnap->context = snapc; - ci->i_head_snapc = NULL; + ci->i_head_snapc = + ceph_get_snap_context(ci->i_snap_realm->cached_context); + dout(" new snapc is %p\n", ci->i_head_snapc); list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps); if (used & CEPH_CAP_FILE_WR) { diff --git a/fs/ceph/super.h b/fs/ceph/super.h index b33929d8f287..c33897ae5725 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -344,7 +344,8 @@ struct ceph_inode_info { unsigned i_cap_exporting_issued; struct ceph_cap_reservation i_cap_migration_resv; struct list_head i_cap_snaps; /* snapped state pending flush to mds */ - struct ceph_snap_context *i_head_snapc; /* set if wr_buffer_head > 0 */ + struct ceph_snap_context *i_head_snapc; /* set if wr_buffer_head > 0 or + dirty|flushing caps */ unsigned i_snap_caps; /* cap bits for snapped files */ int i_nr_by_mode[CEPH_FILE_MODE_NUM]; /* open file counts */ -- cgit v1.2.3-59-g8ed1b From 36e21687e6e51c4225c42e6291938363f7bbfa7c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 24 Aug 2010 16:23:48 -0700 Subject: ceph: initialize fields on new dentry_infos Signed-off-by: Sage Weil --- fs/ceph/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 67bbb41d5526..6e4f43ff23ec 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -46,7 +46,7 @@ int ceph_init_dentry(struct dentry *dentry) else dentry->d_op = &ceph_snap_dentry_ops; - di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS); + di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO); if (!di) return -ENOMEM; /* oh well */ -- cgit v1.2.3-59-g8ed1b From b7d460897739e02f186425b7276e3fdb1595cea7 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 24 Aug 2010 22:44:12 -0700 Subject: x86, mm: Fix CONFIG_VMSPLIT_1G and 2G_OPT trampoline rc2 kernel crashes when booting second cpu on this CONFIG_VMSPLIT_2G_OPT laptop: whereas cloning from kernel to low mappings pgd range does need to limit by both KERNEL_PGD_PTRS and KERNEL_PGD_BOUNDARY, cloning kernel pgd range itself must not be limited by the smaller KERNEL_PGD_BOUNDARY. Signed-off-by: Hugh Dickins LKML-Reference: Signed-off-by: H. Peter Anvin --- arch/x86/kernel/trampoline.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c index a874495b3673..e2a595257390 100644 --- a/arch/x86/kernel/trampoline.c +++ b/arch/x86/kernel/trampoline.c @@ -45,8 +45,7 @@ void __init setup_trampoline_page_table(void) /* Copy kernel address range */ clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY, swapper_pg_dir + KERNEL_PGD_BOUNDARY, - min_t(unsigned long, KERNEL_PGD_PTRS, - KERNEL_PGD_BOUNDARY)); + KERNEL_PGD_PTRS); /* Initialize low mappings */ clone_pgd_range(trampoline_pg_dir, -- cgit v1.2.3-59-g8ed1b From 750d857c682f4db60d14722d430c7ccc35070962 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 13 Aug 2010 16:29:04 +0200 Subject: oprofile: fix crash when accessing freed task structs This patch fixes a crash during shutdown reported below. The crash is caused by accessing already freed task structs. The fix changes the order for registering and unregistering notifier callbacks. All notifiers must be initialized before buffers start working. To stop buffer synchronization we cancel all workqueues, unregister the notifier callback and then flush all buffers. After all of this we finally can free all tasks listed. This should avoid accessing freed tasks. On 22.07.10 01:14:40, Benjamin Herrenschmidt wrote: > So the initial observation is a spinlock bad magic followed by a crash > in the spinlock debug code: > > [ 1541.586531] BUG: spinlock bad magic on CPU#5, events/5/136 > [ 1541.597564] Unable to handle kernel paging request for data at address 0x6b6b6b6b6b6b6d03 > > Backtrace looks like: > > spin_bug+0x74/0xd4 > ._raw_spin_lock+0x48/0x184 > ._spin_lock+0x10/0x24 > .get_task_mm+0x28/0x8c > .sync_buffer+0x1b4/0x598 > .wq_sync_buffer+0xa0/0xdc > .worker_thread+0x1d8/0x2a8 > .kthread+0xa8/0xb4 > .kernel_thread+0x54/0x70 > > So we are accessing a freed task struct in the work queue when > processing the samples. Reported-by: Benjamin Herrenschmidt Cc: stable@kernel.org Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 27 ++++++++++++++------------- drivers/oprofile/cpu_buffer.c | 2 -- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index a9352b2c7ac4..b7e755f4178a 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -141,16 +141,6 @@ static struct notifier_block module_load_nb = { .notifier_call = module_load_notify, }; - -static void end_sync(void) -{ - end_cpu_work(); - /* make sure we don't leak task structs */ - process_task_mortuary(); - process_task_mortuary(); -} - - int sync_start(void) { int err; @@ -158,7 +148,7 @@ int sync_start(void) if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL)) return -ENOMEM; - start_cpu_work(); + mutex_lock(&buffer_mutex); err = task_handoff_register(&task_free_nb); if (err) @@ -173,7 +163,10 @@ int sync_start(void) if (err) goto out4; + start_cpu_work(); + out: + mutex_unlock(&buffer_mutex); return err; out4: profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); @@ -182,7 +175,6 @@ out3: out2: task_handoff_unregister(&task_free_nb); out1: - end_sync(); free_cpumask_var(marked_cpus); goto out; } @@ -190,11 +182,20 @@ out1: void sync_stop(void) { + /* flush buffers */ + mutex_lock(&buffer_mutex); + end_cpu_work(); unregister_module_notifier(&module_load_nb); profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); task_handoff_unregister(&task_free_nb); - end_sync(); + mutex_unlock(&buffer_mutex); + flush_scheduled_work(); + + /* make sure we don't leak task structs */ + process_task_mortuary(); + process_task_mortuary(); + free_cpumask_var(marked_cpus); } diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 219f79e2210a..f179ac2ea801 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -120,8 +120,6 @@ void end_cpu_work(void) cancel_delayed_work(&b->work); } - - flush_scheduled_work(); } /* -- cgit v1.2.3-59-g8ed1b From 8a2e8e5dec7e29c56a46ba176c664ab6a3d04118 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 25 Aug 2010 10:33:56 +0200 Subject: workqueue: fix cwq->nr_active underflow cwq->nr_active is used to keep track of how many work items are active for the cpu workqueue, where 'active' is defined as either pending on global worklist or executing. This is used to implement the max_active limit and workqueue freezing. If a work item is queued after nr_active has already reached max_active, the work item doesn't increment nr_active and is put on the delayed queue and gets activated later as previous active work items retire. try_to_grab_pending() which is used in the cancellation path unconditionally decremented nr_active whether the work item being cancelled is currently active or delayed, so cancelling a delayed work item makes nr_active underflow. This breaks max_active enforcement and triggers BUG_ON() in destroy_workqueue() later on. This patch fixes this bug by adding a flag WORK_STRUCT_DELAYED, which is set while a work item in on the delayed list and making try_to_grab_pending() decrement nr_active iff the work item is currently active. The addition of the flag enlarges cwq alignment to 256 bytes which is getting a bit too large. It's scheduled to be reduced back to 128 bytes by merging WORK_STRUCT_PENDING and WORK_STRUCT_CWQ in the next devel cycle. Signed-off-by: Tejun Heo Reported-by: Johannes Berg --- include/linux/workqueue.h | 16 +++++++++------- kernel/workqueue.c | 30 ++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index c959666eafca..f11100f96482 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -25,18 +25,20 @@ typedef void (*work_func_t)(struct work_struct *work); enum { WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */ - WORK_STRUCT_CWQ_BIT = 1, /* data points to cwq */ - WORK_STRUCT_LINKED_BIT = 2, /* next work is linked to this one */ + WORK_STRUCT_DELAYED_BIT = 1, /* work item is delayed */ + WORK_STRUCT_CWQ_BIT = 2, /* data points to cwq */ + WORK_STRUCT_LINKED_BIT = 3, /* next work is linked to this one */ #ifdef CONFIG_DEBUG_OBJECTS_WORK - WORK_STRUCT_STATIC_BIT = 3, /* static initializer (debugobjects) */ - WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */ + WORK_STRUCT_STATIC_BIT = 4, /* static initializer (debugobjects) */ + WORK_STRUCT_COLOR_SHIFT = 5, /* color for workqueue flushing */ #else - WORK_STRUCT_COLOR_SHIFT = 3, /* color for workqueue flushing */ + WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */ #endif WORK_STRUCT_COLOR_BITS = 4, WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT, + WORK_STRUCT_DELAYED = 1 << WORK_STRUCT_DELAYED_BIT, WORK_STRUCT_CWQ = 1 << WORK_STRUCT_CWQ_BIT, WORK_STRUCT_LINKED = 1 << WORK_STRUCT_LINKED_BIT, #ifdef CONFIG_DEBUG_OBJECTS_WORK @@ -59,8 +61,8 @@ enum { /* * Reserve 7 bits off of cwq pointer w/ debugobjects turned - * off. This makes cwqs aligned to 128 bytes which isn't too - * excessive while allowing 15 workqueue flush colors. + * off. This makes cwqs aligned to 256 bytes and allows 15 + * workqueue flush colors. */ WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT + WORK_STRUCT_COLOR_BITS, diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 362b50d092e2..a2dccfca03ba 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -941,6 +941,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, struct global_cwq *gcwq; struct cpu_workqueue_struct *cwq; struct list_head *worklist; + unsigned int work_flags; unsigned long flags; debug_work_activate(work); @@ -990,14 +991,17 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq, BUG_ON(!list_empty(&work->entry)); cwq->nr_in_flight[cwq->work_color]++; + work_flags = work_color_to_flags(cwq->work_color); if (likely(cwq->nr_active < cwq->max_active)) { cwq->nr_active++; worklist = gcwq_determine_ins_pos(gcwq, cwq); - } else + } else { + work_flags |= WORK_STRUCT_DELAYED; worklist = &cwq->delayed_works; + } - insert_work(cwq, work, worklist, work_color_to_flags(cwq->work_color)); + insert_work(cwq, work, worklist, work_flags); spin_unlock_irqrestore(&gcwq->lock, flags); } @@ -1666,6 +1670,7 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq); move_linked_works(work, pos, NULL); + __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work)); cwq->nr_active++; } @@ -1673,6 +1678,7 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight * @cwq: cwq of interest * @color: color of work which left the queue + * @delayed: for a delayed work * * A work either has completed or is removed from pending queue, * decrement nr_in_flight of its cwq and handle workqueue flushing. @@ -1680,19 +1686,22 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq) * CONTEXT: * spin_lock_irq(gcwq->lock). */ -static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color) +static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color, + bool delayed) { /* ignore uncolored works */ if (color == WORK_NO_COLOR) return; cwq->nr_in_flight[color]--; - cwq->nr_active--; - if (!list_empty(&cwq->delayed_works)) { - /* one down, submit a delayed one */ - if (cwq->nr_active < cwq->max_active) - cwq_activate_first_delayed(cwq); + if (!delayed) { + cwq->nr_active--; + if (!list_empty(&cwq->delayed_works)) { + /* one down, submit a delayed one */ + if (cwq->nr_active < cwq->max_active) + cwq_activate_first_delayed(cwq); + } } /* is flush in progress and are we at the flushing tip? */ @@ -1823,7 +1832,7 @@ __acquires(&gcwq->lock) hlist_del_init(&worker->hentry); worker->current_work = NULL; worker->current_cwq = NULL; - cwq_dec_nr_in_flight(cwq, work_color); + cwq_dec_nr_in_flight(cwq, work_color, false); } /** @@ -2388,7 +2397,8 @@ static int try_to_grab_pending(struct work_struct *work) debug_work_deactivate(work); list_del_init(&work->entry); cwq_dec_nr_in_flight(get_work_cwq(work), - get_work_color(work)); + get_work_color(work), + *work_data_bits(work) & WORK_STRUCT_DELAYED); ret = 1; } } -- cgit v1.2.3-59-g8ed1b From ad1af0fedba14f82b240a03fe20eb9b2fdbd0357 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 25 Aug 2010 02:27:49 -0700 Subject: tcp: Combat per-cpu skew in orphan tests. As reported by Anton Blanchard when we use percpu_counter_read_positive() to make our orphan socket limit checks, the check can be off by up to num_cpus_online() * batch (which is 32 by default) which on a 128 cpu machine can be as large as the default orphan limit itself. Fix this by doing the full expensive sum check if the optimized check triggers. Reported-by: Anton Blanchard Signed-off-by: David S. Miller Acked-by: Eric Dumazet --- include/net/tcp.h | 18 ++++++++++++++---- net/ipv4/tcp.c | 5 +---- net/ipv4/tcp_timer.c | 8 ++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index df6a2eb20193..eaa9582779d0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -268,11 +268,21 @@ static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) return seq3 - seq2 >= seq1 - seq2; } -static inline int tcp_too_many_orphans(struct sock *sk, int num) +static inline bool tcp_too_many_orphans(struct sock *sk, int shift) { - return (num > sysctl_tcp_max_orphans) || - (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && - atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]); + struct percpu_counter *ocp = sk->sk_prot->orphan_count; + int orphans = percpu_counter_read_positive(ocp); + + if (orphans << shift > sysctl_tcp_max_orphans) { + orphans = percpu_counter_sum_positive(ocp); + if (orphans << shift > sysctl_tcp_max_orphans) + return true; + } + + if (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && + atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]) + return true; + return false; } /* syncookies: remember time of last synqueue overflow */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 176e11aaea77..197b9b77fa3e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2011,11 +2011,8 @@ adjudge_to_death: } } if (sk->sk_state != TCP_CLOSE) { - int orphan_count = percpu_counter_read_positive( - sk->sk_prot->orphan_count); - sk_mem_reclaim(sk); - if (tcp_too_many_orphans(sk, orphan_count)) { + if (tcp_too_many_orphans(sk, 0)) { if (net_ratelimit()) printk(KERN_INFO "TCP: too many of orphaned " "sockets\n"); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 808bb920c9f5..c35b469e851c 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -66,18 +66,18 @@ static void tcp_write_err(struct sock *sk) static int tcp_out_of_resources(struct sock *sk, int do_reset) { struct tcp_sock *tp = tcp_sk(sk); - int orphans = percpu_counter_read_positive(&tcp_orphan_count); + int shift = 0; /* If peer does not open window for long time, or did not transmit * anything for long time, penalize it. */ if ((s32)(tcp_time_stamp - tp->lsndtime) > 2*TCP_RTO_MAX || !do_reset) - orphans <<= 1; + shift++; /* If some dubious ICMP arrived, penalize even more. */ if (sk->sk_err_soft) - orphans <<= 1; + shift++; - if (tcp_too_many_orphans(sk, orphans)) { + if (tcp_too_many_orphans(sk, shift)) { if (net_ratelimit()) printk(KERN_INFO "Out of socket memory\n"); -- cgit v1.2.3-59-g8ed1b From 151772dbfad4dbe81721e40f9b3d588ea77bb7aa Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 25 Aug 2010 11:32:38 +1000 Subject: tracing/trace_stack: Fix stack trace on ppc64 save_stack_trace() stores the instruction pointer, not the function descriptor. On ppc64 the trace stack code currently dereferences the instruction pointer and shows 8 bytes of instructions in our backtraces: # cat /sys/kernel/debug/tracing/stack_trace Depth Size Location (26 entries) ----- ---- -------- 0) 5424 112 0x6000000048000004 1) 5312 160 0x60000000ebad01b0 2) 5152 160 0x2c23000041c20030 3) 4992 240 0x600000007c781b79 4) 4752 160 0xe84100284800000c 5) 4592 192 0x600000002fa30000 6) 4400 256 0x7f1800347b7407e0 7) 4144 208 0xe89f0108f87f0070 8) 3936 272 0xe84100282fa30000 Since we aren't dealing with function descriptors, use %pS instead of %pF to fix it: # cat /sys/kernel/debug/tracing/stack_trace Depth Size Location (26 entries) ----- ---- -------- 0) 5424 112 ftrace_call+0x4/0x8 1) 5312 160 .current_io_context+0x28/0x74 2) 5152 160 .get_io_context+0x48/0xa0 3) 4992 240 .cfq_set_request+0x94/0x4c4 4) 4752 160 .elv_set_request+0x60/0x84 5) 4592 192 .get_request+0x2d4/0x468 6) 4400 256 .get_request_wait+0x7c/0x258 7) 4144 208 .__make_request+0x49c/0x610 8) 3936 272 .generic_make_request+0x390/0x434 Signed-off-by: Anton Blanchard Cc: rostedt@goodmis.org Cc: fweisbec@gmail.com LKML-Reference: <20100825013238.GE28360@kryten> Signed-off-by: Ingo Molnar --- kernel/trace/trace_stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 056468eae7cf..a6b7e0e0f3eb 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -249,7 +249,7 @@ static int trace_lookup_stack(struct seq_file *m, long i) { unsigned long addr = stack_dump_trace[i]; - return seq_printf(m, "%pF\n", (void *)addr); + return seq_printf(m, "%pS\n", (void *)addr); } static void print_disabled(struct seq_file *m) -- cgit v1.2.3-59-g8ed1b From 8d330919927ea31fa083b5a80084dc991da813a0 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Wed, 25 Aug 2010 21:06:32 +0000 Subject: perf, x86, Pentium4: Clear the P4_CCCR_FORCE_OVF flag If on Pentium4 CPUs the FORCE_OVF flag is set then an NMI happens on every event, which can generate a flood of NMIs. Clear it. Reported-by: Vince Weaver Signed-off-by: Lin Ming Signed-off-by: Cyrill Gorcunov Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_p4.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index febb12cea795..7e578e9cc58b 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -497,6 +497,8 @@ static int p4_hw_config(struct perf_event *event) event->hw.config |= event->attr.config & (p4_config_pack_escr(P4_ESCR_MASK_HT) | p4_config_pack_cccr(P4_CCCR_MASK_HT | P4_CCCR_RESERVED)); + + event->hw.config &= ~P4_CCCR_FORCE_OVF; } rc = x86_setup_perfctr(event); -- cgit v1.2.3-59-g8ed1b From 45ff34d32a19e9008e7202ba2a7c0d0f40420228 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 25 Aug 2010 15:42:08 +0200 Subject: hwmon: (coretemp) Fix harmless build warning Fix the following build warning: CC [M] drivers/hwmon/coretemp.o drivers/hwmon/coretemp.c: In function "coretemp_init": drivers/hwmon/coretemp.c:521: warning: unused variable "n" drivers/hwmon/coretemp.c:521: warning: unused variable "p" Introduced by commit 851b29cb3b196cb66452ec964ab5f66c9c9cd1ed. When you drop code, you also have to drop the variables this code was using. Signed-off-by: Jean Delvare Cc: Chen Gong Cc: Rudolf Marek Cc: Huaxu Wan --- drivers/hwmon/coretemp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index c070c9714cbe..de8111114f46 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -518,7 +518,6 @@ static struct notifier_block coretemp_cpu_notifier __refdata = { static int __init coretemp_init(void) { int i, err = -ENODEV; - struct pdev_entry *p, *n; /* quick check if we run Intel */ if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL) -- cgit v1.2.3-59-g8ed1b From c12c507d7185fe4e8ada7ed9832957576eefecf8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 25 Aug 2010 15:42:10 +0200 Subject: hwmon: (ads7871) Fix ads7871_probe error paths 1. remove 'status' variable 2. remove unneeded initialization of 'err' variable 3. return missing error code if sysfs_create_group fail. 4. fix the init sequence as: - check hardware existence - kzalloc for ads7871_data - sysfs_create_group - hwmon_device_register Signed-off-by: Axel Lin Cc: stable@kernel.org Signed-off-by: Jean Delvare --- drivers/hwmon/ads7871.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index b300a2048af1..52319340e182 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c @@ -160,30 +160,12 @@ static const struct attribute_group ads7871_group = { static int __devinit ads7871_probe(struct spi_device *spi) { - int status, ret, err = 0; + int ret, err; uint8_t val; struct ads7871_data *pdata; dev_dbg(&spi->dev, "probe\n"); - pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL); - if (!pdata) { - err = -ENOMEM; - goto exit; - } - - status = sysfs_create_group(&spi->dev.kobj, &ads7871_group); - if (status < 0) - goto error_free; - - pdata->hwmon_dev = hwmon_device_register(&spi->dev); - if (IS_ERR(pdata->hwmon_dev)) { - err = PTR_ERR(pdata->hwmon_dev); - goto error_remove; - } - - spi_set_drvdata(spi, pdata); - /* Configure the SPI bus */ spi->mode = (SPI_MODE_0); spi->bits_per_word = 8; @@ -201,6 +183,24 @@ static int __devinit ads7871_probe(struct spi_device *spi) we need to make sure we really have a chip*/ if (val != ret) { err = -ENODEV; + goto exit; + } + + pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL); + if (!pdata) { + err = -ENOMEM; + goto exit; + } + + err = sysfs_create_group(&spi->dev.kobj, &ads7871_group); + if (err < 0) + goto error_free; + + spi_set_drvdata(spi, pdata); + + pdata->hwmon_dev = hwmon_device_register(&spi->dev); + if (IS_ERR(pdata->hwmon_dev)) { + err = PTR_ERR(pdata->hwmon_dev); goto error_remove; } -- cgit v1.2.3-59-g8ed1b From a05e93f3b3fc2f53c1d0de3b17019e207c482349 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 25 Aug 2010 15:42:12 +0200 Subject: hwmon: (k8temp) Differentiate between AM2 and ASB1 Commit 8bf0223ed515be24de0c671eedaff49e78bebc9c (hwmon, k8temp: Fix temperature reporting for ASB1 processor revisions) fixed temperature reporting for ASB1 CPUs. But those CPU models (model 0x6b, 0x6f, 0x7f) were packaged both as AM2 (desktop) and ASB1 (mobile). Thus the commit leads to wrong temperature reporting for AM2 CPU parts. The solution is to determine the package type for models 0x6b, 0x6f, 0x7f. This is done using BrandId from CPUID Fn8000_0001_EBX[15:0]. See "Constructing the processor Name String" in "Revision Guide for AMD NPT Family 0Fh Processors" (Rev. 3.46). Cc: Rudolf Marek Cc: stable@kernel.org [.32.x, .33.x, .34.x, .35.x] Reported-by: Vladislav Guberinic Signed-off-by: Andreas Herrmann Signed-off-by: Jean Delvare --- drivers/hwmon/k8temp.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index b9bb3e0ca530..39ead2a4d3c5 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -143,6 +143,37 @@ static const struct pci_device_id k8temp_ids[] = { MODULE_DEVICE_TABLE(pci, k8temp_ids); +static int __devinit is_rev_g_desktop(u8 model) +{ + u32 brandidx; + + if (model < 0x69) + return 0; + + if (model == 0xc1 || model == 0x6c || model == 0x7c) + return 0; + + /* + * Differentiate between AM2 and ASB1. + * See "Constructing the processor Name String" in "Revision + * Guide for AMD NPT Family 0Fh Processors" (33610). + */ + brandidx = cpuid_ebx(0x80000001); + brandidx = (brandidx >> 9) & 0x1f; + + /* Single core */ + if ((model == 0x6f || model == 0x7f) && + (brandidx == 0x7 || brandidx == 0x9 || brandidx == 0xc)) + return 0; + + /* Dual core */ + if (model == 0x6b && + (brandidx == 0xb || brandidx == 0xc)) + return 0; + + return 1; +} + static int __devinit k8temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -179,9 +210,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, "wrong - check erratum #141\n"); } - if ((model >= 0x69) && - !(model == 0xc1 || model == 0x6c || model == 0x7c || - model == 0x6b || model == 0x6f || model == 0x7f)) { + if (is_rev_g_desktop(model)) { /* * RevG desktop CPUs (i.e. no socket S1G1 or * ASB1 parts) need additional offset, -- cgit v1.2.3-59-g8ed1b From 968591298514167d05b0379377757ddefc76f022 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Wed, 25 Aug 2010 15:42:14 +0200 Subject: MAINTAINERS: hwmon/coretemp: Change maintainers Huaxu and Rudolf want me to be the hwmon coretemp driver maintainer and remove their names from the coretemp maintainer entry. Signed-off-by: Fenghua Yu Acked-by: Rudolf Marek Acked-by: Huaxu Wan Signed-off-by: Jean Delvare --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a1df54b0af79..5fa8451ec80c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1676,8 +1676,7 @@ F: kernel/cgroup* F: mm/*cgroup* CORETEMP HARDWARE MONITORING DRIVER -M: Rudolf Marek -M: Huaxu Wan +M: Fenghua Yu L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/coretemp -- cgit v1.2.3-59-g8ed1b From 268ba5c05b82af575819bd719a2facb2a3169260 Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Tue, 24 Aug 2010 00:33:37 -0700 Subject: Input: mousedev - fix regression of inverting axes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced by 987a6c0298260b7aa40702b349282554d6180e4b a swap in max/min calculation gets fixed by this patch. Reported-by: Bruno Prémont Signed-off-by: Christoph Fritz Signed-off-by: Dmitry Torokhov --- drivers/input/mousedev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 83c24cca234a..d528a2dba064 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -138,8 +138,8 @@ static void mousedev_touchpad_event(struct input_dev *dev, fx(0) = value; if (mousedev->touch && mousedev->pkt_count >= 2) { - size = input_abs_get_min(dev, ABS_X) - - input_abs_get_max(dev, ABS_X); + size = input_abs_get_max(dev, ABS_X) - + input_abs_get_min(dev, ABS_X); if (size == 0) size = 256 * 2; @@ -155,8 +155,8 @@ static void mousedev_touchpad_event(struct input_dev *dev, fy(0) = value; if (mousedev->touch && mousedev->pkt_count >= 2) { /* use X size for ABS_Y to keep the same scale */ - size = input_abs_get_min(dev, ABS_X) - - input_abs_get_max(dev, ABS_X); + size = input_abs_get_max(dev, ABS_X) - + input_abs_get_min(dev, ABS_X); if (size == 0) size = 256 * 2; -- cgit v1.2.3-59-g8ed1b From 288933c02b440621d9c8e7bb5f232cfb7bdef7df Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 24 Aug 2010 16:37:53 -0700 Subject: Input: pxa27x_keypad - remove input_free_device() in pxa27x_keypad_remove() No need to call input_free_device() after input_unregister_device(). Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 0e53b3bc39af..f32404f99189 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -567,8 +567,6 @@ static int __devexit pxa27x_keypad_remove(struct platform_device *pdev) clk_put(keypad->clk); input_unregister_device(keypad->input_dev); - input_free_device(keypad->input_dev); - iounmap(keypad->mmio_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3-59-g8ed1b From 2a643ec67f9efc4b6921a3dd6e257f3b5360622b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 25 Aug 2010 19:58:53 +0200 Subject: cciss: fix reporting of max queue depth since init The ioctl path and the scsi tape path were not accounting for their additions to the queue depth. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 7191c16954d2..6124c2fd2d33 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -297,6 +297,8 @@ static void enqueue_cmd_and_start_io(ctlr_info_t *h, spin_lock_irqsave(&h->lock, flags); addQ(&h->reqQ, c); h->Qdepth++; + if (h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; start_io(h); spin_unlock_irqrestore(&h->lock, flags); } -- cgit v1.2.3-59-g8ed1b From 6cb6cbeaa9d6573c674842b9471c0467967aae99 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 25 Aug 2010 08:58:50 -0700 Subject: MAINTAINERS: Add RCU's public git tree RCU now has a public git tree, so add it via the T: line in the MAINTAINERS file. Signed-off-by: Paul E. McKenney Cc: joe@perches.com LKML-Reference: <20100825155850.GA6601@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5fa8451ec80c..614861a8f377 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4799,6 +4799,7 @@ RCUTORTURE MODULE M: Josh Triplett M: "Paul E. McKenney" S: Supported +T: git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git F: Documentation/RCU/torture.txt F: kernel/rcutorture.c @@ -4823,6 +4824,7 @@ M: Dipankar Sarma M: "Paul E. McKenney" W: http://www.rdrop.com/users/paulmck/rclock/ S: Supported +T: git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git F: Documentation/RCU/ F: include/linux/rcu* F: include/linux/srcu* -- cgit v1.2.3-59-g8ed1b From ac1f12ef569d49b013c3db86e11be7e15d66b1c3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Aug 2010 09:11:35 +0200 Subject: ceph: ceph_get_inode() returns an ERR_PTR ceph_get_inode() returns an ERR_PTR and it doesn't return a NULL. Signed-off-by: Dan Carpenter Signed-off-by: Sage Weil --- fs/ceph/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 3e6b52cb5ee8..e7cca414da03 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1230,11 +1230,11 @@ retry_lookup: in = dn->d_inode; } else { in = ceph_get_inode(parent->d_sb, vino); - if (in == NULL) { + if (IS_ERR(in)) { dout("new_inode badness\n"); d_delete(dn); dput(dn); - err = -ENOMEM; + err = PTR_ERR(in); goto out; } dn = splice_dentry(dn, in, NULL); -- cgit v1.2.3-59-g8ed1b From ad8453ab0a5b98884074302ba3cc37664791e261 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 25 Aug 2010 13:26:32 +0100 Subject: ceph: Fix warnings Just scrubbing some warnings so I can see real problem ones in the build noise. For 32bit we need to coax gcc politely into believing we really honestly intend to the casts. Using (u64)(unsigned long) means we cast from a pointer to a type of the right size and then extend it. This stops the warning spew. Signed-off-by: Alan Cox Signed-off-by: Sage Weil --- fs/ceph/locks.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index ae85af06454f..ff4e753aae92 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c @@ -82,7 +82,8 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) length = fl->fl_end - fl->fl_start + 1; err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, - (u64)fl->fl_pid, (u64)fl->fl_nspid, + (u64)fl->fl_pid, + (u64)(unsigned long)fl->fl_nspid, lock_cmd, fl->fl_start, length, wait); if (!err) { @@ -92,7 +93,8 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) /* undo! This should only happen if the kernel detects * local deadlock. */ ceph_lock_message(CEPH_LOCK_FCNTL, op, file, - (u64)fl->fl_pid, (u64)fl->fl_nspid, + (u64)fl->fl_pid, + (u64)(unsigned long)fl->fl_nspid, CEPH_LOCK_UNLOCK, fl->fl_start, length, 0); dout("got %d on posix_lock_file, undid lock", err); @@ -132,7 +134,8 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) length = fl->fl_end - fl->fl_start + 1; err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, - file, (u64)fl->fl_pid, (u64)fl->fl_nspid, + file, (u64)fl->fl_pid, + (u64)(unsigned long)fl->fl_nspid, lock_cmd, fl->fl_start, length, wait); if (!err) { @@ -141,7 +144,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, file, (u64)fl->fl_pid, - (u64)fl->fl_nspid, + (u64)(unsigned long)fl->fl_nspid, CEPH_LOCK_UNLOCK, fl->fl_start, length, 0); dout("got %d on flock_lock_file_wait, undid lock", err); @@ -235,7 +238,8 @@ int lock_to_ceph_filelock(struct file_lock *lock, cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1); cephlock->client = cpu_to_le64(0); cephlock->pid = cpu_to_le64(lock->fl_pid); - cephlock->pid_namespace = cpu_to_le64((u64)lock->fl_nspid); + cephlock->pid_namespace = + cpu_to_le64((u64)(unsigned long)lock->fl_nspid); switch (lock->fl_type) { case F_RDLCK: -- cgit v1.2.3-59-g8ed1b From 6e63e80d88521a176989ed14b420f42dc418e46a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 25 Aug 2010 21:33:29 +0200 Subject: PCI hotplug: Fix build with CONFIG_ACPI unset One of the recent changes caused complilation of drivers/pci/hotplug/pciehp_core.c to fail. Fix this issue. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/pci/hotplug/pciehp.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 653de6ff8ac6..73d513989263 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -178,5 +178,9 @@ static inline void pciehp_firmware_init(void) } #else #define pciehp_firmware_init() do {} while (0) +static inline int pciehp_acpi_slot_detection_check(struct pci_dev *dev) +{ + return 0; +} #endif /* CONFIG_ACPI */ #endif /* _PCIEHP_H */ -- cgit v1.2.3-59-g8ed1b From aba8a08ded89a74f1ba04ae94ecc98f26e27d41c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 17 Aug 2010 14:13:42 +0200 Subject: pata_cmd64x: revert commit d62f5576 Commit d62f5576 (pata_cmd64x: fix handling of address setup timings) incorrectly called ata_timing_compute() on UDMA mode on 0 @UT leading to devide by zero fault. Revert it until better fix is available. This is reported in bko#16607 by Milan Kocian who also root caused it. https://bugzilla.kernel.org/show_bug.cgi?id=16607 Signed-off-by: Tejun Heo Reported-and-root-caused-by: Milan Kocian Cc: Bartlomiej Zolnierkiewicz Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/pata_cmd64x.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index 9f5da1c7454b..905ff76d3cbb 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -121,14 +121,8 @@ static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 m if (pair) { struct ata_timing tp; - ata_timing_compute(pair, pair->pio_mode, &tp, T, 0); ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); - if (pair->dma_mode) { - ata_timing_compute(pair, pair->dma_mode, - &tp, T, 0); - ata_timing_merge(&tp, &t, &t, ATA_TIMING_SETUP); - } } } -- cgit v1.2.3-59-g8ed1b From 6d981b9a91be29c0deae5ac794a4fe885027032f Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 25 Nov 2009 07:08:33 +0000 Subject: libata: remove no longer needed pata_winbond driver Winbond W83759A controller is fully supported by pata_legacy driver so remove no longer needed pata_winbond driver. Leave PATA_WINBOND_VLB config option for compatibility reasons and teach pata_legacy to preserve the old behavior of pata_winbond driver. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 1 + drivers/ata/Makefile | 1 - drivers/ata/pata_legacy.c | 15 ++- drivers/ata/pata_winbond.c | 282 --------------------------------------------- 4 files changed, 14 insertions(+), 285 deletions(-) delete mode 100644 drivers/ata/pata_winbond.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 65e3e2708371..11ec911016c6 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -828,6 +828,7 @@ config PATA_SAMSUNG_CF config PATA_WINBOND_VLB tristate "Winbond W83759A VLB PATA support (Experimental)" depends on ISA && EXPERIMENTAL + select PATA_LEGACY help Support for the Winbond W83759A controller on Vesa Local Bus systems. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 158eaa961b1e..d5df04a395ca 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -89,7 +89,6 @@ obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o -obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_PXA) += pata_pxa.o diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 9df1ff7e1eaa..eaf194138f21 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -44,6 +44,9 @@ * Specific support is included for the ht6560a/ht6560b/opti82c611a/ * opti82c465mv/promise 20230c/20630/qdi65x0/winbond83759A * + * Support for the Winbond 83759A when operating in advanced mode. + * Multichip mode is not currently supported. + * * Use the autospeed and pio_mask options with: * Appian ADI/2 aka CLPD7220 or AIC25VL01. * Use the jumpers, autospeed and set pio_mask to the mode on the jumpers with @@ -135,12 +138,18 @@ static int ht6560b; /* HT 6560A on primary 1, second 2, both 3 */ static int opti82c611a; /* Opti82c611A on primary 1, sec 2, both 3 */ static int opti82c46x; /* Opti 82c465MV present(pri/sec autodetect) */ static int qdi; /* Set to probe QDI controllers */ -static int winbond; /* Set to probe Winbond controllers, - give I/O port if non standard */ static int autospeed; /* Chip present which snoops speed changes */ static int pio_mask = ATA_PIO4; /* PIO range for autospeed devices */ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ +#ifdef PATA_WINBOND_VLB_MODULE +static int winbond = 1; /* Set to probe Winbond controllers, + give I/O port if non standard */ +#else +static int winbond; /* Set to probe Winbond controllers, + give I/O port if non standard */ +#endif + /** * legacy_probe_add - Add interface to probe list * @port: Controller port @@ -1297,6 +1306,7 @@ MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for legacy ATA"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +MODULE_ALIAS("pata_winbond"); module_param(probe_all, int, 0); module_param(autospeed, int, 0); @@ -1305,6 +1315,7 @@ module_param(ht6560b, int, 0); module_param(opti82c611a, int, 0); module_param(opti82c46x, int, 0); module_param(qdi, int, 0); +module_param(winbond, int, 0); module_param(pio_mask, int, 0); module_param(iordy_mask, int, 0); diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c deleted file mode 100644 index 6d8619b6f670..000000000000 --- a/drivers/ata/pata_winbond.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * pata_winbond.c - Winbond VLB ATA controllers - * (C) 2006 Red Hat - * - * Support for the Winbond 83759A when operating in advanced mode. - * Multichip mode is not currently supported. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "pata_winbond" -#define DRV_VERSION "0.0.3" - -#define NR_HOST 4 /* Two winbond controllers, two channels each */ - -struct winbond_data { - unsigned long config; - struct platform_device *platform_dev; -}; - -static struct ata_host *winbond_host[NR_HOST]; -static struct winbond_data winbond_data[NR_HOST]; -static int nr_winbond_host; - -#ifdef MODULE -static int probe_winbond = 1; -#else -static int probe_winbond; -#endif - -static DEFINE_SPINLOCK(winbond_lock); - -static void winbond_writecfg(unsigned long port, u8 reg, u8 val) -{ - unsigned long flags; - spin_lock_irqsave(&winbond_lock, flags); - outb(reg, port + 0x01); - outb(val, port + 0x02); - spin_unlock_irqrestore(&winbond_lock, flags); -} - -static u8 winbond_readcfg(unsigned long port, u8 reg) -{ - u8 val; - - unsigned long flags; - spin_lock_irqsave(&winbond_lock, flags); - outb(reg, port + 0x01); - val = inb(port + 0x02); - spin_unlock_irqrestore(&winbond_lock, flags); - - return val; -} - -static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct ata_timing t; - struct winbond_data *winbond = ap->host->private_data; - int active, recovery; - u8 reg; - int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); - - reg = winbond_readcfg(winbond->config, 0x81); - - /* Get the timing data in cycles */ - if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ - ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); - else - ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - - active = (clamp_val(t.active, 3, 17) - 1) & 0x0F; - recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F; - timing = (active << 4) | recovery; - winbond_writecfg(winbond->config, timing, reg); - - /* Load the setup timing */ - - reg = 0x35; - if (adev->class != ATA_DEV_ATA) - reg |= 0x08; /* FIFO off */ - if (!ata_pio_need_iordy(adev)) - reg |= 0x02; /* IORDY off */ - reg |= (clamp_val(t.setup, 0, 3) << 6); - winbond_writecfg(winbond->config, timing + 1, reg); -} - - -static unsigned int winbond_data_xfer(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw) -{ - struct ata_port *ap = dev->link->ap; - int slop = buflen & 3; - - if (ata_id_has_dword_io(dev->id)) { - if (rw == READ) - ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else - iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - - if (unlikely(slop)) { - __le32 pad; - if (rw == READ) { - pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); - memcpy(buf + buflen - slop, &pad, slop); - } else { - memcpy(&pad, buf + buflen - slop, slop); - iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); - } - buflen += 4 - slop; - } - } else - buflen = ata_sff_data_xfer(dev, buf, buflen, rw); - - return buflen; -} - -static struct scsi_host_template winbond_sht = { - ATA_PIO_SHT(DRV_NAME), -}; - -static struct ata_port_operations winbond_port_ops = { - .inherits = &ata_sff_port_ops, - .sff_data_xfer = winbond_data_xfer, - .cable_detect = ata_cable_40wire, - .set_piomode = winbond_set_piomode, -}; - -/** - * winbond_init_one - attach a winbond interface - * @type: Type to display - * @io: I/O port start - * @irq: interrupt line - * @fast: True if on a > 33Mhz VLB - * - * Register a VLB bus IDE interface. Such interfaces are PIO and we - * assume do not support IRQ sharing. - */ - -static __init int winbond_init_one(unsigned long port) -{ - struct platform_device *pdev; - u8 reg; - int i, rc; - - reg = winbond_readcfg(port, 0x81); - reg |= 0x80; /* jumpered mode off */ - winbond_writecfg(port, 0x81, reg); - reg = winbond_readcfg(port, 0x83); - reg |= 0xF0; /* local control */ - winbond_writecfg(port, 0x83, reg); - reg = winbond_readcfg(port, 0x85); - reg |= 0xF0; /* programmable timing */ - winbond_writecfg(port, 0x85, reg); - - reg = winbond_readcfg(port, 0x81); - - if (!(reg & 0x03)) /* Disabled */ - return -ENODEV; - - for (i = 0; i < 2 ; i ++) { - unsigned long cmd_port = 0x1F0 - (0x80 * i); - unsigned long ctl_port = cmd_port + 0x206; - struct ata_host *host; - struct ata_port *ap; - void __iomem *cmd_addr, *ctl_addr; - - if (!(reg & (1 << i))) - continue; - - pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - rc = -ENOMEM; - host = ata_host_alloc(&pdev->dev, 1); - if (!host) - goto err_unregister; - ap = host->ports[0]; - - rc = -ENOMEM; - cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); - ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1); - if (!cmd_addr || !ctl_addr) - goto err_unregister; - - ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port); - - ap->ops = &winbond_port_ops; - ap->pio_mask = ATA_PIO4; - ap->flags |= ATA_FLAG_SLAVE_POSS; - ap->ioaddr.cmd_addr = cmd_addr; - ap->ioaddr.altstatus_addr = ctl_addr; - ap->ioaddr.ctl_addr = ctl_addr; - ata_sff_std_ports(&ap->ioaddr); - - /* hook in a private data structure per channel */ - host->private_data = &winbond_data[nr_winbond_host]; - winbond_data[nr_winbond_host].config = port; - winbond_data[nr_winbond_host].platform_dev = pdev; - - /* activate */ - rc = ata_host_activate(host, 14 + i, ata_sff_interrupt, 0, - &winbond_sht); - if (rc) - goto err_unregister; - - winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev); - } - - return 0; - - err_unregister: - platform_device_unregister(pdev); - return rc; -} - -/** - * winbond_init - attach winbond interfaces - * - * Attach winbond IDE interfaces by scanning the ports it may occupy. - */ - -static __init int winbond_init(void) -{ - static const unsigned long config[2] = { 0x130, 0x1B0 }; - - int ct = 0; - int i; - - if (probe_winbond == 0) - return -ENODEV; - - /* - * Check both base addresses - */ - - for (i = 0; i < 2; i++) { - if (probe_winbond & (1< Date: Sat, 24 Jul 2010 16:53:48 +0200 Subject: ahci: add HFLAG_YES_FBS and apply it to 88SE9128 88SE9128 can do FBS and sets it in HOST_CAP but forgets to set FBSCP in PORT_CMD. Implement AHCI_HFLAG_YES_FBS and apply it to 88SE9128. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 11 +++++++++++ drivers/ata/ahci.h | 1 + drivers/ata/libahci.c | 16 ++++++++++++++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index fe75d8befc3a..013727b20417 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -60,6 +60,7 @@ enum board_ids { board_ahci, board_ahci_ign_iferr, board_ahci_nosntf, + board_ahci_yes_fbs, /* board IDs for specific chipsets in alphabetical order */ board_ahci_mcp65, @@ -132,6 +133,14 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_yes_fbs] = + { + AHCI_HFLAGS (AHCI_HFLAG_YES_FBS), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, /* by chipsets */ [board_ahci_mcp65] = { @@ -362,6 +371,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* Marvell */ { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */ { PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */ + { PCI_DEVICE(0x1b4b, 0x9123), + .driver_data = board_ahci_yes_fbs }, /* 88se9128 */ /* Promise */ { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 7113c5724471..474427b6f99f 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -209,6 +209,7 @@ enum { link offline */ AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */ AHCI_HFLAG_NO_FPDMA_AA = (1 << 13), /* no FPDMA AA */ + AHCI_HFLAG_YES_FBS = (1 << 14), /* force FBS cap on */ /* ap->flags bits */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 81e772a94d59..666850d31df2 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -430,6 +430,12 @@ void ahci_save_initial_config(struct device *dev, cap &= ~HOST_CAP_SNTF; } + if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) { + dev_printk(KERN_INFO, dev, + "controller can do FBS, turning on CAP_FBS\n"); + cap |= HOST_CAP_FBS; + } + if (force_port_map && port_map != force_port_map) { dev_printk(KERN_INFO, dev, "forcing port_map 0x%x -> 0x%x\n", port_map, force_port_map); @@ -2036,9 +2042,15 @@ static int ahci_port_start(struct ata_port *ap) u32 cmd = readl(port_mmio + PORT_CMD); if (cmd & PORT_CMD_FBSCP) pp->fbs_supported = true; - else + else if (hpriv->flags & AHCI_HFLAG_YES_FBS) { + dev_printk(KERN_INFO, dev, + "port %d can do FBS, forcing FBSCP\n", + ap->port_no); + pp->fbs_supported = true; + } else dev_printk(KERN_WARNING, dev, - "The port is not capable of FBS\n"); + "port %d is not capable of FBS\n", + ap->port_no); } if (pp->fbs_supported) { -- cgit v1.2.3-59-g8ed1b From d26377b83972917cfb8f5bee193981aaa1130627 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 21 Aug 2010 10:43:25 +0200 Subject: [libata] sata_dwc_460ex: signdness bug dma_dwc_xfer_setup() returns an int and "dma_chan" needs to be signed for the error handling to work. Signed-off-by: Dan Carpenter Signed-off-by: Jeff Garzik --- drivers/ata/sata_dwc_460ex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 2673a3d14806..6cf57c5c2b5f 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1459,7 +1459,7 @@ static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag) { struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; - u32 dma_chan; + int dma_chan; struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); int err; -- cgit v1.2.3-59-g8ed1b From 60f5d6ef6b6e70fe850554381fd8336f11530002 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Aug 2010 11:27:27 +0200 Subject: libata: be less of a drama queen on empty data commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ata_qc_issue() BUG_ON()s on data commands w/o data, which may be submitted via SG_IO. Be less of a drama queen and just trigger WARN_ON_ONCE() and fail the command with AC_ERR_SYSTEM. Signed-off-by: Tejun Heo Reported-by: Stefan Hübner Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7ef7c4f216fa..c035b3d041ee 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5111,15 +5111,18 @@ void ata_qc_issue(struct ata_queued_cmd *qc) qc->flags |= ATA_QCFLAG_ACTIVE; ap->qc_active |= 1 << qc->tag; - /* We guarantee to LLDs that they will have at least one + /* + * We guarantee to LLDs that they will have at least one * non-zero sg if the command is a data command. */ - BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes)); + if (WARN_ON_ONCE(ata_is_data(prot) && + (!qc->sg || !qc->n_elem || !qc->nbytes))) + goto sys_err; if (ata_is_dma(prot) || (ata_is_pio(prot) && (ap->flags & ATA_FLAG_PIO_DMA))) if (ata_sg_setup(qc)) - goto sg_err; + goto sys_err; /* if device is sleeping, schedule reset and abort the link */ if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) { @@ -5136,7 +5139,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) goto err; return; -sg_err: +sys_err: qc->err_mask |= AC_ERR_SYSTEM; err: ata_qc_complete(qc); -- cgit v1.2.3-59-g8ed1b From 44b733809a5aba7f6b15a548d31a56d25bf3851c Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Thu, 19 Aug 2010 21:40:44 -0400 Subject: sata_mv: fix broken DSM/TRIM support (v2) Fix DSM/TRIM commands in sata_mv (v2). These need to be issued using old-school "BM DMA", rather than via the EDMA host queue. Since the chips don't have proper BM DMA status, we need to be more careful with setting the ATA_DMA_INTR bit, since DSM/TRIM often has a long delay between "DMA complete" and "command complete". GEN_I chips don't have BM DMA, so no TRIM for them. Signed-off-by: Mark Lord Signed-off-by: Jeff Garzik Cc: stable@kernel.org --- drivers/ata/sata_mv.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 9463c71dd38e..81982594a014 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1898,19 +1898,25 @@ static void mv_bmdma_start(struct ata_queued_cmd *qc) * LOCKING: * Inherited from caller. */ -static void mv_bmdma_stop(struct ata_queued_cmd *qc) +static void mv_bmdma_stop_ap(struct ata_port *ap) { - struct ata_port *ap = qc->ap; void __iomem *port_mmio = mv_ap_base(ap); u32 cmd; /* clear start/stop bit */ cmd = readl(port_mmio + BMDMA_CMD); - cmd &= ~ATA_DMA_START; - writelfl(cmd, port_mmio + BMDMA_CMD); + if (cmd & ATA_DMA_START) { + cmd &= ~ATA_DMA_START; + writelfl(cmd, port_mmio + BMDMA_CMD); + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_sff_dma_pause(ap); + } +} - /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_sff_dma_pause(ap); +static void mv_bmdma_stop(struct ata_queued_cmd *qc) +{ + mv_bmdma_stop_ap(qc->ap); } /** @@ -1934,8 +1940,21 @@ static u8 mv_bmdma_status(struct ata_port *ap) reg = readl(port_mmio + BMDMA_STATUS); if (reg & ATA_DMA_ACTIVE) status = ATA_DMA_ACTIVE; - else + else if (reg & ATA_DMA_ERR) status = (reg & ATA_DMA_ERR) | ATA_DMA_INTR; + else { + /* + * Just because DMA_ACTIVE is 0 (DMA completed), + * this does _not_ mean the device is "done". + * So we should not yet be signalling ATA_DMA_INTR + * in some cases. Eg. DSM/TRIM, and perhaps others. + */ + mv_bmdma_stop_ap(ap); + if (ioread8(ap->ioaddr.altstatus_addr) & ATA_BUSY) + status = 0; + else + status = ATA_DMA_INTR; + } return status; } @@ -1995,6 +2014,9 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) switch (tf->protocol) { case ATA_PROT_DMA: + if (tf->command == ATA_CMD_DSM) + return; + /* fall-thru */ case ATA_PROT_NCQ: break; /* continue below */ case ATA_PROT_PIO: @@ -2094,6 +2116,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc) if ((tf->protocol != ATA_PROT_DMA) && (tf->protocol != ATA_PROT_NCQ)) return; + if (tf->command == ATA_CMD_DSM) + return; /* use bmdma for this */ /* Fill in Gen IIE command request block */ if (!(tf->flags & ATA_TFLAG_WRITE)) @@ -2289,6 +2313,12 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATA_PROT_DMA: + if (qc->tf.command == ATA_CMD_DSM) { + if (!ap->ops->bmdma_setup) /* no bmdma on GEN_I */ + return AC_ERR_OTHER; + break; /* use bmdma for this */ + } + /* fall thru */ case ATA_PROT_NCQ: mv_start_edma(ap, port_mmio, pp, qc->tf.protocol); pp->req_idx = (pp->req_idx + 1) & MV_MAX_Q_DEPTH_MASK; -- cgit v1.2.3-59-g8ed1b From 55ee67f837882f28a900705a2ca1af257ab6c53d Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Fri, 20 Aug 2010 10:13:16 -0400 Subject: libata-sff: remove harmful BUG_ON from ata_bmdma_qc_issue Remove harmful BUG_ON() from ata_bmdma_qc_issue(), as it casts too wide of a net and breaks sata_mv. It also crashes the kernel while doing the BUG_ON(). There's already a WARN_ON_ONCE() further down to catch the case of POLLING for a BMDMA operation. Signed-off-by: Mark Lord Signed-off-by: Jeff Garzik Cc: stable@kernel.org --- drivers/ata/libata-sff.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 674c1436491f..3b82d8ef76f0 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2735,10 +2735,6 @@ unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - /* see ata_dma_blacklisted() */ - BUG_ON((ap->flags & ATA_FLAG_PIO_POLLING) && - qc->tf.protocol == ATAPI_PROT_DMA); - /* defer PIO handling to sff_qc_issue */ if (!ata_is_dma(qc->tf.protocol)) return ata_sff_qc_issue(qc); -- cgit v1.2.3-59-g8ed1b From c89e5198b26a869ce2842bad8519264f3394dee9 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 26 Aug 2010 02:11:54 +0000 Subject: [CIFS] Eliminate unused variable warning CC: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/sess.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 4788e16a02cc..795095f4eac6 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -620,7 +620,6 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, struct key *spnego_key = NULL; __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ bool first_time; - char *ntlmsspblob; if (ses == NULL) return -EINVAL; @@ -868,6 +867,8 @@ ssetup_ntlmssp_authenticate: iov[1].iov_base = &pSMB->req.SecurityBlob[0]; } else if (phase == NtLmAuthenticate) { int blob_len; + char *ntlmsspblob; + ntlmsspblob = kmalloc(5 * sizeof(struct _AUTHENTICATE_MESSAGE), GFP_KERNEL); -- cgit v1.2.3-59-g8ed1b From 44a1246f320312b84134a962caf3bf6af989e193 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 17 Aug 2010 14:34:00 +1000 Subject: drm/nv50: add dcb type 14 to enum to prevent compiler complaint Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bios.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e4f33a4edea1..e10d851a7240 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6153,7 +6153,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; break; - case 0xe: + case OUTPUT_EOL: /* weird g80 mobile type that "nv" treats as a terminator */ dcb->entries--; return false; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index fd14dfd3d780..c1de2f3fcb0e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -95,6 +95,7 @@ enum dcb_type { OUTPUT_TMDS = 2, OUTPUT_LVDS = 3, OUTPUT_DP = 6, + OUTPUT_EOL = 14, /* DCB 4.0+, appears to be end-of-list */ OUTPUT_ANY = -1 }; -- cgit v1.2.3-59-g8ed1b From acae116ce16833859eb4eb929de571b9a800d685 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 15 Aug 2010 14:31:31 +0200 Subject: drm/nouveau: Use a helper function to match PCI device/subsystem IDs. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 17 ++++------------- drivers/gpu/drm/nouveau/nouveau_drv.h | 9 +++++++++ drivers/gpu/drm/nouveau/nv17_tv.c | 10 +++------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e10d851a7240..b54597f6eadf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -4381,11 +4381,8 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b * * For the moment, a quirk will do :) */ - if ((dev->pdev->device == 0x01d7) && - (dev->pdev->subsystem_vendor == 0x1028) && - (dev->pdev->subsystem_device == 0x01c2)) { + if (nv_match_device(dev, 0x01d7, 0x1028, 0x01c2)) bios->fp.duallink_transition_clk = 80000; - } /* set dual_link flag for EDID case */ if (pxclk && (chip_version < 0x25 || chip_version > 0x28)) @@ -5814,9 +5811,7 @@ parse_dcb_gpio_table(struct nvbios *bios) */ /* Apple iMac G4 NV18 */ - if (dev->pdev->device == 0x0189 && - dev->pdev->subsystem_vendor == 0x10de && - dev->pdev->subsystem_device == 0x0010) { + if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) { struct dcb_gpio_entry *gpio = new_gpio_entry(bios); gpio->tag = DCB_GPIO_TVDAC0; @@ -5898,9 +5893,7 @@ apply_dcb_connector_quirks(struct nvbios *bios, int idx) struct drm_device *dev = bios->dev; /* Gigabyte NX85T */ - if ((dev->pdev->device == 0x0421) && - (dev->pdev->subsystem_vendor == 0x1458) && - (dev->pdev->subsystem_device == 0x344c)) { + if (nv_match_device(dev, 0x0421, 0x1458, 0x344c)) { if (cte->type == DCB_CONNECTOR_HDMI_1) cte->type = DCB_CONNECTOR_DVI_I; } @@ -6321,9 +6314,7 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) * nasty problems until this is sorted (assuming it's not a * VBIOS bug). */ - if ((dev->pdev->device == 0x040d) && - (dev->pdev->subsystem_vendor == 0x1028) && - (dev->pdev->subsystem_device == 0x019b)) { + if (nv_match_device(dev, 0x040d, 0x1028, 0x019b)) { if (*conn == 0x02026312 && *conf == 0x00000020) return false; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1e093a069b7b..b1be617373b6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1389,6 +1389,15 @@ nv_two_reg_pll(struct drm_device *dev) return false; } +static inline bool +nv_match_device(struct drm_device *dev, unsigned device, + unsigned sub_vendor, unsigned sub_device) +{ + return dev->pdev->device == device && + dev->pdev->subsystem_vendor == sub_vendor && + dev->pdev->subsystem_device == sub_device; +} + #define NV_SW 0x0000506e #define NV_SW_DMA_SEMAPHORE 0x00000060 #define NV_SW_SEMAPHORE_OFFSET 0x00000064 diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index eefa5c856932..13cdc05b7c2d 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -121,18 +121,14 @@ static bool get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) { /* Zotac FX5200 */ - if (dev->pdev->device == 0x0322 && - dev->pdev->subsystem_vendor == 0x19da && - (dev->pdev->subsystem_device == 0x1035 || - dev->pdev->subsystem_device == 0x2035)) { + if (nv_match_device(dev, 0x0322, 0x19da, 0x1035) || + nv_match_device(dev, 0x0322, 0x19da, 0x2035)) { *pin_mask = 0xc; return false; } /* MSI nForce2 IGP */ - if (dev->pdev->device == 0x01f0 && - dev->pdev->subsystem_vendor == 0x1462 && - dev->pdev->subsystem_device == 0x5710) { + if (nv_match_device(dev, 0x01f0, 0x1462, 0x5710)) { *pin_mask = 0xc; return false; } -- cgit v1.2.3-59-g8ed1b From f5cb8ab1541390d5ac3bb906f81c4300d0fdb574 Mon Sep 17 00:00:00 2001 From: Patrice Mandin Date: Wed, 18 Aug 2010 16:07:34 +0200 Subject: drm/nv30: Apply modesetting to the correct slave encoder Signed-off-by: Patrice Mandin Reviewed-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_dfp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index a5dcf7685800..ea89f6e69d4c 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -444,6 +444,7 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct dcb_entry *dcbe = nv_encoder->dcb; int head = nouveau_crtc(encoder->crtc)->index; + struct drm_encoder *slave_encoder; if (dcbe->type == OUTPUT_TMDS) run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock); @@ -462,9 +463,10 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); /* Init external transmitters */ - if (get_tmds_slave(encoder)) - get_slave_funcs(get_tmds_slave(encoder))->mode_set( - encoder, &nv_encoder->mode, &nv_encoder->mode); + slave_encoder = get_tmds_slave(encoder); + if (slave_encoder) + get_slave_funcs(slave_encoder)->mode_set( + slave_encoder, &nv_encoder->mode, &nv_encoder->mode); helper->dpms(encoder, DRM_MODE_DPMS_ON); -- cgit v1.2.3-59-g8ed1b From d31e078d847fb2816d26c9476f4a68e89dc65a0b Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 20 Aug 2010 14:19:45 +0200 Subject: drm/nouveau: Fix backlight control on PPC machines with an internal TMDS panel. This commit fixes fdo bug 29685. Reported-by: Vlado Plaga Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 25 ++++--------------------- drivers/gpu/drm/nouveau/nv04_dfp.c | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index b54597f6eadf..f6c615b228d4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -3869,27 +3869,10 @@ static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entr } #ifdef __powerpc__ /* Powerbook specific quirks */ - if ((dev->pci_device & 0xffff) == 0x0179 || - (dev->pci_device & 0xffff) == 0x0189 || - (dev->pci_device & 0xffff) == 0x0329) { - if (script == LVDS_RESET) { - nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); - - } else if (script == LVDS_PANEL_ON) { - bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, - bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) - | (1 << 31)); - bios_wr32(bios, NV_PCRTC_GPIO_EXT, - bios_rd32(bios, NV_PCRTC_GPIO_EXT) | 1); - - } else if (script == LVDS_PANEL_OFF) { - bios_wr32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL, - bios_rd32(bios, NV_PBUS_DEBUG_DUALHEAD_CTL) - & ~(1 << 31)); - bios_wr32(bios, NV_PCRTC_GPIO_EXT, - bios_rd32(bios, NV_PCRTC_GPIO_EXT) & ~3); - } - } + if (script == LVDS_RESET && + (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 || + dev->pci_device == 0x0329)) + nv_write_tmds(dev, dcbent->or, 0, 0x02, 0x72); #endif return 0; diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index ea89f6e69d4c..0d3206a7046c 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -475,6 +475,27 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); } +static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) +{ +#ifdef __powerpc__ + struct drm_device *dev = encoder->dev; + + /* BIOS scripts usually take care of the backlight, thanks + * Apple for your consistency. + */ + if (dev->pci_device == 0x0179 || dev->pci_device == 0x0189 || + dev->pci_device == 0x0329) { + if (mode == DRM_MODE_DPMS_ON) { + nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 0, 1 << 31); + nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 1); + } else { + nv_mask(dev, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0); + nv_mask(dev, NV_PCRTC_GPIO_EXT, 3, 0); + } + } +#endif +} + static inline bool is_powersaving_dpms(int mode) { return (mode != DRM_MODE_DPMS_ON); @@ -522,6 +543,7 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) LVDS_PANEL_OFF, 0); } + nv04_dfp_update_backlight(encoder, mode); nv04_dfp_update_fp_control(encoder, mode); if (mode == DRM_MODE_DPMS_ON) @@ -545,6 +567,7 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode) NV_INFO(dev, "Setting dpms mode %d on tmds encoder (output %d)\n", mode, nv_encoder->dcb->index); + nv04_dfp_update_backlight(encoder, mode); nv04_dfp_update_fp_control(encoder, mode); } -- cgit v1.2.3-59-g8ed1b From fba675283429e41270feb661a1f6f3bc05d71981 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 24 Aug 2010 23:02:02 +0200 Subject: drm/nouveau: Fix TMDS on some DCB1.5 boards. The TMDS output of an nv11 was being detected as LVDS, because it uses DCB type 2 for TMDS instead of type 4. Reported-by: Bertrand VIEILLE Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index f6c615b228d4..974b0f8ae048 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6166,22 +6166,14 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, entry->type = OUTPUT_TV; break; case 2: - case 3: - entry->type = OUTPUT_LVDS; - break; case 4: - switch ((conn & 0x000000f0) >> 4) { - case 0: - entry->type = OUTPUT_TMDS; - break; - case 1: + if (conn & 0x10) entry->type = OUTPUT_LVDS; - break; - default: - NV_ERROR(dev, "Unknown DCB subtype 4/%d\n", - (conn & 0x000000f0) >> 4); - return false; - } + else + entry->type = OUTPUT_TMDS; + break; + case 3: + entry->type = OUTPUT_LVDS; break; default: NV_ERROR(dev, "Unknown DCB type %d\n", conn & 0x0000000f); -- cgit v1.2.3-59-g8ed1b From ee508b821c2042fb852a078e594bd36606973780 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Wed, 25 Aug 2010 12:54:53 +0200 Subject: drm/nv20: Don't use pushbuf calls on the original nv20. The "return" command is buggy on the original nv20, it jumps back to the caller address as expected, but it doesn't clear the subroutine active bit making the subsequent pushbuf calls fail with a "stack" overflow. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index a915dcdd9a49..613f878e6d0f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -663,7 +663,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, push[i].length); } } else - if (dev_priv->card_type >= NV_20) { + if (dev_priv->chipset >= 0x25) { ret = RING_SPACE(chan, req->nr_push * 2); if (ret) { NV_ERROR(dev, "cal_space: %d\n", ret); @@ -738,7 +738,7 @@ out_next: req->suffix0 = 0x00000000; req->suffix1 = 0x00000000; } else - if (dev_priv->card_type >= NV_20) { + if (dev_priv->chipset >= 0x25) { req->suffix0 = 0x00020000; req->suffix1 = 0x00000000; } else { -- cgit v1.2.3-59-g8ed1b From c5ed63d66f24fd4f7089b5a6e087b0ce7202aa8e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 Aug 2010 23:02:17 -0700 Subject: tcp: fix three tcp sysctls tuning As discovered by Anton Blanchard, current code to autotune tcp_death_row.sysctl_max_tw_buckets, sysctl_tcp_max_orphans and sysctl_max_syn_backlog makes little sense. The bigger a page is, the less tcp_max_orphans is : 4096 on a 512GB machine in Anton's case. (tcp_hashinfo.bhash_size * sizeof(struct inet_bind_hashbucket)) is much bigger if spinlock debugging is on. Its wrong to select bigger limits in this case (where kernel structures are also bigger) bhash_size max is 65536, and we get this value even for small machines. A better ground is to use size of ehash table, this also makes code shorter and more obvious. Based on a patch from Anton, and another from David. Reported-and-tested-by: Anton Blanchard Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 197b9b77fa3e..e2add5ff9cb1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3209,7 +3209,7 @@ void __init tcp_init(void) { struct sk_buff *skb = NULL; unsigned long nr_pages, limit; - int order, i, max_share; + int i, max_share, cnt; unsigned long jiffy = jiffies; BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); @@ -3258,22 +3258,12 @@ void __init tcp_init(void) INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain); } - /* Try to be a bit smarter and adjust defaults depending - * on available memory. - */ - for (order = 0; ((1 << order) << PAGE_SHIFT) < - (tcp_hashinfo.bhash_size * sizeof(struct inet_bind_hashbucket)); - order++) - ; - if (order >= 4) { - tcp_death_row.sysctl_max_tw_buckets = 180000; - sysctl_tcp_max_orphans = 4096 << (order - 4); - sysctl_max_syn_backlog = 1024; - } else if (order < 3) { - tcp_death_row.sysctl_max_tw_buckets >>= (3 - order); - sysctl_tcp_max_orphans >>= (3 - order); - sysctl_max_syn_backlog = 128; - } + + cnt = tcp_hashinfo.ehash_mask + 1; + + tcp_death_row.sysctl_max_tw_buckets = cnt / 2; + sysctl_tcp_max_orphans = cnt / 2; + sysctl_max_syn_backlog = max(128, cnt / 256); /* Set the pressure threshold to be a fraction of global memory that * is up to 1/2 at 256 MB, decreasing toward zero with the amount of -- cgit v1.2.3-59-g8ed1b From d84ba638e4ba3c40023ff997aa5e8d3ed002af36 Mon Sep 17 00:00:00 2001 From: KOSAKI Motohiro Date: Tue, 24 Aug 2010 16:05:48 +0000 Subject: tcp: select(writefds) don't hang up when a peer close connection This issue come from ruby language community. Below test program hang up when only run on Linux. % uname -mrsv Linux 2.6.26-2-486 #1 Sat Dec 26 08:37:39 UTC 2009 i686 % ruby -rsocket -ve ' BasicSocket.do_not_reverse_lookup = true serv = TCPServer.open("127.0.0.1", 0) s1 = TCPSocket.open("127.0.0.1", serv.addr[1]) s2 = serv.accept s2.close s1.write("a") rescue p $! s1.write("a") rescue p $! Thread.new { s1.write("a") }.join' ruby 1.9.3dev (2010-07-06 trunk 28554) [i686-linux] # [Hang Here] FreeBSD, Solaris, Mac doesn't. because Ruby's write() method call select() internally. and tcp_poll has a bug. SUS defined 'ready for writing' of select() as following. | A descriptor shall be considered ready for writing when a call to an output | function with O_NONBLOCK clear would not block, whether or not the function | would transfer data successfully. That said, EPIPE situation is clearly one of 'ready for writing'. We don't have read-side issue because tcp_poll() already has read side shutdown care. | if (sk->sk_shutdown & RCV_SHUTDOWN) | mask |= POLLIN | POLLRDNORM | POLLRDHUP; So, Let's insert same logic in write side. - reference url http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/31065 http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/31068 Signed-off-by: KOSAKI Motohiro Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e2add5ff9cb1..3fb1428e526e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -451,7 +451,8 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) mask |= POLLOUT | POLLWRNORM; } - } + } else + mask |= POLLOUT | POLLWRNORM; if (tp->urg_data & TCP_URG_VALID) mask |= POLLPRI; -- cgit v1.2.3-59-g8ed1b From dbbcbc073ad3132bfbc410b11546b2fb4bdf2568 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 23 Aug 2010 08:14:35 +0200 Subject: ALSA: hda - Add Sony VAIO quirk for ALC269 The attached patch enables playback on a Sony VAIO machine. BugLink: http://launchpad.net/bugs/618271 Signed-off-by: David Henningsson Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a4dd04524e43..627bf9963368 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14467,6 +14467,7 @@ static const struct alc_fixup alc269_fixups[] = { static struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), {} }; -- cgit v1.2.3-59-g8ed1b From 37b7370a8d439f6cab51ccf5d5cb41d0fb544fd1 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 24 Aug 2010 18:21:42 +0200 Subject: amd64_edac: Do not report error overflow as a separate error When the Overflow MCi_STATUS bit is set, EDAC reports the lost error with a "no information available" message which often puzzles users parsing the dmesg. This doesn't make much sense since this error has been lost anyway so no need for reporting it separately. Thus, report the overflow bit setting in the MCE dump instead. While at it, remove reporting of MiscV and ErrorEnable (en) which are superfluous. Now it looks like this: [ 1501.650024] MC4_STATUS: Corrected error, other errors lost: yes, CPU context corrupt: no, CECC Error [ 1501.666887] Northbridge Error, node 2 Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 10 ---------- drivers/edac/edac_mce_amd.c | 5 ++--- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 670239ab7511..e7d5d6b5dcf6 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2071,16 +2071,6 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, amd64_handle_ce(mci, info); else if (ecc_type == 1) amd64_handle_ue(mci, info); - - /* - * If main error is CE then overflow must be CE. If main error is UE - * then overflow is unknown. We'll call the overflow a CE - if - * panic_on_ue is set then we're already panic'ed and won't arrive - * here. Else, then apparently someone doesn't think that UE's are - * catastrophic. - */ - if (info->nbsh & K8_NBSH_OVERFLOW) - edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR " Error Overflow"); } void amd64_decode_bus_error(int node_id, struct err_regs *regs) diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 352dcc6c8971..9014df6f605d 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c @@ -365,11 +365,10 @@ static int amd_decode_mce(struct notifier_block *nb, unsigned long val, pr_emerg("MC%d_STATUS: ", m->bank); - pr_cont("%sorrected error, report: %s, MiscV: %svalid, " + pr_cont("%sorrected error, other errors lost: %s, " "CPU context corrupt: %s", ((m->status & MCI_STATUS_UC) ? "Unc" : "C"), - ((m->status & MCI_STATUS_EN) ? "yes" : "no"), - ((m->status & MCI_STATUS_MISCV) ? "" : "in"), + ((m->status & MCI_STATUS_OVER) ? "yes" : "no"), ((m->status & MCI_STATUS_PCC) ? "yes" : "no")); /* do the two bits[14:13] together */ -- cgit v1.2.3-59-g8ed1b From f44c3890d9fd6e4284518ff3bb16879fee194a3a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 26 Aug 2010 11:07:24 +0200 Subject: ceph: ceph_mdsc_build_path() returns an ERR_PTR ceph_mdsc_build_path() returns an ERR_PTR but this code is set up to handle NULL returns. Signed-off-by: Dan Carpenter Signed-off-by: Sage Weil --- fs/ceph/debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index 360c4f22718d..6fd8b20a8611 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c @@ -171,6 +171,8 @@ static int mdsc_show(struct seq_file *s, void *p) } else if (req->r_dentry) { path = ceph_mdsc_build_path(req->r_dentry, &pathlen, &pathbase, 0); + if (IS_ERR(path)) + path = NULL; spin_lock(&req->r_dentry->d_lock); seq_printf(s, " #%llx/%.*s (%s)", ceph_ino(req->r_dentry->d_parent->d_inode), @@ -187,6 +189,8 @@ static int mdsc_show(struct seq_file *s, void *p) if (req->r_old_dentry) { path = ceph_mdsc_build_path(req->r_old_dentry, &pathlen, &pathbase, 0); + if (IS_ERR(path)) + path = NULL; spin_lock(&req->r_old_dentry->d_lock); seq_printf(s, " #%llx/%.*s (%s)", ceph_ino(req->r_old_dentry->d_parent->d_inode), -- cgit v1.2.3-59-g8ed1b From e072f8aa3587710cd35cce0f6b6efd7b4276c327 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 26 Aug 2010 09:26:37 -0700 Subject: ceph: don't BUG on ENOMEM during mds reconnect We are in a position to return an error; do that instead. Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 8d1f11c7a5a2..f091b1351786 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2324,7 +2324,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, path = ceph_mdsc_build_path(dentry, &pathlen, &pathbase, 0); if (IS_ERR(path)) { err = PTR_ERR(path); - BUG_ON(err); + goto out_dput; } } else { path = NULL; @@ -2332,7 +2332,7 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, } err = ceph_pagelist_encode_string(pagelist, path, pathlen); if (err) - goto out; + goto out_free; spin_lock(&inode->i_lock); cap->seq = 0; /* reset cap seq */ @@ -2376,8 +2376,9 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, unlock_kernel(); } -out: +out_free: kfree(path); +out_dput: dput(dentry); return err; } -- cgit v1.2.3-59-g8ed1b From b545787dbb00a041c541a4759d938ddb0108295a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 26 Aug 2010 11:12:38 +0200 Subject: ceph: fix get_ticket_handler() error handling get_ticket_handler() returns a valid pointer or it returns ERR_PTR(-ENOMEM) if kzalloc() fails. Signed-off-by: Dan Carpenter Signed-off-by: Sage Weil --- fs/ceph/auth_x.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/ceph/auth_x.c b/fs/ceph/auth_x.c index 582e0b2caf8a..a2d002cbdec2 100644 --- a/fs/ceph/auth_x.c +++ b/fs/ceph/auth_x.c @@ -376,7 +376,7 @@ static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed) th = get_ticket_handler(ac, service); - if (!th) { + if (IS_ERR(th)) { *pneed |= service; continue; } @@ -399,6 +399,9 @@ static int ceph_x_build_request(struct ceph_auth_client *ac, struct ceph_x_ticket_handler *th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); + if (IS_ERR(th)) + return PTR_ERR(th); + ceph_x_validate_tickets(ac, &need); dout("build_request want %x have %x need %x\n", @@ -450,7 +453,6 @@ static int ceph_x_build_request(struct ceph_auth_client *ac, return -ERANGE; head->op = cpu_to_le16(CEPHX_GET_PRINCIPAL_SESSION_KEY); - BUG_ON(!th); ret = ceph_x_build_authorizer(ac, th, &xi->auth_authorizer); if (ret) return ret; @@ -505,7 +507,8 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, case CEPHX_GET_PRINCIPAL_SESSION_KEY: th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); - BUG_ON(!th); + if (IS_ERR(th)) + return PTR_ERR(th); ret = ceph_x_proc_ticket_reply(ac, &th->session_key, buf + sizeof(*head), end); break; @@ -563,8 +566,8 @@ static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, void *end = p + sizeof(au->reply_buf); th = get_ticket_handler(ac, au->service); - if (!th) - return -EIO; /* hrm! */ + if (IS_ERR(th)) + return PTR_ERR(th); ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply)); if (ret < 0) return ret; @@ -626,7 +629,7 @@ static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac, struct ceph_x_ticket_handler *th; th = get_ticket_handler(ac, peer_type); - if (th && !IS_ERR(th)) + if (!IS_ERR(th)) remove_ticket_handler(ac, th); } -- cgit v1.2.3-59-g8ed1b From f0138a79d74e1e942970ea163be268cd2e4bbcfc Mon Sep 17 00:00:00 2001 From: Suresh Jayaraman Date: Thu, 26 Aug 2010 14:46:09 +0530 Subject: Cannot allocate memory error on mount MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 08/26/2010 01:56 AM, joe hefner wrote: > On a recent Fedora (13), I am seeing a mount failure message that I can not explain. I have a Windows Server 2003ýa with a share set up for access only for a specific username (say userfoo). If I try to mount it from Linux,ýusing userfoo and the correct password all is well. If I try with a bad password or with some other username (userbar), it fails with "Permission denied" as expected. If I try to mount as username = administrator, and give the correct administrator password, I would also expect "Permission denied", but I see "Cannot allocate memory" instead. > ýfs/cifs/netmisc.c: Mapping smb error code 5 to POSIX err -13 > ýfs/cifs/cifssmb.c: Send error in QPathInfo = -13 > ýCIFS VFS: cifs_read_super: get root inode failed Looks like the commit 0b8f18e3 assumed that cifs_get_inode_info() and friends fail only due to memory allocation error when the inode is NULL which is not the case if CIFSSMBQPathInfo() fails and returns an error. Fix this by propagating the actual error code back. Acked-by: Jeff Layton Signed-off-by: Suresh Jayaraman Signed-off-by: Steve French --- fs/cifs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 4bc47e5b5f29..86a164f08a74 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -834,7 +834,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) xid, NULL); if (!inode) - return ERR_PTR(-ENOMEM); + return ERR_PTR(rc); #ifdef CONFIG_CIFS_FSCACHE /* populate tcon->resource_id */ -- cgit v1.2.3-59-g8ed1b From 30c0e1ef0a8a6cab4e0f9357698c81a2f7f73cc5 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 17 Aug 2010 18:46:33 -0400 Subject: nfsd4: bad BUG() in preprocess_stateid_op It's OK for this function to return without setting filp--we do it in the special-stateid case. And there's a legitimate case where we can hit this, since we do permit reads on write-only stateid's. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0a024917f052..b990eadb799c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2983,7 +2983,6 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, *filpp = find_readable_file(stp->st_file); else *filpp = find_writeable_file(stp->st_file); - BUG_ON(!*filpp); /* assured by check_openmode */ } } status = nfs_ok; -- cgit v1.2.3-59-g8ed1b From 18608ad49cffa430cfd0b4e027dedfe3114f916e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 20 Aug 2010 18:06:26 -0400 Subject: nfsd4: typo fix in find_any_file Signed-off-by: J. Bruce Fields --- fs/nfsd/state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 7731a75971dd..84579c86b13d 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -379,7 +379,7 @@ static inline struct file *find_any_file(struct nfs4_file *f) { if (f->fi_fds[O_RDWR]) return f->fi_fds[O_RDWR]; - else if (f->fi_fds[O_RDWR]) + else if (f->fi_fds[O_WRONLY]) return f->fi_fds[O_WRONLY]; else return f->fi_fds[O_RDONLY]; -- cgit v1.2.3-59-g8ed1b From 7d94784293096c0a46897acdb83be5abd9278ece Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 20 Aug 2010 18:09:31 -0400 Subject: nfsd4: fix downgrade/lock logic If we already had a RW open for a file, and get a readonly open, we were piggybacking on the existing RW open. That's inconsistent with the downgrade logic which blows away the RW open assuming you'll still have a readonly open. Also, make sure there is a readonly or writeonly open available for locking, again to prevent bad behavior in downgrade cases when any RW open may be lost. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 25 +++++++++++++++---------- fs/nfsd/state.h | 12 ++++++------ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b990eadb799c..69b266db7f5c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2450,14 +2450,13 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, static __be32 nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) { - u32 op_share_access, new_access; + u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; + bool new_access; __be32 status; - set_access(&new_access, stp->st_access_bmap); - new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; - + new_access = !test_bit(op_share_access, &stp->st_access_bmap); if (new_access) { - status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access); + status = nfs4_get_vfs_file(rqstp, fp, cur_fh, op_share_access); if (status) return status; } @@ -2470,7 +2469,6 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c return status; } /* remember the open */ - op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; __set_bit(op_share_access, &stp->st_access_bmap); __set_bit(open->op_share_deny, &stp->st_deny_bmap); @@ -3560,7 +3558,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_stateowner *open_sop = NULL; struct nfs4_stateowner *lock_sop = NULL; struct nfs4_stateid *lock_stp; - struct file *filp; + struct nfs4_file *fp; + struct file *filp = NULL; struct file_lock file_lock; struct file_lock conflock; __be32 status = 0; @@ -3590,7 +3589,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * lock stateid. */ struct nfs4_stateid *open_stp = NULL; - struct nfs4_file *fp; status = nfserr_stale_clientid; if (!nfsd4_has_session(cstate) && @@ -3633,6 +3631,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (status) goto out; lock_sop = lock->lk_replay_owner; + fp = lock_stp->st_file; } /* lock->lk_replay_owner and lock_stp have been created or found */ @@ -3647,13 +3646,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, switch (lock->lk_type) { case NFS4_READ_LT: case NFS4_READW_LT: - filp = find_readable_file(lock_stp->st_file); + if (find_readable_file(lock_stp->st_file)) { + nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_READ); + filp = find_readable_file(lock_stp->st_file); + } file_lock.fl_type = F_RDLCK; cmd = F_SETLK; break; case NFS4_WRITE_LT: case NFS4_WRITEW_LT: - filp = find_writeable_file(lock_stp->st_file); + if (find_writeable_file(lock_stp->st_file)) { + nfs4_get_vfs_file(rqstp, fp, &cstate->current_fh, NFS4_SHARE_ACCESS_WRITE); + filp = find_writeable_file(lock_stp->st_file); + } file_lock.fl_type = F_WRLCK; cmd = F_SETLK; break; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 84579c86b13d..322518c88e4b 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -363,16 +363,16 @@ struct nfs4_file { * at all? */ static inline struct file *find_writeable_file(struct nfs4_file *f) { - if (f->fi_fds[O_RDWR]) - return f->fi_fds[O_RDWR]; - return f->fi_fds[O_WRONLY]; + if (f->fi_fds[O_WRONLY]) + return f->fi_fds[O_WRONLY]; + return f->fi_fds[O_RDWR]; } static inline struct file *find_readable_file(struct nfs4_file *f) { - if (f->fi_fds[O_RDWR]) - return f->fi_fds[O_RDWR]; - return f->fi_fds[O_RDONLY]; + if (f->fi_fds[O_RDONLY]) + return f->fi_fds[O_RDONLY]; + return f->fi_fds[O_RDWR]; } static inline struct file *find_any_file(struct nfs4_file *f) -- cgit v1.2.3-59-g8ed1b From f6360efb83cd6dd1476cd758834c8277508c1f15 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Aug 2010 15:53:49 +0200 Subject: nfsd: fix NULL dereference in nfsd_statfs() The commit ebabe9a9001af0af56c0c2780ca1576246e7a74b pass a struct path to vfs_statfs introduced the struct path initialization, and this seems to trigger an Oops on my machine. fh_dentry field may be NULL and set later in fh_verify(), thus the initialization of path must be after fh_verify(). Signed-off-by: Takashi Iwai Reviewed-by: Christoph Hellwig Reviewed-by: Minchan Kim Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 96360a83cb91..661a6cf8e826 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -2033,15 +2033,17 @@ out: __be32 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access) { - struct path path = { - .mnt = fhp->fh_export->ex_path.mnt, - .dentry = fhp->fh_dentry, - }; __be32 err; err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access); - if (!err && vfs_statfs(&path, stat)) - err = nfserr_io; + if (!err) { + struct path path = { + .mnt = fhp->fh_export->ex_path.mnt, + .dentry = fhp->fh_dentry, + }; + if (vfs_statfs(&path, stat)) + err = nfserr_io; + } return err; } -- cgit v1.2.3-59-g8ed1b From 25cc69ec34a563e943e85b3b68a79a8aac7f076d Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 26 Aug 2010 20:18:43 +0200 Subject: PM QoS: Fix inline documentation. Fix the pm_qos_add_request() kerneldoc comment that doesn't reflect the behavior of the function after the last PM QoS update. Signed-off-by: Saravana Kannan Acked-by: mark gross Signed-off-by: Rafael J. Wysocki --- kernel/pm_qos_params.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c index 9da439b419aa..b7e4c362361b 100644 --- a/kernel/pm_qos_params.c +++ b/kernel/pm_qos_params.c @@ -212,15 +212,17 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active); /** * pm_qos_add_request - inserts new qos request into the list - * @pm_qos_class: identifies which list of qos request to us + * @dep: pointer to a preallocated handle + * @pm_qos_class: identifies which list of qos request to use * @value: defines the qos request * * This function inserts a new entry in the pm_qos_class list of requested qos * performance characteristics. It recomputes the aggregate QoS expectations - * for the pm_qos_class of parameters, and returns the pm_qos_request list - * element as a handle for use in updating and removal. Call needs to save - * this handle for later use. + * for the pm_qos_class of parameters and initializes the pm_qos_request_list + * handle. Caller needs to save this handle for later use in updates and + * removal. */ + void pm_qos_add_request(struct pm_qos_request_list *dep, int pm_qos_class, s32 value) { -- cgit v1.2.3-59-g8ed1b From bfc960a8eec023a170a80697fe65157cd4f44f81 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 Aug 2010 23:44:35 +0000 Subject: l2tp: test for ethernet header in l2tp_eth_dev_recv() close https://bugzilla.kernel.org/show_bug.cgi?id=16529 Before calling dev_forward_skb(), we should make sure skb head contains at least an ethernet header, even if length included in upper layer said so. Use pskb_may_pull() to make sure this ethernet header is present in skb head. Reported-by: Thomas Heil Reported-by: Ian Campbell Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/l2tp/l2tp_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 58c6c4cda73b..1ae697681bc7 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c @@ -132,7 +132,7 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, printk("\n"); } - if (data_len < ETH_HLEN) + if (!pskb_may_pull(skb, sizeof(ETH_HLEN))) goto error; secpath_reset(skb); -- cgit v1.2.3-59-g8ed1b From fe5f098055ed7f701bfb16f8f87378cf67de9a0e Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Thu, 26 Aug 2010 08:27:58 +0000 Subject: qlge: reset the chip before freeing the buffers Qlge is freeing the buffers before stopping the card DMA, and this can cause some severe error, as a EEH event on PPC. This patch just stop the card and then free the resources. Signed-off-by: Breno Leitao Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 8d63f69b27d9..5f89e83501f4 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3919,12 +3919,12 @@ static int ql_adapter_down(struct ql_adapter *qdev) for (i = 0; i < qdev->rss_ring_count; i++) netif_napi_del(&qdev->rx_ring[i].napi); - ql_free_rx_buffers(qdev); - status = ql_adapter_reset(qdev); if (status) netif_err(qdev, ifdown, qdev->ndev, "reset(func #%d) FAILED!\n", qdev->func); + ql_free_rx_buffers(qdev); + return status; } -- cgit v1.2.3-59-g8ed1b From d71b0e9c0028f3af910226f995e0074873e16979 Mon Sep 17 00:00:00 2001 From: Bernard Pidoux F6BVP Date: Thu, 26 Aug 2010 11:40:00 +0000 Subject: ax25: missplaced sock_put(sk) This patch moves a missplaced sock_put(sk) after bh_unlock_sock(sk) like in other parts of AX25 driver. Signed-off-by: Bernard Pidoux Signed-off-by: David S. Miller --- net/ax25/ax25_ds_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c index 2ce79df00680..c7d81436213d 100644 --- a/net/ax25/ax25_ds_timer.c +++ b/net/ax25/ax25_ds_timer.c @@ -112,8 +112,8 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25) if (sk) { sock_hold(sk); ax25_destroy_socket(ax25); - sock_put(sk); bh_unlock_sock(sk); + sock_put(sk); } else ax25_destroy_socket(ax25); return; -- cgit v1.2.3-59-g8ed1b From e3461a2bc0d67ce60a915e0f26e2a6eb4a4d4b99 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 26 Aug 2010 14:58:57 +1000 Subject: drm: export drm_global_mutex for drivers to use Nouveau needs to be able to drop the mutex before sleeping to prevent a deadlock from occuring. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/drm_fops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 2ca8df8b6102..41dfaae41159 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -41,6 +41,7 @@ /* from BKL pushdown: note that nothing else serializes idr_find() */ DEFINE_MUTEX(drm_global_mutex); +EXPORT_SYMBOL(drm_global_mutex); static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev); -- cgit v1.2.3-59-g8ed1b From ab699ec64a4294f2f6ccd34b9bf8a2dcb4c4cb3c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 26 Aug 2010 15:02:32 +1000 Subject: drm/nouveau: drop drm_global_mutex before sleeping in submission path If we keep hold of the mutex here, the process which currently holds the buffer object will never be able to release it, causing a deadlock. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 613f878e6d0f..93711dfcafc1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -337,7 +337,9 @@ retry: return -EINVAL; } + mutex_unlock(&drm_global_mutex); ret = ttm_bo_wait_cpu(&nvbo->bo, false); + mutex_lock(&drm_global_mutex); if (ret) { NV_ERROR(dev, "fail wait_cpu\n"); return ret; -- cgit v1.2.3-59-g8ed1b From f846619e7f875b0efa9853b1c821bbc756656d47 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 27 Aug 2010 08:39:48 -0600 Subject: lguest: clean up warnings in demonstration launcher. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These days the headers we use are in glibc. If those are too old, you can add the -I lines to get the kernel headers. In file included from ../../include/linux/if_tun.h:19, from lguest.c:33: ../../include/linux/types.h:13:2: warning: #warning "Attempt to use kernel headers from user space, see http://kernelnewbies.org/KernelHeaders" lguest.c: In function ‘setup_tun_net’: lguest.c:1456: warning: dereferencing pointer ‘sin’ does break strict-aliasing rules lguest.c:1457: warning: dereferencing pointer ‘sin’ does break strict-aliasing rules lguest.c:1450: note: initialized from here Signed-off-by: Rusty Russell --- Documentation/lguest/Makefile | 3 ++- Documentation/lguest/lguest.c | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile index 28c8cdfcafd8..bebac6b4f332 100644 --- a/Documentation/lguest/Makefile +++ b/Documentation/lguest/Makefile @@ -1,5 +1,6 @@ # This creates the demonstration utility "lguest" which runs a Linux guest. -CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include -I../../arch/x86/include -U_FORTIFY_SOURCE +# Missing headers? Add "-I../../include -I../../arch/x86/include" +CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE all: lguest diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index e9ce3c554514..8a6a8c6d4980 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c @@ -39,14 +39,14 @@ #include #include #include -#include "linux/lguest_launcher.h" -#include "linux/virtio_config.h" -#include "linux/virtio_net.h" -#include "linux/virtio_blk.h" -#include "linux/virtio_console.h" -#include "linux/virtio_rng.h" -#include "linux/virtio_ring.h" -#include "asm/bootparam.h" +#include +#include +#include +#include +#include +#include +#include +#include "../../include/linux/lguest_launcher.h" /*L:110 * We can ignore the 42 include files we need for this program, but I do want * to draw attention to the use of kernel-style types. @@ -1447,14 +1447,15 @@ static void add_to_bridge(int fd, const char *if_name, const char *br_name) static void configure_device(int fd, const char *tapif, u32 ipaddr) { struct ifreq ifr; - struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; + struct sockaddr_in sin; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, tapif); /* Don't read these incantations. Just cut & paste them like I did! */ - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = htonl(ipaddr); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(ipaddr); + memcpy(&ifr.ifr_addr, &sin, sizeof(sin)); if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) err(1, "Setting %s interface address", tapif); ifr.ifr_flags = IFF_UP; -- cgit v1.2.3-59-g8ed1b From 72e91863cb30076a93901b84ec34286536ef6893 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 27 Aug 2010 08:39:51 -0600 Subject: lguest: Odd Fixes It's been in fix-mode-only for a while now. Signed-off-by: Rusty Russell --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5fa8451ec80c..4523d6cb4c4e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3488,7 +3488,7 @@ LGUEST M: Rusty Russell L: lguest@lists.ozlabs.org W: http://lguest.ozlabs.org/ -S: Maintained +S: Odd Fixes F: Documentation/lguest/ F: arch/x86/lguest/ F: drivers/lguest/ -- cgit v1.2.3-59-g8ed1b From 7521473305f1379403b893a30ac09a2132dc1e25 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 26 Aug 2010 21:44:17 +0200 Subject: drm: mm: fix range restricted allocations With the code cleanup in 7a6b2896f261894dde287d3faefa4b432cddca53 is the first bad commit commit 7a6b2896f261894dde287d3faefa4b432cddca53 Author: Daniel Vetter Date: Fri Jul 2 15:02:15 2010 +0100 drm_mm: extract check_free_mm_node I've botched up the range-restriction checks. The result is usually an X server dying with SIGBUS in libpixman (software fallback rendering). Change the code to adjust the start and end for range restricted allocations. IMHO this even makes the code a bit clearer. Fixes regression bug: https://bugs.freedesktop.org/show_bug.cgi?id=29738 Reported-by-Tested-by: Till MAtthiesen Acked-by: Alex Deucher Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_mm.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index da99edc50888..a6bfc302ed90 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -285,21 +285,21 @@ void drm_mm_put_block(struct drm_mm_node *cur) EXPORT_SYMBOL(drm_mm_put_block); -static int check_free_mm_node(struct drm_mm_node *entry, unsigned long size, - unsigned alignment) +static int check_free_hole(unsigned long start, unsigned long end, + unsigned long size, unsigned alignment) { unsigned wasted = 0; - if (entry->size < size) + if (end - start < size) return 0; if (alignment) { - register unsigned tmp = entry->start % alignment; + unsigned tmp = start % alignment; if (tmp) wasted = alignment - tmp; } - if (entry->size >= size + wasted) { + if (end >= start + size + wasted) { return 1; } @@ -320,7 +320,8 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, best_size = ~0UL; list_for_each_entry(entry, &mm->free_stack, free_stack) { - if (!check_free_mm_node(entry, size, alignment)) + if (!check_free_hole(entry->start, entry->start + entry->size, + size, alignment)) continue; if (!best_match) @@ -353,10 +354,12 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, best_size = ~0UL; list_for_each_entry(entry, &mm->free_stack, free_stack) { - if (entry->start > end || (entry->start+entry->size) < start) - continue; + unsigned long adj_start = entry->start < start ? + start : entry->start; + unsigned long adj_end = entry->start + entry->size > end ? + end : entry->start + entry->size; - if (!check_free_mm_node(entry, size, alignment)) + if (!check_free_hole(adj_start, adj_end, size, alignment)) continue; if (!best_match) @@ -449,7 +452,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) node->free_stack.prev = prev_free; node->free_stack.next = next_free; - if (check_free_mm_node(node, mm->scan_size, mm->scan_alignment)) { + if (check_free_hole(node->start, node->start + node->size, + mm->scan_size, mm->scan_alignment)) { mm->scan_hit_start = node->start; mm->scan_hit_size = node->size; -- cgit v1.2.3-59-g8ed1b From 12acd90f0b97a4ce4574ca1e951cbca026e92560 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 26 Aug 2010 12:22:04 -0400 Subject: drm/radeon/kms: remove stray radeon_i2c_destroy I missed this one in the i2c unification patch. This is handled in the core radeon i2c code now. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 477ba673e1b4..f87efec76236 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -637,8 +637,6 @@ void radeon_pm_fini(struct radeon_device *rdev) } radeon_hwmon_fini(rdev); - if (rdev->pm.i2c_bus) - radeon_i2c_destroy(rdev->pm.i2c_bus); } void radeon_pm_compute_clocks(struct radeon_device *rdev) -- cgit v1.2.3-59-g8ed1b From 08f2e669a81b5906adf6e4716f92d99d7966d224 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 27 Aug 2010 08:55:28 +1000 Subject: drm: fix regression in drm locking since BKL removal. This locking path needs proper auditing but probably too late for changes at this point for 2.6.36, so lets go with the quick fix, which is to drop the lock around schedule. Reported-by: Andreas Schwab Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_lock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index e2f70a516c34..9bf93bc9a32c 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -92,7 +92,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) } /* Contention */ + mutex_unlock(&drm_global_mutex); schedule(); + mutex_lock(&drm_global_mutex); if (signal_pending(current)) { ret = -EINTR; break; -- cgit v1.2.3-59-g8ed1b From adde0f23396fe6c6cd4fe8e66e9cdc7d1f5081d9 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Mon, 23 Aug 2010 10:19:14 -0400 Subject: drm/modes: Fix CVT-R modeline generation Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16651 Signed-off-by: Adam Jackson Tested-by: Adam Serbinski Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_modes.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index f1f473ea97d3..949326d2a8e5 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -251,7 +251,10 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK; /* Fill in HSync values */ drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2; - drm_mode->hsync_start = drm_mode->hsync_end = CVT_RB_H_SYNC; + drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC; + /* Fill in VSync values */ + drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH; + drm_mode->vsync_end = drm_mode->vsync_start + vsync; } /* 15/13. Find pixel clock frequency (kHz for xf86) */ drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod; -- cgit v1.2.3-59-g8ed1b From 30f4437202daa5315a1033b2084ddce96fea99b6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 21 Aug 2010 11:09:14 -0400 Subject: drm/radeon/kms: add missing scratch update in dp_detect Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 31a09cd279ab..1a5ee392e9c7 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -999,6 +999,7 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto } } + radeon_connector_update_scratch_regs(connector, ret); return ret; } -- cgit v1.2.3-59-g8ed1b From 04cbe1de6fbda9649a6f25666194e6955d3e717e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 19 Aug 2010 21:29:43 +0100 Subject: vgaarb: Wrap vga_(get|put) in CONFIG_VGA_ARB Fix link failure without the vga arbitrator. Signed-off-by: Chris Wilson Cc: Dave Airlie Cc: Jesse Barnes Signed-off-by: Dave Airlie --- include/linux/vgaarb.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index 6228b5b77d35..e9e1524b582c 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -93,8 +93,11 @@ extern void vga_set_legacy_decoding(struct pci_dev *pdev, * Nested calls are supported (a per-resource counter is maintained) */ -extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, - int interruptible); +#if defined(CONFIG_VGA_ARB) +extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible); +#else +static inline int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) { return 0; } +#endif /** * vga_get_interruptible @@ -131,7 +134,11 @@ static inline int vga_get_uninterruptible(struct pci_dev *pdev, * are already locked by another card. It can be called in any context */ +#if defined(CONFIG_VGA_ARB) extern int vga_tryget(struct pci_dev *pdev, unsigned int rsrc); +#else +static inline int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) { return 0; } +#endif /** * vga_put - release lock on legacy VGA resources @@ -146,7 +153,11 @@ extern int vga_tryget(struct pci_dev *pdev, unsigned int rsrc); * released if the counter reaches 0. */ +#if defined(CONFIG_VGA_ARB) extern void vga_put(struct pci_dev *pdev, unsigned int rsrc); +#else +#define vga_put(pdev, rsrc) +#endif /** -- cgit v1.2.3-59-g8ed1b From 7e368739e3b3f1d7944794c178a15f05829b56bc Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 26 Aug 2010 16:11:08 -0700 Subject: net/caif/cfrfml.c: use asm/unaligned.h caif does not build on ia64 starting with 2.6.32-rc1. Using asm/unaligned.h instead of linux/unaligned/le_byteshift.h fixes the issue. include/linux/unaligned/le_byteshift.h:40:50: error: redefinition of 'get_unaligned_le16' include/linux/unaligned/le_byteshift.h:45:50: error: redefinition of 'get_unaligned_le32' include/linux/unaligned/le_byteshift.h:50:50: error: redefinition of 'get_unaligned_le64' include/linux/unaligned/le_byteshift.h:55:51: error: redefinition of 'put_unaligned_le16' include/linux/unaligned/le_byteshift.h:60:51: error: redefinition of 'put_unaligned_le32' include/linux/unaligned/le_byteshift.h:65:51: error: redefinition of 'put_unaligned_le64' include/linux/unaligned/le_struct.h:31:51: note: previous definition of 'put_unaligned_le64' was here Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/caif/cfrfml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index eb1602022ac0..9a699242d104 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From f7b66e5e51d31c45c6039db9a6da7863fb75be1e Mon Sep 17 00:00:00 2001 From: John Ogness Date: Fri, 18 Jun 2010 18:59:47 +0200 Subject: mxc_nand: Do not do byte accesses to the NFC buffer. This patch avoids byte access to the NFC buffer. Byte access to the NFC is not allowed. The patch is against linux-next 20100618. Signed-off-by: John Ogness Signed-off-by: Sascha Hauer Tested-by: John Ogness Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index fcf8ceb277d4..26caa01e34a6 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -402,16 +402,16 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) /* Wait for operation to complete */ wait_op_done(host, true); + memcpy(host->data_buf, host->main_area0, 16); + if (this->options & NAND_BUSWIDTH_16) { - void __iomem *main_buf = host->main_area0; /* compress the ID info */ - writeb(readb(main_buf + 2), main_buf + 1); - writeb(readb(main_buf + 4), main_buf + 2); - writeb(readb(main_buf + 6), main_buf + 3); - writeb(readb(main_buf + 8), main_buf + 4); - writeb(readb(main_buf + 10), main_buf + 5); + host->data_buf[1] = host->data_buf[2]; + host->data_buf[2] = host->data_buf[4]; + host->data_buf[3] = host->data_buf[6]; + host->data_buf[4] = host->data_buf[8]; + host->data_buf[5] = host->data_buf[10]; } - memcpy(host->data_buf, host->main_area0, 16); } static uint16_t get_dev_status_v3(struct mxc_nand_host *host) -- cgit v1.2.3-59-g8ed1b From 5225c45899e872383ca39f5533d28ec63c54b39e Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 22 Aug 2010 04:29:17 +0200 Subject: perf: Initialize callchains roots's childen hits Each histogram entry has a callchain root that stores the callchain samples. However we forgot to initialize the tracking of children hits of these roots, which then got random values on their creation. The root children hits is multiplied by the minimum percentage of hits provided by the user, and the result becomes the minimum hits expected from children branches. If the random value due to the uninitialization is big enough, then this minimum number of hits can be huge and eventually filter every children branches. The end result was invisible callchains. All we need to fix this is to initialize the children hits of the root. Reported-by: Christoph Hellwig Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: 2.6.32.x-2.6.35.y --- tools/perf/util/callchain.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 624a96c636fd..6de4313924fb 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -50,6 +50,7 @@ static inline void callchain_init(struct callchain_node *node) INIT_LIST_HEAD(&node->children); INIT_LIST_HEAD(&node->val); + node->children_hit = 0; node->parent = NULL; node->hit = 0; } -- cgit v1.2.3-59-g8ed1b From 15cae77ad891c1533b664759f8eebae246e5edf8 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Sat, 21 Aug 2010 09:03:16 +0900 Subject: ARM: SAMSUNG: Fix on build warning regarding VMALLOC_END type Fix this warning: arch/arm/mm/init.c: In function 'mem_init': arch/arm/mm/init.c:644: warning: format '%08lx' expects type 'long unsigned int', but argument 12 has type 'unsigned int' And removes the useless parens and white space. Reported-by: Kyungmin Park Signed-off-by: Kukjin Kim Cc: Ben Dooks --- arch/arm/mach-s3c2410/include/mach/vmalloc.h | 2 +- arch/arm/mach-s3c64xx/include/mach/vmalloc.h | 2 +- arch/arm/mach-s5p6440/include/mach/vmalloc.h | 2 +- arch/arm/mach-s5p6442/include/mach/vmalloc.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-s3c2410/include/mach/vmalloc.h b/arch/arm/mach-s3c2410/include/mach/vmalloc.h index 315b0078a34d..54297eb0bf5e 100644 --- a/arch/arm/mach-s3c2410/include/mach/vmalloc.h +++ b/arch/arm/mach-s3c2410/include/mach/vmalloc.h @@ -15,6 +15,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END 0xE0000000UL #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-s3c64xx/include/mach/vmalloc.h b/arch/arm/mach-s3c64xx/include/mach/vmalloc.h index 7411ef3711a6..bc0e91389864 100644 --- a/arch/arm/mach-s3c64xx/include/mach/vmalloc.h +++ b/arch/arm/mach-s3c64xx/include/mach/vmalloc.h @@ -15,6 +15,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END 0xE0000000UL #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-s5p6440/include/mach/vmalloc.h b/arch/arm/mach-s5p6440/include/mach/vmalloc.h index 16df257b1dce..e3f0eebf5205 100644 --- a/arch/arm/mach-s5p6440/include/mach/vmalloc.h +++ b/arch/arm/mach-s5p6440/include/mach/vmalloc.h @@ -12,6 +12,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END 0xE0000000UL #endif /* __ASM_ARCH_VMALLOC_H */ diff --git a/arch/arm/mach-s5p6442/include/mach/vmalloc.h b/arch/arm/mach-s5p6442/include/mach/vmalloc.h index be3333688c20..f5c83f02c18e 100644 --- a/arch/arm/mach-s5p6442/include/mach/vmalloc.h +++ b/arch/arm/mach-s5p6442/include/mach/vmalloc.h @@ -12,6 +12,6 @@ #ifndef __ASM_ARCH_VMALLOC_H #define __ASM_ARCH_VMALLOC_H -#define VMALLOC_END (0xE0000000) +#define VMALLOC_END 0xE0000000UL #endif /* __ASM_ARCH_VMALLOC_H */ -- cgit v1.2.3-59-g8ed1b From 4d9147053bb7b90f083220440194a1cff0ee90b6 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 20 Aug 2010 20:41:31 +0900 Subject: ARM: S5PV310: Fix on GPIO base addresses The S5PV310/S5PC210 has following three GPIO base addresses. Part1 Base Address=0x11400000 Part2 Base Address=0x11000000 Part3 Base Address=0x03860000 Signed-off-by: Kyungmin Park [kgene.kim@samsung.com: minor edit of title] Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/include/mach/map.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h index 87697c9fca5b..6c7b1fc9d8ae 100644 --- a/arch/arm/mach-s5pv310/include/mach/map.h +++ b/arch/arm/mach-s5pv310/include/mach/map.h @@ -39,8 +39,12 @@ #define S5PV310_PA_GIC_DIST (0x10501000) #define S5PV310_PA_L2CC (0x10502000) -#define S5PV310_PA_GPIO (0x11000000) -#define S5P_PA_GPIO S5PV310_PA_GPIO +#define S5PV310_PA_GPIO1 (0x11400000) +#define S5PV310_PA_GPIO2 (0x11000000) +#define S5PV310_PA_GPIO3 (0x03860000) +#define S5P_PA_GPIO S5PV310_PA_GPIO1 + +#define S5PV310_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000)) #define S5PV310_PA_UART (0x13800000) @@ -63,6 +67,10 @@ /* compatibiltiy defines. */ #define S3C_PA_UART S5PV310_PA_UART +#define S3C_PA_HSMMC0 S5PV310_PA_HSMMC(0) +#define S3C_PA_HSMMC1 S5PV310_PA_HSMMC(1) +#define S3C_PA_HSMMC2 S5PV310_PA_HSMMC(2) +#define S3C_PA_HSMMC3 S5PV310_PA_HSMMC(3) #define S3C_PA_IIC S5PV310_PA_IIC0 #define S3C_PA_WDT S5PV310_PA_WATCHDOG -- cgit v1.2.3-59-g8ed1b From 68c1dbcb5aeb00eb17caf0c2e42c71b48baac902 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 18 Aug 2010 21:03:24 +0900 Subject: ARM: S5PV310: Fix on default ZRELADDR of ARCH_S5PV310 This patch adds default zreladdr of ARCH_S5PV310. Signed-off-by: Kukjin Kim --- arch/arm/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 92951103255a..a7ed21f0136a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1622,7 +1622,8 @@ config ZRELADDR default 0x40008000 if ARCH_STMP378X ||\ ARCH_STMP37XX ||\ ARCH_SH7372 ||\ - ARCH_SH7377 + ARCH_SH7377 ||\ + ARCH_S5PV310 default 0x50008000 if ARCH_S3C64XX ||\ ARCH_SH7367 default 0x60008000 if ARCH_VEXPRESS -- cgit v1.2.3-59-g8ed1b From 6628bc74f1aa9c35dd386320bf7ec04f12edb1b3 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 27 Aug 2010 09:15:09 +0200 Subject: writeback: do not lose wakeup events when forking bdi threads This patch fixes the following issue: INFO: task mount.nfs4:1120 blocked for more than 120 seconds. "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. mount.nfs4 D 00000000fffc6a21 0 1120 1119 0x00000000 ffff880235643948 0000000000000046 ffffffff00000000 ffffffff00000000 ffff880235643fd8 ffff880235314760 00000000001d44c0 ffff880235643fd8 00000000001d44c0 00000000001d44c0 00000000001d44c0 00000000001d44c0 Call Trace: [] schedule_timeout+0x34/0xf1 [] ? wait_for_common+0x3f/0x130 [] ? trace_hardirqs_on+0xd/0xf [] wait_for_common+0xd2/0x130 [] ? default_wake_function+0x0/0xf [] ? _raw_spin_unlock+0x26/0x2a [] wait_for_completion+0x18/0x1a [] sync_inodes_sb+0xca/0x1bc [] __sync_filesystem+0x47/0x7e [] sync_filesystem+0x47/0x4b [] generic_shutdown_super+0x22/0xd2 [] kill_anon_super+0x11/0x4f [] nfs4_kill_super+0x3f/0x72 [nfs] [] deactivate_locked_super+0x21/0x41 [] deactivate_super+0x40/0x45 [] mntput_no_expire+0xb8/0xed [] release_mounts+0x9a/0xb0 [] put_mnt_ns+0x6a/0x7b [] nfs_follow_remote_path+0x19a/0x296 [nfs] [] nfs4_try_mount+0x75/0xaf [nfs] [] nfs4_get_sb+0x276/0x2ff [nfs] [] vfs_kern_mount+0xb8/0x196 [] do_kern_mount+0x48/0xe8 [] do_mount+0x771/0x7e8 [] sys_mount+0x83/0xbd [] system_call_fastpath+0x16/0x1b The reason of this hang was a race condition: when the flusher thread is forking a bdi thread, we use 'kthread_run()', so we run it _before_ we make it visible in 'bdi->wb.task'. The bdi thread runs, does all works, and goes sleep. 'bdi->wb.task' is still NULL. And this is a dangerous time window. If at this time someone queues a work for this bdi, he does not see the bdi thread and wakes up the forker thread instead! But the forker has already forked this bdi thread, but just did not make it visible yet! The result is that we lose the wake up event for this bdi thread and the NFS4 code waits forever. To fix the problem, we should use 'ktrhead_create()' for creating bdi threads, then make them visible in 'bdi->wb.task', and only after this wake them up. This is exactly what this patch does. Signed-off-by: Artem Bityutskiy Signed-off-by: Jens Axboe --- mm/backing-dev.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mm/backing-dev.c b/mm/backing-dev.c index eaa4a5bbe063..c2bf86f470ed 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -445,8 +445,8 @@ static int bdi_forker_thread(void *ptr) switch (action) { case FORK_THREAD: __set_current_state(TASK_RUNNING); - task = kthread_run(bdi_writeback_thread, &bdi->wb, "flush-%s", - dev_name(bdi->dev)); + task = kthread_create(bdi_writeback_thread, &bdi->wb, + "flush-%s", dev_name(bdi->dev)); if (IS_ERR(task)) { /* * If thread creation fails, force writeout of @@ -457,10 +457,13 @@ static int bdi_forker_thread(void *ptr) /* * The spinlock makes sure we do not lose * wake-ups when racing with 'bdi_queue_work()'. + * And as soon as the bdi thread is visible, we + * can start it. */ spin_lock_bh(&bdi->wb_lock); bdi->wb.task = task; spin_unlock_bh(&bdi->wb_lock); + wake_up_process(task); } break; -- cgit v1.2.3-59-g8ed1b From 35fc950bd5889d62c34e67199a73ea49733614f7 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Fri, 20 Aug 2010 19:09:31 +0900 Subject: ARM: S5PV310: Fix on typo irqs.h of S5PV310 This patch fixes typo 'IRQ_WTD' in the irqs.h of S5PV310. And minor update comments. Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/include/mach/irqs.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h index 56885ca3773c..4cdedda6e652 100644 --- a/arch/arm/mach-s5pv310/include/mach/irqs.h +++ b/arch/arm/mach-s5pv310/include/mach/irqs.h @@ -15,12 +15,14 @@ #include -/* Private Peripheral Interrupt */ +/* PPI: Private Peripheral Interrupt */ + #define IRQ_PPI(x) S5P_IRQ(x+16) #define IRQ_LOCALTIMER IRQ_PPI(13) -/* Shared Peripheral Interrupt */ +/* SPI: Shared Peripheral Interrupt */ + #define IRQ_SPI(x) S5P_IRQ(x+32) #define IRQ_EINT0 IRQ_SPI(40) @@ -36,7 +38,7 @@ #define IRQ_PCIE IRQ_SPI(50) #define IRQ_SYSTEM_TIMER IRQ_SPI(51) #define IRQ_MFC IRQ_SPI(52) -#define IRQ_WTD IRQ_SPI(53) +#define IRQ_WDT IRQ_SPI(53) #define IRQ_AUDIO_SS IRQ_SPI(54) #define IRQ_AC97 IRQ_SPI(55) #define IRQ_SPDIF IRQ_SPI(56) @@ -67,8 +69,9 @@ #define IRQ_IIC COMBINER_IRQ(27, 0) /* Set the default NR_IRQS */ + #define NR_IRQS COMBINER_IRQ(MAX_COMBINER_NR, 0) #define MAX_COMBINER_NR 39 -#endif /* ASM_ARCH_IRQS_H */ +#endif /* __ASM_ARCH_IRQS_H */ -- cgit v1.2.3-59-g8ed1b From c598c47d85cbc0ac04ba808a696d774baa7a0a34 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Wed, 18 Aug 2010 21:45:49 +0900 Subject: ARM: S5PV310: Add CMU block for S5PV310 Clock This patch adds CMU block for S5PV310/S5PC210 clock. (CMU: Clock Management Unit) Of course, changed current clock addresses for it together. Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/cpu.c | 7 ++- arch/arm/mach-s5pv310/include/mach/map.h | 2 + arch/arm/mach-s5pv310/include/mach/regs-clock.h | 59 ++++++++++++------------- arch/arm/plat-s5p/include/plat/map-s5p.h | 1 + 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c index 196c9f12ed85..2b742957d566 100644 --- a/arch/arm/mach-s5pv310/cpu.c +++ b/arch/arm/mach-s5pv310/cpu.c @@ -45,7 +45,12 @@ static struct map_desc s5pv310_iodesc[] __initdata = { .pfn = __phys_to_pfn(S5PV310_PA_L2CC), .length = SZ_4K, .type = MT_DEVICE, - }, + }, { + .virtual = (unsigned long)S5P_VA_CMU, + .pfn = __phys_to_pfn(S5PV310_PA_CMU), + .length = SZ_128K, + .type = MT_DEVICE, + } }; static void s5pv310_idle(void) diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h index 6c7b1fc9d8ae..3c00495c5f22 100644 --- a/arch/arm/mach-s5pv310/include/mach/map.h +++ b/arch/arm/mach-s5pv310/include/mach/map.h @@ -29,6 +29,8 @@ #define S5PV310_PA_SYSCON (0x10020000) #define S5P_PA_SYSCON S5PV310_PA_SYSCON +#define S5PV310_PA_CMU (0x10030000) + #define S5PV310_PA_WATCHDOG (0x10060000) #define S5PV310_PA_COMBINER (0x10448000) diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h index 59e3a7e94d80..7727b4563a26 100644 --- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h @@ -15,48 +15,47 @@ #include -#define S5P_CLKREG(x) (S3C_VA_SYS + (x)) +#define S5P_CLKREG(x) (S5P_VA_CMU + (x)) #define S5P_INFORM0 S5P_CLKREG(0x800) -#define S5P_EPLL_CON0 S5P_CLKREG(0x1C110) -#define S5P_EPLL_CON1 S5P_CLKREG(0x1C114) -#define S5P_VPLL_CON0 S5P_CLKREG(0x1C120) -#define S5P_VPLL_CON1 S5P_CLKREG(0x1C124) +#define S5P_EPLL_CON0 S5P_CLKREG(0x0C110) +#define S5P_EPLL_CON1 S5P_CLKREG(0x0C114) +#define S5P_VPLL_CON0 S5P_CLKREG(0x0C120) +#define S5P_VPLL_CON1 S5P_CLKREG(0x0C124) -#define S5P_CLKSRC_TOP0 S5P_CLKREG(0x1C210) -#define S5P_CLKSRC_TOP1 S5P_CLKREG(0x1C214) +#define S5P_CLKSRC_TOP0 S5P_CLKREG(0x0C210) +#define S5P_CLKSRC_TOP1 S5P_CLKREG(0x0C214) -#define S5P_CLKSRC_PERIL0 S5P_CLKREG(0x1C250) +#define S5P_CLKSRC_PERIL0 S5P_CLKREG(0x0C250) -#define S5P_CLKDIV_TOP S5P_CLKREG(0x1C510) +#define S5P_CLKDIV_TOP S5P_CLKREG(0x0C510) -#define S5P_CLKDIV_PERIL0 S5P_CLKREG(0x1C550) -#define S5P_CLKDIV_PERIL1 S5P_CLKREG(0x1C554) -#define S5P_CLKDIV_PERIL2 S5P_CLKREG(0x1C558) -#define S5P_CLKDIV_PERIL3 S5P_CLKREG(0x1C55C) -#define S5P_CLKDIV_PERIL4 S5P_CLKREG(0x1C560) -#define S5P_CLKDIV_PERIL5 S5P_CLKREG(0x1C564) +#define S5P_CLKDIV_PERIL0 S5P_CLKREG(0x0C550) +#define S5P_CLKDIV_PERIL1 S5P_CLKREG(0x0C554) +#define S5P_CLKDIV_PERIL2 S5P_CLKREG(0x0C558) +#define S5P_CLKDIV_PERIL3 S5P_CLKREG(0x0C55C) +#define S5P_CLKDIV_PERIL4 S5P_CLKREG(0x0C560) +#define S5P_CLKDIV_PERIL5 S5P_CLKREG(0x0C564) -#define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x1C950) +#define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) -#define S5P_CLKSRC_CORE S5P_CLKREG(0x20200) +#define S5P_CLKSRC_CORE S5P_CLKREG(0x10200) +#define S5P_CLKDIV_CORE0 S5P_CLKREG(0x10500) -#define S5P_CLKDIV_CORE0 S5P_CLKREG(0x20500) +#define S5P_APLL_LOCK S5P_CLKREG(0x14000) +#define S5P_MPLL_LOCK S5P_CLKREG(0x14004) +#define S5P_APLL_CON0 S5P_CLKREG(0x14100) +#define S5P_APLL_CON1 S5P_CLKREG(0x14104) +#define S5P_MPLL_CON0 S5P_CLKREG(0x14108) +#define S5P_MPLL_CON1 S5P_CLKREG(0x1410C) -#define S5P_APLL_LOCK S5P_CLKREG(0x24000) -#define S5P_MPLL_LOCK S5P_CLKREG(0x24004) -#define S5P_APLL_CON0 S5P_CLKREG(0x24100) -#define S5P_APLL_CON1 S5P_CLKREG(0x24104) -#define S5P_MPLL_CON0 S5P_CLKREG(0x24108) -#define S5P_MPLL_CON1 S5P_CLKREG(0x2410C) +#define S5P_CLKSRC_CPU S5P_CLKREG(0x14200) +#define S5P_CLKMUX_STATCPU S5P_CLKREG(0x14400) -#define S5P_CLKSRC_CPU S5P_CLKREG(0x24200) -#define S5P_CLKMUX_STATCPU S5P_CLKREG(0x24400) +#define S5P_CLKDIV_CPU S5P_CLKREG(0x14500) +#define S5P_CLKDIV_STATCPU S5P_CLKREG(0x14600) -#define S5P_CLKDIV_CPU S5P_CLKREG(0x24500) -#define S5P_CLKDIV_STATCPU S5P_CLKREG(0x24600) - -#define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x24800) +#define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x14800) #endif /* __ASM_ARCH_REGS_CLOCK_H */ diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h index 54e9fb9d315e..589779205f12 100644 --- a/arch/arm/plat-s5p/include/plat/map-s5p.h +++ b/arch/arm/plat-s5p/include/plat/map-s5p.h @@ -29,6 +29,7 @@ #define S5P_VA_GIC_DIST S5P_VA_COREPERI(0x1000) #define S5P_VA_L2CC S3C_ADDR(0x00900000) +#define S5P_VA_CMU S3C_ADDR(0x00920000) #define S5P_VA_UART(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) #define S5P_VA_UART0 S5P_VA_UART(0) -- cgit v1.2.3-59-g8ed1b From 4d235f7934ab55329a5cb34d7e3949ba50b511d4 Mon Sep 17 00:00:00 2001 From: Jongpill Lee Date: Wed, 18 Aug 2010 22:13:49 +0900 Subject: ARM: S5PV310: Fix on PLL setting for S5PV310 This patch fixes on PLL setting for S5PV310/S5PC210. Signed-off-by: Jongpill Lee Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index 77f2b4d85e6b..1659eb1e7b07 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c @@ -470,11 +470,11 @@ void __init_or_cpufreq s5pv310_setup_clocks(void) apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0), pll_4508); mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0), pll_4508); epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0), - __raw_readl(S5P_EPLL_CON1), pll_4500); + __raw_readl(S5P_EPLL_CON1), pll_4600); vpllsrc = clk_get_rate(&clk_vpllsrc.clk); vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0), - __raw_readl(S5P_VPLL_CON1), pll_4502); + __raw_readl(S5P_VPLL_CON1), pll_4650); clk_fout_apll.rate = apll; clk_fout_mpll.rate = mpll; -- cgit v1.2.3-59-g8ed1b From 3ff310206db33e66c076b1f656e70e9080f5be50 Mon Sep 17 00:00:00 2001 From: Jongpill Lee Date: Wed, 18 Aug 2010 22:20:31 +0900 Subject: ARM: S5PV310: Should be clk_sclk_apll not clk_mout_apll This patch adds clk_sclk_apll so that fixes on clk_mout_apll. Signed-off-by: Jongpill Lee Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/clock.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index 1659eb1e7b07..b3f50426148d 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c @@ -39,6 +39,14 @@ static struct clksrc_clk clk_mout_apll = { }, .sources = &clk_src_apll, .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 0, .size = 1 }, +}; + +static struct clksrc_clk clk_sclk_apll = { + .clk = { + .name = "sclk_apll", + .id = -1, + .parent = &clk_mout_apll.clk, + }, .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 24, .size = 3 }, }; @@ -61,7 +69,7 @@ static struct clksrc_clk clk_mout_mpll = { }; static struct clk *clkset_moutcore_list[] = { - [0] = &clk_mout_apll.clk, + [0] = &clk_sclk_apll.clk, [1] = &clk_mout_mpll.clk, }; @@ -154,7 +162,7 @@ static struct clksrc_clk clk_pclk_dbg = { static struct clk *clkset_corebus_list[] = { [0] = &clk_mout_mpll.clk, - [1] = &clk_mout_apll.clk, + [1] = &clk_sclk_apll.clk, }; static struct clksrc_sources clkset_mout_corebus = { @@ -220,7 +228,7 @@ static struct clksrc_clk clk_pclk_acp = { static struct clk *clkset_aclk_top_list[] = { [0] = &clk_mout_mpll.clk, - [1] = &clk_mout_apll.clk, + [1] = &clk_sclk_apll.clk, }; static struct clksrc_sources clkset_aclk_200 = { @@ -411,6 +419,7 @@ static struct clksrc_clk clksrcs[] = { /* Clock initialization code */ static struct clksrc_clk *sysclks[] = { &clk_mout_apll, + &clk_sclk_apll, &clk_mout_epll, &clk_mout_mpll, &clk_moutcore, -- cgit v1.2.3-59-g8ed1b From 5a847b4af8057f0297356824f793988d311d7aa0 Mon Sep 17 00:00:00 2001 From: Jongpill Lee Date: Fri, 27 Aug 2010 16:50:47 +0900 Subject: ARM: S5PV310: Fix missed uart clocks This patch adds missed uart clocks for S5PV310/S5PC210. Signed-off-by: Jongpill Lee Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/clock.c | 44 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index b3f50426148d..165c8bf412b2 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c @@ -30,6 +30,11 @@ static struct clk clk_sclk_hdmi27m = { .rate = 27000000, }; +static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable); +} + /* Core list of CMU_CPU side */ static struct clksrc_clk clk_mout_apll = { @@ -329,11 +334,6 @@ static struct clksrc_clk clk_sclk_vpll = { .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 8, .size = 1 }, }; -static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable) -{ - return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable); -} - static struct clk init_clocks_disable[] = { { .name = "timers", @@ -345,7 +345,37 @@ static struct clk init_clocks_disable[] = { }; static struct clk init_clocks[] = { - /* Nothing here yet */ + { + .name = "uart", + .id = 0, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 0), + }, { + .name = "uart", + .id = 1, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 1), + }, { + .name = "uart", + .id = 2, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 2), + }, { + .name = "uart", + .id = 3, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 3), + }, { + .name = "uart", + .id = 4, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 4), + }, { + .name = "uart", + .id = 5, + .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 5), + } }; static struct clk *clkset_group_list[] = { @@ -367,8 +397,8 @@ static struct clksrc_clk clksrcs[] = { .clk = { .name = "uclk1", .id = 0, - .ctrlbit = (1 << 0), .enable = s5pv310_clk_ip_peril_ctrl, + .ctrlbit = (1 << 0), }, .sources = &clkset_group, .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 0, .size = 4 }, -- cgit v1.2.3-59-g8ed1b From 3297c2e6d7c3b1498b28c93141056cbe96444fde Mon Sep 17 00:00:00 2001 From: Jongpill Lee Date: Fri, 27 Aug 2010 17:53:26 +0900 Subject: ARM: S5PV310: Bug fix on uclk1 and sclk_pwm This patch fixes on enable and ctrlbit of uclk1 and sclk_pwm. Signed-off-by: Jongpill Lee Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/clock.c | 21 +++++++++++++-------- arch/arm/mach-s5pv310/include/mach/regs-clock.h | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c index 165c8bf412b2..26a0f03df8ea 100644 --- a/arch/arm/mach-s5pv310/clock.c +++ b/arch/arm/mach-s5pv310/clock.c @@ -30,6 +30,11 @@ static struct clk clk_sclk_hdmi27m = { .rate = 27000000, }; +static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable); +} + static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable); @@ -397,7 +402,7 @@ static struct clksrc_clk clksrcs[] = { .clk = { .name = "uclk1", .id = 0, - .enable = s5pv310_clk_ip_peril_ctrl, + .enable = s5pv310_clksrc_mask_peril0_ctrl, .ctrlbit = (1 << 0), }, .sources = &clkset_group, @@ -407,8 +412,8 @@ static struct clksrc_clk clksrcs[] = { .clk = { .name = "uclk1", .id = 1, - .enable = s5pv310_clk_ip_peril_ctrl, - .ctrlbit = (1 << 1), + .enable = s5pv310_clksrc_mask_peril0_ctrl, + .ctrlbit = (1 << 4), }, .sources = &clkset_group, .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 4, .size = 4 }, @@ -417,8 +422,8 @@ static struct clksrc_clk clksrcs[] = { .clk = { .name = "uclk1", .id = 2, - .enable = s5pv310_clk_ip_peril_ctrl, - .ctrlbit = (1 << 2), + .enable = s5pv310_clksrc_mask_peril0_ctrl, + .ctrlbit = (1 << 8), }, .sources = &clkset_group, .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 8, .size = 4 }, @@ -427,8 +432,8 @@ static struct clksrc_clk clksrcs[] = { .clk = { .name = "uclk1", .id = 3, - .enable = s5pv310_clk_ip_peril_ctrl, - .ctrlbit = (1 << 3), + .enable = s5pv310_clksrc_mask_peril0_ctrl, + .ctrlbit = (1 << 12), }, .sources = &clkset_group, .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 12, .size = 4 }, @@ -437,7 +442,7 @@ static struct clksrc_clk clksrcs[] = { .clk = { .name = "sclk_pwm", .id = -1, - .enable = s5pv310_clk_ip_peril_ctrl, + .enable = s5pv310_clksrc_mask_peril0_ctrl, .ctrlbit = (1 << 24), }, .sources = &clkset_group, diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h index 7727b4563a26..4013553cd9be 100644 --- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h +++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h @@ -38,6 +38,8 @@ #define S5P_CLKDIV_PERIL4 S5P_CLKREG(0x0C560) #define S5P_CLKDIV_PERIL5 S5P_CLKREG(0x0C564) +#define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350) + #define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950) #define S5P_CLKSRC_CORE S5P_CLKREG(0x10200) -- cgit v1.2.3-59-g8ed1b From 766211e74818e655593fd3272cbf84868220f9e5 Mon Sep 17 00:00:00 2001 From: Changhwan Youn Date: Fri, 27 Aug 2010 17:57:44 +0900 Subject: ARM: S5PV310: Fix on Secondary CPU startup Following occurs on boot message without this patch. CPU1: processor failed to boot Brought up 1 CPUs SMP: Total of 1 processors activated... This patch adds SYSRAM mapping for fixing Secondary CPU startup. CPU1: Booted secondary processor Brought up 2 CPUs SMP: Total of 2 processors activated... Signed-off-by: Changhwan Youn Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv310/cpu.c | 7 ++++++- arch/arm/mach-s5pv310/include/mach/map.h | 2 ++ arch/arm/mach-s5pv310/platsmp.c | 2 +- arch/arm/plat-s5p/include/plat/map-s5p.h | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c index 2b742957d566..e5b261a99ab2 100644 --- a/arch/arm/mach-s5pv310/cpu.c +++ b/arch/arm/mach-s5pv310/cpu.c @@ -45,12 +45,17 @@ static struct map_desc s5pv310_iodesc[] __initdata = { .pfn = __phys_to_pfn(S5PV310_PA_L2CC), .length = SZ_4K, .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S5P_VA_SYSRAM, + .pfn = __phys_to_pfn(S5PV310_PA_SYSRAM), + .length = SZ_4K, + .type = MT_DEVICE, }, { .virtual = (unsigned long)S5P_VA_CMU, .pfn = __phys_to_pfn(S5PV310_PA_CMU), .length = SZ_128K, .type = MT_DEVICE, - } + }, }; static void s5pv310_idle(void) diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h index 3c00495c5f22..213e1101a3b3 100644 --- a/arch/arm/mach-s5pv310/include/mach/map.h +++ b/arch/arm/mach-s5pv310/include/mach/map.h @@ -23,6 +23,8 @@ #include +#define S5PV310_PA_SYSRAM (0x02025000) + #define S5PV310_PA_CHIPID (0x10000000) #define S5P_PA_CHIPID S5PV310_PA_CHIPID diff --git a/arch/arm/mach-s5pv310/platsmp.c b/arch/arm/mach-s5pv310/platsmp.c index fe9469abd006..d357c198edee 100644 --- a/arch/arm/mach-s5pv310/platsmp.c +++ b/arch/arm/mach-s5pv310/platsmp.c @@ -187,6 +187,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) * until it receives a soft interrupt, and then the * secondary CPU branches to this address. */ - __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_INFORM0); + __raw_writel(BSYM(virt_to_phys(s5pv310_secondary_startup)), S5P_VA_SYSRAM); } } diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h index 589779205f12..c4ff88bf6477 100644 --- a/arch/arm/plat-s5p/include/plat/map-s5p.h +++ b/arch/arm/plat-s5p/include/plat/map-s5p.h @@ -17,6 +17,7 @@ #define S5P_VA_GPIO S3C_ADDR(0x00500000) #define S5P_VA_SYSTIMER S3C_ADDR(0x01200000) #define S5P_VA_SROMC S3C_ADDR(0x01100000) +#define S5P_VA_SYSRAM S3C_ADDR(0x01180000) #define S5P_VA_COMBINER_BASE S3C_ADDR(0x00600000) #define S5P_VA_COMBINER(x) (S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10) -- cgit v1.2.3-59-g8ed1b From a002d148426f40bc2b7dc066982eb177cdebeaaa Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Sun, 8 Aug 2010 14:39:07 +0200 Subject: percpu: fix a memory leak in pcpu_extend_area_map() The original code did not free the old map. This patch fixes it. tj: use @old as memcpy source instead of @chunk->map, and indentation and description update Signed-off-by: Huang Shijie Signed-off-by: Tejun Heo Cc: stable@kernel.org --- mm/percpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/percpu.c b/mm/percpu.c index e61dc2cc5873..a1830d8e3318 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -393,7 +393,9 @@ static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc) goto out_unlock; old_size = chunk->map_alloc * sizeof(chunk->map[0]); - memcpy(new, chunk->map, old_size); + old = chunk->map; + + memcpy(new, old, old_size); chunk->map_alloc = new_alloc; chunk->map = new; -- cgit v1.2.3-59-g8ed1b From 54157c44471f5e266508ac08d270f2bc5857e8bb Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 11 Aug 2010 11:19:19 +0900 Subject: percpu: fix a mismatch between code and comment When pcpu_build_alloc_info() searches best_upa value, it ignores current value if the number of waste units exceeds 1/3 of the number of total cpus. But the comment on the code says that it will ignore if wastage is over 25%. Modify the comment. Signed-off-by: Namhyung Kim Signed-off-by: Tejun Heo --- mm/percpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/percpu.c b/mm/percpu.c index a1830d8e3318..58c572b18b07 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1164,7 +1164,7 @@ static struct pcpu_alloc_info * __init pcpu_build_alloc_info( } /* - * Don't accept if wastage is over 25%. The + * Don't accept if wastage is over 1/3. The * greater-than comparison ensures upa==1 always * passes the following check. */ -- cgit v1.2.3-59-g8ed1b From 7c38875a0d0a9b90eee66be79e36995c86acc70c Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Thu, 26 Aug 2010 10:35:43 -0400 Subject: workqueue: Add a workqueue chapter to the tracepoint docbook Add a workqueue chapter to the traceopint docbook. Current book is at: http://www.kernel.org/doc/htmldocs/tracepoint/ Signed-off-by: Jason Baron Signed-off-by: Tejun Heo --- Documentation/DocBook/tracepoint.tmpl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/DocBook/tracepoint.tmpl b/Documentation/DocBook/tracepoint.tmpl index e8473eae2a20..b57a9ede3224 100644 --- a/Documentation/DocBook/tracepoint.tmpl +++ b/Documentation/DocBook/tracepoint.tmpl @@ -104,4 +104,9 @@ Block IO !Iinclude/trace/events/block.h + + + Workqueue +!Iinclude/trace/events/workqueue.h + -- cgit v1.2.3-59-g8ed1b From f137f15072411618e37b338aa13e5ae43583bcf2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 11 Aug 2010 12:11:41 +0200 Subject: fs/ecryptfs: Return -ENOMEM on memory allocation failure In this code, 0 is returned on memory allocation failure, even though other failures return -ENOMEM or other similar values. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression ret; expression x,e1,e2,e3; @@ ret = 0 ... when != ret = e1 *x = \(kmalloc\|kcalloc\|kzalloc\)(...) ... when != ret = e2 if (x == NULL) { ... when != ret = e3 return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Tyler Hicks --- fs/ecryptfs/keystore.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 89c5476506ef..73811cfa2ea4 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -515,6 +515,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, if (!s) { printk(KERN_ERR "%s: Out of memory whilst trying to kmalloc " "[%zd] bytes of kernel memory\n", __func__, sizeof(*s)); + rc = -ENOMEM; goto out; } s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; @@ -806,6 +807,7 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size, if (!s) { printk(KERN_ERR "%s: Out of memory whilst trying to kmalloc " "[%zd] bytes of kernel memory\n", __func__, sizeof(*s)); + rc = -ENOMEM; goto out; } s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; -- cgit v1.2.3-59-g8ed1b From 7371a38201d04124a9ff2cf05059731d7c1e35a5 Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Tue, 17 Aug 2010 17:24:05 +0200 Subject: ecryptfs: properly mark init functions Some ecryptfs init functions are not prefixed by __init and thus not freed after initialization. This patch saved about 1kB in ecryptfs module. Signed-off-by: Jerome Marchand Signed-off-by: Tyler Hicks --- fs/ecryptfs/crypto.c | 2 +- fs/ecryptfs/kthread.c | 2 +- fs/ecryptfs/messaging.c | 2 +- fs/ecryptfs/miscdev.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index a2e3b562e65d..13ff48b3eacb 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1793,7 +1793,7 @@ struct kmem_cache *ecryptfs_key_tfm_cache; static struct list_head key_tfm_list; struct mutex key_tfm_list_mutex; -int ecryptfs_init_crypto(void) +int __init ecryptfs_init_crypto(void) { mutex_init(&key_tfm_list_mutex); INIT_LIST_HEAD(&key_tfm_list); diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c index d8c3a373aafa..0851ab6980f5 100644 --- a/fs/ecryptfs/kthread.c +++ b/fs/ecryptfs/kthread.c @@ -86,7 +86,7 @@ out: return 0; } -int ecryptfs_init_kthread(void) +int __init ecryptfs_init_kthread(void) { int rc = 0; diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index bcb68c0cb1f0..ab2248090515 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c @@ -473,7 +473,7 @@ sleep: return rc; } -int ecryptfs_init_messaging(void) +int __init ecryptfs_init_messaging(void) { int i; int rc = 0; diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 3745f612bcd4..00208c3d7e92 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c @@ -500,7 +500,7 @@ static struct miscdevice ecryptfs_miscdev = { * * Returns zero on success; non-zero otherwise */ -int ecryptfs_init_ecryptfs_miscdev(void) +int __init ecryptfs_init_ecryptfs_miscdev(void) { int rc; -- cgit v1.2.3-59-g8ed1b From 93c3fe40c279f002906ad14584c30671097d4394 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Wed, 25 Aug 2010 10:26:37 -0500 Subject: eCryptfs: Fix encrypted file name lookup regression Fixes a regression caused by 21edad32205e97dc7ccb81a85234c77e760364c8 When file name encryption was enabled, ecryptfs_lookup() failed to use the encrypted and encoded version of the upper, plaintext, file name when performing a lookup in the lower file system. This made it impossible to lookup existing encrypted file names and any newly created files would have plaintext file names in the lower file system. https://bugs.launchpad.net/ecryptfs/+bug/623087 Signed-off-by: Tyler Hicks --- fs/ecryptfs/crypto.c | 1 - fs/ecryptfs/inode.c | 31 ++++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 13ff48b3eacb..cbadc1bee6e7 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -2169,7 +2169,6 @@ int ecryptfs_encrypt_and_encode_filename( (ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE + encoded_name_no_prefix_size); (*encoded_name)[(*encoded_name_size)] = '\0'; - (*encoded_name_size)++; } else { rc = -EOPNOTSUPP; } diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 6c55113e7222..3fbc94203380 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -349,7 +349,7 @@ out: /** * ecryptfs_new_lower_dentry - * @ename: The name of the new dentry. + * @name: The name of the new dentry. * @lower_dir_dentry: Parent directory of the new dentry. * @nd: nameidata from last lookup. * @@ -386,20 +386,19 @@ ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry, * ecryptfs_lookup_one_lower * @ecryptfs_dentry: The eCryptfs dentry that we are looking up * @lower_dir_dentry: lower parent directory + * @name: lower file name * * Get the lower dentry from vfs. If lower dentry does not exist yet, * create it. */ static struct dentry * ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry, - struct dentry *lower_dir_dentry) + struct dentry *lower_dir_dentry, struct qstr *name) { struct nameidata nd; struct vfsmount *lower_mnt; - struct qstr *name; int err; - name = &ecryptfs_dentry->d_name; lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( ecryptfs_dentry->d_parent)); err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd); @@ -434,6 +433,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, size_t encrypted_and_encoded_name_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; struct dentry *lower_dir_dentry, *lower_dentry; + struct qstr lower_name; int rc = 0; ecryptfs_dentry->d_op = &ecryptfs_dops; @@ -444,9 +444,17 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, goto out_d_drop; } lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); - + lower_name.name = ecryptfs_dentry->d_name.name; + lower_name.len = ecryptfs_dentry->d_name.len; + lower_name.hash = ecryptfs_dentry->d_name.hash; + if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { + rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, + &lower_name); + if (rc < 0) + goto out_d_drop; + } lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, - lower_dir_dentry); + lower_dir_dentry, &lower_name); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " @@ -471,8 +479,17 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, "filename; rc = [%d]\n", __func__, rc); goto out_d_drop; } + lower_name.name = encrypted_and_encoded_name; + lower_name.len = encrypted_and_encoded_name_size; + lower_name.hash = full_name_hash(lower_name.name, lower_name.len); + if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { + rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, + &lower_name); + if (rc < 0) + goto out_d_drop; + } lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, - lower_dir_dentry); + lower_dir_dentry, &lower_name); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " -- cgit v1.2.3-59-g8ed1b From 557de5eb29caeab56c2f97b49eec02e32a2cbe32 Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Sun, 22 Aug 2010 14:22:40 +0300 Subject: libertas: if_sdio: fix buffer alignment in struct if_sdio_card The commit 886275ce41a9751117367fb387ed171049eb6148 (param: lock if_sdio's lbs_helper_name and lbs_fw_name against sysfs changes) introduced new fields into the if_sdio_card structure. It caused missalignment of the if_sdio_card.buffer field and failure at driver load time: ~# modprobe libertas_sdio [ 62.315124] libertas_sdio: Libertas SDIO driver [ 62.319976] libertas_sdio: Copyright Pierre Ossman [ 63.020629] DMA misaligned error with device 48 [ 63.025207] mmci-omap-hs mmci-omap-hs.1: unexpected dma status 800 [ 66.005035] libertas: command 0x0003 timed out [ 66.009826] libertas: Timeout submitting command 0x0003 [ 66.016296] libertas: PREP_CMD: command 0x0003 failed: -110 Adding explicit alignment attribute for the if_sdio_card.buffer field fixes this problem. Signed-off-by: Mike Rapoport Acked-by: Marek Vasut Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 6e71346a7550..382f2371a1ab 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -126,7 +126,7 @@ struct if_sdio_card { const char *helper; const char *firmware; - u8 buffer[65536]; + u8 buffer[65536] __attribute__((aligned(4))); spinlock_t lock; struct if_sdio_packet *packets; -- cgit v1.2.3-59-g8ed1b From ac0a5042befbe4396b7650358ad35298512d683d Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 17 Nov 2009 15:40:30 +0000 Subject: Blackfin: punt duplicate SPORT MMR defines The common bfin_sport.h header now has unified definitions of these, so stop polluting the global namespace. Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/bfin_sport.h | 6 -- .../mach-bf518/include/mach/defBF51x_base.h | 82 ---------------- .../mach-bf527/include/mach/defBF52x_base.h | 82 ---------------- arch/blackfin/mach-bf533/include/mach/defBF532.h | 92 ------------------ arch/blackfin/mach-bf537/include/mach/defBF534.h | 80 --------------- arch/blackfin/mach-bf538/include/mach/defBF539.h | 107 --------------------- .../mach-bf548/include/mach/defBF54x_base.h | 67 ------------- arch/blackfin/mach-bf561/include/mach/defBF561.h | 60 ------------ 8 files changed, 576 deletions(-) diff --git a/arch/blackfin/include/asm/bfin_sport.h b/arch/blackfin/include/asm/bfin_sport.h index 9626cf7e4251..d27600c262c2 100644 --- a/arch/blackfin/include/asm/bfin_sport.h +++ b/arch/blackfin/include/asm/bfin_sport.h @@ -115,12 +115,6 @@ struct sport_register { #endif -/* Workaround defBF*.h SPORT MMRs till they get cleansed */ -#undef DTYPE_NORM -#undef SLEN -#undef SP_WOFF -#undef SP_WSIZE - /* SPORT_TCR1 Masks */ #define TSPEN 0x0001 /* TX enable */ #define ITCLK 0x0002 /* Internal TX Clock Select */ diff --git a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h index 2bc8f4f98011..037a51fd8e93 100644 --- a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h +++ b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h @@ -913,88 +913,6 @@ #define PH6 0x0040 #define PH7 0x0080 - -/* ******************* SERIAL PORT MASKS **************************************/ -/* SPORTx_TCR1 Masks */ -#define TSPEN 0x0001 /* Transmit Enable */ -#define ITCLK 0x0002 /* Internal Transmit Clock Select */ -#define DTYPE_NORM 0x0004 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define TLSBIT 0x0010 /* Transmit Bit Order */ -#define ITFS 0x0200 /* Internal Transmit Frame Sync Select */ -#define TFSR 0x0400 /* Transmit Frame Sync Required Select */ -#define DITFS 0x0800 /* Data-Independent Transmit Frame Sync Select */ -#define LTFS 0x1000 /* Low Transmit Frame Sync Select */ -#define LATFS 0x2000 /* Late Transmit Frame Sync Select */ -#define TCKFE 0x4000 /* Clock Falling Edge Select */ - -/* SPORTx_TCR2 Masks and Macro */ -#define SLEN(x) ((x)&0x1F) /* SPORT TX Word Length (2 - 31) */ -#define TXSE 0x0100 /* TX Secondary Enable */ -#define TSFSE 0x0200 /* Transmit Stereo Frame Sync Enable */ -#define TRFST 0x0400 /* Left/Right Order (1 = Right Channel 1st) */ - -/* SPORTx_RCR1 Masks */ -#define RSPEN 0x0001 /* Receive Enable */ -#define IRCLK 0x0002 /* Internal Receive Clock Select */ -#define DTYPE_NORM 0x0004 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define RLSBIT 0x0010 /* Receive Bit Order */ -#define IRFS 0x0200 /* Internal Receive Frame Sync Select */ -#define RFSR 0x0400 /* Receive Frame Sync Required Select */ -#define LRFS 0x1000 /* Low Receive Frame Sync Select */ -#define LARFS 0x2000 /* Late Receive Frame Sync Select */ -#define RCKFE 0x4000 /* Clock Falling Edge Select */ - -/* SPORTx_RCR2 Masks */ -#define SLEN(x) ((x)&0x1F) /* SPORT RX Word Length (2 - 31) */ -#define RXSE 0x0100 /* RX Secondary Enable */ -#define RSFSE 0x0200 /* RX Stereo Frame Sync Enable */ -#define RRFST 0x0400 /* Right-First Data Order */ - -/* SPORTx_STAT Masks */ -#define RXNE 0x0001 /* Receive FIFO Not Empty Status */ -#define RUVF 0x0002 /* Sticky Receive Underflow Status */ -#define ROVF 0x0004 /* Sticky Receive Overflow Status */ -#define TXF 0x0008 /* Transmit FIFO Full Status */ -#define TUVF 0x0010 /* Sticky Transmit Underflow Status */ -#define TOVF 0x0020 /* Sticky Transmit Overflow Status */ -#define TXHRE 0x0040 /* Transmit Hold Register Empty */ - -/* SPORTx_MCMC1 Macros */ -#define SP_WOFF(x) ((x) & 0x3FF) /* Multichannel Window Offset Field */ - -/* Only use WSIZE Macro With Logic OR While Setting Lower Order Bits */ -#define SP_WSIZE(x) (((((x)>>0x3)-1)&0xF) << 0xC) /* Multichannel Window Size = (x/8)-1 */ - -/* SPORTx_MCMC2 Masks */ -#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */ -#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */ -#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */ -#define MCDTXPE 0x0004 /* Multichannel DMA Transmit Packing */ -#define MCDRXPE 0x0008 /* Multichannel DMA Receive Packing */ -#define MCMEN 0x0010 /* Multichannel Frame Mode Enable */ -#define FSDR 0x0080 /* Multichannel Frame Sync to Data Relationship */ -#define MFD_0 0x0000 /* Multichannel Frame Delay = 0 */ -#define MFD_1 0x1000 /* Multichannel Frame Delay = 1 */ -#define MFD_2 0x2000 /* Multichannel Frame Delay = 2 */ -#define MFD_3 0x3000 /* Multichannel Frame Delay = 3 */ -#define MFD_4 0x4000 /* Multichannel Frame Delay = 4 */ -#define MFD_5 0x5000 /* Multichannel Frame Delay = 5 */ -#define MFD_6 0x6000 /* Multichannel Frame Delay = 6 */ -#define MFD_7 0x7000 /* Multichannel Frame Delay = 7 */ -#define MFD_8 0x8000 /* Multichannel Frame Delay = 8 */ -#define MFD_9 0x9000 /* Multichannel Frame Delay = 9 */ -#define MFD_10 0xA000 /* Multichannel Frame Delay = 10 */ -#define MFD_11 0xB000 /* Multichannel Frame Delay = 11 */ -#define MFD_12 0xC000 /* Multichannel Frame Delay = 12 */ -#define MFD_13 0xD000 /* Multichannel Frame Delay = 13 */ -#define MFD_14 0xE000 /* Multichannel Frame Delay = 14 */ -#define MFD_15 0xF000 /* Multichannel Frame Delay = 15 */ - - /* ********************* ASYNCHRONOUS MEMORY CONTROLLER MASKS *************************/ /* EBIU_AMGCTL Masks */ #define AMCKEN 0x0001 /* Enable CLKOUT */ diff --git a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h index 5f97f01fcda6..3e000756aacd 100644 --- a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h +++ b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h @@ -922,88 +922,6 @@ #define PH14 0x4000 #define PH15 0x8000 - -/* ******************* SERIAL PORT MASKS **************************************/ -/* SPORTx_TCR1 Masks */ -#define TSPEN 0x0001 /* Transmit Enable */ -#define ITCLK 0x0002 /* Internal Transmit Clock Select */ -#define DTYPE_NORM 0x0004 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define TLSBIT 0x0010 /* Transmit Bit Order */ -#define ITFS 0x0200 /* Internal Transmit Frame Sync Select */ -#define TFSR 0x0400 /* Transmit Frame Sync Required Select */ -#define DITFS 0x0800 /* Data-Independent Transmit Frame Sync Select */ -#define LTFS 0x1000 /* Low Transmit Frame Sync Select */ -#define LATFS 0x2000 /* Late Transmit Frame Sync Select */ -#define TCKFE 0x4000 /* Clock Falling Edge Select */ - -/* SPORTx_TCR2 Masks and Macro */ -#define SLEN(x) ((x)&0x1F) /* SPORT TX Word Length (2 - 31) */ -#define TXSE 0x0100 /* TX Secondary Enable */ -#define TSFSE 0x0200 /* Transmit Stereo Frame Sync Enable */ -#define TRFST 0x0400 /* Left/Right Order (1 = Right Channel 1st) */ - -/* SPORTx_RCR1 Masks */ -#define RSPEN 0x0001 /* Receive Enable */ -#define IRCLK 0x0002 /* Internal Receive Clock Select */ -#define DTYPE_NORM 0x0004 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define RLSBIT 0x0010 /* Receive Bit Order */ -#define IRFS 0x0200 /* Internal Receive Frame Sync Select */ -#define RFSR 0x0400 /* Receive Frame Sync Required Select */ -#define LRFS 0x1000 /* Low Receive Frame Sync Select */ -#define LARFS 0x2000 /* Late Receive Frame Sync Select */ -#define RCKFE 0x4000 /* Clock Falling Edge Select */ - -/* SPORTx_RCR2 Masks */ -#define SLEN(x) ((x)&0x1F) /* SPORT RX Word Length (2 - 31) */ -#define RXSE 0x0100 /* RX Secondary Enable */ -#define RSFSE 0x0200 /* RX Stereo Frame Sync Enable */ -#define RRFST 0x0400 /* Right-First Data Order */ - -/* SPORTx_STAT Masks */ -#define RXNE 0x0001 /* Receive FIFO Not Empty Status */ -#define RUVF 0x0002 /* Sticky Receive Underflow Status */ -#define ROVF 0x0004 /* Sticky Receive Overflow Status */ -#define TXF 0x0008 /* Transmit FIFO Full Status */ -#define TUVF 0x0010 /* Sticky Transmit Underflow Status */ -#define TOVF 0x0020 /* Sticky Transmit Overflow Status */ -#define TXHRE 0x0040 /* Transmit Hold Register Empty */ - -/* SPORTx_MCMC1 Macros */ -#define SP_WOFF(x) ((x) & 0x3FF) /* Multichannel Window Offset Field */ - -/* Only use WSIZE Macro With Logic OR While Setting Lower Order Bits */ -#define SP_WSIZE(x) (((((x)>>0x3)-1)&0xF) << 0xC) /* Multichannel Window Size = (x/8)-1 */ - -/* SPORTx_MCMC2 Masks */ -#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */ -#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */ -#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */ -#define MCDTXPE 0x0004 /* Multichannel DMA Transmit Packing */ -#define MCDRXPE 0x0008 /* Multichannel DMA Receive Packing */ -#define MCMEN 0x0010 /* Multichannel Frame Mode Enable */ -#define FSDR 0x0080 /* Multichannel Frame Sync to Data Relationship */ -#define MFD_0 0x0000 /* Multichannel Frame Delay = 0 */ -#define MFD_1 0x1000 /* Multichannel Frame Delay = 1 */ -#define MFD_2 0x2000 /* Multichannel Frame Delay = 2 */ -#define MFD_3 0x3000 /* Multichannel Frame Delay = 3 */ -#define MFD_4 0x4000 /* Multichannel Frame Delay = 4 */ -#define MFD_5 0x5000 /* Multichannel Frame Delay = 5 */ -#define MFD_6 0x6000 /* Multichannel Frame Delay = 6 */ -#define MFD_7 0x7000 /* Multichannel Frame Delay = 7 */ -#define MFD_8 0x8000 /* Multichannel Frame Delay = 8 */ -#define MFD_9 0x9000 /* Multichannel Frame Delay = 9 */ -#define MFD_10 0xA000 /* Multichannel Frame Delay = 10 */ -#define MFD_11 0xB000 /* Multichannel Frame Delay = 11 */ -#define MFD_12 0xC000 /* Multichannel Frame Delay = 12 */ -#define MFD_13 0xD000 /* Multichannel Frame Delay = 13 */ -#define MFD_14 0xE000 /* Multichannel Frame Delay = 14 */ -#define MFD_15 0xF000 /* Multichannel Frame Delay = 15 */ - - /* ********************* ASYNCHRONOUS MEMORY CONTROLLER MASKS *************************/ /* EBIU_AMGCTL Masks */ #define AMCKEN 0x0001 /* Enable CLKOUT */ diff --git a/arch/blackfin/mach-bf533/include/mach/defBF532.h b/arch/blackfin/mach-bf533/include/mach/defBF532.h index e9ff491c0953..04acf1ed10f9 100644 --- a/arch/blackfin/mach-bf533/include/mach/defBF532.h +++ b/arch/blackfin/mach-bf533/include/mach/defBF532.h @@ -509,98 +509,6 @@ #define IREN_P 0x01 #define UCEN_P 0x00 -/* ********** SERIAL PORT MASKS ********************** */ - -/* SPORTx_TCR1 Masks */ -#define TSPEN 0x0001 /* TX enable */ -#define ITCLK 0x0002 /* Internal TX Clock Select */ -#define TDTYPE 0x000C /* TX Data Formatting Select */ -#define DTYPE_NORM 0x0000 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define TLSBIT 0x0010 /* TX Bit Order */ -#define ITFS 0x0200 /* Internal TX Frame Sync Select */ -#define TFSR 0x0400 /* TX Frame Sync Required Select */ -#define DITFS 0x0800 /* Data Independent TX Frame Sync Select */ -#define LTFS 0x1000 /* Low TX Frame Sync Select */ -#define LATFS 0x2000 /* Late TX Frame Sync Select */ -#define TCKFE 0x4000 /* TX Clock Falling Edge Select */ - -/* SPORTx_TCR2 Masks */ -#if defined(__ADSPBF531__) || defined(__ADSPBF532__) || \ - defined(__ADSPBF533__) -# define SLEN 0x001F /*TX Word Length */ -#else -# define SLEN(x) ((x)&0x1F) /* SPORT TX Word Length (2 - 31) */ -#endif -#define TXSE 0x0100 /*TX Secondary Enable */ -#define TSFSE 0x0200 /*TX Stereo Frame Sync Enable */ -#define TRFST 0x0400 /*TX Right-First Data Order */ - -/* SPORTx_RCR1 Masks */ -#define RSPEN 0x0001 /* RX enable */ -#define IRCLK 0x0002 /* Internal RX Clock Select */ -#define RDTYPE 0x000C /* RX Data Formatting Select */ -#define DTYPE_NORM 0x0000 /* no companding */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define RLSBIT 0x0010 /* RX Bit Order */ -#define IRFS 0x0200 /* Internal RX Frame Sync Select */ -#define RFSR 0x0400 /* RX Frame Sync Required Select */ -#define LRFS 0x1000 /* Low RX Frame Sync Select */ -#define LARFS 0x2000 /* Late RX Frame Sync Select */ -#define RCKFE 0x4000 /* RX Clock Falling Edge Select */ - -/* SPORTx_RCR2 Masks */ -/* SLEN defined above */ -#define RXSE 0x0100 /*RX Secondary Enable */ -#define RSFSE 0x0200 /*RX Stereo Frame Sync Enable */ -#define RRFST 0x0400 /*Right-First Data Order */ - -/*SPORTx_STAT Masks */ -#define RXNE 0x0001 /*RX FIFO Not Empty Status */ -#define RUVF 0x0002 /*RX Underflow Status */ -#define ROVF 0x0004 /*RX Overflow Status */ -#define TXF 0x0008 /*TX FIFO Full Status */ -#define TUVF 0x0010 /*TX Underflow Status */ -#define TOVF 0x0020 /*TX Overflow Status */ -#define TXHRE 0x0040 /*TX Hold Register Empty */ - -/*SPORTx_MCMC1 Masks */ -#define SP_WSIZE 0x0000F000 /*Multichannel Window Size Field */ -#define SP_WOFF 0x000003FF /*Multichannel Window Offset Field */ -/* SPORTx_MCMC1 Macros */ -#define SET_SP_WOFF(x) ((x) & 0x3FF) /* Multichannel Window Offset Field */ -/* Only use SET_WSIZE Macro With Logic OR While Setting Lower Order Bits */ -#define SET_SP_WSIZE(x) (((((x)>>0x3)-1)&0xF) << 0xC) /* Multichannel Window Size = (x/8)-1 */ - -/*SPORTx_MCMC2 Masks */ -#define MCCRM 0x00000003 /*Multichannel Clock Recovery Mode */ -#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */ -#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */ -#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */ -#define MCDTXPE 0x00000004 /*Multichannel DMA Transmit Packing */ -#define MCDRXPE 0x00000008 /*Multichannel DMA Receive Packing */ -#define MCMEN 0x00000010 /*Multichannel Frame Mode Enable */ -#define FSDR 0x00000080 /*Multichannel Frame Sync to Data Relationship */ -#define MFD 0x0000F000 /*Multichannel Frame Delay */ -#define MFD_0 0x0000 /* Multichannel Frame Delay = 0 */ -#define MFD_1 0x1000 /* Multichannel Frame Delay = 1 */ -#define MFD_2 0x2000 /* Multichannel Frame Delay = 2 */ -#define MFD_3 0x3000 /* Multichannel Frame Delay = 3 */ -#define MFD_4 0x4000 /* Multichannel Frame Delay = 4 */ -#define MFD_5 0x5000 /* Multichannel Frame Delay = 5 */ -#define MFD_6 0x6000 /* Multichannel Frame Delay = 6 */ -#define MFD_7 0x7000 /* Multichannel Frame Delay = 7 */ -#define MFD_8 0x8000 /* Multichannel Frame Delay = 8 */ -#define MFD_9 0x9000 /* Multichannel Frame Delay = 9 */ -#define MFD_10 0xA000 /* Multichannel Frame Delay = 10 */ -#define MFD_11 0xB000 /* Multichannel Frame Delay = 11 */ -#define MFD_12 0xC000 /* Multichannel Frame Delay = 12 */ -#define MFD_13 0xD000 /* Multichannel Frame Delay = 13 */ -#define MFD_14 0xE000 /* Multichannel Frame Delay = 14 */ -#define MFD_15 0xF000 /* Multichannel Frame Delay = 15 */ - /* ********* PARALLEL PERIPHERAL INTERFACE (PPI) MASKS **************** */ /* PPI_CONTROL Masks */ diff --git a/arch/blackfin/mach-bf537/include/mach/defBF534.h b/arch/blackfin/mach-bf537/include/mach/defBF534.h index aad61b887373..6f56907a18c0 100644 --- a/arch/blackfin/mach-bf537/include/mach/defBF534.h +++ b/arch/blackfin/mach-bf537/include/mach/defBF534.h @@ -1241,86 +1241,6 @@ #define PH14 0x4000 #define PH15 0x8000 -/* ******************* SERIAL PORT MASKS **************************************/ -/* SPORTx_TCR1 Masks */ -#define TSPEN 0x0001 /* Transmit Enable */ -#define ITCLK 0x0002 /* Internal Transmit Clock Select */ -#define DTYPE_NORM 0x0004 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define TLSBIT 0x0010 /* Transmit Bit Order */ -#define ITFS 0x0200 /* Internal Transmit Frame Sync Select */ -#define TFSR 0x0400 /* Transmit Frame Sync Required Select */ -#define DITFS 0x0800 /* Data-Independent Transmit Frame Sync Select */ -#define LTFS 0x1000 /* Low Transmit Frame Sync Select */ -#define LATFS 0x2000 /* Late Transmit Frame Sync Select */ -#define TCKFE 0x4000 /* Clock Falling Edge Select */ - -/* SPORTx_TCR2 Masks and Macro */ -#define SLEN(x) ((x)&0x1F) /* SPORT TX Word Length (2 - 31) */ -#define TXSE 0x0100 /* TX Secondary Enable */ -#define TSFSE 0x0200 /* Transmit Stereo Frame Sync Enable */ -#define TRFST 0x0400 /* Left/Right Order (1 = Right Channel 1st) */ - -/* SPORTx_RCR1 Masks */ -#define RSPEN 0x0001 /* Receive Enable */ -#define IRCLK 0x0002 /* Internal Receive Clock Select */ -#define DTYPE_NORM 0x0004 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define RLSBIT 0x0010 /* Receive Bit Order */ -#define IRFS 0x0200 /* Internal Receive Frame Sync Select */ -#define RFSR 0x0400 /* Receive Frame Sync Required Select */ -#define LRFS 0x1000 /* Low Receive Frame Sync Select */ -#define LARFS 0x2000 /* Late Receive Frame Sync Select */ -#define RCKFE 0x4000 /* Clock Falling Edge Select */ - -/* SPORTx_RCR2 Masks */ -#define SLEN(x) ((x)&0x1F) /* SPORT RX Word Length (2 - 31) */ -#define RXSE 0x0100 /* RX Secondary Enable */ -#define RSFSE 0x0200 /* RX Stereo Frame Sync Enable */ -#define RRFST 0x0400 /* Right-First Data Order */ - -/* SPORTx_STAT Masks */ -#define RXNE 0x0001 /* Receive FIFO Not Empty Status */ -#define RUVF 0x0002 /* Sticky Receive Underflow Status */ -#define ROVF 0x0004 /* Sticky Receive Overflow Status */ -#define TXF 0x0008 /* Transmit FIFO Full Status */ -#define TUVF 0x0010 /* Sticky Transmit Underflow Status */ -#define TOVF 0x0020 /* Sticky Transmit Overflow Status */ -#define TXHRE 0x0040 /* Transmit Hold Register Empty */ - -/* SPORTx_MCMC1 Macros */ -#define SP_WOFF(x) ((x) & 0x3FF) /* Multichannel Window Offset Field */ - -/* Only use WSIZE Macro With Logic OR While Setting Lower Order Bits */ -#define SP_WSIZE(x) (((((x)>>0x3)-1)&0xF) << 0xC) /* Multichannel Window Size = (x/8)-1 */ - -/* SPORTx_MCMC2 Masks */ -#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */ -#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */ -#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */ -#define MCDTXPE 0x0004 /* Multichannel DMA Transmit Packing */ -#define MCDRXPE 0x0008 /* Multichannel DMA Receive Packing */ -#define MCMEN 0x0010 /* Multichannel Frame Mode Enable */ -#define FSDR 0x0080 /* Multichannel Frame Sync to Data Relationship */ -#define MFD_0 0x0000 /* Multichannel Frame Delay = 0 */ -#define MFD_1 0x1000 /* Multichannel Frame Delay = 1 */ -#define MFD_2 0x2000 /* Multichannel Frame Delay = 2 */ -#define MFD_3 0x3000 /* Multichannel Frame Delay = 3 */ -#define MFD_4 0x4000 /* Multichannel Frame Delay = 4 */ -#define MFD_5 0x5000 /* Multichannel Frame Delay = 5 */ -#define MFD_6 0x6000 /* Multichannel Frame Delay = 6 */ -#define MFD_7 0x7000 /* Multichannel Frame Delay = 7 */ -#define MFD_8 0x8000 /* Multichannel Frame Delay = 8 */ -#define MFD_9 0x9000 /* Multichannel Frame Delay = 9 */ -#define MFD_10 0xA000 /* Multichannel Frame Delay = 10 */ -#define MFD_11 0xB000 /* Multichannel Frame Delay = 11 */ -#define MFD_12 0xC000 /* Multichannel Frame Delay = 12 */ -#define MFD_13 0xD000 /* Multichannel Frame Delay = 13 */ -#define MFD_14 0xE000 /* Multichannel Frame Delay = 14 */ -#define MFD_15 0xF000 /* Multichannel Frame Delay = 15 */ - /* ********************* ASYNCHRONOUS MEMORY CONTROLLER MASKS *************************/ /* EBIU_AMGCTL Masks */ #define AMCKEN 0x0001 /* Enable CLKOUT */ diff --git a/arch/blackfin/mach-bf538/include/mach/defBF539.h b/arch/blackfin/mach-bf538/include/mach/defBF539.h index b674a1c4aef1..fe43062b4975 100644 --- a/arch/blackfin/mach-bf538/include/mach/defBF539.h +++ b/arch/blackfin/mach-bf538/include/mach/defBF539.h @@ -1610,113 +1610,6 @@ #define UCEN_P 0x00 -/* ********** SERIAL PORT MASKS ********************** */ -/* SPORTx_TCR1 Masks */ -#define TSPEN 0x0001 /* TX enable */ -#define ITCLK 0x0002 /* Internal TX Clock Select */ -#define TDTYPE 0x000C /* TX Data Formatting Select */ -#define DTYPE_NORM 0x0000 /* Data Format Normal */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define TLSBIT 0x0010 /* TX Bit Order */ -#define ITFS 0x0200 /* Internal TX Frame Sync Select */ -#define TFSR 0x0400 /* TX Frame Sync Required Select */ -#define DITFS 0x0800 /* Data Independent TX Frame Sync Select */ -#define LTFS 0x1000 /* Low TX Frame Sync Select */ -#define LATFS 0x2000 /* Late TX Frame Sync Select */ -#define TCKFE 0x4000 /* TX Clock Falling Edge Select */ -/* SPORTx_RCR1 Deprecated Masks */ -#define TULAW DTYPE_ULAW /* Compand Using u-Law */ -#define TALAW DTYPE_ALAW /* Compand Using A-Law */ - -/* SPORTx_TCR2 Masks */ -#ifdef _MISRA_RULES -#define SLEN(x) ((x)&0x1Fu) /* SPORT TX Word Length (2 - 31) */ -#else -#define SLEN(x) ((x)&0x1F) /* SPORT TX Word Length (2 - 31) */ -#endif /* _MISRA_RULES */ -#define TXSE 0x0100 /*TX Secondary Enable */ -#define TSFSE 0x0200 /*TX Stereo Frame Sync Enable */ -#define TRFST 0x0400 /*TX Right-First Data Order */ - -/* SPORTx_RCR1 Masks */ -#define RSPEN 0x0001 /* RX enable */ -#define IRCLK 0x0002 /* Internal RX Clock Select */ -#define RDTYPE 0x000C /* RX Data Formatting Select */ -#define DTYPE_NORM 0x0000 /* no companding */ -#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */ -#define DTYPE_ALAW 0x000C /* Compand Using A-Law */ -#define RLSBIT 0x0010 /* RX Bit Order */ -#define IRFS 0x0200 /* Internal RX Frame Sync Select */ -#define RFSR 0x0400 /* RX Frame Sync Required Select */ -#define LRFS 0x1000 /* Low RX Frame Sync Select */ -#define LARFS 0x2000 /* Late RX Frame Sync Select */ -#define RCKFE 0x4000 /* RX Clock Falling Edge Select */ -/* SPORTx_RCR1 Deprecated Masks */ -#define RULAW DTYPE_ULAW /* Compand Using u-Law */ -#define RALAW DTYPE_ALAW /* Compand Using A-Law */ - -/* SPORTx_RCR2 Masks */ -#ifdef _MISRA_RULES -#define SLEN(x) ((x)&0x1Fu) /* SPORT RX Word Length (2 - 31) */ -#else -#define SLEN(x) ((x)&0x1F) /* SPORT RX Word Length (2 - 31) */ -#endif /* _MISRA_RULES */ -#define RXSE 0x0100 /*RX Secondary Enable */ -#define RSFSE 0x0200 /*RX Stereo Frame Sync Enable */ -#define RRFST 0x0400 /*Right-First Data Order */ - -/*SPORTx_STAT Masks */ -#define RXNE 0x0001 /*RX FIFO Not Empty Status */ -#define RUVF 0x0002 /*RX Underflow Status */ -#define ROVF 0x0004 /*RX Overflow Status */ -#define TXF 0x0008 /*TX FIFO Full Status */ -#define TUVF 0x0010 /*TX Underflow Status */ -#define TOVF 0x0020 /*TX Overflow Status */ -#define TXHRE 0x0040 /*TX Hold Register Empty */ - -/*SPORTx_MCMC1 Masks */ -#define WOFF 0x000003FF /*Multichannel Window Offset Field */ -/* SPORTx_MCMC1 Macros */ -#ifdef _MISRA_RULES -#define SET_WOFF(x) ((x) & 0x3FFu) /* Multichannel Window Offset Field */ -/* Only use SET_WSIZE Macro With Logic OR While Setting Lower Order Bits */ -#define SET_WSIZE(x) (((((x)>>0x3)-1u)&0xFu) << 0xC) /* Multichannel Window Size = (x/8)-1 */ -#else -#define SET_WOFF(x) ((x) & 0x3FF) /* Multichannel Window Offset Field */ -/* Only use SET_WSIZE Macro With Logic OR While Setting Lower Order Bits */ -#define SET_WSIZE(x) (((((x)>>0x3)-1)&0xF) << 0xC) /* Multichannel Window Size = (x/8)-1 */ -#endif /* _MISRA_RULES */ - - -/*SPORTx_MCMC2 Masks */ -#define MCCRM 0x0003 /*Multichannel Clock Recovery Mode */ -#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */ -#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */ -#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */ -#define MCDTXPE 0x0004 /*Multichannel DMA Transmit Packing */ -#define MCDRXPE 0x0008 /*Multichannel DMA Receive Packing */ -#define MCMEN 0x0010 /*Multichannel Frame Mode Enable */ -#define FSDR 0x0080 /*Multichannel Frame Sync to Data Relationship */ -#define MFD 0xF000 /*Multichannel Frame Delay */ -#define MFD_0 0x0000 /* Multichannel Frame Delay = 0 */ -#define MFD_1 0x1000 /* Multichannel Frame Delay = 1 */ -#define MFD_2 0x2000 /* Multichannel Frame Delay = 2 */ -#define MFD_3 0x3000 /* Multichannel Frame Delay = 3 */ -#define MFD_4 0x4000 /* Multichannel Frame Delay = 4 */ -#define MFD_5 0x5000 /* Multichannel Frame Delay = 5 */ -#define MFD_6 0x6000 /* Multichannel Frame Delay = 6 */ -#define MFD_7 0x7000 /* Multichannel Frame Delay = 7 */ -#define MFD_8 0x8000 /* Multichannel Frame Delay = 8 */ -#define MFD_9 0x9000 /* Multichannel Frame Delay = 9 */ -#define MFD_10 0xA000 /* Multichannel Frame Delay = 10 */ -#define MFD_11 0xB000 /* Multichannel Frame Delay = 11 */ -#define MFD_12 0xC000 /* Multichannel Frame Delay = 12 */ -#define MFD_13 0xD000 /* Multichannel Frame Delay = 13 */ -#define MFD_14 0xE000 /* Multichannel Frame Delay = 14 */ -#define MFD_15 0xF000 /* Multichannel Frame Delay = 15 */ - - /* ********* PARALLEL PERIPHERAL INTERFACE (PPI) MASKS **************** */ /* PPI_CONTROL Masks */ #define PORT_EN 0x0001 /* PPI Port Enable */ diff --git a/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h b/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h index 95ff44601fd1..7866197f5485 100644 --- a/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h +++ b/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h @@ -2221,73 +2221,6 @@ #define RCVDATA16 0xffff /* Receive FIFO 16-Bit Data */ -/* Bit masks for SPORTx_TCR1 */ - -#define TCKFE 0x4000 /* Clock Falling Edge Select */ -#define LATFS 0x2000 /* Late Transmit Frame Sync */ -#define LTFS 0x1000 /* Low Transmit Frame Sync Select */ -#define DITFS 0x800 /* Data-Independent Transmit Frame Sync Select */ -#define TFSR 0x400 /* Transmit Frame Sync Required Select */ -#define ITFS 0x200 /* Internal Transmit Frame Sync Select */ -#define TLSBIT 0x10 /* Transmit Bit Order */ -#define TDTYPE 0xc /* Data Formatting Type Select */ -#define ITCLK 0x2 /* Internal Transmit Clock Select */ -#define TSPEN 0x1 /* Transmit Enable */ - -/* Bit masks for SPORTx_TCR2 */ - -#define TRFST 0x400 /* Left/Right Order */ -#define TSFSE 0x200 /* Transmit Stereo Frame Sync Enable */ -#define TXSE 0x100 /* TxSEC Enable */ -#define SLEN_T 0x1f /* SPORT Word Length */ - -/* Bit masks for SPORTx_RCR1 */ - -#define RCKFE 0x4000 /* Clock Falling Edge Select */ -#define LARFS 0x2000 /* Late Receive Frame Sync */ -#define LRFS 0x1000 /* Low Receive Frame Sync Select */ -#define RFSR 0x400 /* Receive Frame Sync Required Select */ -#define IRFS 0x200 /* Internal Receive Frame Sync Select */ -#define RLSBIT 0x10 /* Receive Bit Order */ -#define RDTYPE 0xc /* Data Formatting Type Select */ -#define IRCLK 0x2 /* Internal Receive Clock Select */ -#define RSPEN 0x1 /* Receive Enable */ - -/* Bit masks for SPORTx_RCR2 */ - -#define RRFST 0x400 /* Left/Right Order */ -#define RSFSE 0x200 /* Receive Stereo Frame Sync Enable */ -#define RXSE 0x100 /* RxSEC Enable */ -#define SLEN_R 0x1f /* SPORT Word Length */ - -/* Bit masks for SPORTx_STAT */ - -#define TXHRE 0x40 /* Transmit Hold Register Empty */ -#define TOVF 0x20 /* Sticky Transmit Overflow Status */ -#define TUVF 0x10 /* Sticky Transmit Underflow Status */ -#define TXF 0x8 /* Transmit FIFO Full Status */ -#define ROVF 0x4 /* Sticky Receive Overflow Status */ -#define RUVF 0x2 /* Sticky Receive Underflow Status */ -#define RXNE 0x1 /* Receive FIFO Not Empty Status */ - -/* Bit masks for SPORTx_MCMC1 */ - -#define SP_WSIZE 0xf000 /* Window Size */ -#define SP_WOFF 0x3ff /* Windows Offset */ - -/* Bit masks for SPORTx_MCMC2 */ - -#define MFD 0xf000 /* Multi channel Frame Delay */ -#define FSDR 0x80 /* Frame Sync to Data Relationship */ -#define MCMEN 0x10 /* Multi channel Frame Mode Enable */ -#define MCDRXPE 0x8 /* Multi channel DMA Receive Packing */ -#define MCDTXPE 0x4 /* Multi channel DMA Transmit Packing */ -#define MCCRM 0x3 /* 2X Clock Recovery Mode */ - -/* Bit masks for SPORTx_CHNL */ - -#define CUR_CHNL 0x3ff /* Current Channel Indicator */ - /* Bit masks for UARTx_LCR */ #if 0 diff --git a/arch/blackfin/mach-bf561/include/mach/defBF561.h b/arch/blackfin/mach-bf561/include/mach/defBF561.h index 4c8e36b7fb33..2674f0097576 100644 --- a/arch/blackfin/mach-bf561/include/mach/defBF561.h +++ b/arch/blackfin/mach-bf561/include/mach/defBF561.h @@ -1007,66 +1007,6 @@ #define IREN_P 0x01 #define UCEN_P 0x00 -/* ********** SERIAL PORT MASKS ********************** */ - -/* SPORTx_TCR1 Masks */ -#define TSPEN 0x0001 /* TX enable */ -#define ITCLK 0x0002 /* Internal TX Clock Select */ -#define TDTYPE 0x000C /* TX Data Formatting Select */ -#define TLSBIT 0x0010 /* TX Bit Order */ -#define ITFS 0x0200 /* Internal TX Frame Sync Select */ -#define TFSR 0x0400 /* TX Frame Sync Required Select */ -#define DITFS 0x0800 /* Data Independent TX Frame Sync Select */ -#define LTFS 0x1000 /* Low TX Frame Sync Select */ -#define LATFS 0x2000 /* Late TX Frame Sync Select */ -#define TCKFE 0x4000 /* TX Clock Falling Edge Select */ - -/* SPORTx_TCR2 Masks */ -#define SLEN 0x001F /*TX Word Length */ -#define TXSE 0x0100 /*TX Secondary Enable */ -#define TSFSE 0x0200 /*TX Stereo Frame Sync Enable */ -#define TRFST 0x0400 /*TX Right-First Data Order */ - -/* SPORTx_RCR1 Masks */ -#define RSPEN 0x0001 /* RX enable */ -#define IRCLK 0x0002 /* Internal RX Clock Select */ -#define RDTYPE 0x000C /* RX Data Formatting Select */ -#define RULAW 0x0008 /* u-Law enable */ -#define RALAW 0x000C /* A-Law enable */ -#define RLSBIT 0x0010 /* RX Bit Order */ -#define IRFS 0x0200 /* Internal RX Frame Sync Select */ -#define RFSR 0x0400 /* RX Frame Sync Required Select */ -#define LRFS 0x1000 /* Low RX Frame Sync Select */ -#define LARFS 0x2000 /* Late RX Frame Sync Select */ -#define RCKFE 0x4000 /* RX Clock Falling Edge Select */ - -/* SPORTx_RCR2 Masks */ -#define SLEN 0x001F /*RX Word Length */ -#define RXSE 0x0100 /*RX Secondary Enable */ -#define RSFSE 0x0200 /*RX Stereo Frame Sync Enable */ -#define RRFST 0x0400 /*Right-First Data Order */ - -/*SPORTx_STAT Masks */ -#define RXNE 0x0001 /*RX FIFO Not Empty Status */ -#define RUVF 0x0002 /*RX Underflow Status */ -#define ROVF 0x0004 /*RX Overflow Status */ -#define TXF 0x0008 /*TX FIFO Full Status */ -#define TUVF 0x0010 /*TX Underflow Status */ -#define TOVF 0x0020 /*TX Overflow Status */ -#define TXHRE 0x0040 /*TX Hold Register Empty */ - -/*SPORTx_MCMC1 Masks */ -#define SP_WSIZE 0x0000F000 /*Multichannel Window Size Field */ -#define SP_WOFF 0x000003FF /*Multichannel Window Offset Field */ - -/*SPORTx_MCMC2 Masks */ -#define MCCRM 0x00000003 /*Multichannel Clock Recovery Mode */ -#define MCDTXPE 0x00000004 /*Multichannel DMA Transmit Packing */ -#define MCDRXPE 0x00000008 /*Multichannel DMA Receive Packing */ -#define MCMEN 0x00000010 /*Multichannel Frame Mode Enable */ -#define FSDR 0x00000080 /*Multichannel Frame Sync to Data Relationship */ -#define MFD 0x0000F000 /*Multichannel Frame Delay */ - /* ********* PARALLEL PERIPHERAL INTERFACE (PPI) MASKS **************** */ /* PPI_CONTROL Masks */ -- cgit v1.2.3-59-g8ed1b From 9e5610a99535723e83b7ddd02f0fd3fe36c86649 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 2 Jun 2010 04:22:11 +0000 Subject: Blackfin: bf52x/bf54x boards: drop unused nand page size Now that the driver for the Blackfin on-chip NFC no longer uses/respects the page_size from the platform resources (figures out the needs on the fly), drop it from the platform resources. This fixes some build errors since the defines no longer exists. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/mach-bf527/boards/cm_bf527.c | 1 - arch/blackfin/mach-bf527/boards/ezbrd.c | 1 - arch/blackfin/mach-bf527/boards/ezkit.c | 1 - arch/blackfin/mach-bf548/boards/cm_bf548.c | 1 - arch/blackfin/mach-bf548/boards/ezkit.c | 1 - 5 files changed, 5 deletions(-) diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c index f392af641657..645ba5c8077b 100644 --- a/arch/blackfin/mach-bf527/boards/cm_bf527.c +++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c @@ -145,7 +145,6 @@ static struct mtd_partition partition_info[] = { }; static struct bf5xx_nand_platform bf5xx_nand_platform = { - .page_size = NFC_PG_SIZE_256, .data_width = NFC_NWIDTH_8, .partitions = partition_info, .nr_partitions = ARRAY_SIZE(partition_info), diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c index 606eb36b9d6e..c975fe88eba3 100644 --- a/arch/blackfin/mach-bf527/boards/ezbrd.c +++ b/arch/blackfin/mach-bf527/boards/ezbrd.c @@ -149,7 +149,6 @@ static struct mtd_partition partition_info[] = { }; static struct bf5xx_nand_platform bf5xx_nand_platform = { - .page_size = NFC_PG_SIZE_256, .data_width = NFC_NWIDTH_8, .partitions = partition_info, .nr_partitions = ARRAY_SIZE(partition_info), diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c index a05c967a24cf..87b41e994ba3 100644 --- a/arch/blackfin/mach-bf527/boards/ezkit.c +++ b/arch/blackfin/mach-bf527/boards/ezkit.c @@ -234,7 +234,6 @@ static struct mtd_partition partition_info[] = { }; static struct bf5xx_nand_platform bf5xx_nand_platform = { - .page_size = NFC_PG_SIZE_256, .data_width = NFC_NWIDTH_8, .partitions = partition_info, .nr_partitions = ARRAY_SIZE(partition_info), diff --git a/arch/blackfin/mach-bf548/boards/cm_bf548.c b/arch/blackfin/mach-bf548/boards/cm_bf548.c index dbb6b1d83f6d..0c38eec9ade1 100644 --- a/arch/blackfin/mach-bf548/boards/cm_bf548.c +++ b/arch/blackfin/mach-bf548/boards/cm_bf548.c @@ -706,7 +706,6 @@ static struct mtd_partition partition_info[] = { }; static struct bf5xx_nand_platform bf5xx_nand_platform = { - .page_size = NFC_PG_SIZE_256, .data_width = NFC_NWIDTH_8, .partitions = partition_info, .nr_partitions = ARRAY_SIZE(partition_info), diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c index 6fcfb9187c35..56682a36e42d 100644 --- a/arch/blackfin/mach-bf548/boards/ezkit.c +++ b/arch/blackfin/mach-bf548/boards/ezkit.c @@ -849,7 +849,6 @@ static struct mtd_partition partition_info[] = { }; static struct bf5xx_nand_platform bf5xx_nand_platform = { - .page_size = NFC_PG_SIZE_256, .data_width = NFC_NWIDTH_8, .partitions = partition_info, .nr_partitions = ARRAY_SIZE(partition_info), -- cgit v1.2.3-59-g8ed1b From 0fb85621df4f9f7c663c6c77c302e821a832c95e Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 20 Aug 2010 10:02:15 +0100 Subject: fanotify: resize pid and reorder structure resize pid and reorder the fanotify_event_metadata so it is naturally aligned and we can work towards dropping the packed attributed Signed-off-by: Tvrtko Ursulin Cc: Andreas Dilger Signed-off-by: Eric Paris --- include/linux/fanotify.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h index 985435622ecd..63531a6b4d2a 100644 --- a/include/linux/fanotify.h +++ b/include/linux/fanotify.h @@ -65,14 +65,14 @@ FAN_ALL_PERM_EVENTS |\ FAN_Q_OVERFLOW) -#define FANOTIFY_METADATA_VERSION 1 +#define FANOTIFY_METADATA_VERSION 2 struct fanotify_event_metadata { __u32 event_len; __u32 vers; - __s32 fd; __u64 mask; - __s64 pid; + __s32 fd; + __s32 pid; } __attribute__ ((packed)); struct fanotify_response { -- cgit v1.2.3-59-g8ed1b From a2f13ad0ba5d94b9768c28469b45ca1e81a2b895 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 24 Aug 2010 12:58:54 +0200 Subject: fanotify: Return EPERM when a process is not privileged The appropriate error code when privileged operations are denied is EPERM, not EACCES. Signed-off-by: Andreas Gruenbacher Signed-off-by: Eric Paris --- fs/notify/fanotify/fanotify_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index b966b7230f47..5ed8e58d7bfc 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -641,7 +641,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) __func__, flags, event_f_flags); if (!capable(CAP_SYS_ADMIN)) - return -EACCES; + return -EPERM; if (flags & ~FAN_ALL_INIT_FLAGS) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From f72adfd540bacc4f6ff57a7d708b1a6c8906bdb4 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 27 Aug 2010 21:24:24 -0400 Subject: fsnotify: fix list walk order Marks were stored on the inode and vfsmonut mark list in order from highest memory address to lowest memory address. The code to walk those lists thought they were in order from lowest to highest with unpredictable results when trying to match up marks from each. It was possible that extra events would be sent to userspace when inode marks ignoring events wouldn't get matched with the vfsmount marks. This problem only affected fanotify when using both vfsmount and inode marks simultaneously. Signed-off-by: Eric Paris --- fs/notify/fsnotify.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 6f2777ce87a1..2169aa593d5f 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -261,27 +261,26 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, while (inode_node || vfsmount_node) { used_inode = used_vfsmount = false; + inode_group = vfsmount_group = NULL; if (inode_node) { inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), struct fsnotify_mark, i.i_list); inode_group = inode_mark->group; - } else - inode_group = (void *)-1; + } if (vfsmount_node) { vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), struct fsnotify_mark, m.m_list); vfsmount_group = vfsmount_mark->group; - } else - vfsmount_group = (void *)-1; + } - if (inode_group < vfsmount_group) { + if (inode_group > vfsmount_group) { /* handle inode */ send_to_group(to_tell, NULL, inode_mark, NULL, mask, data, data_is, cookie, file_name, &event); used_inode = true; - } else if (vfsmount_group < inode_group) { + } else if (vfsmount_group > inode_group) { send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, data_is, cookie, file_name, &event); used_vfsmount = true; -- cgit v1.2.3-59-g8ed1b From 92b4678efa8ce0de9b1e01a74e3d13c4002a4136 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 27 Aug 2010 21:42:11 -0400 Subject: fsnotify: drop two useless bools in the fnsotify main loop The fsnotify main loop has 2 bools which indicated if we processed the inode or vfsmount mark in that particular pass through the loop. These bool can we replaced with the inode_group and vfsmount_group variables and actually make the code a little easier to understand. Signed-off-by: Eric Paris --- fs/notify/fsnotify.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 2169aa593d5f..36802420d69a 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -225,7 +225,6 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, struct fsnotify_event *event = NULL; struct vfsmount *mnt; int idx, ret = 0; - bool used_inode, used_vfsmount; /* global tests shouldn't care about events on child only the specific event */ __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); @@ -260,7 +259,6 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, } while (inode_node || vfsmount_node) { - used_inode = used_vfsmount = false; inode_group = vfsmount_group = NULL; if (inode_node) { @@ -279,23 +277,22 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, /* handle inode */ send_to_group(to_tell, NULL, inode_mark, NULL, mask, data, data_is, cookie, file_name, &event); - used_inode = true; + /* we didn't use the vfsmount_mark */ + vfsmount_group = NULL; } else if (vfsmount_group > inode_group) { send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, data_is, cookie, file_name, &event); - used_vfsmount = true; + inode_group = NULL; } else { send_to_group(to_tell, mnt, inode_mark, vfsmount_mark, mask, data, data_is, cookie, file_name, &event); - used_vfsmount = true; - used_inode = true; } - if (used_inode) + if (inode_group) inode_node = srcu_dereference(inode_node->next, &fsnotify_mark_srcu); - if (used_vfsmount) + if (vfsmount_group) vfsmount_node = srcu_dereference(vfsmount_node->next, &fsnotify_mark_srcu); } -- cgit v1.2.3-59-g8ed1b From c34186ed008229e7f7e3f1de8e6acf6374995358 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 27 Aug 2010 19:31:56 -0700 Subject: net/ipv4: Eliminate kstrdup memory leak The string clone is only used as a temporary copy of the argument val within the while loop, and so it should be freed before leaving the function. The call to strsep, however, modifies clone, so a pointer to the front of the string is kept in saved_clone, to make it possible to free it. The sematic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ local idexpression x; expression E; identifier l; statement S; @@ *x= \(kasprintf\|kstrdup\)(...); ... if (x == NULL) S ... when != kfree(x) when != E = x if (...) { <... when != kfree(x) * goto l; ...> * return ...; } // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- net/ipv4/tcp_cong.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 0ec9bd0ae94f..850c737e08e2 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -196,10 +196,10 @@ void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) int tcp_set_allowed_congestion_control(char *val) { struct tcp_congestion_ops *ca; - char *clone, *name; + char *saved_clone, *clone, *name; int ret = 0; - clone = kstrdup(val, GFP_USER); + saved_clone = clone = kstrdup(val, GFP_USER); if (!clone) return -ENOMEM; @@ -226,6 +226,7 @@ int tcp_set_allowed_congestion_control(char *val) } out: spin_unlock(&tcp_cong_list_lock); + kfree(saved_clone); return ret; } -- cgit v1.2.3-59-g8ed1b From b76b4014f9d988d2412b873e4d4c13c7f9afc4e4 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sat, 28 Aug 2010 08:52:10 +0200 Subject: writeback: Fix lost wake-up shutting down writeback thread Setting the task state here may cause us to miss the wake up from kthread_stop(), so we need to recheck kthread_should_stop() or risk sleeping forever in the following schedule(). Symptom was an indefinite hang on an NFSv4 mount. (NFSv4 may create multiple mounts in a temporary namespace while traversing the mount path, and since the temporary namespace is immediately destroyed, it may end up destroying a mount very soon after it was created, possibly making this race more likely.) INFO: task mount.nfs4:4314 blocked for more than 120 seconds. "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. mount.nfs4 D 0000000000000000 2880 4314 4313 0x00000000 ffff88001ed6da28 0000000000000046 ffff88001ed6dfd8 ffff88001ed6dfd8 ffff88001ed6c000 ffff88001ed6c000 ffff88001ed6c000 ffff88001e5003a0 ffff88001ed6dfd8 ffff88001e5003a8 ffff88001ed6c000 ffff88001ed6dfd8 Call Trace: [] schedule_timeout+0x1cd/0x2e0 [] ? mark_held_locks+0x6c/0xa0 [] ? _raw_spin_unlock_irq+0x30/0x60 [] ? trace_hardirqs_on_caller+0x14d/0x190 [] ? sub_preempt_count+0xe/0xd0 [] wait_for_common+0x120/0x190 [] ? default_wake_function+0x0/0x20 [] wait_for_completion+0x1d/0x20 [] kthread_stop+0x4a/0x150 [] ? thaw_process+0x70/0x80 [] bdi_unregister+0x10a/0x1a0 [] nfs_put_super+0x19/0x20 [] generic_shutdown_super+0x54/0xe0 [] kill_anon_super+0x16/0x60 [] nfs4_kill_super+0x39/0x90 [] deactivate_locked_super+0x45/0x60 [] deactivate_super+0x49/0x70 [] mntput_no_expire+0x84/0xe0 [] release_mounts+0x9f/0xc0 [] put_mnt_ns+0x65/0x80 [] nfs_follow_remote_path+0x1e6/0x420 [] nfs4_try_mount+0x6f/0xd0 [] nfs4_get_sb+0xa2/0x360 [] vfs_kern_mount+0x88/0x1f0 [] do_kern_mount+0x52/0x130 [] ? _lock_kernel+0x6a/0x170 [] do_mount+0x26e/0x7f0 [] ? copy_mount_options+0xea/0x190 [] sys_mount+0x98/0xf0 [] system_call_fastpath+0x16/0x1b 1 lock held by mount.nfs4/4314: #0: (&type->s_umount_key#24){+.+...}, at: [] deactivate_super+0x41/0x70 Signed-off-by: J. Bruce Fields Signed-off-by: Jens Axboe Acked-by: Artem Bityutskiy --- fs/fs-writeback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 7d9d06ba184b..81e086d8aa57 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -808,7 +808,7 @@ int bdi_writeback_thread(void *data) wb->last_active = jiffies; set_current_state(TASK_INTERRUPTIBLE); - if (!list_empty(&bdi->work_list)) { + if (!list_empty(&bdi->work_list) || kthread_should_stop()) { __set_current_state(TASK_RUNNING); continue; } -- cgit v1.2.3-59-g8ed1b From 60f1deb595c08687a96157a6a3ce08ef34142362 Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Sat, 28 Aug 2010 19:52:24 +1200 Subject: ALSA: asihpi - Return hw error directly from oustream_write. If hw error is ignored, status is updated with invalid info. Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpi6205.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index 3b4413448226..22c5fc625533 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c @@ -941,8 +941,7 @@ static void outstream_host_buffer_free(struct hpi_adapter_obj *pao, } -static u32 outstream_get_space_available(struct hpi_hostbuffer_status - *status) +static u32 outstream_get_space_available(struct hpi_hostbuffer_status *status) { return status->size_in_bytes - (status->host_index - status->dSP_index); @@ -987,6 +986,10 @@ static void outstream_write(struct hpi_adapter_obj *pao, /* write it */ phm->function = HPI_OSTREAM_WRITE; hw_message(pao, phm, phr); + + if (phr->error) + return; + /* update status information that the DSP would typically * update (and will update next time the DSP * buffer update task reads data from the host BBM buffer) -- cgit v1.2.3-59-g8ed1b From 3182c8a72b31414e043184a97b0d5d3c0d590168 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 28 Aug 2010 13:25:33 +0900 Subject: sound: oss: fix uninitialized spinlock The spinlock lock in sound_timer.c is used without initialization. Signed-off-by: Akinobu Mita Signed-off-by: Takashi Iwai --- sound/oss/sound_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c index f0f0c19fbff7..48cda6c4c257 100644 --- a/sound/oss/sound_timer.c +++ b/sound/oss/sound_timer.c @@ -26,7 +26,7 @@ static unsigned long prev_event_time; static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ static struct sound_lowlev_timer *tmr; -static spinlock_t lock; +static DEFINE_SPINLOCK(lock); static unsigned long tmr2ticks(int tmr_value) { -- cgit v1.2.3-59-g8ed1b From 7a28826ac73d31a379d93785d8fbd24ab492b0bd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 27 Aug 2010 22:02:15 +0200 Subject: ALSA: pcm: add more format names There were some new formats added in commit 15c0cee6c809 "ALSA: pcm: Define G723 3-bit and 5-bit formats". That commit increased SNDRV_PCM_FORMAT_LAST as well. My concern is that there are a couple places which do: for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { if (dummy->pcm_hw.formats & (1ULL << i)) snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); } I haven't tested these but it looks like if "i" were equal to SNDRV_PCM_FORMAT_G723_24 or higher then we might read past the end of the array. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index cbe815dfbdc8..204af48c5cc1 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -203,10 +203,16 @@ static char *snd_pcm_format_names[] = { FORMAT(S18_3BE), FORMAT(U18_3LE), FORMAT(U18_3BE), + FORMAT(G723_24), + FORMAT(G723_24_1B), + FORMAT(G723_40), + FORMAT(G723_40_1B), }; const char *snd_pcm_format_name(snd_pcm_format_t format) { + if (format >= ARRAY_SIZE(snd_pcm_format_names)) + return "Unknown"; return snd_pcm_format_names[format]; } EXPORT_SYMBOL_GPL(snd_pcm_format_name); -- cgit v1.2.3-59-g8ed1b From f18194275c39835cb84563500995e0d503a32d9a Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 25 Aug 2010 23:12:54 -0700 Subject: mm: fix hang on anon_vma->root->lock After several hours, kbuild tests hang with anon_vma_prepare() spinning on a newly allocated anon_vma's lock - on a box with CONFIG_TREE_PREEMPT_RCU=y (which makes this very much more likely, but it could happen without). The ever-subtle page_lock_anon_vma() now needs a further twist: since anon_vma_prepare() and anon_vma_fork() are liable to change the ->root of a reused anon_vma structure at any moment, page_lock_anon_vma() needs to check page_mapped() again before succeeding, otherwise page_unlock_anon_vma() might address a different root->lock. Signed-off-by: Hugh Dickins Reviewed-by: Rik van Riel Cc: Christoph Lameter Cc: Peter Zijlstra Cc: Andrea Arcangeli Signed-off-by: Linus Torvalds --- mm/rmap.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index 87b9e8ad4509..f6f0d2dda2ea 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -316,7 +316,7 @@ void __init anon_vma_init(void) */ struct anon_vma *page_lock_anon_vma(struct page *page) { - struct anon_vma *anon_vma; + struct anon_vma *anon_vma, *root_anon_vma; unsigned long anon_mapping; rcu_read_lock(); @@ -327,8 +327,21 @@ struct anon_vma *page_lock_anon_vma(struct page *page) goto out; anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON); - anon_vma_lock(anon_vma); - return anon_vma; + root_anon_vma = ACCESS_ONCE(anon_vma->root); + spin_lock(&root_anon_vma->lock); + + /* + * If this page is still mapped, then its anon_vma cannot have been + * freed. But if it has been unmapped, we have no security against + * the anon_vma structure being freed and reused (for another anon_vma: + * SLAB_DESTROY_BY_RCU guarantees that - so the spin_lock above cannot + * corrupt): with anon_vma_prepare() or anon_vma_fork() redirecting + * anon_vma->root before page_unlock_anon_vma() is called to unlock. + */ + if (page_mapped(page)) + return anon_vma; + + spin_unlock(&root_anon_vma->lock); out: rcu_read_unlock(); return NULL; -- cgit v1.2.3-59-g8ed1b From bad849b3dc0fae1297c8d47f846f8d202a6145ed Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 26 Aug 2010 16:00:34 +0100 Subject: NOMMU: Stub out vm_get_page_prot() if there's no MMU Stub out vm_get_page_prot() if there's no MMU. This was added by commit 804af2cf6e7a ("[AGPGART] remove private page protection map") and is used in commit c07fbfd17e61 ("fbmem: VM_IO set, but not propagated") in the fbmem video driver, but the function doesn't exist on NOMMU, resulting in an undefined symbol at link time. Signed-off-by: David Howells Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: Linus Torvalds --- include/linux/mm.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 831c693416b2..e6b1210772ce 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1363,7 +1363,15 @@ static inline unsigned long vma_pages(struct vm_area_struct *vma) return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; } +#ifdef CONFIG_MMU pgprot_t vm_get_page_prot(unsigned long vm_flags); +#else +static inline pgprot_t vm_get_page_prot(unsigned long vm_flags) +{ + return __pgprot(0); +} +#endif + struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr); int remap_pfn_range(struct vm_area_struct *, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t); -- cgit v1.2.3-59-g8ed1b From 62b88dc1912c7d105f768e0e64756f8bd83936db Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 26 Aug 2010 17:44:35 +0100 Subject: Alpha: Fix a missing comma in sys_osf_statfs() Fix a comma that got accidentally deleted from sys_osf_statfs() leading to the following warning: arch/alpha/kernel/osf_sys.c: In function 'SYSC_osf_statfs': arch/alpha/kernel/osf_sys.c:255: error: syntax error before 'buffer' Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/alpha/kernel/osf_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index fb58150a7e8f..5d1e6d6ce684 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -252,7 +252,7 @@ SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname, retval = user_path(pathname, &path); if (!retval) { - retval = do_osf_statfs(&path buffer, bufsiz); + retval = do_osf_statfs(&path, buffer, bufsiz); path_put(&path); } return retval; -- cgit v1.2.3-59-g8ed1b From 7619b1b2e2b96842459f499fd48ec32e3d223d02 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 28 Aug 2010 12:45:01 +0000 Subject: pcnet_cs: add new_id pcnet_cs: add new_id: "KENTRONICS KEP-230" 10Base-T PCMCIA card. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/pcnet_cs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index bfdef72c5d5e..7fd8c55288c9 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1644,6 +1644,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b), PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0), PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956), + PCMCIA_DEVICE_PROD_ID12("KENTRONICS", "KEP-230", 0xaf8144c9, 0x868f6616), PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d3, 0x1eb88e64), PCMCIA_DEVICE_PROD_ID12("KINGMAX", "EN10T2T", 0x7bcb459a, 0xa5c81fa5), PCMCIA_DEVICE_PROD_ID12("Kingston", "KNE-PC2", 0x1128e633, 0xce2a89b3), -- cgit v1.2.3-59-g8ed1b From d9f66c1a46163c7c83411058516a69da547262f8 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sat, 28 Aug 2010 20:35:17 -0700 Subject: Input: wacom - fix mousewheel handling for old wacom tablets This fixes a regression introduced in 3b57ca0f80c5c8994b5b1e3d3f904cfe727951f2. The data[6] byte contains either 1 or -1 depending on the whether the mouse wheel on older wacom tablets is moved down (1) or up (-1). The patch introduced in the above commit changed the cast from (signed char) to (signed). When cast as a signed integer and negated, the value of -1 (stored in the byte as 0xff) became -255 rather than 1. This patch reverts the cast to a (signed char) and also removes an unnecessary (signed) cast, as all the values operated on are bitmasked. Signed-off-by: Mike Auty Reviewed-by: Ping Cheng Cc; stable@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 40d77ba8fdc1..6e29badb969e 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -243,10 +243,10 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) if (features->type == WACOM_G4 || features->type == WACOM_MO) { input_report_abs(input, ABS_DISTANCE, data[6] & 0x3f); - rw = (signed)(data[7] & 0x04) - (data[7] & 0x03); + rw = (data[7] & 0x04) - (data[7] & 0x03); } else { input_report_abs(input, ABS_DISTANCE, data[7] & 0x3f); - rw = -(signed)data[6]; + rw = -(signed char)data[6]; } input_report_rel(input, REL_WHEEL, rw); } -- cgit v1.2.3-59-g8ed1b From 2c4e9671edfef534e9726366707d64e63d44e7e6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 28 Aug 2010 20:35:17 -0700 Subject: Input: use PIT_TICK_RATE in vt beep ioctl The KIOCSOUND and KDMKTONE ioctls are based on the CLOCK_TICK_RATE, which is architecture and sometimes configuration specific. In practice, most user applications assume that it is actually defined as the i8253 PIT base clock of 1193182 Hz, which is true on some architectures but not on others. This patch makes the vt code use the PIT frequency on all architectures, which is much more well-defined. It will change the behavior of user applications sending the beep ioctl on all architectures that define CLOCK_TICK_RATE different from PIT_TICK_RATE. The original breakage was introduced in commit bcc8ca099 "Adapt drivers/char/vt_ioctl.c to non-x86". Hopefully, reverting this change will make the frequency correct in more cases than it will make it incorrect. Signed-off-by: Arnd Bergmann Acked-by: Alan Cox Signed-off-by: Dmitry Torokhov --- drivers/char/vt_ioctl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 2bbeaaea46e9..38df8c19e74c 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -533,11 +533,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KIOCSOUND: if (!perm) goto eperm; - /* FIXME: This is an old broken API but we need to keep it - supported and somehow separate the historic advertised - tick rate from any real one */ + /* + * The use of PIT_TICK_RATE is historic, it used to be + * the platform-dependent CLOCK_TICK_RATE between 2.6.12 + * and 2.6.36, which was a minor but unfortunate ABI + * change. + */ if (arg) - arg = CLOCK_TICK_RATE / arg; + arg = PIT_TICK_RATE / arg; kd_mksound(arg, 0); break; @@ -553,11 +556,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, */ ticks = HZ * ((arg >> 16) & 0xffff) / 1000; count = ticks ? (arg & 0xffff) : 0; - /* FIXME: This is an old broken API but we need to keep it - supported and somehow separate the historic advertised - tick rate from any real one */ if (count) - count = CLOCK_TICK_RATE / count; + count = PIT_TICK_RATE / count; kd_mksound(count, ticks); break; } -- cgit v1.2.3-59-g8ed1b From ba4d695a90c9176fca8e45d6c872bbf4e8bed315 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 28 Aug 2010 21:33:50 -0700 Subject: Input: MT - initialize slots to unused For MT slots, the ABS_MT_TRACKING_ID determines whether a slot is in use, but currently leaves initialization up to the drivers. This patch sets the slot state to unused upon creation. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index a9b025f4147a..ab6982056518 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1599,11 +1599,14 @@ EXPORT_SYMBOL(input_free_device); * @dev: input device supporting MT events and finger tracking * @num_slots: number of slots used by the device * - * This function allocates all necessary memory for MT slot handling - * in the input device, and adds ABS_MT_SLOT to the device capabilities. + * This function allocates all necessary memory for MT slot handling in the + * input device, and adds ABS_MT_SLOT to the device capabilities. All slots + * are initially marked as unused iby setting ABS_MT_TRACKING_ID to -1. */ int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots) { + int i; + if (!num_slots) return 0; @@ -1614,6 +1617,10 @@ int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots) dev->mtsize = num_slots; input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); + /* Mark slots as 'unused' */ + for (i = 0; i < num_slots; i++) + dev->mt[i].abs[ABS_MT_TRACKING_ID - ABS_MT_FIRST] = -1; + return 0; } EXPORT_SYMBOL(input_mt_create_slots); -- cgit v1.2.3-59-g8ed1b From a4dc090b6cb445257d2a8e44f85395ced6d1ed3e Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 28 Aug 2010 14:21:26 +0200 Subject: firewire: ohci: work around VIA and NEC PHY packet reception bug VIA VT6306, VIA VT6308, and NEC OrangeLink controllers do not write packet event codes for received PHY packets (or perhaps write evt_no_status, hard to tell). Work around it by overwriting the packet's ACK by ack_complete, so that upper layers that listen to PHY packet reception get to see these packets. (Also tested: TI TSB82AA2, TI TSB43AB22/A, TI XIO2213A, Agere FW643, JMicron JMB381 --- these do not exhibit this bug.) Clemens proposed a quirks flag for that, IOW whitelist known misbehaving controllers for this workaround. Though to me it seems harmless enough to enable for all controllers. The log_ar_at_event() debug log will continue to show the original status from the DMA unit. Reported-by: Clemens Ladisch (VT6308) Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 7f03540cabe8..be29b0bb2471 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -694,7 +694,15 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) log_ar_at_event('R', p.speed, p.header, evt); /* - * The OHCI bus reset handler synthesizes a phy packet with + * Several controllers, notably from NEC and VIA, forget to + * write ack_complete status at PHY packet reception. + */ + if (evt == OHCI1394_evt_no_status && + (p.header[0] & 0xff) == (OHCI1394_phy_tcode << 4)) + p.ack = ACK_COMPLETE; + + /* + * The OHCI bus reset handler synthesizes a PHY packet with * the new generation number when a bus reset happens (see * section 8.4.2.3). This helps us determine when a request * was received and make sure we send the response in the same -- cgit v1.2.3-59-g8ed1b From 2bfc96a127bc1cc94d26bfaa40159966064f9c8c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 29 Aug 2010 08:36:04 -0700 Subject: Linux 2.6.36-rc3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 031b61cb5274..4df9873f83b2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 36 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Sheep on Meth # *DOCUMENTATION* -- cgit v1.2.3-59-g8ed1b From 8807286e569c4f12fa2bc980187f3e2abc606d11 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 10 Aug 2010 12:33:20 -0400 Subject: drm/radeon/kms: use tracked values for sclk and mclk Rather than calling get_memory_clock and get_engine_clock, used the tracked values from the pm code. Calling the tables adds additional latency in the modesetting and pm paths. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_clocks.c | 8 ++++++++ drivers/gpu/drm/radeon/radeon_device.c | 28 +++++++++------------------- drivers/gpu/drm/radeon/radeon_i2c.c | 2 +- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index 14448a740ba6..690d8907135a 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -327,6 +327,14 @@ void radeon_get_clock_info(struct drm_device *dev) mpll->max_feedback_div = 0xff; mpll->best_vco = 0; + if (!rdev->clock.default_sclk) + rdev->clock.default_sclk = radeon_get_engine_clock(rdev); + if ((!rdev->clock.default_mclk) && rdev->asic->get_memory_clock) + rdev->clock.default_mclk = radeon_get_memory_clock(rdev); + + rdev->pm.current_sclk = rdev->clock.default_sclk; + rdev->pm.current_mclk = rdev->clock.default_mclk; + } /* 10 khz */ diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 69b3c2291e92..256d204a6d24 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -293,30 +293,20 @@ bool radeon_card_posted(struct radeon_device *rdev) void radeon_update_bandwidth_info(struct radeon_device *rdev) { fixed20_12 a; - u32 sclk, mclk; + u32 sclk = rdev->pm.current_sclk; + u32 mclk = rdev->pm.current_mclk; - if (rdev->flags & RADEON_IS_IGP) { - sclk = radeon_get_engine_clock(rdev); - mclk = rdev->clock.default_mclk; - - a.full = dfixed_const(100); - rdev->pm.sclk.full = dfixed_const(sclk); - rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a); - rdev->pm.mclk.full = dfixed_const(mclk); - rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a); + /* sclk/mclk in Mhz */ + a.full = dfixed_const(100); + rdev->pm.sclk.full = dfixed_const(sclk); + rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a); + rdev->pm.mclk.full = dfixed_const(mclk); + rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a); + if (rdev->flags & RADEON_IS_IGP) { a.full = dfixed_const(16); /* core_bandwidth = sclk(Mhz) * 16 */ rdev->pm.core_bandwidth.full = dfixed_div(rdev->pm.sclk, a); - } else { - sclk = radeon_get_engine_clock(rdev); - mclk = radeon_get_memory_clock(rdev); - - a.full = dfixed_const(100); - rdev->pm.sclk.full = dfixed_const(sclk); - rdev->pm.sclk.full = dfixed_div(rdev->pm.sclk, a); - rdev->pm.mclk.full = dfixed_const(mclk); - rdev->pm.mclk.full = dfixed_div(rdev->pm.mclk, a); } } diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 0416804d8f30..6a13ee38a5b9 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -213,7 +213,7 @@ static void post_xfer(struct i2c_adapter *i2c_adap) static u32 radeon_get_i2c_prescale(struct radeon_device *rdev) { - u32 sclk = radeon_get_engine_clock(rdev); + u32 sclk = rdev->pm.current_sclk; u32 prescale = 0; u32 nm; u8 n, m, loop; -- cgit v1.2.3-59-g8ed1b From 87cbf8f2c5d1b1fc4642c3dc0bb6efc587479603 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 27 Aug 2010 13:59:54 -0400 Subject: drm/radeon/kms: fix a regression on r7xx AGP due to the HDP flush fix commit: 812d046915f48236657f02c06d7dc47140e9ceda drm/radeon/kms/r7xx: add workaround for hw issue with HDP flush breaks on AGP boards since there is no VRAM gart table. This patch fixes the issue by creating a VRAM scratch page so that can be used on both AGP and PCIE. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=29834 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 6 +++++ drivers/gpu/drm/radeon/rv770.c | 52 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index d0ebae9dde25..aee8376216a2 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3541,7 +3541,7 @@ void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL */ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = (void *)rdev->vram_scratch.ptr; u32 tmp; WREG32(HDP_DEBUG1, 0); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3dfcfa3ca425..e90d9e3765b4 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1013,6 +1013,11 @@ int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data, int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +/* VRAM scratch page for HDP bug */ +struct r700_vram_scratch { + struct radeon_bo *robj; + volatile uint32_t *ptr; +}; /* * Core structure, functions and helpers. @@ -1079,6 +1084,7 @@ struct radeon_device { const struct firmware *pfp_fw; /* r6/700 PFP firmware */ const struct firmware *rlc_fw; /* r6/700 RLC firmware */ struct r600_blit r600_blit; + struct r700_vram_scratch vram_scratch; int msi_enabled; /* msi enabled */ struct r600_ih ih; /* r6/700 interrupt ring */ struct workqueue_struct *wq; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index f1c796810117..a84e38643788 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -905,6 +905,54 @@ static void rv770_gpu_init(struct radeon_device *rdev) } +static int rv770_vram_scratch_init(struct radeon_device *rdev) +{ + int r; + u64 gpu_addr; + + if (rdev->vram_scratch.robj == NULL) { + r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, + true, RADEON_GEM_DOMAIN_VRAM, + &rdev->vram_scratch.robj); + if (r) { + return r; + } + } + + r = radeon_bo_reserve(rdev->vram_scratch.robj, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rdev->vram_scratch.robj, + RADEON_GEM_DOMAIN_VRAM, &gpu_addr); + if (r) { + radeon_bo_unreserve(rdev->vram_scratch.robj); + return r; + } + r = radeon_bo_kmap(rdev->vram_scratch.robj, + (void **)&rdev->vram_scratch.ptr); + if (r) + radeon_bo_unpin(rdev->vram_scratch.robj); + radeon_bo_unreserve(rdev->vram_scratch.robj); + + return r; +} + +static void rv770_vram_scratch_fini(struct radeon_device *rdev) +{ + int r; + + if (rdev->vram_scratch.robj == NULL) { + return; + } + r = radeon_bo_reserve(rdev->vram_scratch.robj, false); + if (likely(r == 0)) { + radeon_bo_kunmap(rdev->vram_scratch.robj); + radeon_bo_unpin(rdev->vram_scratch.robj); + radeon_bo_unreserve(rdev->vram_scratch.robj); + } + radeon_bo_unref(&rdev->vram_scratch.robj); +} + int rv770_mc_init(struct radeon_device *rdev) { u32 tmp; @@ -970,6 +1018,9 @@ static int rv770_startup(struct radeon_device *rdev) if (r) return r; } + r = rv770_vram_scratch_init(rdev); + if (r) + return r; rv770_gpu_init(rdev); r = r600_blit_init(rdev); if (r) { @@ -1195,6 +1246,7 @@ void rv770_fini(struct radeon_device *rdev) r600_irq_fini(rdev); radeon_irq_kms_fini(rdev); rv770_pcie_gart_fini(rdev); + rv770_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_clocks_fini(rdev); -- cgit v1.2.3-59-g8ed1b From 4afc31345e5f543e5d89a47aeadaaad1d91a5bc8 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 29 Aug 2010 01:55:38 +0900 Subject: nilfs2: fix leak of shadow dat inode in error path of load_nilfs If load_nilfs() gets an error while doing recovery, it will fail to free the shadow inode of dat (nilfs->ns_gc_dat). This fixes the leak issue. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/the_nilfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 4317f177ea7c..ba7c10c917fc 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -446,6 +446,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) nilfs_mdt_destroy(nilfs->ns_cpfile); nilfs_mdt_destroy(nilfs->ns_sufile); nilfs_mdt_destroy(nilfs->ns_dat); + nilfs_mdt_destroy(nilfs->ns_gc_dat); failed: nilfs_clear_recovery_info(&ri); -- cgit v1.2.3-59-g8ed1b From 50e77fcd790e02a095f906df0f6fa72afef7e11c Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Wed, 18 Aug 2010 11:51:13 +0800 Subject: ARM: pxa: remove __init from cpufreq_driver->init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is causing section mismatches when linking, as cpufreq_driver->init() is not supposed to be in init section. Reported-by: Tomáš 'Sleep_Walker' Čech Signed-off-by: Eric Miao --- arch/arm/mach-pxa/cpufreq-pxa2xx.c | 2 +- arch/arm/mach-pxa/cpufreq-pxa3xx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c index 268a9bc6be8a..50d5939a78f1 100644 --- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c +++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c @@ -398,7 +398,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, return 0; } -static __init int pxa_cpufreq_init(struct cpufreq_policy *policy) +static int pxa_cpufreq_init(struct cpufreq_policy *policy) { int i; unsigned int freq; diff --git a/arch/arm/mach-pxa/cpufreq-pxa3xx.c b/arch/arm/mach-pxa/cpufreq-pxa3xx.c index 27fa329d9a8b..0a0d0fe99220 100644 --- a/arch/arm/mach-pxa/cpufreq-pxa3xx.c +++ b/arch/arm/mach-pxa/cpufreq-pxa3xx.c @@ -204,7 +204,7 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, return 0; } -static __init int pxa3xx_cpufreq_init(struct cpufreq_policy *policy) +static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy) { int ret = -EINVAL; -- cgit v1.2.3-59-g8ed1b From be7a6d9dd67251675b83a29f4b15392eae62e70b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 13 Aug 2010 11:39:07 +0800 Subject: ARM: pxa: fix CI_HSYNC and CI_VSYNC MFP defines for pxa300 According to PXA3xx Processor Family Developer Manuall Vol1. section "Pin Descriptions and Control", PXA30x and PXA31x Processor Alternate Function Table shows the Alt FN 0 for GPIO51 is CI_HSYNC and for GPIO52 is CI_VSYNC. This patch fixes the MFP defines and also corrects the order of MFD defines. Signed-off-by: Axel Lin Signed-off-by: Eric Miao --- arch/arm/mach-pxa/include/mach/mfp-pxa300.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h b/arch/arm/mach-pxa/include/mach/mfp-pxa300.h index 7139e0dc26d1..4e1287070d21 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa300.h @@ -71,10 +71,10 @@ #define GPIO46_CI_DD_7 MFP_CFG_DRV(GPIO46, AF0, DS04X) #define GPIO47_CI_DD_8 MFP_CFG_DRV(GPIO47, AF1, DS04X) #define GPIO48_CI_DD_9 MFP_CFG_DRV(GPIO48, AF1, DS04X) -#define GPIO52_CI_HSYNC MFP_CFG_DRV(GPIO52, AF0, DS04X) -#define GPIO51_CI_VSYNC MFP_CFG_DRV(GPIO51, AF0, DS04X) #define GPIO49_CI_MCLK MFP_CFG_DRV(GPIO49, AF0, DS04X) #define GPIO50_CI_PCLK MFP_CFG_DRV(GPIO50, AF0, DS04X) +#define GPIO51_CI_HSYNC MFP_CFG_DRV(GPIO51, AF0, DS04X) +#define GPIO52_CI_VSYNC MFP_CFG_DRV(GPIO52, AF0, DS04X) /* KEYPAD */ #define GPIO3_KP_DKIN_6 MFP_CFG_LPM(GPIO3, AF2, FLOAT) -- cgit v1.2.3-59-g8ed1b From b3282ab116cd7ebd2829ac8088524b5b279330e5 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 12 Aug 2010 08:18:28 +0200 Subject: ARM: pxa: Make id const in pwm_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the compiler warning: arch/arm/plat-pxa/pwm.c: In function 'pwm_probe': arch/arm/plat-pxa/pwm.c:179: warning: initialization discards qualifiers from pointer target type Signed-off-by: Uwe Kleine-König Signed-off-by: Eric Miao --- arch/arm/plat-pxa/pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-pxa/pwm.c b/arch/arm/plat-pxa/pwm.c index 0732c6c8d511..ef32686feef9 100644 --- a/arch/arm/plat-pxa/pwm.c +++ b/arch/arm/plat-pxa/pwm.c @@ -176,7 +176,7 @@ static inline void __add_pwm(struct pwm_device *pwm) static int __devinit pwm_probe(struct platform_device *pdev) { - struct platform_device_id *id = platform_get_device_id(pdev); + const struct platform_device_id *id = platform_get_device_id(pdev); struct pwm_device *pwm, *secondary = NULL; struct resource *r; int ret = 0; -- cgit v1.2.3-59-g8ed1b From ffb287c9daabc3734a92def0d59796f065ad29eb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 26 Aug 2010 05:51:57 +0200 Subject: ARM: pxa168fb: fix section mismatch Signed-off-by: Marek Vasut Acked-by: Haojian Zhuang Signed-off-by: Eric Miao --- drivers/video/pxa168fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index c91a7f70f7b0..5d786bd3e304 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -559,7 +559,7 @@ static struct fb_ops pxa168fb_ops = { .fb_imageblit = cfb_imageblit, }; -static int __init pxa168fb_init_mode(struct fb_info *info, +static int __devinit pxa168fb_init_mode(struct fb_info *info, struct pxa168fb_mach_info *mi) { struct pxa168fb_info *fbi = info->par; @@ -599,7 +599,7 @@ static int __init pxa168fb_init_mode(struct fb_info *info, return ret; } -static int __init pxa168fb_probe(struct platform_device *pdev) +static int __devinit pxa168fb_probe(struct platform_device *pdev) { struct pxa168fb_mach_info *mi; struct fb_info *info = 0; @@ -792,7 +792,7 @@ static struct platform_driver pxa168fb_driver = { .probe = pxa168fb_probe, }; -static int __devinit pxa168fb_init(void) +static int __init pxa168fb_init(void) { return platform_driver_register(&pxa168fb_driver); } -- cgit v1.2.3-59-g8ed1b From 01ebc12f5f2e88a1c6a5436b71a506ac2bf66d6b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 7 Aug 2010 11:09:29 +0200 Subject: UBI: eliminate update of list_for_each_entry loop cursor list_for_each_entry uses its first argument to move from one element to the next, so modifying it can break the iteration. The variable re1 is already used within the loop as a temporary variable, and is not live here. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ iterator name list_for_each_entry; expression x,E; position p1,p2; @@ list_for_each_entry@p1(x,...) { <... x =@p2 E ...> } @@ expression x,E; position r.p1,r.p2; statement S; @@ *x =@p2 E ... list_for_each_entry@p1(x,...) S // Signed-off-by: Julia Lawall Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/cdev.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 4dfa6b90c21c..3d2d1a69e9a0 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -798,18 +798,18 @@ static int rename_volumes(struct ubi_device *ubi, goto out_free; } - re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); - if (!re) { + re1 = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); + if (!re1) { err = -ENOMEM; ubi_close_volume(desc); goto out_free; } - re->remove = 1; - re->desc = desc; - list_add(&re->list, &rename_list); + re1->remove = 1; + re1->desc = desc; + list_add(&re1->list, &rename_list); dbg_msg("will remove volume %d, name \"%s\"", - re->desc->vol->vol_id, re->desc->vol->name); + re1->desc->vol->vol_id, re1->desc->vol->name); } mutex_lock(&ubi->device_mutex); -- cgit v1.2.3-59-g8ed1b From 80c1c16fb89e7055acb560e6d90c881b5c7496c1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sat, 28 Aug 2010 12:11:40 +0300 Subject: UBI: fix forward compatibility Commit 0798cea8c2e1afee59686c51d27d0e96b05e42d1 "UBI: improve corrupted flash handling" broke delet-compatible volumes handling - it introduced a limit of 8 eraseblocks which may be corrupted. And delete-compatible eraseblocks are added to the "corrupted" list, so if we'd have a large delete-compatible volume, UBI would refuse it. The fix is to add delete-compatible volumes to the erase list instead. Indeed, they are corrupted, we just have to erase them. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 372a15ac9995..69b52e9c9489 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -843,7 +843,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, case UBI_COMPAT_DELETE: ubi_msg("\"delete\" compatible internal volume %d:%d" " found, will remove it", vol_id, lnum); - err = add_to_list(si, pnum, ec, &si->corr); + err = add_to_list(si, pnum, ec, &si->erase); if (err) return err; return 0; -- cgit v1.2.3-59-g8ed1b From 7c44ece988a3419e51c833cf14be186a22224dd1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 30 Aug 2010 17:35:52 +1000 Subject: Move .gitignore from drivers/md to lib/raid6 Another missing bit of the raid6 -> /lib move. Reported-by: Andreas Schwab Signed-off-by: NeilBrown --- drivers/md/.gitignore | 4 ---- lib/raid6/.gitignore | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 drivers/md/.gitignore create mode 100644 lib/raid6/.gitignore diff --git a/drivers/md/.gitignore b/drivers/md/.gitignore deleted file mode 100644 index a7afec6b19c6..000000000000 --- a/drivers/md/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -mktables -raid6altivec*.c -raid6int*.c -raid6tables.c diff --git a/lib/raid6/.gitignore b/lib/raid6/.gitignore new file mode 100644 index 000000000000..162becacf97c --- /dev/null +++ b/lib/raid6/.gitignore @@ -0,0 +1,4 @@ +mktables +altivec*.c +int*.c +tables.c -- cgit v1.2.3-59-g8ed1b From 73413b120d5d6eb6c98451bbc19acf43e0e300ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 09:39:57 +0200 Subject: ALSA: hda - embed alc_fixup contents into struct definitions Instead of defining each content as a separate struct, put all into the definition of struct alc_fixup arrays so that reader doesn't go back to see the definition again. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 70 ++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 627bf9963368..50e0c82fd994 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6799,14 +6799,12 @@ enum { PINFIX_HP_DC5750, }; -static struct alc_pincfg alc260_hp_dc5750_pinfix[] = { - { 0x11, 0x90130110 }, /* speaker */ - { } -}; - static const struct alc_fixup alc260_fixups[] = { [PINFIX_HP_DC5750] = { - .pins = alc260_hp_dc5750_pinfix + .pins = (const struct alc_pincfg[]) { + { 0x11, 0x90130110 }, /* speaker */ + { } + } }, }; @@ -10452,24 +10450,20 @@ enum { PINFIX_PB_M5210, }; -static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { - { 0x15, 0x01080104 }, /* side */ - { 0x16, 0x01011012 }, /* rear */ - { 0x17, 0x01016011 }, /* clfe */ - { } -}; - -static const struct hda_verb pb_m5210_verbs[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, - {} -}; - static const struct alc_fixup alc882_fixups[] = { [PINFIX_ABIT_AW9D_MAX] = { - .pins = alc882_abit_aw9d_pinfix + .pins = (const struct alc_pincfg[]) { + { 0x15, 0x01080104 }, /* side */ + { 0x16, 0x01011012 }, /* rear */ + { 0x17, 0x01016011 }, /* clfe */ + { } + } }, [PINFIX_PB_M5210] = { - .verbs = pb_m5210_verbs + .verbs = (const struct hda_verb[]) { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + {} + } }, }; @@ -14454,14 +14448,12 @@ enum { ALC269_FIXUP_SONY_VAIO, }; -static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = { - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, - {} -}; - static const struct alc_fixup alc269_fixups[] = { [ALC269_FIXUP_SONY_VAIO] = { - .verbs = alc269_sony_vaio_fixup_verbs + .verbs = (const struct hda_verb[]) { + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, + {} + } }, }; @@ -15819,15 +15811,13 @@ enum { PINFIX_FSC_AMILO_PI1505, }; -static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = { - { 0x0b, 0x0221101f }, /* HP */ - { 0x0f, 0x90170310 }, /* speaker */ - { } -}; - static const struct alc_fixup alc861_fixups[] = { [PINFIX_FSC_AMILO_PI1505] = { - .pins = alc861_fsc_amilo_pi1505_pinfix + .pins = (const struct alc_pincfg[]) { + { 0x0b, 0x0221101f }, /* HP */ + { 0x0f, 0x90170310 }, /* speaker */ + { } + } }, }; @@ -16794,16 +16784,14 @@ enum { }; /* reset GPIO1 */ -static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = { - {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, - { } -}; - static const struct alc_fixup alc861vd_fixups[] = { [ALC660VD_FIX_ASUS_GPIO1] = { - .verbs = alc660vd_fix_asus_gpio1_verbs, + .verbs = (const struct hda_verb[]) { + {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, + { } + } }, }; -- cgit v1.2.3-59-g8ed1b From bd52b746262c8d77e73903d6608014fb2fcdcd9d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 30 Aug 2010 17:33:33 +1000 Subject: md: don't clear MD_CHANGE_CLEAN in md_update_sb() for external arrays If this bit is cleared in md_update_sb() the kernel will allow writes to the array if userspace triggers md_allow_write(), e.g. through stripe_cache_size, when mdmon is not active. When mdmon is active the array transitions to active-idle bypassing write-pending, setting up a race for mdmon to set the array clean before a write arrives. Signed-off-by: Dan Williams Signed-off-by: NeilBrown --- drivers/md/md.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index c148b6302154..a1f6b59b8b37 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2167,9 +2167,10 @@ repeat: rdev->recovery_offset = mddev->curr_resync_completed; } - if (mddev->external || !mddev->persistent) { + if (!mddev->persistent) { + if (!mddev->external) + clear_bit(MD_CHANGE_CLEAN, &mddev->flags); clear_bit(MD_CHANGE_DEVS, &mddev->flags); - clear_bit(MD_CHANGE_CLEAN, &mddev->flags); wake_up(&mddev->sb_wait); return; } -- cgit v1.2.3-59-g8ed1b From 070dc6dd7103b6b3f7e4d46e754354a5c15f366e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 30 Aug 2010 17:33:34 +1000 Subject: md: resolve confusion of MD_CHANGE_CLEAN MD_CHANGE_CLEAN is used for two different purposes and this leads to confusion. One of the purposes is largely mirrored by MD_CHANGE_PENDING which is not used for anything else, so have MD_CHANGE_PENDING take over that purpose fully. The two purposes are: 1/ tell md_update_sb that an update is needed and that it is just a clean/dirty transition. 2/ tell user-space that an transition from clean to dirty is pending (something wants to write), and tell te kernel (by clearin the flag) that the transition is OK. The first purpose remains wit MD_CHANGE_CLEAN, the second is moved fully to MD_CHANGE_PENDING. This means that various places which conditionally set or cleared MD_CHANGE_CLEAN no longer need to be conditional. Signed-off-by: NeilBrown --- drivers/md/bitmap.c | 3 +-- drivers/md/md.c | 24 +++++++++--------------- drivers/md/md.h | 2 +- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 1ba1e122e948..ed4900ade93a 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1542,8 +1542,7 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector) atomic_read(&bitmap->mddev->recovery_active) == 0); bitmap->mddev->curr_resync_completed = bitmap->mddev->curr_resync; - if (bitmap->mddev->persistent) - set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags); + set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags); sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1); s = 0; while (s < sector && s < bitmap->mddev->resync_max_sectors) { diff --git a/drivers/md/md.c b/drivers/md/md.c index a1f6b59b8b37..43cf9cc9c1df 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2168,8 +2168,7 @@ repeat: } if (!mddev->persistent) { - if (!mddev->external) - clear_bit(MD_CHANGE_CLEAN, &mddev->flags); + clear_bit(MD_CHANGE_CLEAN, &mddev->flags); clear_bit(MD_CHANGE_DEVS, &mddev->flags); wake_up(&mddev->sb_wait); return; @@ -2179,7 +2178,6 @@ repeat: mddev->utime = get_seconds(); - set_bit(MD_CHANGE_PENDING, &mddev->flags); if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags)) force_change = 1; if (test_and_clear_bit(MD_CHANGE_CLEAN, &mddev->flags)) @@ -3372,7 +3370,7 @@ array_state_show(mddev_t *mddev, char *page) case 0: if (mddev->in_sync) st = clean; - else if (test_bit(MD_CHANGE_CLEAN, &mddev->flags)) + else if (test_bit(MD_CHANGE_PENDING, &mddev->flags)) st = write_pending; else if (mddev->safemode) st = active_idle; @@ -3453,9 +3451,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) mddev->in_sync = 1; if (mddev->safemode == 1) mddev->safemode = 0; - if (mddev->persistent) - set_bit(MD_CHANGE_CLEAN, - &mddev->flags); + set_bit(MD_CHANGE_CLEAN, &mddev->flags); } err = 0; } else @@ -3467,8 +3463,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) case active: if (mddev->pers) { restart_array(mddev); - if (mddev->external) - clear_bit(MD_CHANGE_CLEAN, &mddev->flags); + clear_bit(MD_CHANGE_PENDING, &mddev->flags); wake_up(&mddev->sb_wait); err = 0; } else { @@ -6573,6 +6568,7 @@ void md_write_start(mddev_t *mddev, struct bio *bi) if (mddev->in_sync) { mddev->in_sync = 0; set_bit(MD_CHANGE_CLEAN, &mddev->flags); + set_bit(MD_CHANGE_PENDING, &mddev->flags); md_wakeup_thread(mddev->thread); did_change = 1; } @@ -6581,7 +6577,6 @@ void md_write_start(mddev_t *mddev, struct bio *bi) if (did_change) sysfs_notify_dirent_safe(mddev->sysfs_state); wait_event(mddev->sb_wait, - !test_bit(MD_CHANGE_CLEAN, &mddev->flags) && !test_bit(MD_CHANGE_PENDING, &mddev->flags)); } @@ -6617,6 +6612,7 @@ int md_allow_write(mddev_t *mddev) if (mddev->in_sync) { mddev->in_sync = 0; set_bit(MD_CHANGE_CLEAN, &mddev->flags); + set_bit(MD_CHANGE_PENDING, &mddev->flags); if (mddev->safemode_delay && mddev->safemode == 0) mddev->safemode = 1; @@ -6626,7 +6622,7 @@ int md_allow_write(mddev_t *mddev) } else spin_unlock_irq(&mddev->write_lock); - if (test_bit(MD_CHANGE_CLEAN, &mddev->flags)) + if (test_bit(MD_CHANGE_PENDING, &mddev->flags)) return -EAGAIN; else return 0; @@ -6824,8 +6820,7 @@ void md_do_sync(mddev_t *mddev) atomic_read(&mddev->recovery_active) == 0); mddev->curr_resync_completed = mddev->curr_resync; - if (mddev->persistent) - set_bit(MD_CHANGE_CLEAN, &mddev->flags); + set_bit(MD_CHANGE_CLEAN, &mddev->flags); sysfs_notify(&mddev->kobj, NULL, "sync_completed"); } @@ -7104,8 +7099,7 @@ void md_check_recovery(mddev_t *mddev) mddev->recovery_cp == MaxSector) { mddev->in_sync = 1; did_change = 1; - if (mddev->persistent) - set_bit(MD_CHANGE_CLEAN, &mddev->flags); + set_bit(MD_CHANGE_CLEAN, &mddev->flags); } if (mddev->safemode == 1) mddev->safemode = 0; diff --git a/drivers/md/md.h b/drivers/md/md.h index a953fe2808ae..3931299788dc 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -140,7 +140,7 @@ struct mddev_s unsigned long flags; #define MD_CHANGE_DEVS 0 /* Some device status has changed */ #define MD_CHANGE_CLEAN 1 /* transition to or from 'clean' */ -#define MD_CHANGE_PENDING 2 /* superblock update in progress */ +#define MD_CHANGE_PENDING 2 /* switch from 'clean' to 'active' in progress */ int suspended; atomic_t active_io; -- cgit v1.2.3-59-g8ed1b From f3268512c3a5dea587cfe875b8bca98d9e164cd9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 11:00:19 +0200 Subject: ALSA: hda - Refactor input-pin parser for VIA codecs patch_via.c has redundant codes for parsing the input-pins. Although they are pretty similar, but all implemented in different functions just because of hard-coded ids and slight incompatibilities. This patch refactors the codes to use the common helper function, resulting in the reduction of many lines. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 390 +++++++--------------------------------------- 1 file changed, 60 insertions(+), 330 deletions(-) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index ae3acb2b42d1..41861388f43a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -2413,51 +2413,53 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, - const struct auto_pin_cfg *cfg) +static int vt_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg, + hda_nid_t cap_nid, + hda_nid_t pin_idxs[], int num_idxs) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; + int i, err, idx; /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = idx; - imux->num_items++; + for (idx = 0; idx < num_idxs; idx++) { + if (pin_idxs[idx] == 0xff) { + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = idx; + imux->num_items++; + break; + } + } for (i = 0; i < AUTO_PIN_LAST; i++) { if (!cfg->input_pins[i]) continue; - switch (cfg->input_pins[i]) { - case 0x1d: /* Mic */ - idx = 2; - break; - - case 0x1e: /* Line In */ - idx = 3; - break; - - case 0x21: /* Front Mic */ - idx = 4; - break; - - case 0x24: /* CD */ - idx = 1; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x17); + for (idx = 0; idx < num_idxs; idx++) + if (pin_idxs[idx] == cfg->input_pins[i]) + break; + if (idx >= num_idxs) + continue; + err = via_new_analog_input(spec, auto_pin_cfg_labels[i], + idx, cap_nid); if (err < 0) return err; - imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; imux->items[imux->num_items].index = idx; imux->num_items++; } return 0; } +/* create playback/capture controls for input pins */ +static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; + return vt_auto_create_analog_input_ctls(spec, cfg, 0x17, pin_idxs, + ARRAY_SIZE(pin_idxs)); +} + #ifdef CONFIG_SND_HDA_POWER_SAVE static struct hda_amp_list vt1708_loopbacks[] = { { 0x17, HDA_INPUT, 1 }, @@ -3024,46 +3026,9 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = idx; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x1d: /* Mic */ - idx = 2; - break; - - case 0x1e: /* Line In */ - idx = 3; - break; - - case 0x21: /* Front Mic */ - idx = 4; - break; - - case 0x23: /* CD */ - idx = 1; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x18); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - return 0; + static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; + return vt_auto_create_analog_input_ctls(spec, cfg, 0x18, pin_idxs, + ARRAY_SIZE(pin_idxs)); } static int vt1709_parse_auto_config(struct hda_codec *codec) @@ -3591,46 +3556,9 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = idx; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x1a: /* Mic */ - idx = 2; - break; - - case 0x1b: /* Line In */ - idx = 3; - break; - - case 0x1e: /* Front Mic */ - idx = 4; - break; - - case 0x1f: /* CD */ - idx = 1; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x16); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - return 0; + static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; + return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); } static int vt1708B_parse_auto_config(struct hda_codec *codec) @@ -4064,46 +3992,9 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = 5; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x1a: /* Mic */ - idx = 2; - break; - - case 0x1b: /* Line In */ - idx = 3; - break; - - case 0x1e: /* Front Mic */ - idx = 4; - break; - - case 0x1f: /* CD */ - idx = 1; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x16); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx-1; - imux->num_items++; - } - return 0; + static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); } /* fill out digital output widgets; one for master and one for slave outputs */ @@ -4457,42 +4348,9 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = 3; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x14: /* Mic */ - idx = 1; - break; - - case 0x15: /* Line In */ - idx = 2; - break; - - case 0x18: /* Front Mic */ - idx = 3; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x1A); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx-1; - imux->num_items++; - } - return 0; + static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; + return vt_auto_create_analog_input_ctls(spec, cfg, 0x1a, pin_idxs, + ARRAY_SIZE(pin_idxs)); } static int vt1702_parse_auto_config(struct hda_codec *codec) @@ -4875,46 +4733,9 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = 5; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x2b: /* Mic */ - idx = 1; - break; - - case 0x2a: /* Line In */ - idx = 2; - break; - - case 0x29: /* Front Mic */ - idx = 3; - break; - - case 0x2c: /* CD */ - idx = 0; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x21); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } - return 0; + static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; + return vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); } static int vt1718S_parse_auto_config(struct hda_codec *codec) @@ -5374,46 +5195,9 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = 5; - imux->num_items++; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x1a: /* Mic */ - idx = 2; - break; - - case 0x1b: /* Line In */ - idx = 3; - break; - - case 0x1e: /* Front Mic */ - idx = 4; - break; - - case 0x1f: /* CD */ - idx = 1; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x16); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx-1; - imux->num_items++; - } - return 0; + static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; + return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs, + ARRAY_SIZE(pin_idxs)); } static int vt1716S_parse_auto_config(struct hda_codec *codec) @@ -5720,47 +5504,19 @@ static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x2b: /* Mic */ - idx = 0; - break; - - case 0x2a: /* Line In */ - idx = 1; - break; - - case 0x29: /* Front Mic */ - idx = 2; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x21); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } + static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; + int err; + err = vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); + if (err < 0) + return err; /* build volume/mute control of loopback */ err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21); if (err < 0) return err; - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = 3; - imux->num_items++; - /* for digital mic select */ imux->items[imux->num_items].label = "Digital Mic"; imux->items[imux->num_items].index = 4; @@ -6070,46 +5826,20 @@ static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { - static char *labels[] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL - }; struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx = 0; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - - switch (cfg->input_pins[i]) { - case 0x2b: /* Mic */ - idx = 0; - break; + static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; + int err; - case 0x2a: /* Line In */ - idx = 1; - break; + err = vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs, + ARRAY_SIZE(pin_idxs)); + if (err < 0) + return err; - case 0x29: /* Front Mic */ - idx = 2; - break; - } - err = via_new_analog_input(spec, labels[i], idx, 0x21); - if (err < 0) - return err; - imux->items[imux->num_items].label = labels[i]; - imux->items[imux->num_items].index = idx; - imux->num_items++; - } /* build volume/mute control of loopback */ err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21); if (err < 0) return err; - /* for internal loopback recording select */ - imux->items[imux->num_items].label = "Stereo Mixer"; - imux->items[imux->num_items].index = 5; - imux->num_items++; - /* for digital mic select */ imux->items[imux->num_items].label = "Digital Mic"; imux->items[imux->num_items].index = 6; -- cgit v1.2.3-59-g8ed1b From fa66f07aa1f0950e1dc78b7ab39728b3f8aa77a1 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Thu, 26 Aug 2010 16:40:01 +0200 Subject: perf_events: Fix time tracking for events with pid != -1 and cpu != -1 Per-thread events with a cpu filter, i.e., cpu != -1, were not reporting correct timings when the thread never ran on the monitored cpu. The time enabled was reported as a negative value. This patch fixes the problem by updating tstamp_stopped, tstamp_running in event_sched_out() for events with filters and which are marked as INACTIVE. The function group_sched_out() is modified to systematically call into event_sched_out() to avoid duplicating the timing adjustment code twice. With the patch, I now get: $ task_cpu -i -e unhalted_core_cycles,unhalted_core_cycles noploop 2 noploop for 2 seconds CPU0 0 unhalted_core_cycles (ena=1,991,136,594, run=0) CPU0 0 unhalted_core_cycles (ena=1,991,136,594, run=0) CPU1 0 unhalted_core_cycles (ena=1,991,136,594, run=0) CPU1 0 unhalted_core_cycles (ena=1,991,136,594, run=0) CPU2 0 unhalted_core_cycles (ena=1,991,136,594, run=0) CPU2 0 unhalted_core_cycles (ena=1,991,136,594, run=0) CPU3 4,747,990,931 unhalted_core_cycles (ena=1,991,136,594, run=1,991,136,594) CPU3 4,747,990,931 unhalted_core_cycles (ena=1,991,136,594, run=1,991,136,594) Signed-off-by: Stephane Eranian Acked-by: Peter Zijlstra Cc: paulus@samba.org Cc: davem@davemloft.net Cc: fweisbec@gmail.com Cc: perfmon2-devel@lists.sf.net Cc: eranian@google.com LKML-Reference: <4c76802d.aae9d80a.115d.70fe@mx.google.com> Signed-off-by: Ingo Molnar --- kernel/perf_event.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 403d1804b198..657555a5f30f 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -402,11 +402,31 @@ static void perf_group_detach(struct perf_event *event) } } +static inline int +event_filter_match(struct perf_event *event) +{ + return event->cpu == -1 || event->cpu == smp_processor_id(); +} + static void event_sched_out(struct perf_event *event, struct perf_cpu_context *cpuctx, struct perf_event_context *ctx) { + u64 delta; + /* + * An event which could not be activated because of + * filter mismatch still needs to have its timings + * maintained, otherwise bogus information is return + * via read() for time_enabled, time_running: + */ + if (event->state == PERF_EVENT_STATE_INACTIVE + && !event_filter_match(event)) { + delta = ctx->time - event->tstamp_stopped; + event->tstamp_running += delta; + event->tstamp_stopped = ctx->time; + } + if (event->state != PERF_EVENT_STATE_ACTIVE) return; @@ -432,9 +452,7 @@ group_sched_out(struct perf_event *group_event, struct perf_event_context *ctx) { struct perf_event *event; - - if (group_event->state != PERF_EVENT_STATE_ACTIVE) - return; + int state = group_event->state; event_sched_out(group_event, cpuctx, ctx); @@ -444,7 +462,7 @@ group_sched_out(struct perf_event *group_event, list_for_each_entry(event, &group_event->sibling_list, group_entry) event_sched_out(event, cpuctx, ctx); - if (group_event->attr.exclusive) + if (state == PERF_EVENT_STATE_ACTIVE && group_event->attr.exclusive) cpuctx->exclusive = 0; } -- cgit v1.2.3-59-g8ed1b From 1deacd7a1d4bb22f812908c34e3254de76e4faa8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Aug 2010 12:10:59 -0700 Subject: UBI: fix kconfig unmet dependency warning: (OPTPROBES && KPROBES && HAVE_OPTPROBES && !PREEMPT && DEBUG_KERNEL || MTD_UBI_DEBUG && MTD && SYSFS && MTD_UBI || UBIFS_FS_DEBUG && MISC_FILESYSTEMS && UBIFS_FS || LOCKDEP && DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT || LATENCYTOP && HAVE_LATENCYTOP_SUPPORT && DEBUG_KERNEL && STACKTRACE_SUPPORT && PROC_FS) selects KALLSYMS_ALL which has unmet direct dependencies (DEBUG_KERNEL && KALLSYMS) Signed-off-by: Randy Dunlap Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/Kconfig.debug b/drivers/mtd/ubi/Kconfig.debug index 2246f154e2f7..61f6e5e40458 100644 --- a/drivers/mtd/ubi/Kconfig.debug +++ b/drivers/mtd/ubi/Kconfig.debug @@ -6,7 +6,7 @@ config MTD_UBI_DEBUG depends on SYSFS depends on MTD_UBI select DEBUG_FS - select KALLSYMS_ALL + select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL help This option enables UBI debugging. -- cgit v1.2.3-59-g8ed1b From d3f6e6c666c0f68991d785177c4c62fcd1d651f2 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Sun, 29 Aug 2010 23:34:44 +0300 Subject: UBI: do not oops when erroneous PEB is scheduled for scrubbing When an erroneous PEB is scheduling for scrubbing, we end up with the following oops: [] (prot_queue_del+0x0/0x50) from [] (ubi_wl_scrub_peb+0xec/0x13c) [] (ubi_wl_scrub_peb+0x0/0x13c) from [] (ubi_eba_read_leb+0x200/0x428) [] (ubi_eba_read_leb+0x0/0x428) from [] (ubi_leb_read+0xe8/0x138) [] (ubi_leb_read+0x0/0x138) from [] (ubifs_start_scan+0x7c/0xf4) [] (ubifs_start_scan+0x0/0xf4) from [] (ubifs_recover_leb+0x3c/0x730) [] (ubifs_recover_leb+0x0/0x730) from [] (ubifs_recover_log_leb+0xc8/0x2dc) [] (ubifs_recover_log_leb+0x0/0x2dc) from [] (ubifs_replay_journal+0xb90/0x13a4) [] (ubifs_replay_journal+0x0/0x13a4) from [] (ubifs_fill_super+0xb84/0x1054) [] (ubifs_fill_super+0x0/0x1054) from [] (ubifs_get_sb+0xc4/0x2ac) [] (ubifs_get_sb+0x0/0x2ac) from [] (vfs_kern_mount+0x58/0x94) [] (vfs_kern_mount+0x0/0x94) from [] (do_kern_mount+0x40/0xe8) [] (do_kern_mount+0x0/0xe8) from [] (do_new_mount+0x68/0x8c) [] (do_new_mount+0x0/0x8c) from [] (do_mount+0x15c/0x1b8) [] (do_mount+0x0/0x1b8) from [] (sys_mount+0x8c/0xd4) [] (sys_mount+0x0/0xd4) from [] (ret_fast_syscall+0x0/0x2c) Kernel panic - not syncing: Fatal exception The problem is that 'ubi_wl_scrub_peb()' does not expect that PEBs may be in the erroneous tree, which is a bug. This patch fixes the bug and adds corresponding check to 'ubi_wl_scrub_peb()'. Now it will simply ignore erroneous PEBs, instead of causing an oops. Reported-by: Matthieu CASTET Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/wl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index ee7b1d8fbb92..97a435672eaf 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1212,7 +1212,8 @@ int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) retry: spin_lock(&ubi->wl_lock); e = ubi->lookuptbl[pnum]; - if (e == ubi->move_from || in_wl_tree(e, &ubi->scrub)) { + if (e == ubi->move_from || in_wl_tree(e, &ubi->scrub) || + in_wl_tree(e, &ubi->erroneous)) { spin_unlock(&ubi->wl_lock); return 0; } -- cgit v1.2.3-59-g8ed1b From 75e0eb24ee3ec3549c2e53707dcc87e5f7a2c791 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 12:56:55 +0200 Subject: ALSA: hda - Add inputs[] to auto_pin_cfg struct Added the new fields to contain all input-pins to struct auto_pin_cfg. Unlike the existing input_pins[], this array contains all input pins even if the multiple pins are assigned for a single role (i.e. two front mics). The former input_pins[] still remains for a while, but will be removed in near future. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 40 +++++++++++++++++++++++++++++----------- sound/pci/hda/hda_local.h | 12 +++++++++++- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3827092cc1d2..280a739c2a99 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4372,6 +4372,17 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, } +/* add the found input-pin to the cfg->inputs[] table */ +static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, + int type) +{ + if (cfg->num_inputs < AUTO_CFG_MAX_INS) { + cfg->inputs[cfg->num_inputs].pin = nid; + cfg->inputs[cfg->num_inputs].type = type; + cfg->num_inputs++; + } +} + /* * Parse all pin widgets and store the useful pin nids to cfg * @@ -4398,6 +4409,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; + int i; memset(cfg, 0, sizeof(*cfg)); @@ -4482,19 +4494,26 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, cfg->input_pins[preferred] = nid; else if (!cfg->input_pins[alt]) cfg->input_pins[alt] = nid; + add_auto_cfg_input_pin(cfg, nid, preferred); break; } - case AC_JACK_LINE_IN: + case AC_JACK_LINE_IN: { + int type; if (loc == AC_JACK_LOC_FRONT) - cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid; + type = AUTO_PIN_FRONT_LINE; else - cfg->input_pins[AUTO_PIN_LINE] = nid; + type = AUTO_PIN_LINE; + cfg->input_pins[type] = nid; + add_auto_cfg_input_pin(cfg, nid, type); break; + } case AC_JACK_CD: cfg->input_pins[AUTO_PIN_CD] = nid; + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); break; case AC_JACK_AUX: cfg->input_pins[AUTO_PIN_AUX] = nid; + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); break; case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: @@ -4621,14 +4640,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, if (cfg->dig_outs) snd_printd(" dig-out=0x%x/0x%x\n", cfg->dig_out_pins[0], cfg->dig_out_pins[1]); - snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," - " cd=0x%x, aux=0x%x\n", - cfg->input_pins[AUTO_PIN_MIC], - cfg->input_pins[AUTO_PIN_FRONT_MIC], - cfg->input_pins[AUTO_PIN_LINE], - cfg->input_pins[AUTO_PIN_FRONT_LINE], - cfg->input_pins[AUTO_PIN_CD], - cfg->input_pins[AUTO_PIN_AUX]); + snd_printd(" inputs:"); + for (i = 0; i < cfg->num_inputs; i++) { + snd_printdd(" %s=0x%x", + auto_pin_cfg_labels[cfg->inputs[i].type], + cfg->inputs[i].pin); + } + snd_printd("\n"); if (cfg->dig_in_pin) snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 28ab4aead48f..44c909445ba2 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -383,6 +383,14 @@ enum { extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; #define AUTO_CFG_MAX_OUTS 5 +#define AUTO_CFG_MAX_INS 8 + +struct auto_pin_cfg_item { + hda_nid_t pin; + int type; +}; + +struct auto_pin_cfg; struct auto_pin_cfg { int line_outs; @@ -393,7 +401,9 @@ struct auto_pin_cfg { int hp_outs; int line_out_type; /* AUTO_PIN_XXX_OUT */ hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t input_pins[AUTO_PIN_LAST]; + hda_nid_t input_pins[AUTO_PIN_LAST]; /* old config; to be deprecated */ + int num_inputs; + struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS]; int dig_outs; hda_nid_t dig_out_pins[2]; hda_nid_t dig_in_pin; -- cgit v1.2.3-59-g8ed1b From d7b1ae9d8851bd247590cf7ab53248a2dac0419f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 13:00:16 +0200 Subject: ALSA: hda - Add snd_hda_get_input_pin_label() helper function Added snd_hda_get_input_pin_label() helper function to return the string that can be used for control or capture-source ids. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 25 ++++++++++++++++++++++++- sound/pci/hda/hda_local.h | 2 ++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 280a739c2a99..72334b7f60e5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4654,12 +4654,35 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); -/* labels for input pins */ +/* labels for input pins - for obsoleted config stuff */ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" }; EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); +static const char *input_labels[AUTO_PIN_LAST][4] = { + { "Mic", "Mic 2", "Mic 3", "Mic 4" }, + { "Front Mic", "Front Mic 2", "Front Mic 3", "Front Mic 4" }, + { "Line", "Line 2", "Line 3", "Line 4" }, + { "Front Line", "Front Line 2", "Front Line 3", "Front Line 4" }, + { "CD", "CD 2", "CD 3", "CD 4" }, + { "Aux", "Aux 2", "Aux 3", "Aux 4" }, +}; + +const char *snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, + int input) +{ + int type = cfg->inputs[input].type; + int idx; + + for (idx = 0; idx < 3 && --input >= 0; idx++) { + if (type != cfg->inputs[input].type) + break; + } + return input_labels[type][idx]; +} +EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_label); + #ifdef CONFIG_PM /* diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 44c909445ba2..fb561748adb8 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -391,6 +391,8 @@ struct auto_pin_cfg_item { }; struct auto_pin_cfg; +const char *snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, + int input); struct auto_pin_cfg { int line_outs; -- cgit v1.2.3-59-g8ed1b From 9e042e71325eeda03636aedfde6f2d27d6332188 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 13:04:44 +0200 Subject: ALSA: hda - Use new inputs[] field to parse input-pins for AD codecs Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index b697fd2a6f8b..3409d315f507 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2880,7 +2880,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, /* create input playback/capture controls for the given pin */ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, - const char *ctlname, int boost) + const char *ctlname, int ctlidx, int boost) { char name[32]; int err, idx; @@ -2913,16 +2913,23 @@ static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec, const struct auto_pin_cfg *cfg) { struct hda_input_mux *imux = &spec->private_imux; - int i, err; + int i, err, type, type_idx = 0; - for (i = 0; i < AUTO_PIN_LAST; i++) { - err = new_analog_input(spec, cfg->input_pins[i], - auto_pin_cfg_labels[i], - i <= AUTO_PIN_FRONT_MIC); + for (i = 0; i < cfg->num_inputs; i++) { + type = cfg->inputs[i].type; + if (i > 0 && type != cfg->inputs[i - 1].type) + type_idx++; + else + type_idx = 0; + err = new_analog_input(spec, cfg->inputs[i].pin, + auto_pin_cfg_labels[type], type_idx, + type <= AUTO_PIN_FRONT_MIC); if (err < 0) return err; - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; - imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]); + imux->items[imux->num_items].label = + snd_hda_get_input_pin_label(cfg, i); + imux->items[imux->num_items].index = + ad1988_pin_to_adc_idx(cfg->inputs[i].pin); imux->num_items++; } imux->items[imux->num_items].label = "Mix"; @@ -2994,12 +3001,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec) static void ad1988_auto_init_analog_input(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; int i, idx; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (! nid) - continue; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; switch (nid) { case 0x15: /* port-C */ snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); -- cgit v1.2.3-59-g8ed1b From fa4968a8b231816d161583e604a9f972e5713f17 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 13:05:08 +0200 Subject: ALSA: hda - Use new inputs[] field to parse input-pins for CA-IBG codecs Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0110.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index af478019088e..42b3fb4cafc4 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -468,13 +468,14 @@ static void parse_input(struct hda_codec *codec) spec->dig_in = nid; continue; } - for (j = 0; j < AUTO_PIN_LAST; j++) - if (cfg->input_pins[j] == pin) + for (j = 0; j < cfg->num_inputs; j++) + if (cfg->inputs[j].pin == pin) break; - if (j >= AUTO_PIN_LAST) + if (j >= cfg->num_inputs) continue; spec->input_pins[n] = pin; - spec->input_labels[n] = auto_pin_cfg_labels[j]; + spec->input_labels[n] = + auto_pin_cfg_labels[cfg->inputs[j].type]; spec->adcs[n] = nid; n++; } -- cgit v1.2.3-59-g8ed1b From c1e0bb92174dd16ffba5be0e4e5fbd366f61ff7f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 13:05:30 +0200 Subject: ALSA: hda - Use new inputs[] field to parse input-pins for CirrusLogic codecs Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 4ef5efaaaef1..ee1aea7296eb 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -329,7 +329,7 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t pin = cfg->input_pins[idx]; + hda_nid_t pin = cfg->inputs[idx].pin; unsigned int val = snd_hda_query_pin_caps(codec, pin); if (!(val & AC_PINCAP_PRES_DETECT)) return 0; @@ -424,10 +424,8 @@ static int parse_input(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t pin = cfg->input_pins[i]; - if (!pin) - continue; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t pin = cfg->inputs[i].pin; spec->input_idx[spec->num_inputs] = i; spec->capsrc_idx[i] = spec->num_inputs++; spec->cur_input = i; @@ -438,16 +436,17 @@ static int parse_input(struct hda_codec *codec) /* check whether the automatic mic switch is available */ if (spec->num_inputs == 2 && - spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { - if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { - if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { + cfg->inputs[0].type <= AUTO_PIN_FRONT_MIC && + cfg->inputs[1].type == AUTO_PIN_FRONT_MIC) { + if (is_ext_mic(codec, cfg->inputs[0].pin)) { + if (!is_ext_mic(codec, cfg->inputs[1].pin)) { spec->mic_detect = 1; - spec->automic_idx = AUTO_PIN_FRONT_MIC; + spec->automic_idx = 0; } } else { - if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { + if (is_ext_mic(codec, cfg->inputs[1].pin)) { spec->mic_detect = 1; - spec->automic_idx = AUTO_PIN_MIC; + spec->automic_idx = 1; } } } @@ -853,15 +852,12 @@ static void cs_automic(struct hda_codec *codec) hda_nid_t nid; unsigned int present; - nid = cfg->input_pins[spec->automic_idx]; + nid = cfg->inputs[spec->automic_idx].pin; present = snd_hda_jack_detect(codec, nid); if (present) change_cur_input(codec, spec->automic_idx, 0); - else { - unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? - AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC; - change_cur_input(codec, imic, 0); - } + else + change_cur_input(codec, !spec->automic_idx, 0); } /* @@ -918,14 +914,14 @@ static void init_input(struct hda_codec *codec) unsigned int coef; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { + for (i = 0; i < cfg->num_inputs; i++) { unsigned int ctl; - hda_nid_t pin = cfg->input_pins[i]; - if (!pin || !spec->adc_nid[i]) + hda_nid_t pin = cfg->inputs[i].pin; + if (!spec->adc_nid[i]) continue; /* set appropriate pin control and mute first */ ctl = PIN_IN; - if (i <= AUTO_PIN_FRONT_MIC) { + if (cfg->inputs[i].type <= AUTO_PIN_FRONT_MIC) { unsigned int caps = snd_hda_query_pin_caps(codec, pin); caps >>= AC_PINCAP_VREF_SHIFT; if (caps & AC_PINCAP_VREF_80) -- cgit v1.2.3-59-g8ed1b From 66ceeb6bc2809bef0cfa18b1e22ddad5fc9b58b0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 13:05:52 +0200 Subject: ALSA: hda - Use new inputs[] field to parse input-pins for Realtek codecs Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 208 ++++++++++++++++++++++-------------------- 1 file changed, 110 insertions(+), 98 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 50e0c82fd994..3e0f4816aed7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1265,16 +1265,14 @@ static void alc_init_auto_mic(struct hda_codec *codec) int i; /* there must be only two mic inputs exclusively */ - for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) - if (cfg->input_pins[i]) + for (i = 0; i < cfg->num_inputs; i++) + if (cfg->inputs[i].type >= AUTO_PIN_LINE) return; fixed = ext = 0; - for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) { - hda_nid_t nid = cfg->input_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; unsigned int defcfg; - if (!nid) - return; defcfg = snd_hda_codec_get_pincfg(codec, nid); switch (get_defcfg_connect(defcfg)) { case AC_JACK_PORT_FIXED: @@ -4719,7 +4717,7 @@ static struct snd_kcontrol_new alc880_control_templates[] = { /* add dynamic controls */ static int add_control(struct alc_spec *spec, int type, const char *name, - unsigned long val) + int cidx, unsigned long val) { struct snd_kcontrol_new *knew; @@ -4731,6 +4729,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name, knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; + knew->index = cidx; if (get_amp_nid_(val)) knew->subdevice = HDA_SUBDEV_AMP_FLAG; knew->private_value = val; @@ -4739,17 +4738,21 @@ static int add_control(struct alc_spec *spec, int type, const char *name, static int add_control_with_pfx(struct alc_spec *spec, int type, const char *pfx, const char *dir, - const char *sfx, unsigned long val) + const char *sfx, int cidx, unsigned long val) { char name[32]; snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); - return add_control(spec, type, name, val); + return add_control(spec, type, name, cidx, val); } -#define add_pb_vol_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val) -#define add_pb_sw_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val) +#define add_pb_vol_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) +#define add_pb_sw_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) +#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) +#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) #define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) #define alc880_fixed_pin_idx(nid) ((nid) - 0x14) @@ -4902,16 +4905,16 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, /* create input playback/capture controls for the given pin */ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, - const char *ctlname, + const char *ctlname, int ctlidx, int idx, hda_nid_t mix_nid) { int err; - err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, + err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; - err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, + err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; @@ -4932,21 +4935,26 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, { struct alc_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx; + int i, err, idx, type, type_idx = 0; - for (i = 0; i < AUTO_PIN_LAST; i++) { + for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t pin; - pin = cfg->input_pins[i]; + pin = cfg->inputs[i].pin; if (!alc_is_input_pin(codec, pin)) continue; + type = cfg->inputs[i].type; + if (i > 0 && type == cfg->inputs[i - 1].type) + type_idx++; + else + type_idx = 0; if (mixer) { idx = get_connection_index(codec, mixer, pin); if (idx >= 0) { err = new_analog_input(spec, pin, - auto_pin_cfg_labels[i], - idx, mixer); + auto_pin_cfg_labels[type], + type_idx, idx, mixer); if (err < 0) return err; } @@ -4959,7 +4967,7 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, idx = get_connection_index(codec, cap2, pin); if (idx >= 0) { imux->items[imux->num_items].label = - auto_pin_cfg_labels[i]; + snd_hda_get_input_pin_label(cfg, i); imux->items[imux->num_items].index = idx; imux->num_items++; } @@ -5034,10 +5042,11 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec) static void alc880_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; if (alc_is_input_pin(codec, nid)) { alc_set_input_pin(codec, nid, i); if (nid != ALC880_PIN_CD_NID && @@ -5204,19 +5213,13 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) static void fixup_single_adc(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t pin = 0; + struct auto_pin_cfg *cfg = &spec->autocfg; int i; /* search for the input pin; there must be only one */ - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (spec->autocfg.input_pins[i]) { - pin = spec->autocfg.input_pins[i]; - break; - } - } - if (!pin) + if (cfg->num_inputs != 1) return; - i = init_capsrc_for_pin(codec, pin); + i = init_capsrc_for_pin(codec, cfg->inputs[0].pin); if (i >= 0) { /* use only this ADC */ if (spec->capsrc_nids) @@ -5269,6 +5272,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, int num_nids) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; int n; hda_nid_t fallback_adc = 0, fallback_cap = 0; @@ -5294,10 +5298,8 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, fallback_adc = adc; fallback_cap = cap; } - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (!nid) - continue; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; for (j = 0; j < nconns; j++) { if (conn[j] == nid) break; @@ -5305,7 +5307,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, if (j >= nconns) break; } - if (i >= AUTO_PIN_LAST) { + if (i >= cfg->num_inputs) { int num_adcs = spec->num_adc_nids; spec->private_adc_nids[num_adcs] = adc; spec->private_capsrc_nids[num_adcs] = cap; @@ -6672,10 +6674,11 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) static void alc260_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; if (nid >= 0x12) { alc_set_input_pin(codec, nid, i); if (nid != ALC260_PIN_CD_NID && @@ -10538,12 +10541,11 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) static void alc882_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (!nid) - continue; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; alc_set_input_pin(codec, nid, i); if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, nid, 0, @@ -10606,24 +10608,23 @@ static void alc882_auto_init_input_src(struct hda_codec *codec) static int alc_auto_add_mic_boost(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int err; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, err; hda_nid_t nid; - nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; - if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Mic Boost", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; - if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Front Mic Boost", + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type > AUTO_PIN_FRONT_MIC) + break; + nid = cfg->inputs[i].pin; + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { + char label[32]; + snprintf(label, sizeof(label), "%s Boost", + snd_hda_get_input_pin_label(cfg, i)); + err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); - if (err < 0) - return err; + if (err < 0) + return err; + } } return 0; } @@ -15577,10 +15578,11 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec) static void alc861_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; if (nid >= 0x0c && nid <= 0x11) alc_set_input_pin(codec, nid, i); } @@ -16569,10 +16571,11 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec) static void alc861vd_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; if (alc_is_input_pin(codec, nid)) { alc_set_input_pin(codec, nid, i); if (nid != ALC861VD_PIN_CD_NID && @@ -18805,10 +18808,11 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec) static void alc662_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; if (alc_is_input_pin(codec, nid)) { alc_set_input_pin(codec, nid, i); if (nid != ALC662_PIN_CD_NID && @@ -19037,6 +19041,39 @@ static hda_nid_t alc680_adc_nids[3] = { /* * Analog capture ADC cgange */ +static void alc680_rec_autoswitch(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int pin_found = 0; + int type_found = AUTO_PIN_LAST; + hda_nid_t nid; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + nid = cfg->inputs[i].pin; + if (!(snd_hda_query_pin_caps(codec, nid) & + AC_PINCAP_PRES_DETECT)) + continue; + if (snd_hda_jack_detect(codec, nid)) { + if (cfg->inputs[i].type < type_found) { + type_found = cfg->inputs[i].type; + pin_found = nid; + } + } + } + + nid = 0x07; + if (pin_found) + snd_hda_get_connections(codec, pin_found, &nid, 1); + + if (nid != spec->cur_adc) + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = nid; + snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); +} + static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -19044,24 +19081,12 @@ static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int pre_mic, pre_line; - - pre_mic = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); - pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]); + spec->cur_adc = 0x07; spec->cur_adc_stream_tag = stream_tag; spec->cur_adc_format = format; - if (pre_mic || pre_line) { - if (pre_mic) - snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0, - format); - else - snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0, - format); - } else - snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format); + alc680_rec_autoswitch(codec); return 0; } @@ -19147,6 +19172,7 @@ static struct hda_verb alc680_init_verbs[] = { {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, { } }; @@ -19159,25 +19185,11 @@ static void alc680_base_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x16; spec->autocfg.speaker_pins[0] = 0x14; spec->autocfg.speaker_pins[1] = 0x15; - spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18; - spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19; -} - -static void alc680_rec_autoswitch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int present; - hda_nid_t new_adc; - - present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]); - - new_adc = present ? 0x8 : 0x7; - __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1); - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - + spec->autocfg.num_inputs = 2; + spec->autocfg.inputs[0].pin = 0x18; + spec->autocfg.inputs[0].type = AUTO_PIN_MIC; + spec->autocfg.inputs[1].pin = 0x19; + spec->autocfg.inputs[1].type = AUTO_PIN_LINE; } static void alc680_unsol_event(struct hda_codec *codec, -- cgit v1.2.3-59-g8ed1b From eea7dc932bfa802ad0377755ea821f416f4f8623 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 13:06:15 +0200 Subject: ALSA: hda - Use new inputs[] field to parse input-pins for STAC/IDT codecs Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 183 +++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 87 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 95148e58026c..d226edd1e143 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1180,14 +1180,11 @@ static int stac92xx_build_controls(struct hda_codec *codec) if (err < 0) return err; } - for (i = 0; i < AUTO_PIN_LAST; i++) { - nid = cfg->input_pins[i]; - if (nid) { - err = stac92xx_add_jack(codec, nid, - SND_JACK_MICROPHONE); - if (err < 0) - return err; - } + for (i = 0; i < cfg->num_inputs; i++) { + nid = cfg->inputs[i].pin; + err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE); + if (err < 0) + return err; } return 0; @@ -2821,41 +2818,55 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; unsigned int pincap; + int i; if (cfg->line_out_type != AUTO_PIN_LINE_OUT) return 0; - nid = cfg->input_pins[AUTO_PIN_LINE]; - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_OUT) - return nid; + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type == AUTO_PIN_LINE) { + nid = cfg->inputs[i].pin; + pincap = snd_hda_query_pin_caps(codec, nid); + if (pincap & AC_PINCAP_OUT) + return nid; + } + } return 0; } +static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid); + /* check whether the mic-input can be used as line-out */ -static hda_nid_t check_mic_out_switch(struct hda_codec *codec) +static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int def_conf, pincap; - unsigned int mic_pin; + int i, mic_type; + *dac = 0; if (cfg->line_out_type != AUTO_PIN_LINE_OUT) return 0; - mic_pin = AUTO_PIN_MIC; - for (;;) { - hda_nid_t nid = cfg->input_pins[mic_pin]; + mic_type = AUTO_PIN_MIC; + again: + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (cfg->inputs[i].type != mic_type) + continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); /* some laptops have an internal analog microphone * which can't be used as a output */ if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_OUT) - return nid; + if (pincap & AC_PINCAP_OUT) { + *dac = get_unassigned_dac(codec, nid); + if (*dac) + return nid; + } } - if (mic_pin == AUTO_PIN_MIC) - mic_pin = AUTO_PIN_FRONT_MIC; - else - break; + } + if (mic_type == AUTO_PIN_MIC) { + mic_type = AUTO_PIN_FRONT_MIC; + goto again; } return 0; } @@ -3002,17 +3013,14 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) } } /* add mic as output */ - nid = check_mic_out_switch(codec); - if (nid) { - dac = get_unassigned_dac(codec, nid); - if (dac) { - snd_printdd("STAC: Add mic-in 0x%x as output %d\n", - nid, cfg->line_outs); - cfg->line_out_pins[cfg->line_outs] = nid; - cfg->line_outs++; - spec->mic_switch = nid; - add_spec_dacs(spec, dac); - } + nid = check_mic_out_switch(codec, &dac); + if (nid && dac) { + snd_printdd("STAC: Add mic-in 0x%x as output %d\n", + nid, cfg->line_outs); + cfg->line_out_pins[cfg->line_outs] = nid; + cfg->line_outs++; + spec->mic_switch = nid; + add_spec_dacs(spec, dac); } snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", @@ -3202,13 +3210,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, return err; } - for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { - nid = cfg->input_pins[idx]; - if (nid) { - err = stac92xx_add_jack_mode_control(codec, nid, idx); - if (err < 0) - return err; - } + for (idx = 0; idx < cfg->num_inputs; idx++) { + if (cfg->inputs[idx].type > AUTO_PIN_FRONT_LINE) + break; + nid = cfg->inputs[idx].pin; + err = stac92xx_add_jack_mode_control(codec, nid, idx); + if (err < 0) + return err; } return 0; @@ -3415,7 +3423,7 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, /* create a volume assigned to the given pin (only if supported) */ /* return 1 if the volume control is created */ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, - const char *label, int direction) + const char *label, int idx, int direction) { unsigned int caps, nums; char name[32]; @@ -3432,8 +3440,8 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, if (!nums) return 0; snprintf(name, sizeof(name), "%s Capture Volume", label); - err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction)); + err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name, + HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction)); if (err < 0) return err; return 1; @@ -3485,11 +3493,11 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, else label = stac92xx_dmic_labels[dimux->num_items]; - err = create_elem_capture_vol(codec, nid, label, HDA_INPUT); + err = create_elem_capture_vol(codec, nid, label, 0, HDA_INPUT); if (err < 0) return err; if (!err) { - err = create_elem_capture_vol(codec, nid, label, + err = create_elem_capture_vol(codec, nid, label, 0, HDA_OUTPUT); if (err < 0) return err; @@ -3540,10 +3548,11 @@ static int set_mic_route(struct hda_codec *codec, int i; mic->pin = pin; - for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) - if (pin == cfg->input_pins[i]) + for (i = 0; i < cfg->num_inputs; i++) { + if (pin == cfg->inputs[i].pin) break; - if (i <= AUTO_PIN_FRONT_MIC) { + } + if (i < cfg->num_inputs && cfg->inputs[i].type <= AUTO_PIN_FRONT_MIC) { /* analog pin */ i = get_connection_index(codec, spec->mux_nids[0], pin); if (i < 0) @@ -3577,13 +3586,13 @@ static int stac_check_auto_mic(struct hda_codec *codec) hda_nid_t fixed, ext; int i; - for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) { - if (cfg->input_pins[i]) + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type >= AUTO_PIN_LINE) return 0; /* must be exclusively mics */ } fixed = ext = 0; - for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) - if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext)) + for (i = 0; i < cfg->num_inputs; i++) + if (check_mic_pin(codec, cfg->inputs[i].pin, &fixed, &ext)) return 0; for (i = 0; i < spec->num_dmics; i++) if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext)) @@ -3603,14 +3612,12 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const { struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux; - int i, j; + int i, j, type_idx = 0; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = cfg->input_pins[i]; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; int index, err; - if (!nid) - continue; index = -1; for (j = 0; j < spec->num_muxes; j++) { index = get_connection_index(codec, spec->mux_nids[j], @@ -3621,13 +3628,18 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const if (index < 0) continue; + if (i > 0 && cfg->inputs[i].type == cfg->inputs[i - 1].type) + type_idx++; + else + type_idx = 0; err = create_elem_capture_vol(codec, nid, - auto_pin_cfg_labels[i], + auto_pin_cfg_labels[i], type_idx, HDA_INPUT); if (err < 0) return err; - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; + imux->items[imux->num_items].label = + snd_hda_get_input_pin_label(cfg, i); imux->items[imux->num_items].index = index; imux->num_items++; } @@ -4304,37 +4316,34 @@ static int stac92xx_init(struct hda_codec *codec) if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) stac_issue_unsol_event(codec, spec->ext_mic.pin); } - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = cfg->input_pins[i]; - if (nid) { - unsigned int pinctl, conf; - if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { - /* for mic pins, force to initialize */ - pinctl = stac92xx_get_default_vref(codec, nid); + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + int type = cfg->inputs[i].type; + unsigned int pinctl, conf; + if (type == AUTO_PIN_MIC || type == AUTO_PIN_FRONT_MIC) { + /* for mic pins, force to initialize */ + pinctl = stac92xx_get_default_vref(codec, nid); + pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, pinctl); + } else { + pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + /* if PINCTL already set then skip */ + /* Also, if both INPUT and OUTPUT are set, + * it must be a BIOS bug; need to override, too + */ + if (!(pinctl & AC_PINCTL_IN_EN) || + (pinctl & AC_PINCTL_OUT_EN)) { + pinctl &= ~AC_PINCTL_OUT_EN; pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); - } else { - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - /* if PINCTL already set then skip */ - /* Also, if both INPUT and OUTPUT are set, - * it must be a BIOS bug; need to override, too - */ - if (!(pinctl & AC_PINCTL_IN_EN) || - (pinctl & AC_PINCTL_OUT_EN)) { - pinctl &= ~AC_PINCTL_OUT_EN; - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, - pinctl); - } - } - conf = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { - if (enable_pin_detect(codec, nid, - STAC_INSERT_EVENT)) - stac_issue_unsol_event(codec, nid); } } + conf = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { + if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT)) + stac_issue_unsol_event(codec, nid); + } } for (i = 0; i < spec->num_dmics; i++) stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], -- cgit v1.2.3-59-g8ed1b From 7b315bb4980448250c80a7464c256b54d546cb26 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Aug 2010 13:06:30 +0200 Subject: ALSA: hda - Use new inputs[] field to parse input-pins for VIA codecs Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 144 +++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 41861388f43a..93b86adbce63 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -444,8 +444,8 @@ static hda_nid_t vt1812_adc_nids[2] = { /* add dynamic controls */ -static int via_add_control(struct via_spec *spec, int type, const char *name, - unsigned long val) +static int __via_add_control(struct via_spec *spec, int type, const char *name, + int idx, unsigned long val) { struct snd_kcontrol_new *knew; @@ -463,6 +463,9 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, return 0; } +#define via_add_control(spec, type, name, val) \ + __via_add_control(spec, type, name, 0, val) + static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, struct snd_kcontrol_new *tmpl) { @@ -494,18 +497,18 @@ static void via_free_kctls(struct hda_codec *codec) /* create input playback/capture controls for the given pin */ static int via_new_analog_input(struct via_spec *spec, const char *ctlname, - int idx, int mix_nid) + int type_idx, int idx, int mix_nid) { char name[32]; int err; sprintf(name, "%s Playback Volume", ctlname); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, + err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; sprintf(name, "%s Playback Switch", ctlname); - err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, + err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; @@ -557,14 +560,12 @@ static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); static void via_auto_init_analog_input(struct hda_codec *codec) { struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int ctl; int i; - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (!nid) - continue; - + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; if (spec->smart51_enabled && is_smart51_pins(spec, nid)) ctl = PIN_OUT; else if (i <= AUTO_PIN_FRONT_MIC) @@ -1322,15 +1323,14 @@ static void mute_aa_path(struct hda_codec *codec, int mute) } static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin) { - int res = 0; - int index; - for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) { - if (pin == spec->autocfg.input_pins[index]) { - res = 1; - break; - } + const struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + if (pin == cfg->inputs[i].pin) + return cfg->inputs[i].type < AUTO_PIN_FRONT_LINE; } - return res; + return 0; } static int via_smart51_info(struct snd_kcontrol *kcontrol, @@ -1348,25 +1348,21 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; + const struct auto_pin_cfg *cfg = &spec->autocfg; int on = 1; int i; - for (i = 0; i < ARRAY_SIZE(index); i++) { - hda_nid_t nid = spec->autocfg.input_pins[index[i]]; - if (nid) { - int ctl = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, - 0); - if (i == AUTO_PIN_FRONT_MIC - && spec->hp_independent_mode - && spec->codec_type != VT1718S) - continue; /* ignore FMic for independent HP */ - if (ctl & AC_PINCTL_IN_EN - && !(ctl & AC_PINCTL_OUT_EN)) - on = 0; - } + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + int ctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (cfg->inputs[i].type >= AUTO_PIN_FRONT_LINE) + continue; + if (cfg->inputs[i].type == AUTO_PIN_FRONT_MIC && + spec->hp_independent_mode && spec->codec_type != VT1718S) + continue; /* ignore FMic for independent HP */ + if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN)) + on = 0; } *ucontrol->value.integer.value = on; return 0; @@ -1377,36 +1373,38 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; int out_in = *ucontrol->value.integer.value ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN; - int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; int i; - for (i = 0; i < ARRAY_SIZE(index); i++) { - hda_nid_t nid = spec->autocfg.input_pins[index[i]]; - if (i == AUTO_PIN_FRONT_MIC - && spec->hp_independent_mode - && spec->codec_type != VT1718S) + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + unsigned int parm; + + if (cfg->inputs[i].type >= AUTO_PIN_FRONT_LINE) + continue; + if (cfg->inputs[i].type == AUTO_PIN_FRONT_MIC && + spec->hp_independent_mode && spec->codec_type != VT1718S) continue; /* don't retask FMic for independent HP */ - if (nid) { - unsigned int parm = snd_hda_codec_read( - codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - parm |= out_in; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - parm); - if (out_in == AC_PINCTL_OUT_EN) { - mute_aa_path(codec, 1); - notify_aa_path_ctls(codec); - } - if (spec->codec_type == VT1718S) - snd_hda_codec_amp_stereo( + + parm = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); + parm |= out_in; + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + parm); + if (out_in == AC_PINCTL_OUT_EN) { + mute_aa_path(codec, 1); + notify_aa_path_ctls(codec); + } + if (spec->codec_type == VT1718S) { + snd_hda_codec_amp_stereo( codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE); } - if (i == AUTO_PIN_FRONT_MIC) { + if (cfg->inputs[i].type == AUTO_PIN_FRONT_MIC) { if (spec->codec_type == VT1708S || spec->codec_type == VT1716S) { /* input = index 1 (AOW3) */ @@ -1442,7 +1440,7 @@ static struct snd_kcontrol_new via_smart51_mixer[2] = { static int via_smart51_build(struct via_spec *spec) { struct snd_kcontrol_new *knew; - int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; + const struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; int i; @@ -1450,13 +1448,14 @@ static int via_smart51_build(struct via_spec *spec) if (knew == NULL) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(index); i++) { - nid = spec->autocfg.input_pins[index[i]]; - if (nid) { + for (i = 0; i < cfg->num_inputs; i++) { + nid = cfg->inputs[i].pin; + if (cfg->inputs[i].type < AUTO_PIN_FRONT_LINE) { knew = via_clone_control(spec, &via_smart51_mixer[1]); if (knew == NULL) return -ENOMEM; knew->subdevice = nid; + break; } } @@ -2419,7 +2418,7 @@ static int vt_auto_create_analog_input_ctls(struct via_spec *spec, hda_nid_t pin_idxs[], int num_idxs) { struct hda_input_mux *imux = &spec->private_imux[0]; - int i, err, idx; + int i, err, idx, type, type_idx = 0; /* for internal loopback recording select */ for (idx = 0; idx < num_idxs; idx++) { @@ -2431,20 +2430,23 @@ static int vt_auto_create_analog_input_ctls(struct via_spec *spec, } } - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!cfg->input_pins[i]) - continue; - + for (i = 0; i < cfg->num_inputs; i++) { + type = cfg->inputs[i].type; for (idx = 0; idx < num_idxs; idx++) - if (pin_idxs[idx] == cfg->input_pins[i]) + if (pin_idxs[idx] == cfg->inputs[i].pin) break; if (idx >= num_idxs) continue; - err = via_new_analog_input(spec, auto_pin_cfg_labels[i], - idx, cap_nid); + if (i > 0 && type == cfg->inputs[i - 1].type) + type_idx++; + else + type_idx = 0; + err = via_new_analog_input(spec, auto_pin_cfg_labels[type], + type_idx, idx, cap_nid); if (err < 0) return err; - imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; + imux->items[imux->num_items].label = + snd_hda_get_input_pin_label(cfg, i); imux->items[imux->num_items].index = idx; imux->num_items++; } @@ -5513,7 +5515,7 @@ static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec, if (err < 0) return err; /* build volume/mute control of loopback */ - err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21); + err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21); if (err < 0) return err; @@ -5836,7 +5838,7 @@ static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, return err; /* build volume/mute control of loopback */ - err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21); + err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From c3dc66de59531c921c4638b1285075ea1c831186 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 30 Aug 2010 15:43:25 +0200 Subject: HID: add support for another BTC Emprex remote control Add device ID for another variant of this remote control. Reported-by: Gregor Fuis Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-topseed.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 0c52899be964..b2b3bb90dd64 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1287,6 +1287,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b309525ae280..7c69f1ebb390 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -128,6 +128,7 @@ #define USB_VENDOR_ID_BTC 0x046e #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 +#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 #define USB_VENDOR_ID_CANDO 0x2087 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c index 5771f851f856..956ed9ac19d4 100644 --- a/drivers/hid/hid-topseed.c +++ b/drivers/hid/hid-topseed.c @@ -64,6 +64,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, static const struct hid_device_id ts_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { } }; -- cgit v1.2.3-59-g8ed1b From ebd11fecd3096b080c84fb35014916ae2b5ba64a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 30 Aug 2010 13:11:42 +0200 Subject: HID: Add quirk for eGalax touch controler. This patch adds a quirk for the eGalax touch controller which reports two pairs of axes. Signed-off-by: Thierry Reding Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 89fa4ac989f9..16808f19a4b4 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -33,6 +33,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.3-59-g8ed1b From 8f587df479c3cea14ba1a9b9d58f34fd2fd6d58b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 4 Aug 2010 16:27:45 +0000 Subject: 9p: potential ERR_PTR() dereference p9_client_walk() can return error values if we run out of space or there is a problem with the network. Signed-off-by: Dan Carpenter Signed-off-by: Eric Van Hensbergen --- fs/9p/fid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 358563689064..6406f896bf95 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -242,7 +242,8 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) } kfree(wnames); fid_out: - v9fs_fid_add(dentry, fid); + if (!IS_ERR(fid)) + v9fs_fid_add(dentry, fid); err_out: up_read(&v9ses->rename_sem); return fid; -- cgit v1.2.3-59-g8ed1b From edce6820a9fdda85521211cb334a183e34cc455e Mon Sep 17 00:00:00 2001 From: Jeffrey Carlyle Date: Mon, 30 Aug 2010 19:55:09 +0200 Subject: scatterlist: prevent invalid free when alloc fails When alloc fails, free_table is being called. Depending on the number of bytes requested, we determine if we are going to call _get_free_page() or kmalloc(). When alloc fails, our math is wrong (due to sg_size - 1), and the last buffer is wrongfully assumed to have been allocated by kmalloc. Hence, kfree gets called and a panic occurs. Signed-off-by: Jeffrey Carlyle Signed-off-by: Olusanya Soyannwo Acked-by: Tejun Heo Signed-off-by: Jens Axboe --- lib/scatterlist.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/scatterlist.c b/lib/scatterlist.c index a5ec42868f99..4ceb05d772ae 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -248,8 +248,18 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents, left -= sg_size; sg = alloc_fn(alloc_size, gfp_mask); - if (unlikely(!sg)) - return -ENOMEM; + if (unlikely(!sg)) { + /* + * Adjust entry count to reflect that the last + * entry of the previous table won't be used for + * linkage. Without this, sg_kfree() may get + * confused. + */ + if (prv) + table->nents = ++table->orig_nents; + + return -ENOMEM; + } sg_init_table(sg, alloc_size); table->nents = table->orig_nents += sg_size; -- cgit v1.2.3-59-g8ed1b From d8e1ba76d619dbc0be8fbeee4e6c683b5c812d3a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 24 Aug 2010 15:27:34 -0400 Subject: ath5k: check return value of ieee80211_get_tx_rate This avoids a NULL pointer dereference as reported here: https://bugzilla.redhat.com/show_bug.cgi?id=625889 When the WARN condition is hit in ieee80211_get_tx_rate, it will return NULL. So, we need to check the return value and avoid dereferencing it in that case. Signed-off-by: John W. Linville Cc: stable@kernel.org Acked-by: Bob Copeland --- drivers/net/wireless/ath/ath5k/base.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 373dcfec689c..d77ce9906b6c 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1327,6 +1327,10 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, PCI_DMA_TODEVICE); rate = ieee80211_get_tx_rate(sc->hw, info); + if (!rate) { + ret = -EINVAL; + goto err_unmap; + } if (info->flags & IEEE80211_TX_CTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; -- cgit v1.2.3-59-g8ed1b From f880c2050f30b23c9b6f80028c09f76e693bf309 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 24 Aug 2010 22:54:05 +0200 Subject: p54: fix tx feedback status flag check Michael reported that p54* never really entered power save mode, even tough it was enabled. It turned out that upon a power save mode change the firmware will set a special flag onto the last outgoing frame tx status (which in this case is almost always the designated PSM nullfunc frame). This flag confused the driver; It erroneously reported transmission failures to the stack, which then generated the next nullfunc. and so on... Cc: Reported-by: Michael Buesch Tested-by: Michael Buesch Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 173aec3d6e7e..0e937dc0c9c4 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -446,7 +446,7 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) } if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && - (!payload->status)) + !(payload->status & P54_TX_FAILED)) info->flags |= IEEE80211_TX_STAT_ACK; if (payload->status & P54_TX_PSM_CANCELLED) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; -- cgit v1.2.3-59-g8ed1b From 071249b1d501b1f31a6b1af3fbcbe03158a84e5c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 25 Aug 2010 14:47:38 +0200 Subject: mac80211: delete work timer The new workqueue changes helped me find this bug that's been lingering since the changes to the work processing in mac80211 -- the work timer is never deleted properly. Do that to avoid having it fire after all data structures have been freed. It can't be re-armed because all it will do, if running, is schedule the work, but that gets flushed later and won't have anything to do since all work items are gone by now (by way of interface removal). Cc: stable@kernel.org [2.6.34+] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 798a91b100cc..ded5c3843e06 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -732,6 +732,12 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rtnl_unlock(); + /* + * Now all work items will be gone, but the + * timer might still be armed, so delete it + */ + del_timer_sync(&local->work_timer); + cancel_work_sync(&local->reconfig_filter); ieee80211_clear_tx_pending(local); -- cgit v1.2.3-59-g8ed1b From 9ef808048564928a83f3a52c65c5725688cf5cbe Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 27 Aug 2010 09:44:12 -0400 Subject: MAINTAINERS: change broken url for prism54 Reported-by: Joe Perches Signed-off-by: John W. Linville --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 44620aebb369..8e85429d3bb0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4549,7 +4549,7 @@ F: include/linux/preempt.h PRISM54 WIRELESS DRIVER M: "Luis R. Rodriguez" L: linux-wireless@vger.kernel.org -W: http://prism54.org +W: http://wireless.kernel.org/en/users/Drivers/p54 S: Obsolete F: drivers/net/wireless/prism54/ -- cgit v1.2.3-59-g8ed1b From 42da2f948d949efd0111309f5827bf0298bcc9a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Aug 2010 12:24:54 +0200 Subject: wireless extensions: fix kernel heap content leak Wireless extensions have an unfortunate, undocumented requirement which requires drivers to always fill iwp->length when returning a successful status. When a driver doesn't do this, it leads to a kernel heap content leak when userspace offers a larger buffer than would have been necessary. Arguably, this is a driver bug, as it should, if it returns 0, fill iwp->length, even if it separately indicated that the buffer contents was not valid. However, we can also at least avoid the memory content leak if the driver doesn't do this by setting the iwp length to max_tokens, which then reflects how big the buffer is that the driver may fill, regardless of how big the userspace buffer is. To illustrate the point, this patch also fixes a corresponding cfg80211 bug (since this requirement isn't documented nor was ever pointed out by anyone during code review, I don't trust all drivers nor all cfg80211 handlers to implement it correctly). Cc: stable@kernel.org [all the way back] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/wext-compat.c | 3 +++ net/wireless/wext-core.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index bb5e0a5ecfa1..7e5c3a45f811 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -1420,6 +1420,9 @@ int cfg80211_wext_giwessid(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; + data->flags = 0; + data->length = 0; + switch (wdev->iftype) { case NL80211_IFTYPE_ADHOC: return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 0ef17bc42bac..8f5116f5af19 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -782,6 +782,22 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, } } + if (IW_IS_GET(cmd) && !(descr->flags & IW_DESCR_FLAG_NOMAX)) { + /* + * If this is a GET, but not NOMAX, it means that the extra + * data is not bounded by userspace, but by max_tokens. Thus + * set the length to max_tokens. This matches the extra data + * allocation. + * The driver should fill it with the number of tokens it + * provided, and it may check iwp->length rather than having + * knowledge of max_tokens. If the driver doesn't change the + * iwp->length, this ioctl just copies back max_token tokens + * filled with zeroes. Hopefully the driver isn't claiming + * them to be valid data. + */ + iwp->length = descr->max_tokens; + } + err = handler(dev, info, (union iwreq_data *) iwp, extra); iwp->length += essid_compat; -- cgit v1.2.3-59-g8ed1b From 4562c986f0d694124de20815adf7e1aad8a94668 Mon Sep 17 00:00:00 2001 From: Matthew McClintock Date: Fri, 27 Aug 2010 11:58:21 +0000 Subject: powerpc/kexec: Adds correct calling convention for kexec purgatory Call kexec purgatory code correctly. We were getting lucky before. If you examine the powerpc 32bit kexec "purgatory" code you will see it expects the following: >From kexec-tools: purgatory/arch/ppc/v2wrap_32.S -> calling convention: -> r3 = physical number of this cpu (all cpus) -> r4 = address of this chunk (master only) As such, we need to set r3 to the current core, r4 happens to be unused by purgatory at the moment but we go ahead and set it here as well Signed-off-by: Matthew McClintock Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/misc_32.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 6bbd7a604d24..a7a570dcdd57 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -810,6 +810,9 @@ relocate_new_kernel: isync sync + mfspr r3, SPRN_PIR /* current core we are running on */ + mr r4, r5 /* load physical address of chunk called */ + /* jump to the entry point, usually the setup routine */ mtlr r5 blrl -- cgit v1.2.3-59-g8ed1b From b0d278b7d3ae9115939ddcea93f516308cc367e2 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 10 Aug 2010 20:38:23 +0000 Subject: powerpc/perf_event: Reduce latency of calling perf_event_do_pending Commit 0fe1ac48 ("powerpc/perf_event: Fix oops due to perf_event_do_pending call") moved the call to perf_event_do_pending in timer_interrupt() down so that it was after the irq_enter() call. Unfortunately this moved it after the code that checks whether it is time for the next decrementer clock event. The result is that the call to perf_event_do_pending() won't happen until the next decrementer clock event is due. This was pointed out by Milton Miller. This fixes it by moving the check for whether it's time for the next decrementer clock event down to the point where we're about to call the event handler, after we've called perf_event_do_pending. This has the side effect that on old pre-Core99 Powermacs where we use the ppc_n_lost_interrupts mechanism to replay interrupts, a replayed interrupt will incur a little more latency since it will now do the code from the irq_enter down to the irq_exit, that it used to skip. However, these machines are now old and rare enough that this doesn't matter. To make it clear that ppc_n_lost_interrupts is only used on Powermacs, and to speed up the code slightly on non-Powermac ppc32 machines, the code that tests ppc_n_lost_interrupts is now conditional on CONFIG_PMAC as well as CONFIG_PPC32. Signed-off-by: Paul Mackerras Cc: stable@kernel.org Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/time.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index ce53dfa7130d..8533b3b83f5d 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -577,20 +577,11 @@ void timer_interrupt(struct pt_regs * regs) * some CPUs will continuue to take decrementer exceptions */ set_dec(DECREMENTER_MAX); -#ifdef CONFIG_PPC32 +#if defined(CONFIG_PPC32) && defined(CONFIG_PMAC) if (atomic_read(&ppc_n_lost_interrupts) != 0) do_IRQ(regs); #endif - now = get_tb_or_rtc(); - if (now < decrementer->next_tb) { - /* not time for this event yet */ - now = decrementer->next_tb - now; - if (now <= DECREMENTER_MAX) - set_dec((int)now); - trace_timer_interrupt_exit(regs); - return; - } old_regs = set_irq_regs(regs); irq_enter(); @@ -606,8 +597,16 @@ void timer_interrupt(struct pt_regs * regs) get_lppaca()->int_dword.fields.decr_int = 0; #endif - if (evt->event_handler) - evt->event_handler(evt); + now = get_tb_or_rtc(); + if (now >= decrementer->next_tb) { + decrementer->next_tb = ~(u64)0; + if (evt->event_handler) + evt->event_handler(evt); + } else { + now = decrementer->next_tb - now; + if (now <= DECREMENTER_MAX) + set_dec((int)now); + } #ifdef CONFIG_PPC_ISERIES if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) -- cgit v1.2.3-59-g8ed1b From 54a834043314c257210db2a9d59f8cc605571639 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 25 Aug 2010 21:04:25 +0000 Subject: powerpc: Don't use kernel stack with translation off In f761622e59433130bc33ad086ce219feee9eb961 we changed early_setup_secondary so it's called using the proper kernel stack rather than the emergency one. Unfortunately, this stack pointer can't be used when translation is off on PHYP as this stack pointer might be outside the RMO. This results in the following on all non zero cpus: cpu 0x1: Vector: 300 (Data Access) at [c00000001639fd10] pc: 000000000001c50c lr: 000000000000821c sp: c00000001639ff90 msr: 8000000000001000 dar: c00000001639ffa0 dsisr: 42000000 current = 0xc000000016393540 paca = 0xc000000006e00200 pid = 0, comm = swapper The original patch was only tested on bare metal system, so it never caught this problem. This changes __secondary_start so that we calculate the new stack pointer but only start using it after we've called early_setup_secondary. With this patch, the above problem goes away. Signed-off-by: Michael Neuling Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/head_64.S | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 4d6681dce816..c571cd3c1453 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -575,13 +575,19 @@ __secondary_start: /* Initialize the kernel stack. Just a repeat for iSeries. */ LOAD_REG_ADDR(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ - ldx r1,r3,r28 - addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD - std r1,PACAKSAVE(r13) + ldx r14,r3,r28 + addi r14,r14,THREAD_SIZE-STACK_FRAME_OVERHEAD + std r14,PACAKSAVE(r13) /* Do early setup for that CPU (stab, slb, hash table pointer) */ bl .early_setup_secondary + /* + * setup the new stack pointer, but *don't* use this until + * translation is on. + */ + mr r1, r14 + /* Clear backchain so we get nice backtraces */ li r7,0 mtlr r7 -- cgit v1.2.3-59-g8ed1b From 628e300cccaa628d8fb92aa28cb7530a3d5f2257 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 30 Aug 2010 18:35:24 -0700 Subject: irda: Correctly clean up self->ias_obj on irda_bind() failure. If irda_open_tsap() fails, the irda_bind() code tries to destroy the ->ias_obj object by hand, but does so wrongly. In particular, it fails to a) release the hashbin attached to the object and b) reset the self->ias_obj pointer to NULL. Fix both problems by using irias_delete_object() and explicitly setting self->ias_obj to NULL, just as irda_release() does. Reported-by: Tavis Ormandy Signed-off-by: David S. Miller --- net/irda/af_irda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 79986a674f6e..fd55b5135de5 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -824,8 +824,8 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); if (err < 0) { - kfree(self->ias_obj->name); - kfree(self->ias_obj); + irias_delete_object(self->ias_obj); + self->ias_obj = NULL; goto out; } -- cgit v1.2.3-59-g8ed1b From b137b9942a07843c64a934cfdb7d43155e507e13 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 23 Aug 2010 20:25:32 +0000 Subject: ACPI: Don't report current_now if battery reports in mWh ACPI batteries can report in units of either current or energy. Right now we expose the current_now file even if the battery is reporting energy units, resulting in a file that should contain mA instead containing mW. Don't expose this value unless the battery is reporting current. Signed-off-by: Matthew Garrett Cc: Arjan van de Ven Acked-by: Rafael J. Wysocki Acked-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/battery.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index dc58402b0a17..98417201e9ce 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -273,7 +273,6 @@ static enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_POWER_NOW, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, POWER_SUPPLY_PROP_ENERGY_FULL, -- cgit v1.2.3-59-g8ed1b From 10f0412f57f2a76a90eff4376f59cbb0a39e4e18 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 30 Aug 2010 10:56:18 +0200 Subject: oprofile, x86: fix init_sysfs error handling On failure init_sysfs() might not properly free resources. The error code of the function is not checked. And, when reinitializing the exit function might be called twice. This patch fixes all this. Cc: stable@kernel.org Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index f6b48f6c5951..73a41d3c6c09 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -568,8 +568,13 @@ static int __init init_sysfs(void) int error; error = sysdev_class_register(&oprofile_sysclass); - if (!error) - error = sysdev_register(&device_oprofile); + if (error) + return error; + + error = sysdev_register(&device_oprofile); + if (error) + sysdev_class_unregister(&oprofile_sysclass); + return error; } @@ -695,6 +700,8 @@ int __init op_nmi_init(struct oprofile_operations *ops) char *cpu_type = NULL; int ret = 0; + using_nmi = 0; + if (!cpu_has_apic) return -ENODEV; @@ -774,7 +781,10 @@ int __init op_nmi_init(struct oprofile_operations *ops) mux_init(ops); - init_sysfs(); + ret = init_sysfs(); + if (ret) + return ret; + using_nmi = 1; printk(KERN_INFO "oprofile: using NMI interrupt.\n"); return 0; -- cgit v1.2.3-59-g8ed1b From 477a3c33d1efa0342a74bd02da2e049191993e2c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 31 Aug 2010 10:54:35 +0200 Subject: workqueue: fix GCWQ_DISASSOCIATED initialization init_workqueues() incorrectly marks workqueues for all possible CPUs associated. Combined with mayday_mask initialization bug, this can make rescuers keep trying to bind to an offline gcwq indefinitely. Fix init_workqueues() such that only online CPUs have their gcwqs have GCWQ_DISASSOCIATED cleared. Signed-off-by: Tejun Heo Reported-by: CAI Qian --- kernel/workqueue.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index a2dccfca03ba..c8183b235d16 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3558,8 +3558,7 @@ static int __init init_workqueues(void) spin_lock_init(&gcwq->lock); INIT_LIST_HEAD(&gcwq->worklist); gcwq->cpu = cpu; - if (cpu == WORK_CPU_UNBOUND) - gcwq->flags |= GCWQ_DISASSOCIATED; + gcwq->flags |= GCWQ_DISASSOCIATED; INIT_LIST_HEAD(&gcwq->idle_list); for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++) @@ -3583,6 +3582,8 @@ static int __init init_workqueues(void) struct global_cwq *gcwq = get_gcwq(cpu); struct worker *worker; + if (cpu != WORK_CPU_UNBOUND) + gcwq->flags &= ~GCWQ_DISASSOCIATED; worker = create_worker(gcwq, true); BUG_ON(!worker); spin_lock_irq(&gcwq->lock); -- cgit v1.2.3-59-g8ed1b From 9c37547ab62f88aac3e1e3c2065b611f811de9b5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 31 Aug 2010 11:18:34 +0200 Subject: workqueue: use zalloc_cpumask_var() for gcwq->mayday_mask alloc_mayday_mask() was using alloc_cpumask_var() making gcwq->mayday_mask contain garbage after initialization on CONFIG_CPUMASK_OFFSTACK=y configurations. This combined with the previously fixed GCWQ_DISASSOCIATED initialization bug could make rescuers fall into infinite loop trying to bind to an offline cpu. Signed-off-by: Tejun Heo Reported-by: CAI Qian --- kernel/workqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c8183b235d16..785542976b00 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -196,7 +196,7 @@ typedef cpumask_var_t mayday_mask_t; cpumask_test_and_set_cpu((cpu), (mask)) #define mayday_clear_cpu(cpu, mask) cpumask_clear_cpu((cpu), (mask)) #define for_each_mayday_cpu(cpu, mask) for_each_cpu((cpu), (mask)) -#define alloc_mayday_mask(maskp, gfp) alloc_cpumask_var((maskp), (gfp)) +#define alloc_mayday_mask(maskp, gfp) zalloc_cpumask_var((maskp), (gfp)) #define free_mayday_mask(mask) free_cpumask_var((mask)) #else typedef unsigned long mayday_mask_t; -- cgit v1.2.3-59-g8ed1b From 6d4f2fb0860c36e7ef16cc41126242a8b6542771 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 31 Aug 2010 04:15:22 +0200 Subject: powerpc/85xx: Fix compilation of mpc85xx_mds.c Commit 99d8238f berobbed the for_each loop of its iterator! Let's be nice and give it back, so it compiles for us. CC: Anton Vorontsov Signed-off-by: Alexander Graf Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/mpc85xx_mds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index da64be19d099..aa34cac4eb5c 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -357,6 +357,7 @@ static void __init mpc85xx_mds_setup_arch(void) { #ifdef CONFIG_PCI struct pci_controller *hose; + struct device_node *np; #endif dma_addr_t max = 0xffffffff; -- cgit v1.2.3-59-g8ed1b From dc1c41f450a5f201f1d8c19aef32319f3b84c273 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 31 Aug 2010 11:39:25 -0500 Subject: powerpc/85xx: Fix compile issue with p1022_ds due to lmb rename to memblock arch/powerpc/platforms/85xx/p1022_ds.c:22:23: error: linux/lmb.h: No such file or directory arch/powerpc/platforms/85xx/p1022_ds.c: In function 'p1022_ds_setup_arch': arch/powerpc/platforms/85xx/p1022_ds.c:100: error: implicit declaration of function 'memblock_end_of_DRAM' arch/powerpc/platforms/85xx/p1022_ds.c: At top level: arch/powerpc/platforms/85xx/p1022_ds.c:147: error: 'udbg_progress' undeclared here (not in a function) make[2]: *** [arch/powerpc/platforms/85xx/p1022_ds.o] Error 1 Signed-off-by: Kumar Gala --- arch/powerpc/platforms/85xx/p1022_ds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index e1467c937450..34e00902ce86 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -97,7 +97,7 @@ static void __init p1022_ds_setup_arch(void) #endif #ifdef CONFIG_SWIOTLB - if (lmb_end_of_DRAM() > max) { + if (memblock_end_of_DRAM() > max) { ppc_swiotlb_enable = 1; set_pci_dma_ops(&swiotlb_dma_ops); ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; -- cgit v1.2.3-59-g8ed1b From b963ea89f00f13c648af4082e5efb2172d369727 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 30 Aug 2010 19:08:01 -0700 Subject: netlink: Make NETLINK_USERSOCK work again. Once we started enforcing the a nl_table[] entry exist for a protocol, NETLINK_USERSOCK stopped working. Add a dummy table entry so that it works again. Reported-by: Thomas Voegtle Tested-by: Thomas Voegtle Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 980fe4ad0016..cd96ed3ccee4 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2102,6 +2102,26 @@ static void __net_exit netlink_net_exit(struct net *net) #endif } +static void __init netlink_add_usersock_entry(void) +{ + unsigned long *listeners; + int groups = 32; + + listeners = kzalloc(NLGRPSZ(groups) + sizeof(struct listeners_rcu_head), + GFP_KERNEL); + if (!listeners) + panic("netlink_add_usersock_entry: Cannot allocate listneres\n"); + + netlink_table_grab(); + + nl_table[NETLINK_USERSOCK].groups = groups; + nl_table[NETLINK_USERSOCK].listeners = listeners; + nl_table[NETLINK_USERSOCK].module = THIS_MODULE; + nl_table[NETLINK_USERSOCK].registered = 1; + + netlink_table_ungrab(); +} + static struct pernet_operations __net_initdata netlink_net_ops = { .init = netlink_net_init, .exit = netlink_net_exit, @@ -2150,6 +2170,8 @@ static int __init netlink_proto_init(void) hash->rehash_time = jiffies; } + netlink_add_usersock_entry(); + sock_register(&netlink_family_ops); register_pernet_subsys(&netlink_net_ops); /* The netlink device handler may be needed early. */ -- cgit v1.2.3-59-g8ed1b From c3d34d5d9654ec9c2510f9341bfb1030b8f029d1 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 30 Aug 2010 17:36:40 -0400 Subject: wireless: register wiphy rfkill w/o holding cfg80211_mutex Otherwise lockdep complains... https://bugzilla.kernel.org/show_bug.cgi?id=17311 [ INFO: possible circular locking dependency detected ] 2.6.36-rc2-git4 #12 ------------------------------------------------------- kworker/0:3/3630 is trying to acquire lock: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x12/0x14 but task is already holding lock: (rfkill_global_mutex){+.+.+.}, at: [] rfkill_switch_all+0x24/0x49 [rfkill] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (rfkill_global_mutex){+.+.+.}: [] lock_acquire+0x120/0x15b [] __mutex_lock_common+0x54/0x52e [] mutex_lock_nested+0x34/0x39 [] rfkill_register+0x2b/0x29c [rfkill] [] wiphy_register+0x1ae/0x270 [cfg80211] [] ieee80211_register_hw+0x1b4/0x3cf [mac80211] [] iwl_ucode_callback+0x9e9/0xae3 [iwlagn] [] request_firmware_work_func+0x54/0x6f [] kthread+0x8c/0x94 [] kernel_thread_helper+0x4/0x10 -> #1 (cfg80211_mutex){+.+.+.}: [] lock_acquire+0x120/0x15b [] __mutex_lock_common+0x54/0x52e [] mutex_lock_nested+0x34/0x39 [] cfg80211_get_dev_from_ifindex+0x1b/0x7c [cfg80211] [] cfg80211_wext_giwscan+0x58/0x990 [cfg80211] [] ioctl_standard_iw_point+0x1a8/0x272 [] ioctl_standard_call+0x91/0xa7 [] T.723+0xbd/0x12c [] wext_handle_ioctl+0x31/0x6d [] dev_ioctl+0x63d/0x67a [] sock_ioctl+0x48/0x21d [] do_vfs_ioctl+0x4ba/0x509 [] sys_ioctl+0x51/0x74 [] system_call_fastpath+0x16/0x1b -> #0 (rtnl_mutex){+.+.+.}: [] __lock_acquire+0xa93/0xd9a [] lock_acquire+0x120/0x15b [] __mutex_lock_common+0x54/0x52e [] mutex_lock_nested+0x34/0x39 [] rtnl_lock+0x12/0x14 [] cfg80211_rfkill_set_block+0x1a/0x7b [cfg80211] [] rfkill_set_block+0x80/0xd5 [rfkill] [] __rfkill_switch_all+0x3f/0x6f [rfkill] [] rfkill_switch_all+0x38/0x49 [rfkill] [] rfkill_op_handler+0x105/0x136 [rfkill] [] process_one_work+0x248/0x403 [] worker_thread+0x139/0x214 [] kthread+0x8c/0x94 [] kernel_thread_helper+0x4/0x10 Signed-off-by: John W. Linville Acked-by: Johannes Berg --- net/wireless/core.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 541e2fff5e9c..d6d046b9f6f2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -475,12 +475,10 @@ int wiphy_register(struct wiphy *wiphy) mutex_lock(&cfg80211_mutex); res = device_add(&rdev->wiphy.dev); - if (res) - goto out_unlock; - - res = rfkill_register(rdev->rfkill); - if (res) - goto out_rm_dev; + if (res) { + mutex_unlock(&cfg80211_mutex); + return res; + } /* set up regulatory info */ wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); @@ -509,13 +507,18 @@ int wiphy_register(struct wiphy *wiphy) cfg80211_debugfs_rdev_add(rdev); mutex_unlock(&cfg80211_mutex); + /* + * due to a locking dependency this has to be outside of the + * cfg80211_mutex lock + */ + res = rfkill_register(rdev->rfkill); + if (res) + goto out_rm_dev; + return 0; out_rm_dev: device_del(&rdev->wiphy.dev); - -out_unlock: - mutex_unlock(&cfg80211_mutex); return res; } EXPORT_SYMBOL(wiphy_register); -- cgit v1.2.3-59-g8ed1b From 803288e61e346ba367373bc7d5eeb6e11c81a33c Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 30 Aug 2010 19:26:32 -0400 Subject: ath9k_hw: Fix EEPROM uncompress block reading on AR9003 The EEPROM is compressed on AR9003, upon decompression the wrong upper limit was being used for the block which prevented the 5 GHz CTL indexes from being used, which are stored towards the end of the EEPROM block. This fix allows the actual intended regulatory limits to be used on AR9003 hardware. Cc: stable@kernel.org [2.6.36+] Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index b883b174385b..057fb69ddf7f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -797,7 +797,7 @@ static bool ar9300_uncompress_block(struct ath_hw *ah, length = block[it+1]; length &= 0xff; - if (length > 0 && spot >= 0 && spot+length < mdataSize) { + if (length > 0 && spot >= 0 && spot+length <= mdataSize) { ath_print(common, ATH_DBG_EEPROM, "Restore at %d: spot=%d " "offset=%d length=%d\n", -- cgit v1.2.3-59-g8ed1b From 904879748d7439a6dabdc6be9aad983e216b027d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 30 Aug 2010 19:26:33 -0400 Subject: ath9k_hw: fix parsing of HT40 5 GHz CTLs The 5 GHz CTL indexes were not being read for all hardware devices due to the masking out through the CTL_MODE_M mask being one bit too short. Without this the calibrated regulatory maximum values were not being picked up when devices operate on 5 GHz in HT40 mode. The final output power used for Atheros devices is the minimum between the calibrated CTL values and what CRDA provides. Cc: stable@kernel.org [2.6.27+] Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/eeprom.h | 2 +- drivers/net/wireless/ath/regd.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 7f48df1e2903..0b09db0f8e7d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -62,7 +62,7 @@ #define SD_NO_CTL 0xE0 #define NO_CTL 0xff -#define CTL_MODE_M 7 +#define CTL_MODE_M 0xf #define CTL_11A 0 #define CTL_11B 1 #define CTL_11G 2 diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index a1c39526161a..345dd9721b41 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -31,7 +31,6 @@ enum ctl_group { #define NO_CTL 0xff #define SD_NO_CTL 0xE0 #define NO_CTL 0xff -#define CTL_MODE_M 7 #define CTL_11A 0 #define CTL_11B 1 #define CTL_11G 2 -- cgit v1.2.3-59-g8ed1b From 3aaba20f26f58843e8f20611e5c0b1c06954310f Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Mon, 23 Aug 2010 16:50:12 +0800 Subject: tracing: Fix a race in function profile While we are reading trace_stat/functionX and someone just disabled function_profile at that time, we can trigger this: divide error: 0000 [#1] PREEMPT SMP ... EIP is at function_stat_show+0x90/0x230 ... This fix just takes the ftrace_profile_lock and checks if rec->counter is 0. If it's 0, we know the profile buffer has been reset. Signed-off-by: Li Zefan Cc: stable@kernel.org LKML-Reference: <4C723644.4040708@cn.fujitsu.com> Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0d88ce9b9fb8..7cb1f45a1de1 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -381,12 +381,19 @@ static int function_stat_show(struct seq_file *m, void *v) { struct ftrace_profile *rec = v; char str[KSYM_SYMBOL_LEN]; + int ret = 0; #ifdef CONFIG_FUNCTION_GRAPH_TRACER - static DEFINE_MUTEX(mutex); static struct trace_seq s; unsigned long long avg; unsigned long long stddev; #endif + mutex_lock(&ftrace_profile_lock); + + /* we raced with function_profile_reset() */ + if (unlikely(rec->counter == 0)) { + ret = -EBUSY; + goto out; + } kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); seq_printf(m, " %-30.30s %10lu", str, rec->counter); @@ -408,7 +415,6 @@ static int function_stat_show(struct seq_file *m, void *v) do_div(stddev, (rec->counter - 1) * 1000); } - mutex_lock(&mutex); trace_seq_init(&s); trace_print_graph_duration(rec->time, &s); trace_seq_puts(&s, " "); @@ -416,11 +422,12 @@ static int function_stat_show(struct seq_file *m, void *v) trace_seq_puts(&s, " "); trace_print_graph_duration(stddev, &s); trace_print_seq(m, &s); - mutex_unlock(&mutex); #endif seq_putc(m, '\n'); +out: + mutex_unlock(&ftrace_profile_lock); - return 0; + return ret; } static void ftrace_profile_reset(struct ftrace_profile_stat *stat) -- cgit v1.2.3-59-g8ed1b From ff33f1821259d00d3fd85d86f59783e2ca3c9ee1 Mon Sep 17 00:00:00 2001 From: Li Yang Date: Fri, 18 Jun 2010 14:24:20 +0800 Subject: fsl_rio: fix compile errors Fixes the following compile problem on E500 platforms: arch/powerpc/sysdev/fsl_rio.c: In function 'fsl_rio_mcheck_exception': arch/powerpc/sysdev/fsl_rio.c:248: error: 'MCSR_MASK' undeclared (first use in this function) Also fixes the compile problem on non-E500 platforms. Signed-off-by: Li Yang Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_rio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index 6425abe5b7db..3017532319c8 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -240,12 +240,13 @@ struct rio_priv { static void __iomem *rio_regs_win; +#ifdef CONFIG_E500 static int (*saved_mcheck_exception)(struct pt_regs *regs); static int fsl_rio_mcheck_exception(struct pt_regs *regs) { const struct exception_table_entry *entry = NULL; - unsigned long reason = (mfspr(SPRN_MCSR) & MCSR_MASK); + unsigned long reason = mfspr(SPRN_MCSR); if (reason & MCSR_BUS_RBERR) { reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); @@ -269,6 +270,7 @@ static int fsl_rio_mcheck_exception(struct pt_regs *regs) else return cur_cpu_spec->machine_check(regs); } +#endif /** * fsl_rio_doorbell_send - Send a MPC85xx doorbell message @@ -1517,8 +1519,10 @@ int fsl_rio_setup(struct platform_device *dev) fsl_rio_doorbell_init(port); fsl_rio_port_write_init(port); +#ifdef CONFIG_E500 saved_mcheck_exception = ppc_md.machine_check_exception; ppc_md.machine_check_exception = fsl_rio_mcheck_exception; +#endif /* Ensure that RFXE is set */ mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000)); -- cgit v1.2.3-59-g8ed1b From fa9fc821f8892590211a9aa9e855eb83152b9870 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 29 Aug 2010 21:47:18 +0200 Subject: arch/powerpc/platforms/83xx/mpc837x_mds.c: Add missing iounmap The function of_iomap returns the result of calling ioremap, so iounmap should be called on the result in the error handling code, as done in the normal exit of the function. The sematic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ local idexpression x; expression E,E1; identifier l; statement S; @@ *x = of_iomap(...); ... when != iounmap(x) when != if (...) { ... iounmap(x); ... } when != E = x when any ( if (x == NULL) S | if (...) { ... when != iounmap(x) when != if (...) { ... iounmap(x); ... } ( return <+...x...+>; | * return ...; ) } ) ... when != x = E1 when any iounmap(x); // Signed-off-by: Julia Lawall Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/mpc837x_mds.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/83xx/mpc837x_mds.c b/arch/powerpc/platforms/83xx/mpc837x_mds.c index f9751c8905be..83068322abd1 100644 --- a/arch/powerpc/platforms/83xx/mpc837x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc837x_mds.c @@ -48,8 +48,10 @@ static int mpc837xmds_usb_cfg(void) return -1; np = of_find_node_by_name(NULL, "usb"); - if (!np) - return -ENODEV; + if (!np) { + ret = -ENODEV; + goto out; + } phy_type = of_get_property(np, "phy_type", NULL); if (phy_type && !strcmp(phy_type, "ulpi")) { clrbits8(bcsr_regs + 12, BCSR12_USB_SER_PIN); @@ -65,8 +67,9 @@ static int mpc837xmds_usb_cfg(void) } of_node_put(np); +out: iounmap(bcsr_regs); - return 0; + return ret; } /* ************************************************************************ -- cgit v1.2.3-59-g8ed1b From 5aac4d73dc234fe7be91679b547af2436d7f8d1e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 29 Aug 2010 11:52:44 +0200 Subject: arch/powerpc/sysdev/qe_lib/qe.c: Add of_node_put to avoid memory leak Add a call to of_node_put in the error handling code following a call to of_find_compatible_node. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ local idexpression x; expression E,E1; statement S; @@ *x = (of_find_node_by_path |of_find_node_by_name |of_find_node_by_phandle |of_get_parent |of_get_next_parent |of_get_next_child |of_find_compatible_node |of_match_node )(...); ... if (x == NULL) S <... when != x = E *if (...) { ... when != of_node_put(x) when != if (...) { ... of_node_put(x); ... } ( return <+...x...+>; | * return ...; ) } ...> of_node_put(x); // Signed-off-by: Julia Lawall Acked-by: Timur Tabi Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/qe_lib/qe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 3da8014931c9..90020de4dcf2 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -640,6 +640,7 @@ unsigned int qe_get_num_of_snums(void) if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) { /* No QE ever has fewer than 28 SNUMs */ pr_err("QE: number of snum is invalid\n"); + of_node_put(qe); return -EINVAL; } } -- cgit v1.2.3-59-g8ed1b From a28dec2f26013aad89446b1f708f948617bc28a2 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 8 Aug 2010 18:03:33 +0400 Subject: powerpc/85xx: Add P1021 PCI IDs and quirks This is needed for proper PCI-E support on P1021 SoCs. Signed-off-by: Anton Vorontsov Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_pci.c | 2 ++ include/linux/pci_ids.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 209384b6e039..4ae933225251 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -399,6 +399,8 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013E, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020E, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1021E, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1021, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022E, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010E, quirk_fsl_pcie_header); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f6a3b2d36cad..10d33309e9a6 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2300,6 +2300,8 @@ #define PCI_DEVICE_ID_P2010 0x0079 #define PCI_DEVICE_ID_P1020E 0x0100 #define PCI_DEVICE_ID_P1020 0x0101 +#define PCI_DEVICE_ID_P1021E 0x0102 +#define PCI_DEVICE_ID_P1021 0x0103 #define PCI_DEVICE_ID_P1011E 0x0108 #define PCI_DEVICE_ID_P1011 0x0109 #define PCI_DEVICE_ID_P1022E 0x0110 -- cgit v1.2.3-59-g8ed1b From 17134d96735115644cc2f0e2b1bab51ca6e3ab95 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 31 Aug 2010 15:25:55 -0700 Subject: PCI: bus speed strings should be const Signed-off-by: Stephen Hemminger Signed-off-by: Jesse Barnes --- drivers/pci/slot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 659eaa0fc48f..968cfea04f74 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -49,7 +49,7 @@ static ssize_t address_read_file(struct pci_slot *slot, char *buf) } /* these strings match up with the values in pci_bus_speed */ -static char *pci_bus_speed_strings[] = { +static const char *pci_bus_speed_strings[] = { "33 MHz PCI", /* 0x00 */ "66 MHz PCI", /* 0x01 */ "66 MHz PCI-X", /* 0x02 */ -- cgit v1.2.3-59-g8ed1b From 950eaaca681c44aab87a46225c9e44f902c080aa Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 31 Aug 2010 17:00:18 -0700 Subject: pid: make setpgid() system call use RCU read-side critical section [ 23.584719] [ 23.584720] =================================================== [ 23.585059] [ INFO: suspicious rcu_dereference_check() usage. ] [ 23.585176] --------------------------------------------------- [ 23.585176] kernel/pid.c:419 invoked rcu_dereference_check() without protection! [ 23.585176] [ 23.585176] other info that might help us debug this: [ 23.585176] [ 23.585176] [ 23.585176] rcu_scheduler_active = 1, debug_locks = 1 [ 23.585176] 1 lock held by rc.sysinit/728: [ 23.585176] #0: (tasklist_lock){.+.+..}, at: [] sys_setpgid+0x5f/0x193 [ 23.585176] [ 23.585176] stack backtrace: [ 23.585176] Pid: 728, comm: rc.sysinit Not tainted 2.6.36-rc2 #2 [ 23.585176] Call Trace: [ 23.585176] [] lockdep_rcu_dereference+0x99/0xa2 [ 23.585176] [] find_task_by_pid_ns+0x50/0x6a [ 23.585176] [] find_task_by_vpid+0x1d/0x1f [ 23.585176] [] sys_setpgid+0x67/0x193 [ 23.585176] [] system_call_fastpath+0x16/0x1b [ 24.959669] type=1400 audit(1282938522.956:4): avc: denied { module_request } for pid=766 comm="hwclock" kmod="char-major-10-135" scontext=system_u:system_r:hwclock_t:s0 tcontext=system_u:system_r:kernel_t:s0 tclas It turns out that the setpgid() system call fails to enter an RCU read-side critical section before doing a PID-to-task_struct translation. This commit therefore does rcu_read_lock() before the translation, and also does rcu_read_unlock() after the last use of the returned pointer. Reported-by: Andrew Morton Signed-off-by: Paul E. McKenney Acked-by: David Howells --- kernel/sys.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/sys.c b/kernel/sys.c index e9ad44489828..7f5a0cd296a9 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -931,6 +931,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) pgid = pid; if (pgid < 0) return -EINVAL; + rcu_read_lock(); /* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM @@ -984,6 +985,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) out: /* All paths lead to here, thus we are safe. -DaveM */ write_unlock_irq(&tasklist_lock); + rcu_read_unlock(); return err; } -- cgit v1.2.3-59-g8ed1b From 57157becdd1d23e6c2b8661ffe6c78d7d605d121 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Tue, 31 Aug 2010 17:27:02 -0700 Subject: Input: bcm5974 - adjust major/minor to scale By visual inspection, the reported touch_major and touch_minor axes are a factor of two too small. Presumably the device actually reports the semi-major and semi-minor axes. Corrected with this patch. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/bcm5974.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index ea67c49146a3..b95231763911 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -337,10 +337,14 @@ static void report_finger_data(struct input_dev *input, const struct bcm5974_config *cfg, const struct tp_finger *f) { - input_report_abs(input, ABS_MT_TOUCH_MAJOR, raw2int(f->force_major)); - input_report_abs(input, ABS_MT_TOUCH_MINOR, raw2int(f->force_minor)); - input_report_abs(input, ABS_MT_WIDTH_MAJOR, raw2int(f->size_major)); - input_report_abs(input, ABS_MT_WIDTH_MINOR, raw2int(f->size_minor)); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, + raw2int(f->force_major) << 1); + input_report_abs(input, ABS_MT_TOUCH_MINOR, + raw2int(f->force_minor) << 1); + input_report_abs(input, ABS_MT_WIDTH_MAJOR, + raw2int(f->size_major) << 1); + input_report_abs(input, ABS_MT_WIDTH_MINOR, + raw2int(f->size_minor) << 1); input_report_abs(input, ABS_MT_ORIENTATION, MAX_FINGER_ORIENTATION - raw2int(f->orientation)); input_report_abs(input, ABS_MT_POSITION_X, raw2int(f->abs_x)); -- cgit v1.2.3-59-g8ed1b From af045b86662f17bf130239a65995c61a34f00a6b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 31 Aug 2010 17:27:02 -0700 Subject: Input: i8042 - fix device removal on unload We need to call platform_device_unregister(i8042_platform_device) before calling platform_driver_unregister() because i8042_remove() resets i8042_platform_device to NULL. This leaves the platform device instance behind and prevents driver reload. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=16613 Reported-by: Seryodkin Victor Cc: stable@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 46e4ba0b9246..f58513160480 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1485,8 +1485,8 @@ static int __init i8042_init(void) static void __exit i8042_exit(void) { - platform_driver_unregister(&i8042_driver); platform_device_unregister(i8042_platform_device); + platform_driver_unregister(&i8042_driver); i8042_platform_exit(); panic_blink = NULL; -- cgit v1.2.3-59-g8ed1b From 6445671b00b3c4bcb26c8e0fc74abe780a67b901 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 31 Aug 2010 22:26:15 -0400 Subject: alpha: remove homegrown L1_CACHE_ALIGN macro Let's use the standard L1_CACHE_ALIGN macro instead. Signed-off-by: FUJITA Tomonori Signed-off-by: Matt Turner --- arch/alpha/include/asm/cache.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/alpha/include/asm/cache.h b/arch/alpha/include/asm/cache.h index f199e69a5d0b..ad368a93a46a 100644 --- a/arch/alpha/include/asm/cache.h +++ b/arch/alpha/include/asm/cache.h @@ -17,7 +17,6 @@ # define L1_CACHE_SHIFT 5 #endif -#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) #define SMP_CACHE_BYTES L1_CACHE_BYTES #endif -- cgit v1.2.3-59-g8ed1b From 59b25ed91400ace98d6cf0d59b1cb6928ad5cd37 Mon Sep 17 00:00:00 2001 From: "Morten H. Larsen" Date: Tue, 31 Aug 2010 22:29:13 -0400 Subject: Fix call to replaced SuperIO functions This patch fixes the failure to compile Alpha Generic because of previously overlooked calls to ns87312_enable_ide(). The function has been replaced by newer SuperIO code. Tested-by: Michael Cree Signed-off-by: Morten H. Larsen Signed-off-by: Matt Turner --- arch/alpha/kernel/proto.h | 3 --- arch/alpha/kernel/sys_cabriolet.c | 19 ++++++++++++++++--- arch/alpha/kernel/sys_takara.c | 11 +++++++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index 3d2627ec9860..d3e52d3fd592 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -156,9 +156,6 @@ extern void SMC669_Init(int); /* es1888.c */ extern void es1888_init(void); -/* ns87312.c */ -extern void ns87312_enable_ide(long ide_base); - /* ../lib/fpreg.c */ extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); extern unsigned long alpha_read_fp_reg (unsigned long reg); diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c index affd0f3f25df..14c8898d19ec 100644 --- a/arch/alpha/kernel/sys_cabriolet.c +++ b/arch/alpha/kernel/sys_cabriolet.c @@ -33,7 +33,7 @@ #include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" - +#include "pc873xx.h" /* Note mask bit is true for DISABLED irqs. */ static unsigned long cached_irq_mask = ~0UL; @@ -235,18 +235,31 @@ cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin) return COMMON_TABLE_LOOKUP; } +static inline void __init +cabriolet_enable_ide(void) +{ + if (pc873xx_probe() == -1) { + printk(KERN_ERR "Probing for PC873xx Super IO chip failed.\n"); + } else { + printk(KERN_INFO "Found %s Super IO chip at 0x%x\n", + pc873xx_get_model(), pc873xx_get_base()); + + pc873xx_enable_ide(); + } +} + static inline void __init cabriolet_init_pci(void) { common_init_pci(); - ns87312_enable_ide(0x398); + cabriolet_enable_ide(); } static inline void __init cia_cab_init_pci(void) { cia_init_pci(); - ns87312_enable_ide(0x398); + cabriolet_enable_ide(); } /* diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c index 230464885b5c..4da596b6adbb 100644 --- a/arch/alpha/kernel/sys_takara.c +++ b/arch/alpha/kernel/sys_takara.c @@ -29,7 +29,7 @@ #include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" - +#include "pc873xx.h" /* Note mask bit is true for DISABLED irqs. */ static unsigned long cached_irq_mask[2] = { -1, -1 }; @@ -264,7 +264,14 @@ takara_init_pci(void) alpha_mv.pci_map_irq = takara_map_irq_srm; cia_init_pci(); - ns87312_enable_ide(0x26e); + + if (pc873xx_probe() == -1) { + printk(KERN_ERR "Probing for PC873xx Super IO chip failed.\n"); + } else { + printk(KERN_INFO "Found %s Super IO chip at 0x%x\n", + pc873xx_get_model(), pc873xx_get_base()); + pc873xx_enable_ide(); + } } -- cgit v1.2.3-59-g8ed1b From 7b598cdd03e35a4361f4ff7ebc630aa508c35be6 Mon Sep 17 00:00:00 2001 From: Michael Cree Date: Tue, 31 Aug 2010 22:46:04 -0400 Subject: alpha: convert perf_event to use local_t Updates the Alpha perf_event code to match the changes recently made to the core perf_event code in commit e78505958cf123048fb48cb56b79cebb8edd15fb. Signed-off-by: Michael Cree Signed-off-by: Matt Turner --- arch/alpha/kernel/perf_event.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c index 51c39fa41693..85d8e4f58c83 100644 --- a/arch/alpha/kernel/perf_event.c +++ b/arch/alpha/kernel/perf_event.c @@ -241,20 +241,20 @@ static inline unsigned long alpha_read_pmc(int idx) static int alpha_perf_event_set_period(struct perf_event *event, struct hw_perf_event *hwc, int idx) { - long left = atomic64_read(&hwc->period_left); + long left = local64_read(&hwc->period_left); long period = hwc->sample_period; int ret = 0; if (unlikely(left <= -period)) { left = period; - atomic64_set(&hwc->period_left, left); + local64_set(&hwc->period_left, left); hwc->last_period = period; ret = 1; } if (unlikely(left <= 0)) { left += period; - atomic64_set(&hwc->period_left, left); + local64_set(&hwc->period_left, left); hwc->last_period = period; ret = 1; } @@ -269,7 +269,7 @@ static int alpha_perf_event_set_period(struct perf_event *event, if (left > (long)alpha_pmu->pmc_max_period[idx]) left = alpha_pmu->pmc_max_period[idx]; - atomic64_set(&hwc->prev_count, (unsigned long)(-left)); + local64_set(&hwc->prev_count, (unsigned long)(-left)); alpha_write_pmc(idx, (unsigned long)(-left)); @@ -300,10 +300,10 @@ static unsigned long alpha_perf_event_update(struct perf_event *event, long delta; again: - prev_raw_count = atomic64_read(&hwc->prev_count); + prev_raw_count = local64_read(&hwc->prev_count); new_raw_count = alpha_read_pmc(idx); - if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count, + if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, new_raw_count) != prev_raw_count) goto again; @@ -316,8 +316,8 @@ again: delta += alpha_pmu->pmc_max_period[idx] + 1; } - atomic64_add(delta, &event->count); - atomic64_sub(delta, &hwc->period_left); + local64_add(delta, &event->count); + local64_sub(delta, &hwc->period_left); return new_raw_count; } @@ -636,7 +636,7 @@ static int __hw_perf_event_init(struct perf_event *event) if (!hwc->sample_period) { hwc->sample_period = alpha_pmu->pmc_max_period[0]; hwc->last_period = hwc->sample_period; - atomic64_set(&hwc->period_left, hwc->sample_period); + local64_set(&hwc->period_left, hwc->sample_period); } return 0; -- cgit v1.2.3-59-g8ed1b From 68d3f1d810500e8b975bdf0b20dd83d060076b4b Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Tue, 31 Aug 2010 23:00:07 -0400 Subject: lockup_detector: Sync touch_*_watchdog back to old semantics During my rewrite, the semantics of touch_nmi_watchdog and touch_softlockup_watchdog changed enough to break some drivers (mostly over preemptable regions). These are cases where long delays on one CPU (due to print_delay for example) can cause long delays on other CPUs - so we must 'touch' the nmi_watchdog flag of those other CPUs as well. This change brings those touch_*_watchdog() functions back in line with to how they used to work. Signed-off-by: Don Zickus Acked-by: Cyrill Gorcunov Cc: peterz@infradead.org Cc: fweisbec@gmail.com LKML-Reference: <1283310009-22168-2-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- kernel/watchdog.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 0d53c8e853b1..7f9c3c52ecc1 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -122,7 +122,7 @@ static void __touch_watchdog(void) void touch_softlockup_watchdog(void) { - __get_cpu_var(watchdog_touch_ts) = 0; + __raw_get_cpu_var(watchdog_touch_ts) = 0; } EXPORT_SYMBOL(touch_softlockup_watchdog); @@ -142,7 +142,14 @@ void touch_all_softlockup_watchdogs(void) #ifdef CONFIG_HARDLOCKUP_DETECTOR void touch_nmi_watchdog(void) { - __get_cpu_var(watchdog_nmi_touch) = true; + if (watchdog_enabled) { + unsigned cpu; + + for_each_present_cpu(cpu) { + if (per_cpu(watchdog_nmi_touch, cpu) != true) + per_cpu(watchdog_nmi_touch, cpu) = true; + } + } touch_softlockup_watchdog(); } EXPORT_SYMBOL(touch_nmi_watchdog); @@ -433,6 +440,9 @@ static int watchdog_enable(int cpu) wake_up_process(p); } + /* if any cpu succeeds, watchdog is considered enabled for the system */ + watchdog_enabled = 1; + return 0; } @@ -455,9 +465,6 @@ static void watchdog_disable(int cpu) per_cpu(softlockup_watchdog, cpu) = NULL; kthread_stop(p); } - - /* if any cpu succeeds, watchdog is considered enabled for the system */ - watchdog_enabled = 1; } static void watchdog_enable_all_cpus(void) -- cgit v1.2.3-59-g8ed1b From 25d3584797a39f57b69cd835722ac7c41113fb9a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 16 Aug 2010 15:15:14 +0100 Subject: ARM: 6330/1: perf: reword comments relating to perf_event_do_pending This is purely a cosmetic change to the ARM perf backend because the current comments about the relationship between NMIs, interrupt context and perf_event_do_pending are misleading. This patch updates the comments so that they reflect what the code actually does (which is in line with other architectures). Acked-by: Jamie Iles Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/perf_event.h | 2 +- arch/arm/kernel/perf_event.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index 48837e6d8887..b5799a3b7117 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h @@ -17,7 +17,7 @@ * counter interrupts are regular interrupts and not an NMI. This * means that when we receive the interrupt we can call * perf_event_do_pending() that handles all of the work with - * interrupts enabled. + * interrupts disabled. */ static inline void set_perf_event_pending(void) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 417c392ddf1c..e2139256524e 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -1041,8 +1041,8 @@ armv6pmu_handle_irq(int irq_num, /* * Handle the pending perf events. * - * Note: this call *must* be run with interrupts enabled. For - * platforms that can have the PMU interrupts raised as a PMI, this + * Note: this call *must* be run with interrupts disabled. For + * platforms that can have the PMU interrupts raised as an NMI, this * will not work. */ perf_event_do_pending(); @@ -2017,8 +2017,8 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) /* * Handle the pending perf events. * - * Note: this call *must* be run with interrupts enabled. For - * platforms that can have the PMU interrupts raised as a PMI, this + * Note: this call *must* be run with interrupts disabled. For + * platforms that can have the PMU interrupts raised as an NMI, this * will not work. */ perf_event_do_pending(); -- cgit v1.2.3-59-g8ed1b From 418cf646c9999f2f7d216b1a693c2c575ab8094c Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Wed, 25 Aug 2010 20:49:01 +0100 Subject: ARM: 6343/1: wire up fanotify and prlimit64 syscalls on ARM The 2.6.36-rc kernel added three new system calls: fanotify_init, fanotify_mark, and prlimit64. This patch wires them up on ARM. The only non-trivial issue here is the u64 argument to sys_fanotify_mark(), but it is the 3rd argument and thus passed in r2/r3 in both kernel and user space, so it causes no problems. Tested with a 2.6.36-rc2 EABI kernel on an ixp4xx machine. Tested-by: Anand Gadiyar Signed-off-by: Mikael Pettersson Signed-off-by: Russell King --- arch/arm/include/asm/unistd.h | 3 +++ arch/arm/kernel/calls.S | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index d02cfb683487..c891eb76c0e3 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -393,6 +393,9 @@ #define __NR_perf_event_open (__NR_SYSCALL_BASE+364) #define __NR_recvmmsg (__NR_SYSCALL_BASE+365) #define __NR_accept4 (__NR_SYSCALL_BASE+366) +#define __NR_fanotify_init (__NR_SYSCALL_BASE+367) +#define __NR_fanotify_mark (__NR_SYSCALL_BASE+368) +#define __NR_prlimit64 (__NR_SYSCALL_BASE+369) /* * The following SWIs are ARM private. diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index afeb71fa72cb..5c26eccef998 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -376,6 +376,9 @@ CALL(sys_perf_event_open) /* 365 */ CALL(sys_recvmmsg) CALL(sys_accept4) + CALL(sys_fanotify_init) + CALL(sys_fanotify_mark) + CALL(sys_prlimit64) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted -- cgit v1.2.3-59-g8ed1b From af54decd6a2b8efa335020afc77254355c4c1bab Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 14 Aug 2010 11:03:16 +0200 Subject: regulator/ab8500: move dereference below the check for NULL I moved the dereference of "ab8500" below the check for NULL. Signed-off-by: Dan Carpenter Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index dc3f1a491675..cc7cbafc5b94 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -344,13 +344,14 @@ static inline struct ab8500_regulator_info *find_regulator_info(int id) static __devinit int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); - struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev); + struct ab8500_platform_data *pdata; int i, err; if (!ab8500) { dev_err(&pdev->dev, "null mfd parent\n"); return -EINVAL; } + pdata = dev_get_platdata(ab8500->dev); /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { -- cgit v1.2.3-59-g8ed1b From b3fcf3e576749b911e984e752b6b390c326efb76 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 14 Aug 2010 21:31:01 +0800 Subject: regulator: ab3100 - fix the logic to remove already registered regulators in error path In current implementation, ab3100_regulators[0].rdev is not unregistered if the error happen at i > 0. This patch fixes the resource leak and also improves the readability. Signed-off-by: Axel Lin Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab3100.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 11790990277a..b349266a43de 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -634,12 +634,9 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev) "%s: failed to register regulator %s err %d\n", __func__, ab3100_regulator_desc[i].name, err); - i--; /* remove the already registered regulators */ - while (i > 0) { + while (--i >= 0) regulator_unregister(ab3100_regulators[i].rdev); - i--; - } return err; } -- cgit v1.2.3-59-g8ed1b From d4876a3bc041e8e40af20b8addbec6d0a42e3842 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 14 Aug 2010 21:44:04 +0800 Subject: regulator: ab8500 - fix the logic to remove already registered regulators in error path In current implementation, ab8500_regulator_info[0].regulator is not unregistered if the error happen at i > 0. This patch fixes the resource leak and also improves the readability. Signed-off-by: Axel Lin Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index cc7cbafc5b94..3d09580dc883 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -369,11 +369,9 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); /* when we fail, un-register all earlier regulators */ - i--; - while (i > 0) { + while (--i >= 0) { info = &ab8500_regulator_info[i]; regulator_unregister(info->regulator); - i--; } return err; } -- cgit v1.2.3-59-g8ed1b From 3e352f9e02a37c11df695aabfe49faebf507971b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 18 Aug 2010 11:37:21 +0800 Subject: regulator: max1586 - improve the logic of choosing selector A little bit improvement in the logic of choosing selector. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max1586.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 8867c2710a6d..559cfa271a44 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -121,14 +121,14 @@ static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV) return -EINVAL; - if (min_uV >= 3000000) - selector = 3; - if (min_uV < 3000000) - selector = 2; - if (min_uV < 2500000) - selector = 1; if (min_uV < 1800000) selector = 0; + else if (min_uV < 2500000) + selector = 1; + else if (min_uV < 3000000) + selector = 2; + else if (min_uV >= 3000000) + selector = 3; if (max1586_v6_calc_voltage(selector) > max_uV) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 7112b2dfea4966c58d21b7197c3f099041248e59 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 14 Aug 2010 22:32:13 +0800 Subject: regulator: tps6507x - remove incorrect comments This driver is a platform driver, not a i2c driver. Thus remove incorrect tps6507x_remove comments. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/tps6507x-regulator.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index c239f42aa4a3..020f5878d7ff 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -626,12 +626,6 @@ fail: return error; } -/** - * tps6507x_remove - TPS6507x driver i2c remove handler - * @client: i2c driver client device structure - * - * Unregister TPS driver as an i2c client device driver - */ static int __devexit tps6507x_pmic_remove(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); -- cgit v1.2.3-59-g8ed1b From 11fa0d1d20c7cc432c77369bc8bbfbc21030e457 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 19 Aug 2010 10:29:19 +0800 Subject: regulator: max8998 - fix memory allocation size for max8998->rdev We only use max8998->rdev[0] .. max8998->rdev[pdata->num_regulators-1], max8998->rdev[pdata->num_regulators] is not used. Thus fix the memory allocation size. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max8998.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index ab67298799f9..fbcb385034a9 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -549,7 +549,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) if (!max8998) return -ENOMEM; - size = sizeof(struct regulator_dev *) * (pdata->num_regulators + 1); + size = sizeof(struct regulator_dev *) * pdata->num_regulators; max8998->rdev = kzalloc(size, GFP_KERNEL); if (!max8998->rdev) { kfree(max8998); @@ -583,7 +583,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) return 0; err: - for (i = 0; i <= max8998->num_regulators; i++) + for (i = 0; i < max8998->num_regulators; i++) if (rdev[i]) regulator_unregister(rdev[i]); @@ -599,7 +599,7 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev) struct regulator_dev **rdev = max8998->rdev; int i; - for (i = 0; i <= max8998->num_regulators; i++) + for (i = 0; i < max8998->num_regulators; i++) if (rdev[i]) regulator_unregister(rdev[i]); -- cgit v1.2.3-59-g8ed1b From c356cbc2d4d99cf5a1429603fa1841e50987c4d3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 22 Aug 2010 15:26:49 +0800 Subject: regulator: max8998 - set max8998->num_regulators Set max8998->num_regulators = pdata->num_regulators, otherwise it's default value is 0. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max8998.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index fbcb385034a9..8b9bfdf8ffe5 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -558,6 +558,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) rdev = max8998->rdev; max8998->iodev = iodev; + max8998->num_regulators = pdata->num_regulators; platform_set_drvdata(pdev, max8998); for (i = 0; i < pdata->num_regulators; i++) { -- cgit v1.2.3-59-g8ed1b From 327531bada36e5786b13bb6918ad8afc545adfa2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 22 Aug 2010 22:38:15 +0800 Subject: regulator: tps6586x-regulator - fix value range checking for val val is used as array index of ri->voltages. Thus the valid value range should be 0 .. ri->desc.n_voltages - 1. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/tps6586x-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 8cff1413a147..facd439d0f12 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -133,7 +133,7 @@ static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; val = (val & mask) >> ri->volt_shift; - if (val > ri->desc.n_voltages) + if (val >= ri->desc.n_voltages) BUG(); return ri->voltages[val] * 1000; -- cgit v1.2.3-59-g8ed1b From 938b45927c240cf75a01ce29af3f173762e762f8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 22 Aug 2010 22:42:42 +0800 Subject: regulator: tps6586x-regulator - fix bit_mask parameter for tps6586x_set_bits() The third parameter of tps6586x_set_bits() is the bit_mask, thus we should use (1 << ri->go_bit) instead of ri->go_bit. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/tps6586x-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index facd439d0f12..51237fbb1bbb 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -150,7 +150,7 @@ static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev, if (ret) return ret; - return tps6586x_set_bits(parent, ri->go_reg, ri->go_bit); + return tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit); } static int tps6586x_regulator_enable(struct regulator_dev *rdev) -- cgit v1.2.3-59-g8ed1b From 747cc851dc42ffeac2872da066ca4293a6d90baf Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 27 Aug 2010 16:37:34 +0800 Subject: regulator: set max8998->dev to &pdev->dev. max8998->dev is NULL in current implementation, set it to &pdev->dev. regulator_register() still return success if max8998->dev is NULL, but rdev->dev.parent will be set to NULL which is incorrect. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max8998.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 8b9bfdf8ffe5..a1baf1fbe004 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -557,6 +557,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) } rdev = max8998->rdev; + max8998->dev = &pdev->dev; max8998->iodev = iodev; max8998->num_regulators = pdata->num_regulators; platform_set_drvdata(pdev, max8998); -- cgit v1.2.3-59-g8ed1b From 606b2f490fb80e55d05cf0e6cec0b6c0ff0fc18f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 27 Aug 2010 22:33:38 +0100 Subject: regulator: Update e-mail address for Liam Girdwood Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- Documentation/power/regulator/overview.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/power/regulator/overview.txt b/Documentation/power/regulator/overview.txt index 9363e056188a..8ed17587a74b 100644 --- a/Documentation/power/regulator/overview.txt +++ b/Documentation/power/regulator/overview.txt @@ -13,7 +13,7 @@ regulators (where voltage output is controllable) and current sinks (where current limit is controllable). (C) 2008 Wolfson Microelectronics PLC. -Author: Liam Girdwood +Author: Liam Girdwood Nomenclature -- cgit v1.2.3-59-g8ed1b From 58d463eec844f6381d63d04dc89d319ae3057ca9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 1 Sep 2010 10:29:18 +0800 Subject: regulator: ad5398 - fix a memory leak In current implementation, the address return from regulator_register() is different from the address for regulator_unregister(). Signed-off-by: Axel Lin Acked-by: Sonic Zhang Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ad5398.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index d59d2f2314af..df1fb53c09d2 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -25,7 +25,7 @@ struct ad5398_chip_info { unsigned int current_level; unsigned int current_mask; unsigned int current_offset; - struct regulator_dev rdev; + struct regulator_dev *rdev; }; static int ad5398_calc_current(struct ad5398_chip_info *chip, @@ -211,7 +211,6 @@ MODULE_DEVICE_TABLE(i2c, ad5398_id); static int __devinit ad5398_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct regulator_dev *rdev; struct regulator_init_data *init_data = client->dev.platform_data; struct ad5398_chip_info *chip; const struct ad5398_current_data_format *df = @@ -233,9 +232,10 @@ static int __devinit ad5398_probe(struct i2c_client *client, chip->current_offset = df->current_offset; chip->current_mask = (chip->current_level - 1) << chip->current_offset; - rdev = regulator_register(&ad5398_reg, &client->dev, init_data, chip); - if (IS_ERR(rdev)) { - ret = PTR_ERR(rdev); + chip->rdev = regulator_register(&ad5398_reg, &client->dev, + init_data, chip); + if (IS_ERR(chip->rdev)) { + ret = PTR_ERR(chip->rdev); dev_err(&client->dev, "failed to register %s %s\n", id->name, ad5398_reg.name); goto err; @@ -254,7 +254,7 @@ static int __devexit ad5398_remove(struct i2c_client *client) { struct ad5398_chip_info *chip = i2c_get_clientdata(client); - regulator_unregister(&chip->rdev); + regulator_unregister(chip->rdev); kfree(chip); i2c_set_clientdata(client, NULL); -- cgit v1.2.3-59-g8ed1b From b9e5d11a7e70000ace3ba92100bf1e81ff607604 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 1 Sep 2010 13:09:41 +0800 Subject: regulator: isl6271a-regulator - fix regulator_desc parameter for regulator_register() Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/isl6271a-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index e49d2bd393f2..d61ecb885a8c 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -165,7 +165,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, mutex_init(&pmic->mtx); for (i = 0; i < 3; i++) { - pmic->rdev[i] = regulator_register(&isl_rd[0], &i2c->dev, + pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev, init_data, pmic); if (IS_ERR(pmic->rdev[i])) { dev_err(&i2c->dev, "failed to register %s\n", id->name); -- cgit v1.2.3-59-g8ed1b From cc0fc0bbeb17dd33ed7bfea58d0178e9c007ff67 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Sep 2010 08:55:22 -0600 Subject: spi/spi_s3c64xx: Make probe more robust against missing board config The S3C64xx SPI driver requires the machine to call s3c64xx_spi_set_info() to select a few options, including the clock to use for the SPI controller. If this is not done then a NULL will be passed as the clock name for clk_get(), causing an obscure crash. Guard against this and other missing configuration by validating that the clock name has been filled in in the platform data that ets passed in. Signed-off-by: Mark Brown Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 97365815a729..a0b63b785418 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -919,6 +919,13 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) return -ENODEV; } + sci = pdev->dev.platform_data; + if (!sci->src_clk_name) { + dev_err(&pdev->dev, + "Board init must call s3c64xx_spi_set_info()\n"); + return -EINVAL; + } + /* Check for availability of necessary resource */ dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -946,8 +953,6 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) return -ENOMEM; } - sci = pdev->dev.platform_data; - platform_set_drvdata(pdev, master); sdd = spi_master_get_devdata(master); -- cgit v1.2.3-59-g8ed1b From 8944f4f3d9695e04f7091ab61da9aab7a4be5846 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Sep 2010 08:55:23 -0600 Subject: spi/spi_s3c64xx: Staticise non-exported functions Signed-off-by: Mark Brown Acked-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index a0b63b785418..7e627f73bc6c 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -447,8 +447,8 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) writel(val, regs + S3C64XX_SPI_CLK_CFG); } -void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) +static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, + int size, enum s3c2410_dma_buffresult res) { struct s3c64xx_spi_driver_data *sdd = buf_id; unsigned long flags; @@ -467,8 +467,8 @@ void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id, spin_unlock_irqrestore(&sdd->lock, flags); } -void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id, - int size, enum s3c2410_dma_buffresult res) +static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id, + int size, enum s3c2410_dma_buffresult res) { struct s3c64xx_spi_driver_data *sdd = buf_id; unsigned long flags; -- cgit v1.2.3-59-g8ed1b From 9f1a1fca35066117353994bff80a5115cddad7a2 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 1 Sep 2010 08:55:23 -0600 Subject: of: Fix missing includes - ll_temac It is the next patch which is fixing missing header which were removed from prom.h. Related patches: "of/address: Clean up function declarations" (sha1 id 22ae782f8) "of: Fix missing includes" (sha1 id f1ca09b2b) Signed-off-by: Michal Simek Signed-off-by: Grant Likely --- drivers/net/ll_temac_main.c | 1 + drivers/net/ll_temac_mdio.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index bdf2149e5296..87f0a93b165c 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include /* needed for sizeof(tcphdr) */ diff --git a/drivers/net/ll_temac_mdio.c b/drivers/net/ll_temac_mdio.c index 5ae28c975b38..8cf9d4f56bb2 100644 --- a/drivers/net/ll_temac_mdio.c +++ b/drivers/net/ll_temac_mdio.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3-59-g8ed1b From 4e4438b86527e8bf1f49503a30d487e401e64f9c Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 1 Sep 2010 08:55:24 -0600 Subject: gpiolib: Add 'struct gpio_chip' forward declaration for !GPIOLIB case With CONFIG_GPIOLIB=n, the 'struct gpio_chip' is not declared, so the following pops up on PowerPC: cc1: warnings being treated as errors In file included from arch/powerpc/platforms/52xx/mpc52xx_common.c:19: include/linux/of_gpio.h:74: warning: 'struct gpio_chip' declared inside parameter list include/linux/of_gpio.h:74: warning: its scope is only this definition or declaration, which is probably not what you want include/linux/of_gpio.h:75: warning: 'struct gpio_chip' declared inside parameter list make[2]: *** [arch/powerpc/platforms/52xx/mpc52xx_common.o] Error 1 This patch fixes the issue by providing the proper forward declaration. Signed-off-by: Anton Vorontsov Signed-off-by: Grant Likely --- include/linux/gpio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 03f616b78cfa..e41f7dd1ae67 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -13,6 +13,7 @@ #include struct device; +struct gpio_chip; /* * Some platforms don't support the GPIO programming interface. -- cgit v1.2.3-59-g8ed1b From 34860089c9e8abcc77428d29743b37ff756197e7 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 30 Aug 2010 23:54:17 +0200 Subject: spi: free children in spi_unregister_master, not siblings introduced by 49dce689 ("spi doesn't need class_device") and bad-fixed by 350d0076 ("spi: fix double-free on spi_unregister_master"), spi_unregister_master would previously device_unregister all of the spi master's siblings (instead of its children). hilarity ensues. fix it to unregister children. Signed-off-by: David Lamparter Signed-off-by: Grant Likely --- drivers/spi/spi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index a9e5c79ae52a..0bcf4c1601a2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -554,11 +554,9 @@ done: EXPORT_SYMBOL_GPL(spi_register_master); -static int __unregister(struct device *dev, void *master_dev) +static int __unregister(struct device *dev, void *null) { - /* note: before about 2.6.14-rc1 this would corrupt memory: */ - if (dev != master_dev) - spi_unregister_device(to_spi_device(dev)); + spi_unregister_device(to_spi_device(dev)); return 0; } @@ -576,8 +574,7 @@ void spi_unregister_master(struct spi_master *master) { int dummy; - dummy = device_for_each_child(master->dev.parent, &master->dev, - __unregister); + dummy = device_for_each_child(&master->dev, NULL, __unregister); device_unregister(&master->dev); } EXPORT_SYMBOL_GPL(spi_unregister_master); -- cgit v1.2.3-59-g8ed1b From 3e073367a57d41e506f20aebb98e308387ce3090 Mon Sep 17 00:00:00 2001 From: Michael Cree Date: Wed, 1 Sep 2010 11:25:17 -0400 Subject: alpha: Fix printk format errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling alpha generic build get errors such as: arch/alpha/kernel/err_marvel.c: In function ‘marvel_print_err_cyc’: arch/alpha/kernel/err_marvel.c:119: error: format ‘%ld’ expects type ‘long int’, but argument 6 has type ‘u64’ Replaced a number of %ld format specifiers with %lld since u64 is unsigned long long. Signed-off-by: Michael Cree Signed-off-by: Matt Turner --- arch/alpha/kernel/err_marvel.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/alpha/kernel/err_marvel.c b/arch/alpha/kernel/err_marvel.c index 52a79dfc13c6..5c905aaaeccd 100644 --- a/arch/alpha/kernel/err_marvel.c +++ b/arch/alpha/kernel/err_marvel.c @@ -109,7 +109,7 @@ marvel_print_err_cyc(u64 err_cyc) #define IO7__ERR_CYC__CYCLE__M (0x7) printk("%s Packet In Error: %s\n" - "%s Error in %s, cycle %ld%s%s\n", + "%s Error in %s, cycle %lld%s%s\n", err_print_prefix, packet_desc[EXTRACT(err_cyc, IO7__ERR_CYC__PACKET)], err_print_prefix, @@ -313,7 +313,7 @@ marvel_print_po7_ugbge_sym(u64 ugbge_sym) } printk("%s Up Hose Garbage Symptom:\n" - "%s Source Port: %ld - Dest PID: %ld - OpCode: %s\n", + "%s Source Port: %lld - Dest PID: %lld - OpCode: %s\n", err_print_prefix, err_print_prefix, EXTRACT(ugbge_sym, IO7__PO7_UGBGE_SYM__UPH_SRC_PORT), @@ -552,7 +552,7 @@ marvel_print_pox_spl_cmplt(u64 spl_cmplt) #define IO7__POX_SPLCMPLT__REM_BYTE_COUNT__M (0xfff) printk("%s Split Completion Error:\n" - "%s Source (Bus:Dev:Func): %ld:%ld:%ld\n", + "%s Source (Bus:Dev:Func): %lld:%lld:%lld\n", err_print_prefix, err_print_prefix, EXTRACT(spl_cmplt, IO7__POX_SPLCMPLT__SOURCE_BUS), -- cgit v1.2.3-59-g8ed1b From 59482fe5959675f180469ae95e4fcd0a15920ced Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 31 Aug 2010 17:43:51 +0900 Subject: powerpc/512x: fix clk_get() return value clk_get() should return an ERR_PTR value on error, not NULL. Signed-off-by: Akinobu Mita Signed-off-by: Grant Likely --- arch/powerpc/platforms/512x/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c index 5b243bd3eb3b..3dc2a8d262b8 100644 --- a/arch/powerpc/platforms/512x/clock.c +++ b/arch/powerpc/platforms/512x/clock.c @@ -57,7 +57,7 @@ static struct clk *mpc5121_clk_get(struct device *dev, const char *id) int id_match = 0; if (dev == NULL || id == NULL) - return NULL; + return clk; mutex_lock(&clocks_mutex); list_for_each_entry(p, &clocks, node) { -- cgit v1.2.3-59-g8ed1b From 269f45c25028c75fe10e6d9be86e7202ab461fbc Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 1 Sep 2010 14:50:50 +0200 Subject: oprofile, x86: fix init_sysfs() function stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The use of the return value of init_sysfs() with commit 10f0412 oprofile, x86: fix init_sysfs error handling discovered the following build error for !CONFIG_PM: .../linux/arch/x86/oprofile/nmi_int.c: In function ‘op_nmi_init’: .../linux/arch/x86/oprofile/nmi_int.c:784: error: expected expression before ‘do’ make[2]: *** [arch/x86/oprofile/nmi_int.o] Error 1 make[1]: *** [arch/x86/oprofile] Error 2 This patch fixes this. Reported-by: Ingo Molnar Cc: stable@kernel.org Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 73a41d3c6c09..cfe4faabb0f6 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -585,8 +585,10 @@ static void exit_sysfs(void) } #else -#define init_sysfs() do { } while (0) -#define exit_sysfs() do { } while (0) + +static inline int init_sysfs(void) { return 0; } +static inline void exit_sysfs(void) { } + #endif /* CONFIG_PM */ static int __init p4_init(char **cpu_type) -- cgit v1.2.3-59-g8ed1b From aa8a9e25c5e865de85410be4e9269b552974f7a2 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 1 Sep 2010 13:10:53 -0700 Subject: MAINTAINERS: Add ehea driver as Supported This change just add the IBM eHEA 10Gb network drivers as supported. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8e85429d3bb0..db6b351af2ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2171,6 +2171,12 @@ L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/hw/ehca/ +EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER +M: Breno Leitao +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ehea/ + EMBEDDED LINUX M: Paul Gortmaker M: Matt Mackall -- cgit v1.2.3-59-g8ed1b From 78b620ce9e168d08ecfac2f4bb056c511b0601ec Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 31 Aug 2010 02:05:57 +0000 Subject: vhost: stop worker only if created Its currently illegal to call kthread_stop(NULL) Reported-by: Ingo Molnar Signed-off-by: Eric Dumazet Acked-by: Tejun Heo Signed-off-by: David S. Miller --- drivers/vhost/vhost.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index e05557d52999..4b99117f3ecd 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -323,7 +323,10 @@ void vhost_dev_cleanup(struct vhost_dev *dev) dev->mm = NULL; WARN_ON(!list_empty(&dev->work_list)); - kthread_stop(dev->worker); + if (dev->worker) { + kthread_stop(dev->worker); + dev->worker = NULL; + } } static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz) -- cgit v1.2.3-59-g8ed1b From 0f04cfd098fb81fded74e78ea1a1b86cc6c6c31e Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 31 Aug 2010 13:21:42 +0000 Subject: net sched: fix kernel leak in act_police While reviewing commit 1c40be12f7d8ca1d387510d39787b12e512a7ce8, I audited other users of tc_action_ops->dump for information leaks. That commit covered almost all of them but act_police still had a leak. opt.limit and opt.capab aren't zeroed out before the structure is passed out. This patch uses the C99 initializers to zero everything unused out. Signed-off-by: Jeff Mahoney Acked-by: Jeff Mahoney Signed-off-by: David S. Miller --- net/sched/act_police.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 537a48732e9e..7ebf7439b478 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -350,22 +350,19 @@ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { unsigned char *b = skb_tail_pointer(skb); struct tcf_police *police = a->priv; - struct tc_police opt; - - opt.index = police->tcf_index; - opt.action = police->tcf_action; - opt.mtu = police->tcfp_mtu; - opt.burst = police->tcfp_burst; - opt.refcnt = police->tcf_refcnt - ref; - opt.bindcnt = police->tcf_bindcnt - bind; + struct tc_police opt = { + .index = police->tcf_index, + .action = police->tcf_action, + .mtu = police->tcfp_mtu, + .burst = police->tcfp_burst, + .refcnt = police->tcf_refcnt - ref, + .bindcnt = police->tcf_bindcnt - bind, + }; + if (police->tcfp_R_tab) opt.rate = police->tcfp_R_tab->rate; - else - memset(&opt.rate, 0, sizeof(opt.rate)); if (police->tcfp_P_tab) opt.peakrate = police->tcfp_P_tab->rate; - else - memset(&opt.peakrate, 0, sizeof(opt.peakrate)); NLA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); if (police->tcfp_result) NLA_PUT_U32(skb, TCA_POLICE_RESULT, police->tcfp_result); -- cgit v1.2.3-59-g8ed1b From 9c01ae58d4fee39e2af5b1379ee5431dd585cf62 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Sun, 29 Aug 2010 21:21:38 +0000 Subject: pxa168_eth: fix a mdiobus leak mdiobus resources must be released on exit Signed-off-by: Denis Kirjanov Acked-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/pxa168_eth.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index 410ea0a61371..85eddda276bd 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -1606,6 +1606,8 @@ static int pxa168_eth_remove(struct platform_device *pdev) iounmap(pep->base); pep->base = NULL; + mdiobus_unregister(pep->smi_bus); + mdiobus_free(pep->smi_bus); unregister_netdev(dev); flush_scheduled_work(); free_netdev(dev); -- cgit v1.2.3-59-g8ed1b From 3b2eb6131e2f6ff646abb0fc69648179b8b70216 Mon Sep 17 00:00:00 2001 From: Michal Soltys Date: Mon, 30 Aug 2010 11:34:10 +0000 Subject: net/sched/sch_hfsc.c: initialize parent's cl_cfmin properly in init_vf() This patch fixes init_vf() function, so on each new backlog period parent's cl_cfmin is properly updated (including further propgation towards the root), even if the activated leaf has no upperlimit curve defined. Signed-off-by: Michal Soltys Signed-off-by: David S. Miller --- net/sched/sch_hfsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index abd904be4287..47496098d35c 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -761,8 +761,8 @@ init_vf(struct hfsc_class *cl, unsigned int len) if (f != cl->cl_f) { cl->cl_f = f; cftree_update(cl); - update_cfmin(cl->cl_parent); } + update_cfmin(cl->cl_parent); } } -- cgit v1.2.3-59-g8ed1b From 928497f0209027ccd649480a38a499fab9c3f6f6 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 31 Aug 2010 05:54:00 +0000 Subject: xfrm_user: avoid a warning with some compiler Attached is a small patch to remove a warning ("warning: ISO C90 forbids mixed declarations and code" with gcc 4.3.2). Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b14ed4b1f27c..8bae6b22c846 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1801,7 +1801,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, struct xfrm_user_expire *ue = nlmsg_data(nlh); struct xfrm_usersa_info *p = &ue->state; struct xfrm_mark m; - u32 mark = xfrm_mark_get(attrs, &m);; + u32 mark = xfrm_mark_get(attrs, &m); x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family); -- cgit v1.2.3-59-g8ed1b From 750e9fad8c7f44e0005ffb7195f72dd76978c2cf Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 31 Aug 2010 05:50:43 +0000 Subject: ipv4: minor fix about RPF in help of Kconfig Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv4/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 7c3a7d191249..571f8950ed06 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -46,7 +46,7 @@ config IP_ADVANCED_ROUTER rp_filter on use: echo 1 > /proc/sys/net/ipv4/conf//rp_filter - and + or echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter Note that some distributions enable it in startup scripts. -- cgit v1.2.3-59-g8ed1b From de6be6c1f77798c4da38301693d33aff1cd76e84 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 30 Aug 2010 07:51:17 +0000 Subject: sky2: don't do GRO on second port There's something very important I forgot to tell you. What? Don't cross the GRO streams. Why? It would be bad. I'm fuzzy on the whole good/bad thing. What do you mean, "bad"? Try to imagine all the Internet as you know it stopping instantaneously and every bit in every packet swapping at the speed of light. Total packet reordering. Right. That's bad. Okay. All right. Important safety tip. Thanks, Hubert The simplest way to stop this is just avoid doing GRO on the second port. Very few Marvell boards support two ports per ring, and GRO is just an optimization. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/sky2.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 194e5cf8c763..a6ff113d34bb 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2520,24 +2520,27 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) } } -static inline void sky2_skb_rx(const struct sky2_port *sky2, +static inline void sky2_skb_rx(struct napi_struct *napi, + const struct sky2_port *sky2, u32 status, struct sk_buff *skb) { #ifdef SKY2_VLAN_TAG_USED - u16 vlan_tag = be16_to_cpu(sky2->rx_tag); if (sky2->vlgrp && (status & GMR_FS_VLAN)) { - if (skb->ip_summed == CHECKSUM_NONE) + u16 vlan_tag = be16_to_cpu(sky2->rx_tag); + + if (skb->ip_summed == CHECKSUM_NONE || + sky2->netdev != napi->dev) vlan_hwaccel_receive_skb(skb, sky2->vlgrp, vlan_tag); else - vlan_gro_receive(&sky2->hw->napi, sky2->vlgrp, - vlan_tag, skb); + vlan_gro_receive(napi, sky2->vlgrp, vlan_tag, skb); return; } #endif - if (skb->ip_summed == CHECKSUM_NONE) + if (skb->ip_summed == CHECKSUM_NONE || + sky2->netdev != napi->dev) netif_receive_skb(skb); else - napi_gro_receive(&sky2->hw->napi, skb); + napi_gro_receive(napi, skb); } static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port, @@ -2638,7 +2641,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) skb->protocol = eth_type_trans(skb, dev); - sky2_skb_rx(sky2, status, skb); + sky2_skb_rx(&hw->napi, sky2, status, skb); /* Stop after net poll weight */ if (++work_done >= to_do) -- cgit v1.2.3-59-g8ed1b From a9d8fb4d09ec8823045f44ebcde53a563fce2feb Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Fri, 27 Aug 2010 12:57:39 -0700 Subject: [ARM] tegra: Add ZRELADDR default for ARCH_TEGRA fixes the warning: .config:369:warning: symbol value '' invalid for ZRELADDR and the prompt for ZRELADDR on make Signed-off-by: Erik Gilling --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a7ed21f0136a..16bc8eb4901c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1601,6 +1601,7 @@ config ZRELADDR ARCH_ORION5X ||\ ARCH_SPEAR3XX ||\ ARCH_SPEAR6XX ||\ + ARCH_TEGRA ||\ ARCH_U8500 ||\ ARCH_VERSATILE ||\ ARCH_W90X900 -- cgit v1.2.3-59-g8ed1b From 93f68f1ef787d97ab688f78a01f446e85bb9a496 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Wed, 18 Aug 2010 09:58:46 +0000 Subject: powerpc/pseries: Correct rtas_data_buf locking in dlpar code The dlpar code can cause a deadlock to occur when making the RTAS configure-connector call. This occurs because we make kmalloc calls, which can block, while parsing the rtas_data_buf and holding the rtas_data_buf_lock. This an cause issues if someone else attempts to grab the rtas_data_bug_lock. This patch alleviates this issue by copying the contents of the rtas_data_buf to a local buffer before parsing. This allows us to only hold the rtas_data_buf_lock around the RTAS configure-connector calls. Signed-off-by: Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/dlpar.c | 42 +++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 227c1c3d585e..72d8054fa739 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -129,20 +129,35 @@ struct device_node *dlpar_configure_connector(u32 drc_index) struct property *property; struct property *last_property = NULL; struct cc_workarea *ccwa; + char *data_buf; int cc_token; - int rc; + int rc = -1; cc_token = rtas_token("ibm,configure-connector"); if (cc_token == RTAS_UNKNOWN_SERVICE) return NULL; - spin_lock(&rtas_data_buf_lock); - ccwa = (struct cc_workarea *)&rtas_data_buf[0]; + data_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); + if (!data_buf) + return NULL; + + ccwa = (struct cc_workarea *)&data_buf[0]; ccwa->drc_index = drc_index; ccwa->zero = 0; - rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); - while (rc) { + do { + /* Since we release the rtas_data_buf lock between configure + * connector calls we want to re-populate the rtas_data_buffer + * with the contents of the previous call. + */ + spin_lock(&rtas_data_buf_lock); + + memcpy(rtas_data_buf, data_buf, RTAS_DATA_BUF_SIZE); + rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); + memcpy(data_buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); + + spin_unlock(&rtas_data_buf_lock); + switch (rc) { case NEXT_SIBLING: dn = dlpar_parse_cc_node(ccwa); @@ -197,18 +212,19 @@ struct device_node *dlpar_configure_connector(u32 drc_index) "returned from configure-connector\n", rc); goto cc_error; } + } while (rc); - rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); +cc_error: + kfree(data_buf); + + if (rc) { + if (first_dn) + dlpar_free_cc_nodes(first_dn); + + return NULL; } - spin_unlock(&rtas_data_buf_lock); return first_dn; - -cc_error: - if (first_dn) - dlpar_free_cc_nodes(first_dn); - spin_unlock(&rtas_data_buf_lock); - return NULL; } static struct device_node *derive_parent(const char *path) -- cgit v1.2.3-59-g8ed1b From 24cd804d1dc60a74c53da983094df3516500c276 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 30 Aug 2010 14:15:33 +0000 Subject: 3c59x: Remove incorrect locking; correct documented lock hierarchy vortex_ioctl() was grabbing vortex_private::lock around its call to generic_mii_ioctl(). This is no longer necessary since there are more specific locks which the mdio_{read,write}() functions will obtain. Worse, those functions do not save and restore IRQ flags when locking the MII state, so interrupts will be enabled when generic_mii_ioctl() returns. Since there is currently no need for any function to call mdio_{read,write}() while holding another spinlock, do not change them to save and restore IRQ flags but remove the specification of ordering between vortex_private::lock and vortex_private::mii_lock. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c685a55fc2f4..a045559c81cf 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -647,7 +647,7 @@ struct vortex_private { u16 io_size; /* Size of PCI region (for release_region) */ /* Serialises access to hardware other than MII and variables below. - * The lock hierarchy is rtnl_lock > lock > mii_lock > window_lock. */ + * The lock hierarchy is rtnl_lock > {lock, mii_lock} > window_lock. */ spinlock_t lock; spinlock_t mii_lock; /* Serialises access to MII */ @@ -2984,7 +2984,6 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int err; struct vortex_private *vp = netdev_priv(dev); - unsigned long flags; pci_power_t state = 0; if(VORTEX_PCI(vp)) @@ -2994,9 +2993,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if(state != 0) pci_set_power_state(VORTEX_PCI(vp), PCI_D0); - spin_lock_irqsave(&vp->lock, flags); err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL); - spin_unlock_irqrestore(&vp->lock, flags); if(state != 0) pci_set_power_state(VORTEX_PCI(vp), state); -- cgit v1.2.3-59-g8ed1b From 0b3b4fea0a50cc669acc8634806c2ecd6474f68c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 1 Sep 2010 11:24:42 -0400 Subject: drm/radeon/kms: remove useless clock code This code was originally for forcing some clocks on certain asics. However, this code was later moved to asic specific functions for all of the affected asics. The only users of the original code at this point were r600, rv770, and evergreen and the code was not relevant for those asics. So, remove it. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 9 ------ drivers/gpu/drm/radeon/r600.c | 9 ------ drivers/gpu/drm/radeon/radeon.h | 2 -- drivers/gpu/drm/radeon/radeon_asic.c | 18 ------------ drivers/gpu/drm/radeon/radeon_clocks.c | 50 ---------------------------------- drivers/gpu/drm/radeon/radeon_mode.h | 1 - drivers/gpu/drm/radeon/rv770.c | 9 ------ 7 files changed, 98 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 957d5067ad9c..fe31b0db1e9c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2054,11 +2054,6 @@ int evergreen_resume(struct radeon_device *rdev) */ /* post card */ atom_asic_init(rdev->mode_info.atom_context); - /* Initialize clocks */ - r = radeon_clocks_init(rdev); - if (r) { - return r; - } r = evergreen_startup(rdev); if (r) { @@ -2164,9 +2159,6 @@ int evergreen_init(struct radeon_device *rdev) radeon_surface_init(rdev); /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - r = radeon_clocks_init(rdev); - if (r) - return r; /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -2236,7 +2228,6 @@ void evergreen_fini(struct radeon_device *rdev) evergreen_pcie_gart_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); - radeon_clocks_fini(rdev); radeon_agp_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index aee8376216a2..04f134d1aae7 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2489,11 +2489,6 @@ int r600_resume(struct radeon_device *rdev) */ /* post card */ atom_asic_init(rdev->mode_info.atom_context); - /* Initialize clocks */ - r = radeon_clocks_init(rdev); - if (r) { - return r; - } r = r600_startup(rdev); if (r) { @@ -2586,9 +2581,6 @@ int r600_init(struct radeon_device *rdev) radeon_surface_init(rdev); /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - r = radeon_clocks_init(rdev); - if (r) - return r; /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -2663,7 +2655,6 @@ void r600_fini(struct radeon_device *rdev) radeon_agp_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); - radeon_clocks_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); kfree(rdev->bios); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e90d9e3765b4..a168d644bf9e 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1339,8 +1339,6 @@ extern bool radeon_card_posted(struct radeon_device *rdev); extern void radeon_update_bandwidth_info(struct radeon_device *rdev); extern void radeon_update_display_priority(struct radeon_device *rdev); extern bool radeon_boot_test_post_card(struct radeon_device *rdev); -extern int radeon_clocks_init(struct radeon_device *rdev); -extern void radeon_clocks_fini(struct radeon_device *rdev); extern void radeon_scratch_init(struct radeon_device *rdev); extern void radeon_surface_init(struct radeon_device *rdev); extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index a21bf88e8c2d..25e1dd197791 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -858,21 +858,3 @@ int radeon_asic_init(struct radeon_device *rdev) return 0; } -/* - * Wrapper around modesetting bits. Move to radeon_clocks.c? - */ -int radeon_clocks_init(struct radeon_device *rdev) -{ - int r; - - r = radeon_static_clocks_init(rdev->ddev); - if (r) { - return r; - } - DRM_INFO("Clocks initialized !\n"); - return 0; -} - -void radeon_clocks_fini(struct radeon_device *rdev) -{ -} diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index 690d8907135a..5249af8931e6 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -905,53 +905,3 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) } } -static void radeon_apply_clock_quirks(struct radeon_device *rdev) -{ - uint32_t tmp; - - /* XXX make sure engine is idle */ - - if (rdev->family < CHIP_RS600) { - tmp = RREG32_PLL(RADEON_SCLK_CNTL); - if (ASIC_IS_R300(rdev) || ASIC_IS_RV100(rdev)) - tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP; - if ((rdev->family == CHIP_RV250) - || (rdev->family == CHIP_RV280)) - tmp |= - RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_DISP2; - if ((rdev->family == CHIP_RV350) - || (rdev->family == CHIP_RV380)) - tmp |= R300_SCLK_FORCE_VAP; - if (rdev->family == CHIP_R420) - tmp |= R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX; - WREG32_PLL(RADEON_SCLK_CNTL, tmp); - } else if (rdev->family < CHIP_R600) { - tmp = RREG32_PLL(AVIVO_CP_DYN_CNTL); - tmp |= AVIVO_CP_FORCEON; - WREG32_PLL(AVIVO_CP_DYN_CNTL, tmp); - - tmp = RREG32_PLL(AVIVO_E2_DYN_CNTL); - tmp |= AVIVO_E2_FORCEON; - WREG32_PLL(AVIVO_E2_DYN_CNTL, tmp); - - tmp = RREG32_PLL(AVIVO_IDCT_DYN_CNTL); - tmp |= AVIVO_IDCT_FORCEON; - WREG32_PLL(AVIVO_IDCT_DYN_CNTL, tmp); - } -} - -int radeon_static_clocks_init(struct drm_device *dev) -{ - struct radeon_device *rdev = dev->dev_private; - - /* XXX make sure engine is idle */ - - if (radeon_dynclks != -1) { - if (radeon_dynclks) { - if (rdev->asic->set_clock_gating) - radeon_set_clock_gating(rdev, 1); - } - } - radeon_apply_clock_quirks(rdev); - return 0; -} diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 8f93e2b4b0c8..efbe975312dc 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -600,7 +600,6 @@ extern bool radeon_get_atom_connector_info_from_supported_devices_table(struct d void radeon_enc_destroy(struct drm_encoder *encoder); void radeon_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj); void radeon_combios_asic_init(struct drm_device *dev); -extern int radeon_static_clocks_init(struct drm_device *dev); bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index a84e38643788..bfa59db374d2 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1074,11 +1074,6 @@ int rv770_resume(struct radeon_device *rdev) */ /* post card */ atom_asic_init(rdev->mode_info.atom_context); - /* Initialize clocks */ - r = radeon_clocks_init(rdev); - if (r) { - return r; - } r = rv770_startup(rdev); if (r) { @@ -1169,9 +1164,6 @@ int rv770_init(struct radeon_device *rdev) radeon_surface_init(rdev); /* Initialize clocks */ radeon_get_clock_info(rdev->ddev); - r = radeon_clocks_init(rdev); - if (r) - return r; /* Fence driver */ r = radeon_fence_driver_init(rdev); if (r) @@ -1249,7 +1241,6 @@ void rv770_fini(struct radeon_device *rdev) rv770_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); - radeon_clocks_fini(rdev); radeon_agp_fini(rdev); radeon_bo_fini(rdev); radeon_atombios_fini(rdev); -- cgit v1.2.3-59-g8ed1b From 0d9958b18e10d7426d94cc3dd024920a40db3ee2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 1 Sep 2010 12:03:37 -0400 Subject: drm/radeon/kms: force legacy pll algo for RV515 LVDS There has been periodic evidence that LVDS, on at least some panels, prefers the dividers selected by the legacy pll algo. This patch forces the use of the legacy pll algo on RV515 LVDS panels. The old behavior (new pll algo) can be selected by setting the new_pll module parameter to 1. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 577239a24fd5..977f5c20ef1b 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -534,6 +534,20 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, pll->algo = PLL_ALGO_LEGACY; pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; } + /* There is some evidence (often anecdotal) that RV515 LVDS + * (on some boards at least) prefers the legacy algo. I'm not + * sure whether this should handled generically or on a + * case-by-case quirk basis. Both algos should work fine in the + * majority of cases. + */ + if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && + (rdev->family == CHIP_RV515)) { + /* allow the user to overrride just in case */ + if (radeon_new_pll == 1) + pll->algo = PLL_ALGO_NEW; + else + pll->algo = PLL_ALGO_LEGACY; + } } else { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; -- cgit v1.2.3-59-g8ed1b From cf4c12f9a2289e3679722590e1226ae8deb14385 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 1 Sep 2010 17:15:06 -0400 Subject: drm/radeon/kms: fix tv module parameter The tv parameter was added to disable the tv-out connector, however, it caused a crash if it was set to 0 due to drm_connector_init not getting called. If tv=0, don't attempt to add the connector. Might fix: https://bugzilla.kernel.org/show_bug.cgi?id=17241 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 78 ++++++++++++++++-------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 1a5ee392e9c7..a9dd7847d96e 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1051,10 +1051,16 @@ radeon_add_atom_connector(struct drm_device *dev, uint32_t subpixel_order = SubPixelNone; bool shared_ddc = false; - /* fixme - tv/cv/din */ if (connector_type == DRM_MODE_CONNECTOR_Unknown) return; + /* if the user selected tv=0 don't try and add the connector */ + if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) || + (connector_type == DRM_MODE_CONNECTOR_Composite) || + (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) && + (radeon_tv == 0)) + return; + /* see if we already added it */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { radeon_connector = to_radeon_connector(connector); @@ -1209,19 +1215,17 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: case DRM_MODE_CONNECTOR_9PinDIN: - if (radeon_tv == 1) { - drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); - drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); - radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, - rdev->mode_info.load_detect_property, - 1); - drm_connector_attach_property(&radeon_connector->base, - rdev->mode_info.tv_std_property, - radeon_atombios_get_tv_info(rdev)); - /* no HPD on analog connectors */ - radeon_connector->hpd.hpd = RADEON_HPD_NONE; - } + drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); + radeon_connector->dac_load_detect = true; + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + 1); + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.tv_std_property, + radeon_atombios_get_tv_info(rdev)); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; break; case DRM_MODE_CONNECTOR_LVDS: radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); @@ -1272,10 +1276,16 @@ radeon_add_legacy_connector(struct drm_device *dev, struct radeon_connector *radeon_connector; uint32_t subpixel_order = SubPixelNone; - /* fixme - tv/cv/din */ if (connector_type == DRM_MODE_CONNECTOR_Unknown) return; + /* if the user selected tv=0 don't try and add the connector */ + if (((connector_type == DRM_MODE_CONNECTOR_SVIDEO) || + (connector_type == DRM_MODE_CONNECTOR_Composite) || + (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) && + (radeon_tv == 0)) + return; + /* see if we already added it */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { radeon_connector = to_radeon_connector(connector); @@ -1347,26 +1357,24 @@ radeon_add_legacy_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: case DRM_MODE_CONNECTOR_9PinDIN: - if (radeon_tv == 1) { - drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); - drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); - radeon_connector->dac_load_detect = true; - /* RS400,RC410,RS480 chipset seems to report a lot - * of false positive on load detect, we haven't yet - * found a way to make load detect reliable on those - * chipset, thus just disable it for TV. - */ - if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) - radeon_connector->dac_load_detect = false; - drm_connector_attach_property(&radeon_connector->base, - rdev->mode_info.load_detect_property, - radeon_connector->dac_load_detect); - drm_connector_attach_property(&radeon_connector->base, - rdev->mode_info.tv_std_property, - radeon_combios_get_tv_info(rdev)); - /* no HPD on analog connectors */ - radeon_connector->hpd.hpd = RADEON_HPD_NONE; - } + drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); + radeon_connector->dac_load_detect = true; + /* RS400,RC410,RS480 chipset seems to report a lot + * of false positive on load detect, we haven't yet + * found a way to make load detect reliable on those + * chipset, thus just disable it for TV. + */ + if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) + radeon_connector->dac_load_detect = false; + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.load_detect_property, + radeon_connector->dac_load_detect); + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.tv_std_property, + radeon_combios_get_tv_info(rdev)); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; break; case DRM_MODE_CONNECTOR_LVDS: drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); -- cgit v1.2.3-59-g8ed1b From 95347871865ca5093c7e87a223274f7c3b5eccda Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 1 Sep 2010 17:20:42 -0400 Subject: drm/radeon/kms: properly set crtc high base on r7xx Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 977f5c20ef1b..71b31509afc9 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1070,11 +1070,11 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, if (rdev->family >= CHIP_RV770) { if (radeon_crtc->crtc_id) { - WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); - WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); + WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); + WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); } else { - WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0); - WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0); + WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); + WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(fb_location)); } } WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, -- cgit v1.2.3-59-g8ed1b From 87f94b4e91dc042620c527f3c30c37e5127ef757 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 1 Sep 2010 18:06:39 -0700 Subject: bridge: Clear INET control block of SKBs passed into ip_fragment(). In a similar vain to commit 17762060c25590bfddd68cc1131f28ec720f405f ("bridge: Clear IPCB before possible entry into IP stack") Any time we call into the IP stack we have to make sure the state there is as expected by the ipv4 code. With help from Eric Dumazet and Herbert Xu. Reported-by: Bandan Das Signed-off-by: David S. Miller --- net/bridge/br_netfilter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 5ed00bd7009f..137f23259a93 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -761,9 +761,11 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb) { if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) && skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu && - !skb_is_gso(skb)) + !skb_is_gso(skb)) { + /* BUG: Should really parse the IP options here. */ + memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); return ip_fragment(skb, br_dev_queue_push_xmit); - else + } else return br_dev_queue_push_xmit(skb); } #else -- cgit v1.2.3-59-g8ed1b From 3d3be4333fdf6faa080947b331a6a19bce1a4f57 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 1 Sep 2010 00:50:51 +0000 Subject: gro: fix different skb headrooms Packets entering GRO might have different headrooms, even for a given flow (because of implementation details in drivers, like copybreak). We cant force drivers to deliver packets with a fixed headroom. 1) fix skb_segment() skb_segment() makes the false assumption headrooms of fragments are same than the head. When CHECKSUM_PARTIAL is used, this can give csum_start errors, and crash later in skb_copy_and_csum_dev() 2) allocate a minimal skb for head of frag_list skb_gro_receive() uses netdev_alloc_skb(headroom + skb_gro_offset(p)) to allocate a fresh skb. This adds NET_SKB_PAD to a padding already provided by netdevice, depending on various things, like copybreak. Use alloc_skb() to allocate an exact padding, to reduce cache line needs: NET_SKB_PAD + NET_IP_ALIGN bugzilla : https://bugzilla.kernel.org/show_bug.cgi?id=16626 Many thanks to Plamen Petrov, testing many debugging patches ! With help of Jarek Poplawski. Reported-by: Plamen Petrov Signed-off-by: Eric Dumazet CC: Jarek Poplawski Signed-off-by: David S. Miller --- net/core/skbuff.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3a2513f0d0c3..26396ff67cf9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2573,6 +2573,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) __copy_skb_header(nskb, skb); nskb->mac_len = skb->mac_len; + /* nskb and skb might have different headroom */ + if (nskb->ip_summed == CHECKSUM_PARTIAL) + nskb->csum_start += skb_headroom(nskb) - headroom; + skb_reset_mac_header(nskb); skb_set_network_header(nskb, skb->mac_len); nskb->transport_header = (nskb->network_header + @@ -2702,8 +2706,8 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) } else if (skb_gro_len(p) != pinfo->gso_size) return -E2BIG; - headroom = skb_headroom(p); - nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p)); + headroom = NET_SKB_PAD + NET_IP_ALIGN; + nskb = alloc_skb(headroom + skb_gro_offset(p), GFP_ATOMIC); if (unlikely(!nskb)) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From ea39302b87b8d944d567ef29c0647c09da5743fa Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 27 Aug 2010 16:04:29 -0400 Subject: drm/radeon/kms/evergreen: work around bad data in some i2c tables The 7th entry in a lot of evergreen i2c gpio tables is partially zeroed. Fix the entry. Should fix the missing ddc entry in: https://bugs.freedesktop.org/show_bug.cgi?id=29255 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 61141981880d..ebae14c4b768 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -85,6 +85,19 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev for (i = 0; i < num_indices; i++) { gpio = &i2c_info->asGPIO_Info[i]; + /* some evergreen boards have bad data for this entry */ + if (ASIC_IS_DCE4(rdev)) { + if ((i == 7) && + (gpio->usClkMaskRegisterIndex == 0x1936) && + (gpio->sucI2cId.ucAccess == 0)) { + gpio->sucI2cId.ucAccess = 0x97; + gpio->ucDataMaskShift = 8; + gpio->ucDataEnShift = 8; + gpio->ucDataY_Shift = 8; + gpio->ucDataA_Shift = 8; + } + } + if (gpio->sucI2cId.ucAccess == id) { i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; @@ -147,6 +160,20 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) for (i = 0; i < num_indices; i++) { gpio = &i2c_info->asGPIO_Info[i]; i2c.valid = false; + + /* some evergreen boards have bad data for this entry */ + if (ASIC_IS_DCE4(rdev)) { + if ((i == 7) && + (gpio->usClkMaskRegisterIndex == 0x1936) && + (gpio->sucI2cId.ucAccess == 0)) { + gpio->sucI2cId.ucAccess = 0x97; + gpio->ucDataMaskShift = 8; + gpio->ucDataEnShift = 8; + gpio->ucDataY_Shift = 8; + gpio->ucDataA_Shift = 8; + } + } + i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; -- cgit v1.2.3-59-g8ed1b From 9bc08a45fb117c696e4940cfa1208cb1cc7a2f25 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 2 Sep 2010 15:14:38 +1000 Subject: xfs: improve buffer cache hash scalability When doing large parallel file creates on a 16p machines, large amounts of time is being spent in _xfs_buf_find(). A system wide profile with perf top shows this: 1134740.00 19.3% _xfs_buf_find 733142.00 12.5% __ticket_spin_lock The problem is that the hash contains 45,000 buffers, and the hash table width is only 256 buffers. That means we've got around 200 buffers per chain, and searching it is quite expensive. The hash table size needs to increase. Secondly, every time we do a lookup, we promote the buffer we find to the head of the hash chain. This is causing cachelines to be dirtied and causes invalidation of cachelines across all CPUs that may have walked the hash chain recently. hence every walk of the hash chain is effectively a cold cache walk. Remove the promotion to avoid this invalidation. The results are: 1045043.00 21.2% __ticket_spin_lock 326184.00 6.6% _xfs_buf_find A 70% drop in the CPU usage when looking up buffers. Unfortunately that does not result in an increase in performance underthis workload as contention on the inode_lock soaks up most of the reduction in CPU usage. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/linux-2.6/xfs_buf.c | 8 +------- fs/xfs/linux-2.6/xfs_buf.h | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index ea79072f5210..d72cf2bb054a 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -440,12 +440,7 @@ _xfs_buf_find( ASSERT(btp == bp->b_target); if (bp->b_file_offset == range_base && bp->b_buffer_length == range_length) { - /* - * If we look at something, bring it to the - * front of the list for next time. - */ atomic_inc(&bp->b_hold); - list_move(&bp->b_hash_list, &hash->bh_list); goto found; } } @@ -1443,8 +1438,7 @@ xfs_alloc_bufhash( { unsigned int i; - btp->bt_hashshift = external ? 3 : 8; /* 8 or 256 buckets */ - btp->bt_hashmask = (1 << btp->bt_hashshift) - 1; + btp->bt_hashshift = external ? 3 : 12; /* 8 or 4096 buckets */ btp->bt_hash = kmem_zalloc_large((1 << btp->bt_hashshift) * sizeof(xfs_bufhash_t)); for (i = 0; i < (1 << btp->bt_hashshift); i++) { diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index d072e5ff923b..2a05614f0b92 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -137,7 +137,6 @@ typedef struct xfs_buftarg { size_t bt_smask; /* per device buffer hash table */ - uint bt_hashmask; uint bt_hashshift; xfs_bufhash_t *bt_hash; -- cgit v1.2.3-59-g8ed1b From 048e78a5bc22c27410cb5ca9680c3c7ac400607f Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 2 Sep 2010 08:35:47 +0200 Subject: ALSA: hda - Add a new hp-laptop model for Conexant 5066, tested on HP G60 This new model adds the following functionality to HP G60: - Automute of internal speakers - Autoswitch of internal/external mics - Remove SPDIF not physically present BugLink: http://launchpad.net/bugs/587388 Cc: stable@kernel.org Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_conexant.c | 57 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index ce46fa1e643e..37c6aad5e590 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -296,6 +296,7 @@ Conexant 5051 Conexant 5066 ============= laptop Basic Laptop config (default) + hp-laptop HP laptops, e g G60 dell-laptop Dell laptops dell-vostro Dell Vostro olpc-xo-1_5 OLPC XO 1.5 diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5cdb80edbd7f..4f0619908a30 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -116,6 +116,7 @@ struct conexant_spec { unsigned int dell_vostro:1; unsigned int ideapad:1; unsigned int thinkpad:1; + unsigned int hp_laptop:1; unsigned int ext_mic_present; unsigned int recording; @@ -2299,6 +2300,18 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) } } +/* toggle input of built-in digital mic and mic jack appropriately */ +static void cxt5066_hp_laptop_automic(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_jack_detect(codec, 0x1b); + snd_printdd("CXT5066: external microphone present=%d\n", present); + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, + present ? 1 : 3); +} + + /* toggle input of built-in digital mic and mic jack appropriately order is: external mic -> dock mic -> interal mic */ static void cxt5066_thinkpad_automic(struct hda_codec *codec) @@ -2407,6 +2420,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) } } +/* unsolicited event for jack sensing */ +static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) +{ + snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); + switch (res >> 26) { + case CONEXANT_HP_EVENT: + cxt5066_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5066_hp_laptop_automic(codec); + break; + } +} + /* unsolicited event for jack sensing */ static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) { @@ -2989,6 +3016,14 @@ static struct hda_verb cxt5066_init_verbs_portd_lo[] = { { } /* end */ }; + +static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + { } /* end */ +}; + /* initialize jack-sensing, too */ static int cxt5066_init(struct hda_codec *codec) { @@ -3004,6 +3039,8 @@ static int cxt5066_init(struct hda_codec *codec) cxt5066_ideapad_automic(codec); else if (spec->thinkpad) cxt5066_thinkpad_automic(codec); + else if (spec->hp_laptop) + cxt5066_hp_laptop_automic(codec); } cxt5066_set_mic_boost(codec); return 0; @@ -3031,6 +3068,7 @@ enum { CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ + CXT5066_HP_LAPTOP, /* HP Laptop */ CXT5066_MODELS }; @@ -3041,6 +3079,7 @@ static const char *cxt5066_models[CXT5066_MODELS] = { [CXT5066_DELL_VOSTO] = "dell-vostro", [CXT5066_IDEAPAD] = "ideapad", [CXT5066_THINKPAD] = "thinkpad", + [CXT5066_HP_LAPTOP] = "hp-laptop", }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { @@ -3052,6 +3091,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), @@ -3116,6 +3156,23 @@ static int patch_cxt5066(struct hda_codec *codec) spec->num_init_verbs++; spec->dell_automute = 1; break; + case CXT5066_HP_LAPTOP: + codec->patch_ops.init = cxt5066_init; + codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; + spec->init_verbs[spec->num_init_verbs] = + cxt5066_init_verbs_hp_laptop; + spec->num_init_verbs++; + spec->hp_laptop = 1; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + /* no S/PDIF out */ + spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ + spec->input_mux = NULL; + spec->port_d_mode = 0; + spec->mic_boost = 3; /* default 30dB gain */ + break; + case CXT5066_OLPC_XO_1_5: codec->patch_ops.init = cxt5066_olpc_init; codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; -- cgit v1.2.3-59-g8ed1b From 65f04443c96dbda11b8fff21d6390e082846aa3c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 2 Sep 2010 12:58:25 +0200 Subject: ALSA: usb-audio: fix Fast Track Ultra (8R) 44.1 sample rates The M-Audio Fast Track Ultra series devices did not play sound correctly at 44.1/88.2 kHz. Changing the output endpoint attribute to adaptive fixes this. Signed-off-by: Felix Homann Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 2 -- sound/usb/quirks-table.h | 90 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 1a701f1e8f50..bb9f938558fd 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -404,8 +404,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) break; case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ - case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */ - case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ /* doesn't set the sample rate attribute, but supports it */ fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; break; diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 2e8003f98fca..4818fbdc02fb 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1830,7 +1830,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), USB_DEVICE(0x0763, 0x2080), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { /* .vendor_name = "M-Audio", */ - /* .product_name = "Fast Track Ultra 8", */ + /* .product_name = "Fast Track Ultra", */ .ifnum = QUIRK_ANY_INTERFACE, .type = QUIRK_COMPOSITE, .data = & (const struct snd_usb_audio_quirk[]) { @@ -1840,11 +1840,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, { .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x01, + .ep_attr = 0x09, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, { .ifnum = 2, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x81, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, /* interface 3 (MIDI) is standard compliant */ { @@ -1867,11 +1907,51 @@ YAMAHA_DEVICE(0x7010, "UB99"), }, { .ifnum = 1, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x01, + .ep_attr = 0x09, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, { .ifnum = 2, - .type = QUIRK_AUDIO_STANDARD_INTERFACE + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = & (const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x81, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } }, /* interface 3 (MIDI) is standard compliant */ { -- cgit v1.2.3-59-g8ed1b From 7b6717e144de6592e614fd7fc3b914b6bf686a9d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 2 Sep 2010 17:13:15 +0800 Subject: ALSA: usb-audio: Assume first control interface is for audio For devices with more than one control interface, let's assume the first one contains the audio controls. Unfortunately, there is no field in any of the descriptors to tell us whether a control interface is for audio or MIDI controls, so a better check is not easy to implement. On a composite device with audio and MIDI functions, for example, the code currently overwrites chip->ctrl_intf, causing operations on the control interface to fail if they are issued after the device probe. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/card.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 9feb00c831a0..b443a33d31c9 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -465,7 +465,13 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __error; } - chip->ctrl_intf = alts; + /* + * For devices with more than one control interface, we assume the + * first contains the audio controls. We might need a more specific + * check here in the future. + */ + if (!chip->ctrl_intf) + chip->ctrl_intf = alts; if (err > 0) { /* create normal USB audio interfaces */ -- cgit v1.2.3-59-g8ed1b From 026b5ca3b65f878019a8eb0c7a702cd5c20a4104 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Wed, 1 Sep 2010 14:33:29 +0100 Subject: ARM: 6344/1: Mark CPU_32v6K as depended on CPU_V7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPU_32v6K is selected by CPU_V7 but it only depends on CPU_V6. Signed-off-by: Catalin Marinas Acked-by: Uwe Kleine-König Signed-off-by: Russell King --- arch/arm/mm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 33c3f570aaa0..a0a2928ae4dd 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -398,7 +398,7 @@ config CPU_V6 # ARMv6k config CPU_32v6K bool "Support ARM V6K processor extensions" if !SMP - depends on CPU_V6 + depends on CPU_V6 || CPU_V7 default y if SMP && !(ARCH_MX3 || ARCH_OMAP2) help Say Y here if your ARMv6 processor supports the 'K' extension. -- cgit v1.2.3-59-g8ed1b From 23963e54ce187ca6e907c83176c15508b0f6e60d Mon Sep 17 00:00:00 2001 From: Arkadiusz Mi?kiewicz Date: Thu, 26 Aug 2010 10:19:43 +0000 Subject: xfs: Disallow 32bit project quota id Currently on-disk structure is able to keep only 16bit project quota id, so disallow 32bit ones. This fixes a problem where parts of kernel structures holding project quota id are 32bit while parts (on-disk) are 16bit variables which causes project quota member files to be inaccessible for some operations (like mv/rm). Signed-off-by: Arkadiusz Mi?kiewicz Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_ioctl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 237f5ffb2ee8..4fec427b83ef 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -906,6 +906,13 @@ xfs_ioctl_setattr( if (XFS_FORCED_SHUTDOWN(mp)) return XFS_ERROR(EIO); + /* + * Disallow 32bit project ids because on-disk structure + * is 16bit only. + */ + if ((mask & FSX_PROJID) && (fa->fsx_projid > (__uint16_t)-1)) + return XFS_ERROR(EINVAL); + /* * If disk quotas is on, we make sure that the dquots do exist on disk, * before we start any other transactions. Trying to do this later -- cgit v1.2.3-59-g8ed1b From 65b4711ff513767341aa1915c822de6ec0de65cb Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 2 Sep 2010 09:32:08 +0100 Subject: ARM: 6352/1: perf: fix event validation The validate_event function in the ARM perf events backend has the following problems: 1.) Events that are disabled count towards the cost. 2.) Events associated with other PMUs [for example, software events or breakpoints] do not count towards the cost, but do fail validation, causing the group to fail. This patch changes validate_event so that it ignores events in the PERF_EVENT_STATE_OFF state or that are scheduled for other PMUs. Reported-by: Pawel Moll Acked-by: Jamie Iles Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/perf_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index e2139256524e..ecbb0288e5dd 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -319,8 +319,8 @@ validate_event(struct cpu_hw_events *cpuc, { struct hw_perf_event fake_event = event->hw; - if (event->pmu && event->pmu != &pmu) - return 0; + if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF) + return 1; return armpmu->get_event_idx(cpuc, &fake_event) >= 0; } -- cgit v1.2.3-59-g8ed1b From 5e4e7573e1ec286120109e73bf54cff465488725 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 2 Sep 2010 09:39:09 -0700 Subject: Revert "sky2: don't do GRO on second port" This reverts commit de6be6c1f77798c4da38301693d33aff1cd76e84. After some discussion with Jarek Poplawski and Eric Dumazet, we've decided that this change is incorrect. Signed-off-by: David S. Miller --- drivers/net/sky2.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a6ff113d34bb..194e5cf8c763 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2520,27 +2520,24 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) } } -static inline void sky2_skb_rx(struct napi_struct *napi, - const struct sky2_port *sky2, +static inline void sky2_skb_rx(const struct sky2_port *sky2, u32 status, struct sk_buff *skb) { #ifdef SKY2_VLAN_TAG_USED + u16 vlan_tag = be16_to_cpu(sky2->rx_tag); if (sky2->vlgrp && (status & GMR_FS_VLAN)) { - u16 vlan_tag = be16_to_cpu(sky2->rx_tag); - - if (skb->ip_summed == CHECKSUM_NONE || - sky2->netdev != napi->dev) + if (skb->ip_summed == CHECKSUM_NONE) vlan_hwaccel_receive_skb(skb, sky2->vlgrp, vlan_tag); else - vlan_gro_receive(napi, sky2->vlgrp, vlan_tag, skb); + vlan_gro_receive(&sky2->hw->napi, sky2->vlgrp, + vlan_tag, skb); return; } #endif - if (skb->ip_summed == CHECKSUM_NONE || - sky2->netdev != napi->dev) + if (skb->ip_summed == CHECKSUM_NONE) netif_receive_skb(skb); else - napi_gro_receive(napi, skb); + napi_gro_receive(&sky2->hw->napi, skb); } static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port, @@ -2641,7 +2638,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx) skb->protocol = eth_type_trans(skb, dev); - sky2_skb_rx(&hw->napi, sky2, status, skb); + sky2_skb_rx(sky2, status, skb); /* Stop after net poll weight */ if (++work_done >= to_do) -- cgit v1.2.3-59-g8ed1b From 7bcbf81a2296a8f71342445560dcbe16100b567c Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Wed, 1 Sep 2010 23:07:10 +0000 Subject: ipvs: avoid oops for passive FTP Fix Passive FTP problem in ip_vs_ftp: - Do not oops in nf_nat_set_seq_adjust (adjust_tcp_sequence) when iptable_nat module is not loaded Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- net/netfilter/ipvs/ip_vs_ftp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index f228a17ec649..33b329bfc2d2 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -359,7 +360,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, buf_len = strlen(buf); ct = nf_ct_get(skb, &ctinfo); - if (ct && !nf_ct_is_untracked(ct)) { + if (ct && !nf_ct_is_untracked(ct) && nfct_nat(ct)) { /* If mangling fails this function will return 0 * which will cause the packet to be dropped. * Mangling can only fail under memory pressure, -- cgit v1.2.3-59-g8ed1b From 8f34a430ac16d5fbd9d6b383184d35e152f5a963 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 2 Sep 2010 15:23:16 -0400 Subject: nfsd4: mask out non-access bits in nfs4_access_to_omode This fixes an unnecessary BUG(). Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3dfef0623968..cf0d2ffb3c84 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -440,7 +440,7 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { static int nfs4_access_to_omode(u32 access) { - switch (access) { + switch (access & NFS4_SHARE_ACCESS_BOTH) { case NFS4_SHARE_ACCESS_READ: return O_RDONLY; case NFS4_SHARE_ACCESS_WRITE: -- cgit v1.2.3-59-g8ed1b From d842a93c4b3a20d31f4fb97357e0964210d6066f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 12 Aug 2010 14:31:05 +0200 Subject: [SCSI] fix bio.bi_rw handling Return of the bi_rw tests is no longer bool after commit 74450be1. So testing against constants doesn't make sense anymore. Fix this bug in osd_req_read by removing "== 1" in test. This is not a problem now, where REQ_WRITE is 1, but this can change in the future and we don't want to rely on that. Signed-off-by: Jiri Slaby Signed-off-by: James Bottomley --- drivers/scsi/osd/osd_initiator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index fda4de3440c4..e88bbdde49c5 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -865,7 +865,7 @@ void osd_req_read(struct osd_request *or, { _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len); WARN_ON(or->in.bio || or->in.total_bytes); - WARN_ON(1 == (bio->bi_rw & REQ_WRITE)); + WARN_ON(bio->bi_rw & REQ_WRITE); or->in.bio = bio; or->in.total_bytes = len; } -- cgit v1.2.3-59-g8ed1b From b15d05b0d358cedf9c4d420a60d2ee2d0f530788 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 12 Aug 2010 23:36:06 +0530 Subject: [SCSI] be2iscsi: Fix for Login failure The current code in tree has problems with Login. This patch fixes the Login Failure . Signed-off-by: Jayamohan Kallickal [mnc: Can't believe I missed that.] Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 5 ++--- drivers/scsi/be2iscsi/be_mgmt.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 7d4d2275573c..7f11f3e48e12 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -300,8 +300,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); - int len = 0; - int status; + int status = 0; SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param); switch (param) { @@ -315,7 +314,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, default: return iscsi_host_get_param(shost, param, buf); } - return len; + return status; } int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba) diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 26350e470bcc..877324fc594c 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -368,7 +368,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba, memset(req, 0, sizeof(*req)); wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 1); + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD, sizeof(*req)); -- cgit v1.2.3-59-g8ed1b From 36ed2176fedaa180b8ea3cdacf68c958e0090a3c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 25 Aug 2010 10:44:14 -0500 Subject: [SCSI] hpsa: disable doorbell reset on reset_devices The doorbell reset initially appears to work correctly, the controller resets, comes up, some i/o can even be done, but on at least some Smart Arrays in some servers, it eventually causes a subsequent controller lockup due to some kind of PCIe error, and kdump can end up leaving the root filesystem in an unbootable state. For this reason, until the problem is fixed, or at least isolated to certain hardware enough to be avoided, the doorbell reset should not be used at all. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4f5551b5fe53..c5d0606ad097 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3231,6 +3231,12 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) misc_fw_support = readl(&cfgtable->misc_fw_support); use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; + /* The doorbell reset seems to cause lockups on some Smart + * Arrays (e.g. P410, P410i, maybe others). Until this is + * fixed or at least isolated, avoid the doorbell reset. + */ + use_doorbell = 0; + rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell); if (rc) goto unmap_cfgtable; -- cgit v1.2.3-59-g8ed1b From 6f131ce1dfa9b283ddc212df42b015d152c670a5 Mon Sep 17 00:00:00 2001 From: Jean Sacren Date: Wed, 25 Aug 2010 17:58:09 -0600 Subject: [SCSI] Fix warning: zero-length gnu_printf format string warning: zero-length gnu_printf format string Fix the above warning by inserting a space into the literal string. Signed-off-by: Jean Sacren Signed-off-by: James Bottomley --- drivers/scsi/constants.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index cd05e049d5f6..d0c82340f0e2 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1404,13 +1404,13 @@ void scsi_print_sense(char *name, struct scsi_cmnd *cmd) { struct scsi_sense_hdr sshdr; - scmd_printk(KERN_INFO, cmd, ""); + scmd_printk(KERN_INFO, cmd, " "); scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sshdr); scsi_show_sense_hdr(&sshdr); scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sshdr); - scmd_printk(KERN_INFO, cmd, ""); + scmd_printk(KERN_INFO, cmd, " "); scsi_show_extd_sense(sshdr.asc, sshdr.ascq); } EXPORT_SYMBOL(scsi_print_sense); @@ -1453,7 +1453,7 @@ EXPORT_SYMBOL(scsi_show_result); void scsi_print_result(struct scsi_cmnd *cmd) { - scmd_printk(KERN_INFO, cmd, ""); + scmd_printk(KERN_INFO, cmd, " "); scsi_show_result(cmd->result); } EXPORT_SYMBOL(scsi_print_result); -- cgit v1.2.3-59-g8ed1b From 0b5d404e349c0236b11466c0a4785520c0be6982 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Thu, 2 Sep 2010 13:22:11 -0700 Subject: pkt_sched: Fix lockdep warning on est_tree_lock in gen_estimator This patch fixes a lockdep warning: [ 516.287584] ========================================================= [ 516.288386] [ INFO: possible irq lock inversion dependency detected ] [ 516.288386] 2.6.35b #7 [ 516.288386] --------------------------------------------------------- [ 516.288386] swapper/0 just changed the state of lock: [ 516.288386] (&qdisc_tx_lock){+.-...}, at: [] est_timer+0x62/0x1b4 [ 516.288386] but this lock took another, SOFTIRQ-unsafe lock in the past: [ 516.288386] (est_tree_lock){+.+...} [ 516.288386] [ 516.288386] and interrupts could create inverse lock ordering between them. ... So, est_tree_lock needs BH protection because it's taken by qdisc_tx_lock, which is used both in BH and process contexts. (Full warning with this patch at netdev, 02 Sep 2010.) Fixes commit: ae638c47dc040b8def16d05dc6acdd527628f231 ("pkt_sched: gen_estimator: add a new lock") Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/core/gen_estimator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 9fbe7f7429b0..6743146e4d6b 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -232,7 +232,7 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, est->last_packets = bstats->packets; est->avpps = rate_est->pps<<10; - spin_lock(&est_tree_lock); + spin_lock_bh(&est_tree_lock); if (!elist[idx].timer.function) { INIT_LIST_HEAD(&elist[idx].list); setup_timer(&elist[idx].timer, est_timer, idx); @@ -243,7 +243,7 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, list_add_rcu(&est->list, &elist[idx].list); gen_add_node(est); - spin_unlock(&est_tree_lock); + spin_unlock_bh(&est_tree_lock); return 0; } @@ -270,7 +270,7 @@ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, { struct gen_estimator *e; - spin_lock(&est_tree_lock); + spin_lock_bh(&est_tree_lock); while ((e = gen_find_node(bstats, rate_est))) { rb_erase(&e->node, &est_root); @@ -281,7 +281,7 @@ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, list_del_rcu(&e->list); call_rcu(&e->e_rcu, __gen_kill_estimator); } - spin_unlock(&est_tree_lock); + spin_unlock_bh(&est_tree_lock); } EXPORT_SYMBOL(gen_kill_estimator); @@ -320,9 +320,9 @@ bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, ASSERT_RTNL(); - spin_lock(&est_tree_lock); + spin_lock_bh(&est_tree_lock); res = gen_find_node(bstats, rate_est) != NULL; - spin_unlock(&est_tree_lock); + spin_unlock_bh(&est_tree_lock); return res; } -- cgit v1.2.3-59-g8ed1b From 2e4c332913b5d39fef686b3964098f0d8fd97ead Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 31 Aug 2010 13:35:31 -0700 Subject: [SCSI] sd, sym53c8xx: Remove warnings after vsprintf %pV introducation. GCC warns about empty printf format strings, and after the addition of %pV these existing such cases in the scsi driver layer were exposed enough for the compiler to start seeing them. Based almost entirely upon a patch by Joe Perches. [jejb: fix up sym53c8xx msg] Signed-off-by: David S. Miller Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 6 +++--- drivers/scsi/sym53c8xx_2/sym_hipd.c | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2714becc2eaf..cd71f46a3d47 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2625,15 +2625,15 @@ module_exit(exit_sd); static void sd_print_sense_hdr(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr) { - sd_printk(KERN_INFO, sdkp, ""); + sd_printk(KERN_INFO, sdkp, " "); scsi_show_sense_hdr(sshdr); - sd_printk(KERN_INFO, sdkp, ""); + sd_printk(KERN_INFO, sdkp, " "); scsi_show_extd_sense(sshdr->asc, sshdr->ascq); } static void sd_print_result(struct scsi_disk *sdkp, int result) { - sd_printk(KERN_INFO, sdkp, ""); + sd_printk(KERN_INFO, sdkp, " "); scsi_show_result(result); } diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index a7bc8b7b09ac..2c3e89ddf069 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -72,10 +72,7 @@ static void sym_printl_hex(u_char *p, int n) static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg) { - if (label) - sym_print_addr(cp->cmd, "%s: ", label); - else - sym_print_addr(cp->cmd, ""); + sym_print_addr(cp->cmd, "%s: ", label); spi_print_msg(msg); printf("\n"); @@ -4558,7 +4555,8 @@ static void sym_int_sir(struct sym_hcb *np) switch (np->msgin [2]) { case M_X_MODIFY_DP: if (DEBUG_FLAGS & DEBUG_POINTER) - sym_print_msg(cp, NULL, np->msgin); + sym_print_msg(cp, "extended msg ", + np->msgin); tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + (np->msgin[5]<<8) + (np->msgin[6]); sym_modify_dp(np, tp, cp, tmp); @@ -4585,7 +4583,7 @@ static void sym_int_sir(struct sym_hcb *np) */ case M_IGN_RESIDUE: if (DEBUG_FLAGS & DEBUG_POINTER) - sym_print_msg(cp, NULL, np->msgin); + sym_print_msg(cp, "1 or 2 byte ", np->msgin); if (cp->host_flags & HF_SENSE) OUTL_DSP(np, SCRIPTA_BA(np, clrack)); else -- cgit v1.2.3-59-g8ed1b From dc4e96ce2dceb649224ee84f83592aac8c54c9b7 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Sat, 28 Aug 2010 13:35:05 +0000 Subject: RDMA/cxgb3: Don't exceed the max HW CQ depth The max depth supported by T3 is 64K entries. This fixes a bug introduced in commit 9918b28d ("RDMA/cxgb3: Increase the max CQ depth") that causes stalls and possibly crashes in large MPI clusters. Signed-off-by: Steve Wise Cc: Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb3/cxio_hal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index 8f0caf7d4482..78fbe9ffe7f0 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -53,7 +53,7 @@ #define T3_MAX_PBL_SIZE 256 #define T3_MAX_RQ_SIZE 1024 #define T3_MAX_QP_DEPTH (T3_MAX_RQ_SIZE-1) -#define T3_MAX_CQ_DEPTH 262144 +#define T3_MAX_CQ_DEPTH 65536 #define T3_MAX_NUM_STAG (1<<15) #define T3_MAX_MR_SIZE 0x100000000ULL #define T3_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */ -- cgit v1.2.3-59-g8ed1b From 3ba6462355c1c69dde58739a871d13bbb993e2e3 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 28 Aug 2010 17:56:33 +0200 Subject: drm/nouveau: Take fence spinlock before reading the last sequence. It fixes a race between the TTM delayed work queue and the GEM IOCTLs (fdo bug 29583) uncovered by the BKL removal. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fence.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 6b208ffafa8d..87ac21ec23d2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -64,16 +64,17 @@ nouveau_fence_update(struct nouveau_channel *chan) struct nouveau_fence *fence; uint32_t sequence; + spin_lock(&chan->fence.lock); + if (USE_REFCNT) sequence = nvchan_rd32(chan, 0x48); else sequence = atomic_read(&chan->fence.last_sequence_irq); if (chan->fence.sequence_ack == sequence) - return; + goto out; chan->fence.sequence_ack = sequence; - spin_lock(&chan->fence.lock); list_for_each_safe(entry, tmp, &chan->fence.pending) { fence = list_entry(entry, struct nouveau_fence, entry); @@ -85,6 +86,7 @@ nouveau_fence_update(struct nouveau_channel *chan) if (sequence == chan->fence.sequence_ack) break; } +out: spin_unlock(&chan->fence.lock); } -- cgit v1.2.3-59-g8ed1b From 374c3af880ef260f36dfc968d9725494666dff31 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 29 Aug 2010 12:21:16 +0200 Subject: drm/nouveau: Don't take struct_mutex around the pushbuf IOCTL. We don't need it and it can lead to lock order inversions with respect to drm_global_mutex, potentially causing dead locks. Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_gem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 93711dfcafc1..10cace94395c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -245,7 +245,7 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence) list_del(&nvbo->entry); nvbo->reserved_by = NULL; ttm_bo_unreserve(&nvbo->bo); - drm_gem_object_unreference(nvbo->gem); + drm_gem_object_unreference_unlocked(nvbo->gem); } } @@ -300,7 +300,7 @@ retry: validate_fini(op, NULL); if (ret == -EAGAIN) ret = ttm_bo_wait_unreserved(&nvbo->bo, false); - drm_gem_object_unreference(gem); + drm_gem_object_unreference_unlocked(gem); if (ret) { NV_ERROR(dev, "fail reserve\n"); return ret; @@ -616,8 +616,6 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, return PTR_ERR(bo); } - mutex_lock(&dev->struct_mutex); - /* Mark push buffers as being used on PFIFO, the validation code * will then make sure that if the pushbuf bo moves, that they * happen on the kernel channel, which will in turn cause a sync @@ -731,7 +729,6 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, out: validate_fini(&op, fence); nouveau_fence_unref((void**)&fence); - mutex_unlock(&dev->struct_mutex); kfree(bo); kfree(push); -- cgit v1.2.3-59-g8ed1b From 615661f3948a066fd22a36fe8ea0c528b75ee373 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 22 Aug 2010 20:54:08 +0200 Subject: drm/nv50: initialize ramht_refs list for faked 0 channel We need it for PFIFO_INTR_CACHE_ERROR interrupt handling, because nouveau_fifo_swmthd looks for matching gpuobj in ramht_refs list. It fixes kernel panic in nouveau_gpuobj_ref_find. Signed-off-by: Marcin Slusarz Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_instmem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index c95bf9b681dd..91ef93cf1f35 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -139,6 +139,8 @@ nv50_instmem_init(struct drm_device *dev) chan->file_priv = (struct drm_file *)-2; dev_priv->fifos[0] = dev_priv->fifos[127] = chan; + INIT_LIST_HEAD(&chan->ramht_refs); + /* Channel's PRAMIN object + heap */ ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0, NULL, &chan->ramin); -- cgit v1.2.3-59-g8ed1b From 72656c46f50b8dfe50e15793692982e636e3df20 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 3 Sep 2010 12:19:33 +1000 Subject: xfs: prevent 32bit overflow in space reservation If we attempt to preallocate more than 2^32 blocks of space in a single syscall, the transaction block reservation will overflow leading to a hangs in the superblock block accounting code. This is trivially reproduced with xfs_io. Fix the problem by capping the allocation reservation to the maximum number of blocks a single xfs_bmapi() call can allocate (2^21 blocks). Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig --- fs/xfs/xfs_vnodeops.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 66d585c6917c..4c7c7bfb2b2f 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -2299,15 +2299,22 @@ xfs_alloc_file_space( e = allocatesize_fsb; } + /* + * The transaction reservation is limited to a 32-bit block + * count, hence we need to limit the number of blocks we are + * trying to reserve to avoid an overflow. We can't allocate + * more than @nimaps extents, and an extent is limited on disk + * to MAXEXTLEN (21 bits), so use that to enforce the limit. + */ + resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps)); if (unlikely(rt)) { - resrtextents = qblocks = (uint)(e - s); + resrtextents = qblocks = resblks; resrtextents /= mp->m_sb.sb_rextsize; resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); quota_flag = XFS_QMOPT_RES_RTBLKS; } else { resrtextents = 0; - resblks = qblocks = \ - XFS_DIOSTRAT_SPACE_RES(mp, (uint)(e - s)); + resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks); quota_flag = XFS_QMOPT_RES_REGBLKS; } -- cgit v1.2.3-59-g8ed1b From 2e556b5b320838fde98480a1f6cf220a5af200fc Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Thu, 2 Sep 2010 15:07:47 -0400 Subject: perf, x86: Fix accidentally ack'ing a second event on intel perf counter During testing of a patch to stop having the perf subsytem swallow nmis, it was uncovered that Nehalem boxes were randomly getting unknown nmis when using the perf tool. Moving the ack'ing of the PMI closer to when we get the status allows the hardware to properly re-set the PMU bit signaling another PMI was triggered during the processing of the first PMI. This allows the new logic for dealing with the shortcomings of multiple PMIs to handle the extra NMI by 'eat'ing it later. Now one can wonder why are we getting a second PMI when we disable all the PMUs in the begining of the NMI handler to prevent such a case, for that I do not know. But I know the fix below helps deal with this quirk. Tested on multiple Nehalems where the problem was occuring. With the patch, the code now loops a second time to handle the second PMI (whereas before it was not). Signed-off-by: Don Zickus Cc: peterz@infradead.org Cc: robert.richter@amd.com Cc: gorcunov@gmail.com Cc: fweisbec@gmail.com Cc: ying.huang@intel.com Cc: ming.m.lin@intel.com Cc: eranian@google.com LKML-Reference: <1283454469-1909-2-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index d8d86d014008..1297bf15cb88 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -712,7 +712,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) struct perf_sample_data data; struct cpu_hw_events *cpuc; int bit, loops; - u64 ack, status; + u64 status; perf_sample_data_init(&data, 0); @@ -728,6 +728,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) loops = 0; again: + intel_pmu_ack_status(status); if (++loops > 100) { WARN_ONCE(1, "perfevents: irq loop stuck!\n"); perf_event_print_debug(); @@ -736,7 +737,6 @@ again: } inc_irq_stat(apic_perf_irqs); - ack = status; intel_pmu_lbr_read(); @@ -761,8 +761,6 @@ again: x86_pmu_stop(event); } - intel_pmu_ack_status(ack); - /* * Repeat if there is more work to be done: */ -- cgit v1.2.3-59-g8ed1b From de725dec9de7a7541996176d59cf8542365b8b0e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 2 Sep 2010 15:07:49 -0400 Subject: perf, x86: Fix handle_irq return values Now that we rely on the number of handled overflows, ensure all handle_irq implementations actually return the right number. Signed-off-by: Peter Zijlstra Signed-off-by: Don Zickus Cc: peterz@infradead.org Cc: robert.richter@amd.com Cc: gorcunov@gmail.com Cc: fweisbec@gmail.com Cc: ying.huang@intel.com Cc: ming.m.lin@intel.com Cc: eranian@google.com LKML-Reference: <1283454469-1909-4-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 9 +++++++-- arch/x86/kernel/cpu/perf_event_p4.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 1297bf15cb88..ee05c90012d2 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -713,6 +713,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs) struct cpu_hw_events *cpuc; int bit, loops; u64 status; + int handled = 0; perf_sample_data_init(&data, 0); @@ -743,12 +744,16 @@ again: /* * PEBS overflow sets bit 62 in the global status register */ - if (__test_and_clear_bit(62, (unsigned long *)&status)) + if (__test_and_clear_bit(62, (unsigned long *)&status)) { + handled++; x86_pmu.drain_pebs(regs); + } for_each_set_bit(bit, (unsigned long *)&status, X86_PMC_IDX_MAX) { struct perf_event *event = cpuc->events[bit]; + handled++; + if (!test_bit(bit, cpuc->active_mask)) continue; @@ -770,7 +775,7 @@ again: done: intel_pmu_enable_all(0); - return 1; + return handled; } static struct event_constraint * diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index 7e578e9cc58b..b560db3305be 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c @@ -692,7 +692,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs) inc_irq_stat(apic_perf_irqs); } - return handled > 0; + return handled; } /* -- cgit v1.2.3-59-g8ed1b From 4177c42a6301a34c20038ec2771a33dcc30bb338 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 2 Sep 2010 15:07:48 -0400 Subject: perf, x86: Try to handle unknown nmis with an enabled PMU When the PMU is enabled it is valid to have unhandled nmis, two events could trigger 'simultaneously' raising two back-to-back NMIs. If the first NMI handles both, the latter will be empty and daze the CPU. The solution to avoid an 'unknown nmi' massage in this case was simply to stop the nmi handler chain when the PMU is enabled by stating the nmi was handled. This has the drawback that a) we can not detect unknown nmis anymore, and b) subsequent nmi handlers are not called. This patch addresses this. Now, we check this unknown NMI if it could be a PMU back-to-back NMI. Otherwise we pass it and let the kernel handle the unknown nmi. This is a debug log: cpu #6, nmi #32333, skip_nmi #32330, handled = 1, time = 1934364430 cpu #6, nmi #32334, skip_nmi #32330, handled = 1, time = 1934704616 cpu #6, nmi #32335, skip_nmi #32336, handled = 2, time = 1936032320 cpu #6, nmi #32336, skip_nmi #32336, handled = 0, time = 1936034139 cpu #6, nmi #32337, skip_nmi #32336, handled = 1, time = 1936120100 cpu #6, nmi #32338, skip_nmi #32336, handled = 1, time = 1936404607 cpu #6, nmi #32339, skip_nmi #32336, handled = 1, time = 1937983416 cpu #6, nmi #32340, skip_nmi #32341, handled = 2, time = 1938201032 cpu #6, nmi #32341, skip_nmi #32341, handled = 0, time = 1938202830 cpu #6, nmi #32342, skip_nmi #32341, handled = 1, time = 1938443743 cpu #6, nmi #32343, skip_nmi #32341, handled = 1, time = 1939956552 cpu #6, nmi #32344, skip_nmi #32341, handled = 1, time = 1940073224 cpu #6, nmi #32345, skip_nmi #32341, handled = 1, time = 1940485677 cpu #6, nmi #32346, skip_nmi #32347, handled = 2, time = 1941947772 cpu #6, nmi #32347, skip_nmi #32347, handled = 1, time = 1941949818 cpu #6, nmi #32348, skip_nmi #32347, handled = 0, time = 1941951591 Uhhuh. NMI received for unknown reason 00 on CPU 6. Do you have a strange power saving mode enabled? Dazed and confused, but trying to continue Deltas: nmi #32334 340186 nmi #32335 1327704 nmi #32336 1819 <<<< back-to-back nmi [1] nmi #32337 85961 nmi #32338 284507 nmi #32339 1578809 nmi #32340 217616 nmi #32341 1798 <<<< back-to-back nmi [2] nmi #32342 240913 nmi #32343 1512809 nmi #32344 116672 nmi #32345 412453 nmi #32346 1462095 <<<< 1st nmi (standard) handling 2 counters nmi #32347 2046 <<<< 2nd nmi (back-to-back) handling one counter nmi #32348 1773 <<<< 3rd nmi (back-to-back) handling no counter! [3] For back-to-back nmi detection there are the following rules: The PMU nmi handler was handling more than one counter and no counter was handled in the subsequent nmi (see [1] and [2] above). There is another case if there are two subsequent back-to-back nmis [3]. The 2nd is detected as back-to-back because the first handled more than one counter. If the second handles one counter and the 3rd handles nothing, we drop the 3rd nmi because it could be a back-to-back nmi. Signed-off-by: Robert Richter Signed-off-by: Peter Zijlstra [ renamed nmi variable to pmu_nmi to avoid clash with .nmi in entry.S ] Signed-off-by: Don Zickus Cc: peterz@infradead.org Cc: gorcunov@gmail.com Cc: fweisbec@gmail.com Cc: ying.huang@intel.com Cc: ming.m.lin@intel.com Cc: eranian@google.com LKML-Reference: <1283454469-1909-3-git-send-email-dzickus@redhat.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 59 +++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index f2da20fda02d..3efdf2870a35 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1154,7 +1154,7 @@ static int x86_pmu_handle_irq(struct pt_regs *regs) /* * event overflow */ - handled = 1; + handled++; data.period = event->hw.last_period; if (!x86_perf_event_set_period(event)) @@ -1200,12 +1200,20 @@ void perf_events_lapic_init(void) apic_write(APIC_LVTPC, APIC_DM_NMI); } +struct pmu_nmi_state { + unsigned int marked; + int handled; +}; + +static DEFINE_PER_CPU(struct pmu_nmi_state, pmu_nmi); + static int __kprobes perf_event_nmi_handler(struct notifier_block *self, unsigned long cmd, void *__args) { struct die_args *args = __args; - struct pt_regs *regs; + unsigned int this_nmi; + int handled; if (!atomic_read(&active_events)) return NOTIFY_DONE; @@ -1214,22 +1222,47 @@ perf_event_nmi_handler(struct notifier_block *self, case DIE_NMI: case DIE_NMI_IPI: break; - + case DIE_NMIUNKNOWN: + this_nmi = percpu_read(irq_stat.__nmi_count); + if (this_nmi != __get_cpu_var(pmu_nmi).marked) + /* let the kernel handle the unknown nmi */ + return NOTIFY_DONE; + /* + * This one is a PMU back-to-back nmi. Two events + * trigger 'simultaneously' raising two back-to-back + * NMIs. If the first NMI handles both, the latter + * will be empty and daze the CPU. So, we drop it to + * avoid false-positive 'unknown nmi' messages. + */ + return NOTIFY_STOP; default: return NOTIFY_DONE; } - regs = args->regs; - apic_write(APIC_LVTPC, APIC_DM_NMI); - /* - * Can't rely on the handled return value to say it was our NMI, two - * events could trigger 'simultaneously' raising two back-to-back NMIs. - * - * If the first NMI handles both, the latter will be empty and daze - * the CPU. - */ - x86_pmu.handle_irq(regs); + + handled = x86_pmu.handle_irq(args->regs); + if (!handled) + return NOTIFY_DONE; + + this_nmi = percpu_read(irq_stat.__nmi_count); + if ((handled > 1) || + /* the next nmi could be a back-to-back nmi */ + ((__get_cpu_var(pmu_nmi).marked == this_nmi) && + (__get_cpu_var(pmu_nmi).handled > 1))) { + /* + * We could have two subsequent back-to-back nmis: The + * first handles more than one counter, the 2nd + * handles only one counter and the 3rd handles no + * counter. + * + * This is the 2nd nmi because the previous was + * handling more than one counter. We will mark the + * next (3rd) and then drop it if unhandled. + */ + __get_cpu_var(pmu_nmi).marked = this_nmi + 1; + __get_cpu_var(pmu_nmi).handled = handled; + } return NOTIFY_STOP; } -- cgit v1.2.3-59-g8ed1b From ef5dc121d5a0bb1fa477c5395277259f07d318a3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 2 Sep 2010 15:48:16 -0700 Subject: mutex: Fix annotations to include it in kernel-locking docbook Fix kernel-doc notation in linux/mutex.h and kernel/mutex.c, then add these 2 files to the kernel-locking docbook as the Mutex API reference chapter. Add one API function to mutex-design.txt and correct a typo in that file. Signed-off-by: Randy Dunlap Cc: Rusty Russell LKML-Reference: <20100902154816.6cc2f9ad.randy.dunlap@oracle.com> Signed-off-by: Ingo Molnar --- Documentation/DocBook/kernel-locking.tmpl | 6 ++++++ Documentation/mutex-design.txt | 3 ++- include/linux/mutex.h | 8 ++++++++ kernel/mutex.c | 23 +++++++---------------- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl index 0b1a3f97f285..a0d479d1e1dd 100644 --- a/Documentation/DocBook/kernel-locking.tmpl +++ b/Documentation/DocBook/kernel-locking.tmpl @@ -1961,6 +1961,12 @@ machines due to caching. + + Mutex API reference +!Iinclude/linux/mutex.h +!Ekernel/mutex.c + + Further reading diff --git a/Documentation/mutex-design.txt b/Documentation/mutex-design.txt index c91ccc0720fa..38c10fd7f411 100644 --- a/Documentation/mutex-design.txt +++ b/Documentation/mutex-design.txt @@ -9,7 +9,7 @@ firstly, there's nothing wrong with semaphores. But if the simpler mutex semantics are sufficient for your code, then there are a couple of advantages of mutexes: - - 'struct mutex' is smaller on most architectures: .e.g on x86, + - 'struct mutex' is smaller on most architectures: E.g. on x86, 'struct semaphore' is 20 bytes, 'struct mutex' is 16 bytes. A smaller structure size means less RAM footprint, and better CPU-cache utilization. @@ -136,3 +136,4 @@ the APIs of 'struct mutex' have been streamlined: void mutex_lock_nested(struct mutex *lock, unsigned int subclass); int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass); + int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock); diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 878cab4f5fcc..f363bc8fdc74 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -78,6 +78,14 @@ struct mutex_waiter { # include #else # define __DEBUG_MUTEX_INITIALIZER(lockname) +/** + * mutex_init - initialize the mutex + * @mutex: the mutex to be initialized + * + * Initialize the mutex to unlocked state. + * + * It is not allowed to initialize an already locked mutex. + */ # define mutex_init(mutex) \ do { \ static struct lock_class_key __key; \ diff --git a/kernel/mutex.c b/kernel/mutex.c index 4c0b7b3e6d2e..200407c1502f 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -36,15 +36,6 @@ # include #endif -/*** - * mutex_init - initialize the mutex - * @lock: the mutex to be initialized - * @key: the lock_class_key for the class; used by mutex lock debugging - * - * Initialize the mutex to unlocked state. - * - * It is not allowed to initialize an already locked mutex. - */ void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) { @@ -68,7 +59,7 @@ EXPORT_SYMBOL(__mutex_init); static __used noinline void __sched __mutex_lock_slowpath(atomic_t *lock_count); -/*** +/** * mutex_lock - acquire the mutex * @lock: the mutex to be acquired * @@ -105,7 +96,7 @@ EXPORT_SYMBOL(mutex_lock); static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count); -/*** +/** * mutex_unlock - release the mutex * @lock: the mutex to be released * @@ -364,8 +355,8 @@ __mutex_lock_killable_slowpath(atomic_t *lock_count); static noinline int __sched __mutex_lock_interruptible_slowpath(atomic_t *lock_count); -/*** - * mutex_lock_interruptible - acquire the mutex, interruptable +/** + * mutex_lock_interruptible - acquire the mutex, interruptible * @lock: the mutex to be acquired * * Lock the mutex like mutex_lock(), and return 0 if the mutex has @@ -456,15 +447,15 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count) return prev == 1; } -/*** - * mutex_trylock - try acquire the mutex, without waiting +/** + * mutex_trylock - try to acquire the mutex, without waiting * @lock: the mutex to be acquired * * Try to acquire the mutex atomically. Returns 1 if the mutex * has been acquired successfully, and 0 on contention. * * NOTE: this function follows the spin_trylock() convention, so - * it is negated to the down_trylock() return values! Be careful + * it is negated from the down_trylock() return values! Be careful * about this when converting semaphore users to mutexes. * * This function must not be used in interrupt context. The -- cgit v1.2.3-59-g8ed1b From d34c4aa43df20bbf2730a67f14c1cf6d133d99e6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Sep 2010 23:05:09 +0200 Subject: HID: add no-get quirk for eGalax touch controller Add no-get quirk for eGalax touch controller to avoid timeout at probe. Signed-off-by: Johan Hovold Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 16808f19a4b4..70da3181c8a0 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -33,7 +33,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET }, { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.3-59-g8ed1b From 9af25465081480a75824fd7a16a37a5cfebeede9 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Mon, 30 Aug 2010 02:44:03 +0000 Subject: xfs: Make fiemap work with sparse files In xfs_vn_fiemap, we set bvm_count to fi_extent_max + 1 and want to return fi_extent_max extents, but actually it won't work for a sparse file. The reason is that in xfs_getbmap we will calculate holes and set it in 'out', while out is malloced by bmv_count(fi_extent_max+1) which didn't consider holes. So in the worst case, if 'out' vector looks like [hole, extent, hole, extent, hole, ... hole, extent, hole], we will only return half of fi_extent_max extents. This patch add a new parameter BMV_IF_NO_HOLES for bvm_iflags. So with this flags, we don't use our 'out' in xfs_getbmap for a hole. The solution is a bit ugly by just don't increasing index of 'out' vector. I felt that it is not easy to skip it at the very beginning since we have the complicated check and some function like xfs_getbmapx_fix_eof_hole to adjust 'out'. Cc: Dave Chinner Signed-off-by: Tao Ma Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_iops.c | 2 +- fs/xfs/xfs_bmap.c | 14 +++++++++++++- fs/xfs/xfs_fs.h | 4 +++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 68be25dcd301..b1fc2a6bfe83 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -664,7 +664,7 @@ xfs_vn_fiemap( fieinfo->fi_extents_max + 1; bm.bmv_count = min_t(__s32, bm.bmv_count, (PAGE_SIZE * 16 / sizeof(struct getbmapx))); - bm.bmv_iflags = BMV_IF_PREALLOC; + bm.bmv_iflags = BMV_IF_PREALLOC | BMV_IF_NO_HOLES; if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) bm.bmv_iflags |= BMV_IF_ATTRFORK; if (!(fieinfo->fi_flags & FIEMAP_FLAG_SYNC)) diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 23f14e595c18..f90dadd5a968 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -5533,12 +5533,24 @@ xfs_getbmap( map[i].br_startblock)) goto out_free_map; - nexleft--; bmv->bmv_offset = out[cur_ext].bmv_offset + out[cur_ext].bmv_length; bmv->bmv_length = max_t(__int64_t, 0, bmvend - bmv->bmv_offset); + + /* + * In case we don't want to return the hole, + * don't increase cur_ext so that we can reuse + * it in the next loop. + */ + if ((iflags & BMV_IF_NO_HOLES) && + map[i].br_startblock == HOLESTARTBLOCK) { + memset(&out[cur_ext], 0, sizeof(out[cur_ext])); + continue; + } + + nexleft--; bmv->bmv_entries++; cur_ext++; } diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index 7cf7220e7d5f..87c2e9d02288 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h @@ -114,8 +114,10 @@ struct getbmapx { #define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ #define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ #define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ +#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ #define BMV_IF_VALID \ - (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|BMV_IF_DELALLOC) + (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ + BMV_IF_DELALLOC|BMV_IF_NO_HOLES) /* bmv_oflags values - returned for each non-header segment */ #define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ -- cgit v1.2.3-59-g8ed1b From 1ef78abec6b5e9e3062e3ae6660eabaf055a718d Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 3 Sep 2010 06:17:10 +0000 Subject: be2net: fix net-snmp error because of wrong packet stats Wrong packet statistics for multicast Rx was causing net-snmp error messages every 15 seconds. Instead of picking the multicast stats from hardware, now maintain it in the driver itself. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 1 + drivers/net/benet/be_ethtool.c | 1 + drivers/net/benet/be_hw.h | 7 +++++-- drivers/net/benet/be_main.c | 15 +++++++++++---- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 99197bd54da5..53306bf3f401 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -181,6 +181,7 @@ struct be_drvr_stats { u64 be_rx_bytes_prev; u64 be_rx_pkts; u32 be_rx_rate; + u32 be_rx_mcast_pkt; /* number of non ether type II frames dropped where * frame len > length field of Mac Hdr */ u32 be_802_3_dropped_frames; diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index cd16243c7c36..13f0abbc5205 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -60,6 +60,7 @@ static const struct be_ethtool_stat et_stats[] = { {DRVSTAT_INFO(be_rx_events)}, {DRVSTAT_INFO(be_tx_compl)}, {DRVSTAT_INFO(be_rx_compl)}, + {DRVSTAT_INFO(be_rx_mcast_pkt)}, {DRVSTAT_INFO(be_ethrx_post_fail)}, {DRVSTAT_INFO(be_802_3_dropped_frames)}, {DRVSTAT_INFO(be_802_3_malformed_frames)}, diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index 5d38046402b2..a2ec5df0d733 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -167,8 +167,11 @@ #define FLASH_FCoE_BIOS_START_g3 (13631488) #define FLASH_REDBOOT_START_g3 (262144) - - +/************* Rx Packet Type Encoding **************/ +#define BE_UNICAST_PACKET 0 +#define BE_MULTICAST_PACKET 1 +#define BE_BROADCAST_PACKET 2 +#define BE_RSVD_PACKET 3 /* * BE descriptors: host memory data structures whose formats diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 74e146f470c6..a5a24e6c773e 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -247,6 +247,7 @@ void netdev_stats_update(struct be_adapter *adapter) dev_stats->tx_packets = drvr_stats(adapter)->be_tx_pkts; dev_stats->rx_bytes = drvr_stats(adapter)->be_rx_bytes; dev_stats->tx_bytes = drvr_stats(adapter)->be_tx_bytes; + dev_stats->multicast = drvr_stats(adapter)->be_rx_mcast_pkt; /* bad pkts received */ dev_stats->rx_errors = port_stats->rx_crc_errors + @@ -294,7 +295,6 @@ void netdev_stats_update(struct be_adapter *adapter) /* no space available in linux */ dev_stats->tx_dropped = 0; - dev_stats->multicast = port_stats->rx_multicast_frames; dev_stats->collisions = 0; /* detailed tx_errors */ @@ -848,7 +848,7 @@ static void be_rx_rate_update(struct be_adapter *adapter) } static void be_rx_stats_update(struct be_adapter *adapter, - u32 pktsize, u16 numfrags) + u32 pktsize, u16 numfrags, u8 pkt_type) { struct be_drvr_stats *stats = drvr_stats(adapter); @@ -856,6 +856,9 @@ static void be_rx_stats_update(struct be_adapter *adapter, stats->be_rx_frags += numfrags; stats->be_rx_bytes += pktsize; stats->be_rx_pkts++; + + if (pkt_type == BE_MULTICAST_PACKET) + stats->be_rx_mcast_pkt++; } static inline bool do_pkt_csum(struct be_eth_rx_compl *rxcp, bool cso) @@ -925,9 +928,11 @@ static void skb_fill_rx_data(struct be_adapter *adapter, u16 rxq_idx, i, j; u32 pktsize, hdr_len, curr_frag_len, size; u8 *start; + u8 pkt_type; rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); + pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl, cast_enc, rxcp); page_info = get_rx_page_info(adapter, rxq_idx); @@ -993,7 +998,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, BUG_ON(j > MAX_SKB_FRAGS); done: - be_rx_stats_update(adapter, pktsize, num_rcvd); + be_rx_stats_update(adapter, pktsize, num_rcvd, pkt_type); } /* Process the RX completion indicated by rxcp when GRO is disabled */ @@ -1060,6 +1065,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; u16 i, rxq_idx = 0, vid, j; u8 vtm; + u8 pkt_type; num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); /* Is it a flush compl that has no data */ @@ -1070,6 +1076,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp); + pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl, cast_enc, rxcp); /* vlanf could be wrongly set in some cards. * ignore if vtm is not set */ @@ -1125,7 +1132,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid); } - be_rx_stats_update(adapter, pkt_size, num_rcvd); + be_rx_stats_update(adapter, pkt_size, num_rcvd, pkt_type); } static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) -- cgit v1.2.3-59-g8ed1b From d053de911bff69ba7cdda36d3107c1da0fba7ccd Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 3 Sep 2010 06:23:30 +0000 Subject: be2net: fix a bug in UE detection logic The ONLINE registers can return 0xFFFFFFFF on more than one occassion. On systems that care, reading these registers could lead to problems. So the new code decides that the ASIC has encountered and error by reading the UE_STATUS_LOW/HIGH registers. AND them with the mask values and a non-zero result indicates an error. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 2 +- drivers/net/benet/be_cmds.h | 2 +- drivers/net/benet/be_main.c | 32 ++++++++------------------------ 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 3d305494a606..78f32fe68c0e 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -207,7 +207,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) if (msecs > 4000) { dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); - be_dump_ue(adapter); + be_detect_dump_ue(adapter); return -1; } diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index bdc10a28cfda..ad1e6fac60c5 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -992,5 +992,5 @@ extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, extern int be_cmd_get_phy_info(struct be_adapter *adapter, struct be_dma_mem *cmd); extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain); -extern void be_dump_ue(struct be_adapter *adapter); +extern void be_detect_dump_ue(struct be_adapter *adapter); diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a5a24e6c773e..6eda7a022256 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1750,26 +1750,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) return 1; } -static inline bool be_detect_ue(struct be_adapter *adapter) -{ - u32 online0 = 0, online1 = 0; - - pci_read_config_dword(adapter->pdev, PCICFG_ONLINE0, &online0); - - pci_read_config_dword(adapter->pdev, PCICFG_ONLINE1, &online1); - - if (!online0 || !online1) { - adapter->ue_detected = true; - dev_err(&adapter->pdev->dev, - "UE Detected!! online0=%d online1=%d\n", - online0, online1); - return true; - } - - return false; -} - -void be_dump_ue(struct be_adapter *adapter) +void be_detect_dump_ue(struct be_adapter *adapter) { u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask; u32 i; @@ -1786,6 +1767,11 @@ void be_dump_ue(struct be_adapter *adapter) ue_status_lo = (ue_status_lo & (~ue_status_lo_mask)); ue_status_hi = (ue_status_hi & (~ue_status_hi_mask)); + if (ue_status_lo || ue_status_hi) { + adapter->ue_detected = true; + dev_err(&adapter->pdev->dev, "UE Detected!!\n"); + } + if (ue_status_lo) { for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) { if (ue_status_lo & 1) @@ -1821,10 +1807,8 @@ static void be_worker(struct work_struct *work) adapter->rx_post_starved = false; be_post_rx_frags(adapter); } - if (!adapter->ue_detected) { - if (be_detect_ue(adapter)) - be_dump_ue(adapter); - } + if (!adapter->ue_detected) + be_detect_dump_ue(adapter); schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); } -- cgit v1.2.3-59-g8ed1b From 323f30b361b2e6febb9065ab4a1a5298acb66ac1 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Fri, 3 Sep 2010 06:24:13 +0000 Subject: be2net: remove a BUG_ON in be_cmds.c Async notifications other than link status are possible in certain configurations. Remove the BUG_ON in the mcc completion processing path. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 78f32fe68c0e..34abcc9403d6 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -140,10 +140,8 @@ int be_process_mcc(struct be_adapter *adapter, int *status) while ((compl = be_mcc_compl_get(adapter))) { if (compl->flags & CQE_FLAGS_ASYNC_MASK) { /* Interpret flags as an async trailer */ - BUG_ON(!is_link_state_evt(compl->flags)); - - /* Interpret compl as a async link evt */ - be_async_link_state_process(adapter, + if (is_link_state_evt(compl->flags)) + be_async_link_state_process(adapter, (struct be_async_event_link_state *) compl); } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { *status = be_mcc_compl_process(adapter, compl); -- cgit v1.2.3-59-g8ed1b From 3fb5a991916091a908d53608a5899240039fb51e Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Thu, 2 Sep 2010 15:42:43 +0000 Subject: cls_cgroup: Fix rcu lockdep warning Dave reported an rcu lockdep warning on 2.6.35.4 kernel task->cgroups and task->cgroups->subsys[i] are protected by RCU. So we avoid accessing invalid pointers here. This might happen, for example, when you are deref-ing those pointers while someone move @task from one cgroup to another. Reported-by: Dave Jones Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- include/net/cls_cgroup.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h index 726cc3536409..ef6c24a529e1 100644 --- a/include/net/cls_cgroup.h +++ b/include/net/cls_cgroup.h @@ -27,11 +27,17 @@ struct cgroup_cls_state #ifdef CONFIG_NET_CLS_CGROUP static inline u32 task_cls_classid(struct task_struct *p) { + int classid; + if (in_interrupt()) return 0; - return container_of(task_subsys_state(p, net_cls_subsys_id), - struct cgroup_cls_state, css)->classid; + rcu_read_lock(); + classid = container_of(task_subsys_state(p, net_cls_subsys_id), + struct cgroup_cls_state, css)->classid; + rcu_read_unlock(); + + return classid; } #else extern int net_cls_subsys_id; -- cgit v1.2.3-59-g8ed1b From aa70201fdc374f245cfa1874e11df145ace3ffaf Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 30 Aug 2010 16:32:43 +0200 Subject: ALSA: usb-audio: add Edirol PCR-1 PCM support Add a quirk for the other logical device of the PCR-1 so that not only the MIDI interface but also the audio interface works. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 4818fbdc02fb..838b81b74fd7 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1135,12 +1135,35 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_MIDI_STANDARD_INTERFACE } }, +{ + /* has ID 0x0066 when not in "Advanced Driver" mode */ + USB_DEVICE(0x0582, 0x0064), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, { /* has ID 0x0067 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0065), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "EDIROL", - .product_name = "PCR-1", + /* .vendor_name = "EDIROL", */ + /* .product_name = "PCR-1", */ .ifnum = 0, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const struct snd_usb_midi_endpoint_info) { -- cgit v1.2.3-59-g8ed1b From 9d0c91938e3a42c683e4e55d108b928e89a3bbc4 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 30 Aug 2010 16:42:17 +0200 Subject: ALSA: usb-audio: add Roland A-PRO support Add a quirk for the Roland/Cakewalk A-300PRO/A-500PRO/A-800PRO keyboards. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 838b81b74fd7..92f099a804ca 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1548,6 +1548,20 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* has ID 0x0110 when not in Advanced Driver mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "A-PRO", */ + .ifnum = 1, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } + } +}, /* Guillemot devices */ { -- cgit v1.2.3-59-g8ed1b From 7b28079b3284ccb15ad4f003fb7073890600d0c1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 30 Aug 2010 16:45:38 +0200 Subject: ALSA: usb-audio: add BOSS ME-25 support Add a quirk to make the BOSS ME-25 work. Many thanks to Kees van Veen. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 92f099a804ca..c86c613e0b96 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1562,6 +1562,36 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + USB_DEVICE(0x0582, 0x0113), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "BOSS", */ + /* .product_name = "ME-25", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { -- cgit v1.2.3-59-g8ed1b From a2acad8298a42b7be684a32fafaf83332bba9c2b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 3 Sep 2010 10:53:11 +0200 Subject: ALSA: usb-audio: fix detection of vendor-specific device protocol settings The Audio Class v2 support code in 2.6.35 added checks for the bInterfaceProtocol field. However, there are devices (usually those detected by vendor-specific quirks) that do not have one of the predefined values in this field, which made the driver reject them. To fix this regression, restore the old behaviour, i.e., assume that a device with an unknown bInterfaceProtocol field (other than UAC_VERSION_2) has more or less UAC-v1-compatible descriptors. [compile warning fixes by tiwai] Signed-off-by: Clemens Ladisch Cc: Daniel Mack Cc: Signed-off-by: Takashi Iwai --- sound/usb/card.c | 9 +++++---- sound/usb/clock.c | 3 +-- sound/usb/endpoint.c | 11 ++++++----- sound/usb/format.c | 22 ++++++++++------------ sound/usb/mixer.c | 10 +++++++++- sound/usb/pcm.c | 3 +-- 6 files changed, 32 insertions(+), 26 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index b443a33d31c9..32e4be8a187c 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -216,6 +216,11 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) } switch (protocol) { + default: + snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n", + protocol); + /* fall through */ + case UAC_VERSION_1: { struct uac1_ac_header_descriptor *h1 = control_header; @@ -253,10 +258,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) break; } - - default: - snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol); - return -EINVAL; } return 0; diff --git a/sound/usb/clock.c b/sound/usb/clock.c index b853f8df794f..7754a1034545 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -295,12 +295,11 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, switch (altsd->bInterfaceProtocol) { case UAC_VERSION_1: + default: return set_sample_rate_v1(chip, iface, alts, fmt, rate); case UAC_VERSION_2: return set_sample_rate_v2(chip, iface, alts, fmt, rate); } - - return -EINVAL; } diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 1a701f1e8f50..ef0a07e34844 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -275,6 +275,12 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) /* get audio formats */ switch (protocol) { + default: + snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n", + dev->devnum, iface_no, altno, protocol); + protocol = UAC_VERSION_1; + /* fall through */ + case UAC_VERSION_1: { struct uac1_as_header_descriptor *as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); @@ -336,11 +342,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) dev->devnum, iface_no, altno, as->bTerminalLink); continue; } - - default: - snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n", - dev->devnum, iface_no, altno, protocol); - continue; } /* get format type */ diff --git a/sound/usb/format.c b/sound/usb/format.c index 3a1375459c06..69148212aa70 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -49,7 +49,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, u64 pcm_formats; switch (protocol) { - case UAC_VERSION_1: { + case UAC_VERSION_1: + default: { struct uac_format_type_i_discrete_descriptor *fmt = _fmt; sample_width = fmt->bBitResolution; sample_bytes = fmt->bSubframeSize; @@ -64,9 +65,6 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, format <<= 1; break; } - - default: - return -EINVAL; } pcm_formats = 0; @@ -384,6 +382,10 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, * audio class v2 uses class specific EP0 range requests for that. */ switch (protocol) { + default: + snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n", + chip->dev->devnum, fp->iface, fp->altsetting, protocol); + /* fall through */ case UAC_VERSION_1: fp->channels = fmt->bNrChannels; ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); @@ -392,10 +394,6 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, /* fp->channels is already set in this case */ ret = parse_audio_format_rates_v2(chip, fp); break; - default: - snd_printk(KERN_ERR "%d:%u:%d : invalid protocol version %d\n", - chip->dev->devnum, fp->iface, fp->altsetting, protocol); - return -EINVAL; } if (fp->channels < 1) { @@ -438,6 +436,10 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, fp->channels = 1; switch (protocol) { + default: + snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n", + chip->dev->devnum, fp->iface, fp->altsetting, protocol); + /* fall through */ case UAC_VERSION_1: { struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; brate = le16_to_cpu(fmt->wMaxBitRate); @@ -456,10 +458,6 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, ret = parse_audio_format_rates_v2(chip, fp); break; } - default: - snd_printk(KERN_ERR "%d:%u:%d : invalid protocol version %d\n", - chip->dev->devnum, fp->iface, fp->altsetting, protocol); - return -EINVAL; } return ret; diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c166db0057d3..3ed3901369ce 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2175,7 +2175,15 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, } host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; - mixer->protocol = get_iface_desc(host_iface)->bInterfaceProtocol; + switch (get_iface_desc(host_iface)->bInterfaceProtocol) { + case UAC_VERSION_1: + default: + mixer->protocol = UAC_VERSION_1; + break; + case UAC_VERSION_2: + mixer->protocol = UAC_VERSION_2; + break; + } if ((err = snd_usb_mixer_controls(mixer)) < 0 || (err = snd_usb_mixer_status_create(mixer)) < 0) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3634cedf9306..3b5135c93062 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -173,13 +173,12 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, switch (altsd->bInterfaceProtocol) { case UAC_VERSION_1: + default: return init_pitch_v1(chip, iface, alts, fmt); case UAC_VERSION_2: return init_pitch_v2(chip, iface, alts, fmt); } - - return -EINVAL; } /* -- cgit v1.2.3-59-g8ed1b From 57f9bdac2510cd7fda58e4a111d250861eb1ebeb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Aug 2010 09:12:29 +0200 Subject: sysfs: checking for NULL instead of ERR_PTR d_path() returns an ERR_PTR and it doesn't return NULL. Signed-off-by: Dan Carpenter Cc: stable Reviewed-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1b27b5688f62..da3fefe91a8f 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -340,7 +340,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) char *p; p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file)); - if (p) + if (!IS_ERR(p)) memmove(last_sysfs_file, p, strlen(p) + 1); /* need attr_sd for attr and ops, its parent for kobj */ -- cgit v1.2.3-59-g8ed1b From 9fc2b2d0cf743008d8f6be6293278f4ef61f09f3 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 22 Aug 2010 17:37:24 +0200 Subject: vt: Fix console corruption on driver hand-over. After 02f0777a0d6560eb995aade34a1b82f95c0452da "vc_origin" is no longer reset to the screen buffer before calling the con_init() hook of the new console driver. If the old driver wasn't using a fixed scanout buffer (e.g. the case of vgacon) "vc_origin" may be a pointer to a VRAM location, and its contents aren't guaranteed to be preserved after calling con_deinit() on the old driver and con_init() on the new driver, i.e. the subsequent console resize may fill the framebuffer with garbage. It can be reproduced in the transition from vgacon to the nouveau framebuffer driver: in that case the legacy VGA aperture "vc_origin" points to becomes unreadable after fbcon_init(). This patch reverts the mentioned commit. To avoid the problem it intended to fix, stop using "vc_scr_end" in vc_do_resize() to calculate how many rows we have to copy (actually the code looks simpler this way without the help of "vc_scr_end"). Signed-off-by: Francisco Jerez Cc: qiaochong Cc: Greg Kroah-Hartman Cc: Andrew Morton Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/vt.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 50590c7f2c01..281aada7b4a1 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -906,22 +906,16 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, * bottom of buffer */ old_origin += (old_rows - new_rows) * old_row_size; - end = vc->vc_scr_end; } else { /* * Cursor is in no man's land, copy 1/2 screenful * from the top and bottom of cursor position */ old_origin += (vc->vc_y - new_rows/2) * old_row_size; - end = old_origin + (old_row_size * new_rows); } - } else - /* - * Cursor near the top, copy contents from the top of buffer - */ - end = (old_rows > new_rows) ? old_origin + - (old_row_size * new_rows) : - vc->vc_scr_end; + } + + end = old_origin + old_row_size * min(old_rows, new_rows); update_attr(vc); @@ -3075,8 +3069,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last, old_was_color = vc->vc_can_do_color; vc->vc_sw->con_deinit(vc); - if (!vc->vc_origin) - vc->vc_origin = (unsigned long)vc->vc_screenbuf; + vc->vc_origin = (unsigned long)vc->vc_screenbuf; visual_init(vc, i, 0); set_origin(vc); update_attr(vc); -- cgit v1.2.3-59-g8ed1b From d86b3001a1a6f9b8be15e5e060338de085d2bbbc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 31 Aug 2010 17:08:52 +0200 Subject: MAINTAINERS: orphan isicom I do not maintain isicom anymore... Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c36f5d76e1a2..c5afc93dea63 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3923,8 +3923,7 @@ F: Documentation/sound/oss/MultiSound F: sound/oss/msnd* MULTITECH MULTIPORT CARD (ISICOM) -M: Jiri Slaby -S: Maintained +S: Orphan F: drivers/char/isicom.c F: include/linux/isicom.h -- cgit v1.2.3-59-g8ed1b From 71cad0554956de87c3fc413b1eac9313887eb14f Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Tue, 31 Aug 2010 14:19:09 +0200 Subject: serial: fix port type conflict between NS16550A & U6_16550A Bug seen by Dr. David Alan Gilbert with sparse Signed-off-by: Philippe Langlais Cc: stable Signed-off-by: Greg Kroah-Hartman --- include/linux/serial.h | 3 +-- include/linux/serial_core.h | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/serial.h b/include/linux/serial.h index 1ebc694a6d52..ef914061511e 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -77,8 +77,7 @@ struct serial_struct { #define PORT_16654 11 #define PORT_16850 12 #define PORT_RSA 13 /* RSA-DV II/S card */ -#define PORT_U6_16550A 14 -#define PORT_MAX 14 +#define PORT_MAX 13 #define SERIAL_IO_PORT 0 #define SERIAL_IO_HUB6 1 diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 64458a9a8938..563e23400913 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -44,7 +44,8 @@ #define PORT_RM9000 16 /* PMC-Sierra RM9xxx internal UART */ #define PORT_OCTEON 17 /* Cavium OCTEON internal UART */ #define PORT_AR7 18 /* Texas Instruments AR7 internal UART */ -#define PORT_MAX_8250 18 /* max port ID */ +#define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */ +#define PORT_MAX_8250 19 /* max port ID */ /* * ARM specific type numbers. These are not currently guaranteed -- cgit v1.2.3-59-g8ed1b From 336746918299f2ca16b31490655b4ff7c8824c87 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Sat, 28 Aug 2010 16:32:55 -0400 Subject: serial: bfin_sport_uart: restore transmit frame sync fix The large cleanup/rewrite of resources in commit ccf68e59e93181df9353c0cc accidentally reverted an earlier fix in commit a19e8b205915b2925aca75b. So restore it here. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger Cc: stable [.34 and newer] Signed-off-by: Greg Kroah-Hartman --- drivers/serial/bfin_sport_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c index e57fb3d228e2..5318dd3774ae 100644 --- a/drivers/serial/bfin_sport_uart.c +++ b/drivers/serial/bfin_sport_uart.c @@ -121,7 +121,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate) unsigned int sclk = get_sclk(); /* Set TCR1 and TCR2, TFSR is not enabled for uart */ - SPORT_PUT_TCR1(up, (ITFS | TLSBIT | ITCLK)); + SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK)); SPORT_PUT_TCR2(up, size + 1); pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); -- cgit v1.2.3-59-g8ed1b From 6eb68d6f3bf1707d5d816ea9242b7d38f25b942e Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Thu, 2 Sep 2010 16:06:16 +0200 Subject: tty: fix tty_line must not be equal to number of allocated tty pointers in tty driver I found a bug "by chance" in drivers/char/tty_io.c I mean "by chance" because I was just reading the code of the tty_find_polling_driver() to make a new tty_find_by_name() function. In tty_find_polling_driver() the driver actually test "tty_line <= p->num" while num refers to the number of struct tty_struct pointers allocated for the p->ttys (p is a tty_driver), and tty_line is scanned in a tty name, which can be for example ttyS2. Then tty_line equals 2. And if p->num is 2, we have only p->ttys[0] and p->ttys[1], but no p->ttys[2]. This is actually unharmful, for tty_find_polling_driver() is used only in drivers/serial/kgdboc.c, and there's a test over there to find a console with a matching index, which will never happen. This is still a bug anyway. Signed-off-by: Nathael Pajani Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 949067a0bd47..613c852ee0fe 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -355,7 +355,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (*stp == '\0') stp = NULL; - if (tty_line >= 0 && tty_line <= p->num && p->ops && + if (tty_line >= 0 && tty_line < p->num && p->ops && p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) { res = tty_driver_kref_get(p); *line = tty_line; -- cgit v1.2.3-59-g8ed1b From 0f1312b260499b34bb92fc9bd8ca1560dda2c4da Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Fri, 13 Aug 2010 21:29:30 +0200 Subject: USB: s3c-hsotg: Remove DEBUG define DEBUG is defined unconditionally, remove it as this clutters the message log. Signed-off-by: Maurus Cuelenaere Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/s3c-hsotg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 521ebed0118d..a229744a8c7d 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -12,8 +12,6 @@ * published by the Free Software Foundation. */ -#define DEBUG - #include #include #include -- cgit v1.2.3-59-g8ed1b From 08a3b3b1c2e622e378d9086aee9e2e42ce37591d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 14 Aug 2010 11:06:19 +0200 Subject: USB: ehci-ppc-of: problems in unwind The iounmap(ehci->ohci_hcctrl_reg); should be the first thing we do because the ioremap() was the last thing we did. Also if we hit any of the goto statements in the original code then it would have led to a NULL dereference of "ehci". This bug was introduced in: 796bcae7361c "USB: powerpc: Workaround for the PPC440EPX USBH_23 errata [take 3]" I modified the few lines in front a little so that my code didn't obscure the return success code path. Signed-off-by: Dan Carpenter Reviewed-by: Grant Likely Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-ppc-of.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 335ee699fd85..ba52be473027 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -192,17 +192,19 @@ ehci_hcd_ppc_of_probe(struct platform_device *op, const struct of_device_id *mat } rv = usb_add_hcd(hcd, irq, 0); - if (rv == 0) - return 0; + if (rv) + goto err_ehci; + + return 0; +err_ehci: + if (ehci->has_amcc_usb23) + iounmap(ehci->ohci_hcctrl_reg); iounmap(hcd->regs); err_ioremap: irq_dispose_mapping(irq); err_irq: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - if (ehci->has_amcc_usb23) - iounmap(ehci->ohci_hcctrl_reg); err_rmr: usb_put_hcd(hcd); -- cgit v1.2.3-59-g8ed1b From 793f03aa7bda8f492e12ada3de711b4ad7f4d8d0 Mon Sep 17 00:00:00 2001 From: Henrik Kretzschmar Date: Fri, 20 Aug 2010 19:57:50 +0200 Subject: USB: rndis: section mismatch fix This patch removes the following section mismatch warning, by moving the function rndis_init() from .init.text to .text. WARNING: vmlinux.o(.text+0x1aeca5a): Section mismatch in reference from the function rndis_bind_config() to the function .init.text:rndis_init() The function rndis_bind_config() references the function __init rndis_init(). This is often because rndis_bind_config lacks a __init annotation or the annotation of rndis_init is wrong. Signed-off-by: Henrik Kretzschmar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/rndis.c | 2 +- drivers/usb/gadget/rndis.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 020fa5a25fda..ee337f72c644 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1148,7 +1148,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ -int __init rndis_init (void) +int rndis_init(void) { u8 i; diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index c236aaa9dcd1..907c33008118 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -262,7 +262,7 @@ int rndis_signal_disconnect (int configNr); int rndis_state (int configNr); extern void rndis_set_host_mac (int configNr, const u8 *addr); -int __devinit rndis_init (void); +int rndis_init(void); void rndis_exit (void); #endif /* _LINUX_RNDIS_H */ -- cgit v1.2.3-59-g8ed1b From 037d3656adbd7e8cb848f01cf5dec423ed76bbe7 Mon Sep 17 00:00:00 2001 From: Maxim Osipov Date: Sat, 21 Aug 2010 14:54:06 +0400 Subject: USB: Fix kernel oops with g_ether and Windows Please find attached patch for https://bugzilla.kernel.org/show_bug.cgi?id=16023 problem. Signed-off-by: Maxim Osipov Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/rndis.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index ee337f72c644..972d5ddd1e18 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -293,9 +293,13 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, /* mandatory */ case OID_GEN_VENDOR_DESCRIPTION: pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); - length = strlen (rndis_per_dev_params [configNr].vendorDescr); - memcpy (outbuf, - rndis_per_dev_params [configNr].vendorDescr, length); + if ( rndis_per_dev_params [configNr].vendorDescr ) { + length = strlen (rndis_per_dev_params [configNr].vendorDescr); + memcpy (outbuf, + rndis_per_dev_params [configNr].vendorDescr, length); + } else { + outbuf[0] = 0; + } retval = 0; break; -- cgit v1.2.3-59-g8ed1b From c7aa8f44b4d1dc73591894a2dd6909213612d299 Mon Sep 17 00:00:00 2001 From: Dirk De Schepper Date: Tue, 24 Aug 2010 20:38:35 +0100 Subject: USB: option: fix incorrect novatel entries Unfortunately some of the hardware PID belonging to auto-install CDROM (AICD) of Novatel modems found their way into the option module. This causes the AICD to be treated as a modem in stead of a disk. Since the modem ports do not appear until after the AICD is ejected, this essentially disables the modem. After a couple of minutes the AICD should auto-eject, but it is just too long a wait. The frequency of the failure seems to depend on both the hardware and the linux distribution. Here is a patch that fixes this up, and also adds a couple of new PID, offering some explanations and removing some incomplete and unnecessary comments. Signed-off-by: Dirk De Schepper Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 119 ++++++++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 44 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index adcbdb994de3..c46911af282f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -164,6 +164,14 @@ static void option_instat_callback(struct urb *urb); #define YISO_VENDOR_ID 0x0EAB #define YISO_PRODUCT_U893 0xC893 +/* + * NOVATEL WIRELESS PRODUCTS + * + * Note from Novatel Wireless: + * If your Novatel modem does not work on linux, don't + * change the option module, but check our website. If + * that does not help, contact ddeschepper@nvtl.com +*/ /* MERLIN EVDO PRODUCTS */ #define NOVATELWIRELESS_PRODUCT_V640 0x1100 #define NOVATELWIRELESS_PRODUCT_V620 0x1110 @@ -185,24 +193,39 @@ static void option_instat_callback(struct urb *urb); #define NOVATELWIRELESS_PRODUCT_EU730 0x2400 #define NOVATELWIRELESS_PRODUCT_EU740 0x2410 #define NOVATELWIRELESS_PRODUCT_EU870D 0x2420 - /* OVATION PRODUCTS */ #define NOVATELWIRELESS_PRODUCT_MC727 0x4100 #define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 -#define NOVATELWIRELESS_PRODUCT_U727 0x5010 -#define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100 -#define NOVATELWIRELESS_PRODUCT_MC760 0x6000 +/* + * Note from Novatel Wireless: + * All PID in the 5xxx range are currently reserved for + * auto-install CDROMs, and should not be added to this + * module. + * + * #define NOVATELWIRELESS_PRODUCT_U727 0x5010 + * #define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100 +*/ #define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002 - -/* FUTURE NOVATEL PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001 -#define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0X7000 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0X7001 -#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED 0X8000 -#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0X8001 -#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0X9000 -#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0X9001 -#define NOVATELWIRELESS_PRODUCT_GLOBAL 0XA001 +#define NOVATELWIRELESS_PRODUCT_MC780 0x6010 +#define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0x6000 +#define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0x6001 +#define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0x7000 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0x7001 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3 0x7003 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4 0x7004 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5 0x7005 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED6 0x7006 +#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED7 0x7007 +#define NOVATELWIRELESS_PRODUCT_MC996D 0x7030 +#define NOVATELWIRELESS_PRODUCT_MF3470 0x7041 +#define NOVATELWIRELESS_PRODUCT_MC547 0x7042 +#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED 0x8000 +#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 +#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 +#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 +#define NOVATELWIRELESS_PRODUCT_G1 0xA001 +#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 +#define NOVATELWIRELESS_PRODUCT_G2 0xA010 /* AMOI PRODUCTS */ #define AMOI_VENDOR_ID 0x1614 @@ -490,36 +513,44 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, /* Novatel Merlin EX720/V740/X720 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V720) }, /* Novatel Merlin V720/S720/PC720 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U730) }, /* Novatel U730/U740 (VF version) */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U740) }, /* Novatel U740 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U870) }, /* Novatel U870 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_XU870) }, /* Novatel Merlin XU870 HSDPA/3G */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_X950D) }, /* Novatel X950D */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EV620) }, /* Novatel EV620/ES620 CDMA/EV-DO */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_ES720) }, /* Novatel ES620/ES720/U720/USB720 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E725) }, /* Novatel E725/E726 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_ES620) }, /* Novatel Merlin ES620 SM Bus */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU730) }, /* Novatel EU730 and Vodafone EU740 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU740) }, /* Novatel non-Vodafone EU740 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, /* Novatel EU850D/EU860D/EU870D */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727_NEW) }, /* Novatel MC727/U727/USB727 refresh */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, /* Novatel Ovation MC760 */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) }, /* Novatel EVDO product */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED) }, /* Novatel HSPA product */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED) }, /* Novatel EVDO Embedded product */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED) }, /* Novatel HSPA Embedded product */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_GLOBAL) }, /* Novatel Global product */ + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V720) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U730) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U740) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U870) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_XU870) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_X950D) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EV620) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_ES720) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E725) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_ES620) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU730) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU740) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC780) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED6) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED7) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC996D) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MF3470) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC547) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, -- cgit v1.2.3-59-g8ed1b From 541e05ec3add5ab5bcf238d60161b53480280b20 Mon Sep 17 00:00:00 2001 From: Craig Shelley Date: Mon, 23 Aug 2010 20:50:57 +0100 Subject: USB: CP210x Add new device ID New device ID added for Balluff RFID reader. Signed-off-by: Craig Shelley Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 80bf8333bb03..103f9d227fa1 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -109,6 +109,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ @@ -122,14 +123,14 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ - { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ - { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ - { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ - { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ + { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ + { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ + { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; -- cgit v1.2.3-59-g8ed1b From 0bf7a81c5d447c21db434be35363c44c0a30f598 Mon Sep 17 00:00:00 2001 From: Jason Detring Date: Thu, 26 Aug 2010 15:08:54 -0500 Subject: USB: cp210x: Add B&G H3000 link cable ID This is the cable between an H3000 navigation unit and a multi-function display. http://www.bandg.com/en/Products/H3000/Spares-and-Accessories/Cables/H3000-CPU-USB-Cable-Pack/ Signed-off-by: Jason Detring Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 103f9d227fa1..8ed6ff6e861d 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -88,6 +88,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */ { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ + { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ -- cgit v1.2.3-59-g8ed1b From 5b22a32e76defeb573991b301a27d299472c5714 Mon Sep 17 00:00:00 2001 From: A E Lawrence Date: Sun, 29 Aug 2010 21:51:52 +0100 Subject: USB: cp210x usb driver: add USB_DEVICE for Pirelli DP-L10 mobile. The Pirelli DP-L10 mobile is sold under various brand names. One, already supported by cp210x, is the T-COM TC300. Here is the lsusb for that version: ------------------------------------------------------------------- Bus 001 Device 002: ID 0489:e000 Foxconn / Hon Hai T-Com TC 300 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0489 Foxconn / Hon Hai idProduct 0xe000 T-Com TC 300 bcdDevice 1.00 iManufacturer 1 Silicon Labs iProduct 2 TC 300 iSerial 3 0001 [snip] --------------------------------------------------------------------------- However the native Pirelli DP-L10 is not supported: ------------------------------------------------------------------ Bus 001 Device 003: ID 0489:e003 Foxconn / Hon Hai Pirelli DP-L10 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0489 Foxconn / Hon Hai idProduct 0xe003 Pirelli DP-L10 bcdDevice 1.00 iManufacturer 1 Silicon Labs iProduct 2 DP-L10 iSerial 3 0001 [snip] ------------------------------------------------------------------------- All that is required is an extra USB_DEVICE entry: { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM +Mobile */ The patch adds that entry. Tested under 2.6.36-rc2 from git. Signed-off-by: A E Lawrence Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 8ed6ff6e861d..4f1744c5871f 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -56,6 +56,7 @@ static int debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ + { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ -- cgit v1.2.3-59-g8ed1b From 0791971ba8fbc44e4f476079f856335ed45e6324 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Sat, 28 Aug 2010 03:06:29 -0300 Subject: usb: allow drivers to use allocated bandwidth until unbound When using the remove sysfs file, the device configuration is set to -1 (unconfigured). This eventually unbind drivers with the bandwidth_mutex held. Some drivers may call functions that hold said mutex, like usb_reset_device. This is the case for rtl8187, for example. This will lead to the same process holding the mutex twice, which deadlocks. Besides, according to Alan Stern: "The deadlock problem probably could be handled somehow, but there's a separate issue: Until the usb_disable_device call finishes unbinding the drivers, the drivers are free to continue using their allocated bandwidth. We musn't change the bandwidth allocations until after the unbinding is done. So this patch is indeed necessary." Unbinding the driver before holding the bandwidth_mutex solves the problem. If any operation after that fails, drivers are not bound again. But that would be a problem anyway that the user may solve resetting the device configuration to one that works, just like he would need to do in most other failure cases. Signed-off-by: Thadeu Lima de Souza Cascardo Cc: Alan Stern Cc: Sarah Sharp Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index fd4c36ea5e46..844683e50383 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1724,6 +1724,15 @@ free_interfaces: if (ret) goto free_interfaces; + /* if it's already configured, clear out old state first. + * getting rid of old interfaces means unbinding their drivers. + */ + if (dev->state != USB_STATE_ADDRESS) + usb_disable_device(dev, 1); /* Skip ep0 */ + + /* Get rid of pending async Set-Config requests for this device */ + cancel_async_set_config(dev); + /* Make sure we have bandwidth (and available HCD resources) for this * configuration. Remove endpoints from the schedule if we're dropping * this configuration to set configuration 0. After this point, the @@ -1733,20 +1742,11 @@ free_interfaces: mutex_lock(&hcd->bandwidth_mutex); ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); if (ret < 0) { - usb_autosuspend_device(dev); mutex_unlock(&hcd->bandwidth_mutex); + usb_autosuspend_device(dev); goto free_interfaces; } - /* if it's already configured, clear out old state first. - * getting rid of old interfaces means unbinding their drivers. - */ - if (dev->state != USB_STATE_ADDRESS) - usb_disable_device(dev, 1); /* Skip ep0 */ - - /* Get rid of pending async Set-Config requests for this device */ - cancel_async_set_config(dev); - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); @@ -1761,8 +1761,8 @@ free_interfaces: if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); - usb_autosuspend_device(dev); mutex_unlock(&hcd->bandwidth_mutex); + usb_autosuspend_device(dev); goto free_interfaces; } mutex_unlock(&hcd->bandwidth_mutex); -- cgit v1.2.3-59-g8ed1b From 3c35b002da0c749ec15cf25cfe58f06aa230ae9c Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Wed, 25 Aug 2010 18:21:23 -0400 Subject: USB: ssu100: turn off debug flag Remove the hard coding of the debug flag to 1. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ssu100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 68c18fdfc6da..e986002b3844 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -46,7 +46,7 @@ #define FULLPWRBIT 0x00000080 #define NEXT_BOARD_POWER_BIT 0x00000004 -static int debug = 1; +static int debug; /* Version Information */ #define DRIVER_VERSION "v0.1" -- cgit v1.2.3-59-g8ed1b From caf3a636a9f809fdca5fa746e6687096457accb1 Mon Sep 17 00:00:00 2001 From: Dave Ludlow Date: Tue, 31 Aug 2010 14:26:17 -0400 Subject: usb: serial: mos7840: Add USB ID to support the B&B Electronics USOPTL4-2P. Add the USB ID needed to support B&B Electronic's 2-port, optically-isolated, powered, USB to RS485 converter. Signed-off-by: Dave Ludlow Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 585b7e663740..9a5ea9dba464 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -129,6 +129,7 @@ #define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 #define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 #define BANDB_DEVICE_ID_USOPTL2_4 0xAC24 +#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02 /* This driver also supports * ATEN UC2324 device using Moschip MCS7840 @@ -192,6 +193,7 @@ static const struct usb_device_id moschip_port_id_table[] = { {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ @@ -209,6 +211,7 @@ static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ -- cgit v1.2.3-59-g8ed1b From 4035e45632c2a8bb4edae83c20447051bd9a9604 Mon Sep 17 00:00:00 2001 From: Toby Gray Date: Wed, 1 Sep 2010 16:01:19 +0100 Subject: USB: cdc-acm: Adding second ACM channel support for various Nokia and one Samsung phones S60 phones from Nokia and Samsung expose two ACM channels. The first is a modem with a standard AT-command interface, which is picked up correctly by CDC-ACM. The second ACM port is marked as having a vendor-specific protocol. This means that the ACM driver will not claim the second channel by default. This adds support for the second ACM channel for the following devices: Nokia E63 Nokia E75 Nokia 6760 Slide Nokia E52 Nokia E55 Nokia E72 Nokia X6 Nokia N97 Mini Nokia 5800 Xpressmusic Nokia E90 Samsung GTi8510 (INNOV8) Signed-off-by: Toby Gray Cc: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 1833b3a71515..a3d6c4db2a03 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1481,6 +1481,11 @@ static int acm_reset_resume(struct usb_interface *intf) USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ USB_CDC_ACM_PROTO_VENDOR) +#define SAMSUNG_PCSUITE_ACM_INFO(x) \ + USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \ + USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ + USB_CDC_ACM_PROTO_VENDOR) + /* * USB driver structure. */ @@ -1591,6 +1596,17 @@ static const struct usb_device_id acm_ids[] = { { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */ + { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */ + { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */ + { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */ + { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */ + { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */ + { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */ + { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */ + { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */ + { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */ + { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */ + { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ -- cgit v1.2.3-59-g8ed1b From 870408c8291015872a7a0b583673a9e56b3e73f4 Mon Sep 17 00:00:00 2001 From: Dave Ludlow Date: Wed, 1 Sep 2010 12:33:30 -0400 Subject: usb: serial: mos7840: Add USB IDs to support more B&B USB/RS485 converters. Add the USB IDs needed to support the B&B USOPTL4-4P, USO9ML2-2P, and USO9ML2-4P. This patch expands and corrects a typo in the patch sent on 08-31-2010. Signed-off-by: Dave Ludlow Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7840.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 9a5ea9dba464..1c9b6e9b2386 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -119,17 +119,20 @@ * by making a change here, in moschip_port_id_table, and in * moschip_id_table_combined */ -#define USB_VENDOR_ID_BANDB 0x0856 -#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 -#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24 -#define BANDB_DEVICE_ID_US9ML2_2 0xAC29 -#define BANDB_DEVICE_ID_US9ML2_4 0xAC30 -#define BANDB_DEVICE_ID_USPTL4_2 0xAC31 -#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 -#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 -#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24 -#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02 +#define USB_VENDOR_ID_BANDB 0x0856 +#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 +#define BANDB_DEVICE_ID_USO9ML2_2P 0xBC00 +#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24 +#define BANDB_DEVICE_ID_USO9ML2_4P 0xBC01 +#define BANDB_DEVICE_ID_US9ML2_2 0xAC29 +#define BANDB_DEVICE_ID_US9ML2_4 0xAC30 +#define BANDB_DEVICE_ID_USPTL4_2 0xAC31 +#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 +#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 +#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02 +#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 +#define BANDB_DEVICE_ID_USOPTL4_4P 0xBC03 +#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24 /* This driver also supports * ATEN UC2324 device using Moschip MCS7840 @@ -185,15 +188,18 @@ static const struct usb_device_id moschip_port_id_table[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ @@ -203,15 +209,18 @@ static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, + {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4P)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ -- cgit v1.2.3-59-g8ed1b From 902ffc3c707c1d459ea57428a619a807cbe412f9 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Wed, 1 Sep 2010 18:37:12 +0100 Subject: USB: cxacru: Use a bulk/int URB to access the command endpoint The command endpoint is either a bulk or interrupt endpoint, but using the wrong type of transfer causes an error if CONFIG_USB_DEBUG is enabled after commit f661c6f8c67bd55e93348f160d590ff9edf08904, which checks for this mismatch. Detect which type of endpoint it is and use a bulk/int URB as appropriate. There are other function calls specifying a bulk pipe, but usb_clear_halt doesn't use the pipe type (only the endpoint) and usb_bulk_msg auto-detects interrupt transfers. Signed-off-by: Simon Arlott Cc: stable [.34 and newer] Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 593fc5e2d2e6..5af23cc5ea9f 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -1127,6 +1127,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, { struct cxacru_data *instance; struct usb_device *usb_dev = interface_to_usbdev(intf); + struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD]; int ret; /* instance init */ @@ -1171,15 +1172,34 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, goto fail; } - usb_fill_int_urb(instance->rcv_urb, + if (!cmd_ep) { + dbg("cxacru_bind: no command endpoint"); + ret = -ENODEV; + goto fail; + } + + if ((cmd_ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT) { + usb_fill_int_urb(instance->rcv_urb, usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD), instance->rcv_buf, PAGE_SIZE, cxacru_blocking_completion, &instance->rcv_done, 1); - usb_fill_int_urb(instance->snd_urb, + usb_fill_int_urb(instance->snd_urb, usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD), instance->snd_buf, PAGE_SIZE, cxacru_blocking_completion, &instance->snd_done, 4); + } else { + usb_fill_bulk_urb(instance->rcv_urb, + usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD), + instance->rcv_buf, PAGE_SIZE, + cxacru_blocking_completion, &instance->rcv_done); + + usb_fill_bulk_urb(instance->snd_urb, + usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD), + instance->snd_buf, PAGE_SIZE, + cxacru_blocking_completion, &instance->snd_done); + } mutex_init(&instance->cm_serialize); -- cgit v1.2.3-59-g8ed1b From 5b239f0aebd4dd6f85b13decf5e18e86e35d57f0 Mon Sep 17 00:00:00 2001 From: Philippe Corbes Date: Tue, 31 Aug 2010 19:31:32 +0200 Subject: USB: cdc-acm: Add pseudo modem without AT command capabilities cdc-acm.c : Manage pseudo-modem without AT commands capabilities Enable to drive electronic simple gadgets based on microcontrolers. The Interface descriptor is like this: bInterfaceClass 2 Communications bInterfaceSubClass 2 Abstract (modem) bInterfaceProtocol 0 None Signed-off-by: Philippe Corbes Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index a3d6c4db2a03..597defc1d7bf 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1615,6 +1615,10 @@ static const struct usb_device_id acm_ids[] = { .driver_info = NOT_A_MODEM, }, + /* control interfaces without any protocol set */ + { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, + USB_CDC_PROTO_NONE) }, + /* control interfaces with various AT-command sets */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_ACM_PROTO_AT_V25TER) }, -- cgit v1.2.3-59-g8ed1b From 577045c0a76e34294f902a7d5d60e90b04d094d0 Mon Sep 17 00:00:00 2001 From: Toby Gray Date: Thu, 2 Sep 2010 10:46:20 +0100 Subject: USB: cdc-acm: Fixing crash when ACM probing interfaces with no endpoint descriptors. Certain USB devices, such as the Nokia X6 mobile phone, don't expose any endpoint descriptors on some of their interfaces. If the ACM driver is forced to probe all interfaces on a device the a NULL pointer dereference will occur when the ACM driver attempts to use the endpoint of the alternative settings. One way to get the ACM driver to probe all the interfaces is by using the /sys/bus/usb/drivers/cdc_acm/new_id interface. This patch checks that the endpoint pointer for the current alternate settings is non-NULL before using it. Signed-off-by: Toby Gray Cc: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 597defc1d7bf..bc62fae0680f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -965,7 +965,8 @@ static int acm_probe(struct usb_interface *intf, } if (!buflen) { - if (intf->cur_altsetting->endpoint->extralen && + if (intf->cur_altsetting->endpoint && + intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { dev_dbg(&intf->dev, "Seeking extra descriptors on endpoint\n"); -- cgit v1.2.3-59-g8ed1b From 657373883417b2618023fd4135d251ba06a2c30a Mon Sep 17 00:00:00 2001 From: Luke Lowrey Date: Thu, 2 Sep 2010 11:39:49 +0100 Subject: USB: ftdi_sio: Added custom PIDs for ChamSys products Added the 0xDAF8 to 0xDAFF PID range for ChamSys limited USB interface/wing products Signed-off-by: Luke Lowrey Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 8 ++++++++ drivers/usb/serial/ftdi_sio_ids.h | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c792c96f590e..97cc87d654ce 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -753,6 +753,14 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 2e95857c9633..15a4583775ad 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -134,6 +134,18 @@ #define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ #define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ +/* + * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs + */ +#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8 +#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9 +#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA +#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB +#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC +#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD +#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE +#define FTDI_CHAMSYS_WING_PID 0xDAFF + /* * Westrex International devices submitted by Cory Lee */ -- cgit v1.2.3-59-g8ed1b From b681b5886bb5d1f5b6750a0ed7c62846da7ccea4 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 3 Aug 2010 19:15:31 +0000 Subject: staging: hv: Fix missing functions for net_device_ops Fix missing functions for net_device_ops. It's a bug when porting the drivers from 2.6.27 to 2.6.32. In 2.6.27, the default functions for Ethernet, like eth_change_mtu(), were assigned by ether_setup(). But in 2.6.32, these function pointers moved to net_device_ops structure and no longer be assigned in ether_setup(). So we need to set these functions in our driver code. It will ensure the MTU won't be set beyond 1500. Otherwise, this can cause an error on the server side, because the HyperV linux driver doesn't support jumbo frame yet. Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index 56e11575c977..64a01147ecae 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -327,6 +327,9 @@ static const struct net_device_ops device_ops = { .ndo_stop = netvsc_close, .ndo_start_xmit = netvsc_start_xmit, .ndo_set_multicast_list = netvsc_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, }; static int netvsc_probe(struct device *device) -- cgit v1.2.3-59-g8ed1b From 0c47a70a9a8a6d1ec37a53d2f9cb82f8b8ef8aa2 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Thu, 5 Aug 2010 19:29:44 +0000 Subject: staging: hv: Fixed bounce kmap problem by using correct index Fixed bounce offset kmap problem by using correct index. The symptom of the problem is that in some NAS appliances this problem represents Itself by a unresponsive VM under a load with many clients writing small files. Signed-off-by:Hank Janssen Signed-off-by:Haiyang Zhang Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/storvsc_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c index 075b61bd492f..3b9ccb062008 100644 --- a/drivers/staging/hv/storvsc_drv.c +++ b/drivers/staging/hv/storvsc_drv.c @@ -495,7 +495,7 @@ static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */ - if (j == 0) + if (bounce_addr == 0) bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0); while (srclen) { @@ -556,7 +556,7 @@ static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, destlen = orig_sgl[i].length; /* ASSERT(orig_sgl[i].offset + orig_sgl[i].length <= PAGE_SIZE); */ - if (j == 0) + if (bounce_addr == 0) bounce_addr = (unsigned long)kmap_atomic(sg_page((&bounce_sgl[j])), KM_IRQ0); while (destlen) { -- cgit v1.2.3-59-g8ed1b From e5fa721d1c2a54261a37eb59686e18dee34b6af6 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Thu, 5 Aug 2010 19:30:01 +0000 Subject: staging: hv: Fixed the value of the 64bit-hole inside ring buffer Fixed the value of the 64bit-hole inside ring buffer, this caused a problem on Hyper-V when running checked Windows builds. Checked builds of Windows are used internally and given to external system integrators at times. They are builds that for example that all elements in a structure follow the definition of that Structure. The bug this fixed was for a field that we did not fill in at all (Because we do Not use it on the Linux side), and the checked build of windows gives errors on it internally to the Windows logs. This fixes that error. Signed-off-by:Hank Janssen Signed-off-by:Haiyang Zhang Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/ring_buffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/hv/ring_buffer.c b/drivers/staging/hv/ring_buffer.c index 17bc7626f70a..d78c569ac94a 100644 --- a/drivers/staging/hv/ring_buffer.c +++ b/drivers/staging/hv/ring_buffer.c @@ -193,8 +193,7 @@ Description: static inline u64 GetRingBufferIndices(struct hv_ring_buffer_info *RingInfo) { - return ((u64)RingInfo->RingBuffer->WriteIndex << 32) - || RingInfo->RingBuffer->ReadIndex; + return (u64)RingInfo->RingBuffer->WriteIndex << 32; } -- cgit v1.2.3-59-g8ed1b From 15dd1c9f53b31cdc84b8072a88c23fa09527c596 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Thu, 5 Aug 2010 19:30:31 +0000 Subject: staging: hv: Increased storvsc ringbuffer and max_io_requests Increased storvsc ringbuffer and max_io_requests. This now more closely mimics the numbers on Hyper-V. And will allow more IO requests to take place for the SCSI driver. Max_IO is set to double from what it was before, Hyper-V allows it and we have had appliance builder requests to see if it was a problem to increase the number. Ringbuffer size for storvsc is now increased because I have seen A few buffer problems on extremely busy systems. They were Set pretty low before. And since max_io_requests is increased I Really needed to increase the buffer as well. Signed-off-by:Hank Janssen Signed-off-by:Haiyang Zhang Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/storvsc_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/hv/storvsc_api.h b/drivers/staging/hv/storvsc_api.h index 0063bde9a4b2..8505a1c5f9ee 100644 --- a/drivers/staging/hv/storvsc_api.h +++ b/drivers/staging/hv/storvsc_api.h @@ -28,10 +28,10 @@ #include "vmbus_api.h" /* Defines */ -#define STORVSC_RING_BUFFER_SIZE (10*PAGE_SIZE) +#define STORVSC_RING_BUFFER_SIZE (20*PAGE_SIZE) #define BLKVSC_RING_BUFFER_SIZE (20*PAGE_SIZE) -#define STORVSC_MAX_IO_REQUESTS 64 +#define STORVSC_MAX_IO_REQUESTS 128 /* * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In -- cgit v1.2.3-59-g8ed1b From 77c5ceaff31645ea049c6706b99e699eae81fb88 Mon Sep 17 00:00:00 2001 From: Hank Janssen Date: Wed, 1 Sep 2010 11:10:41 -0700 Subject: staging: hv: Fixed lockup problem with bounce_buffer scatter list Fixed lockup problem with bounce_buffer scatter list which caused crashes in heavy loads. And minor code indentation cleanup in effected area. Removed whitespace and noted minor indentation changes in description as pointed out by Joe Perches. (Thanks for reviewing Joe) Signed-off-by: Hank Janssen Signed-off-by: Haiyang Zhang Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/storvsc_drv.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c index 3b9ccb062008..62882a437aa4 100644 --- a/drivers/staging/hv/storvsc_drv.c +++ b/drivers/staging/hv/storvsc_drv.c @@ -615,6 +615,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd, unsigned int request_size = 0; int i; struct scatterlist *sgl; + unsigned int sg_count = 0; DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d " "queue depth %d tagged %d", scmnd, scmnd->sc_data_direction, @@ -697,6 +698,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd, request->DataBuffer.Length = scsi_bufflen(scmnd); if (scsi_sg_count(scmnd)) { sgl = (struct scatterlist *)scsi_sglist(scmnd); + sg_count = scsi_sg_count(scmnd); /* check if we need to bounce the sgl */ if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) { @@ -731,15 +733,16 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd, scsi_sg_count(scmnd)); sgl = cmd_request->bounce_sgl; + sg_count = cmd_request->bounce_sgl_count; } request->DataBuffer.Offset = sgl[0].offset; - for (i = 0; i < scsi_sg_count(scmnd); i++) { + for (i = 0; i < sg_count; i++) { DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d\n", i, sgl[i].length, sgl[i].offset); request->DataBuffer.PfnArray[i] = - page_to_pfn(sg_page((&sgl[i]))); + page_to_pfn(sg_page((&sgl[i]))); } } else if (scsi_sglist(scmnd)) { /* ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); */ -- cgit v1.2.3-59-g8ed1b From f8d261d39a24f9f612cb8b2d5ad68654727543cd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 30 Aug 2010 08:57:49 +0200 Subject: staging: spectra needs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On one of my m68k test builds I get: drivers/staging/spectra/ffsport.c: In function ‘ioctl_read_page_data’: drivers/staging/spectra/ffsport.c:196: error: implicit declaration of function ‘kmalloc’ drivers/staging/spectra/ffsport.c:196: warning: assignment makes pointer from integer without a cast drivers/staging/spectra/ffsport.c:212: error: implicit declaration of function ‘kfree’ drivers/staging/spectra/ffsport.c: In function ‘ioctl_write_page_data’: drivers/staging/spectra/ffsport.c:229: warning: assignment makes pointer from integer without a cast drivers/staging/spectra/ffsport.c: In function ‘SBD_setup_device’: drivers/staging/spectra/ffsport.c:637: warning: assignment makes pointer from integer without a cast Signed-off-by: Geert Uytterhoeven Acked-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/ffsport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 44a7fbe7eccd..fa21a0fd8e84 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -28,6 +28,7 @@ #include #include #include +#include /**** Helper functions used for Div, Remainder operation on u64 ****/ -- cgit v1.2.3-59-g8ed1b From 10022a0675a8f8722068d956a798f1fddb02e71c Mon Sep 17 00:00:00 2001 From: Andreas Bombe Date: Sat, 14 Aug 2010 03:24:22 +0200 Subject: staging: comedi das08_cs.c: Fix io_req_t conversion Commit 90abdc3b9 converted all PCMCIA users away from io_req_t. In das08_cs.c the converted IO lines mask setting was added but the old line using the now inexistent p_dev->io was not removed. Signed-off-by: Andreas Bombe Signed-off-by: Dominik Brodowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/das08_cs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index c6aa52f8dcee..48d9fb1227df 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -222,7 +222,6 @@ static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev, p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(io->flags); - p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; p_dev->resource[0]->start = io->win[0].base; p_dev->resource[0]->end = io->win[0].len; if (io->nwin > 1) { -- cgit v1.2.3-59-g8ed1b From 9e693e4375689cb1cd1529aba011de0044f74ef5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 29 Aug 2010 02:13:11 +0100 Subject: Staging: rt2870sta: Add more device IDs from vendor drivers Taken from DPO_RT3070_LinuxSTA_V2.3.0.4_20100604.tar.bz2 and 2010_0709_RT2870_Linux_STA_v2.4.0.1.tar.bz2, with duplicates removed. Signed-off-by: Ben Hutchings Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rt2860/usb_main_dev.c | 41 +++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rt2860/usb_main_dev.c b/drivers/staging/rt2860/usb_main_dev.c index a0fe31de0a6d..ebf9074a9083 100644 --- a/drivers/staging/rt2860/usb_main_dev.c +++ b/drivers/staging/rt2860/usb_main_dev.c @@ -44,6 +44,7 @@ struct usb_device_id rtusb_usb_id[] = { {USB_DEVICE(0x07B8, 0x2870)}, /* AboCom */ {USB_DEVICE(0x07B8, 0x2770)}, /* AboCom */ {USB_DEVICE(0x0DF6, 0x0039)}, /* Sitecom 2770 */ + {USB_DEVICE(0x0DF6, 0x003F)}, /* Sitecom 2770 */ {USB_DEVICE(0x083A, 0x7512)}, /* Arcadyan 2770 */ {USB_DEVICE(0x0789, 0x0162)}, /* Logitec 2870 */ {USB_DEVICE(0x0789, 0x0163)}, /* Logitec 2870 */ @@ -95,7 +96,8 @@ struct usb_device_id rtusb_usb_id[] = { {USB_DEVICE(0x050d, 0x815c)}, {USB_DEVICE(0x1482, 0x3C09)}, /* Abocom */ {USB_DEVICE(0x14B2, 0x3C09)}, /* Alpha */ - {USB_DEVICE(0x04E8, 0x2018)}, /* samsung */ + {USB_DEVICE(0x04E8, 0x2018)}, /* samsung linkstick2 */ + {USB_DEVICE(0x1690, 0x0740)}, /* Askey */ {USB_DEVICE(0x5A57, 0x0280)}, /* Zinwell */ {USB_DEVICE(0x5A57, 0x0282)}, /* Zinwell */ {USB_DEVICE(0x7392, 0x7718)}, @@ -105,21 +107,34 @@ struct usb_device_id rtusb_usb_id[] = { {USB_DEVICE(0x1737, 0x0071)}, /* Linksys WUSB600N */ {USB_DEVICE(0x0411, 0x00e8)}, /* Buffalo WLI-UC-G300N */ {USB_DEVICE(0x050d, 0x815c)}, /* Belkin F5D8053 */ + {USB_DEVICE(0x100D, 0x9031)}, /* Motorola 2770 */ #endif /* RT2870 // */ #ifdef RT3070 {USB_DEVICE(0x148F, 0x3070)}, /* Ralink 3070 */ {USB_DEVICE(0x148F, 0x3071)}, /* Ralink 3071 */ {USB_DEVICE(0x148F, 0x3072)}, /* Ralink 3072 */ {USB_DEVICE(0x0DB0, 0x3820)}, /* Ralink 3070 */ + {USB_DEVICE(0x0DB0, 0x871C)}, /* Ralink 3070 */ + {USB_DEVICE(0x0DB0, 0x822C)}, /* Ralink 3070 */ + {USB_DEVICE(0x0DB0, 0x871B)}, /* Ralink 3070 */ + {USB_DEVICE(0x0DB0, 0x822B)}, /* Ralink 3070 */ {USB_DEVICE(0x0DF6, 0x003E)}, /* Sitecom 3070 */ {USB_DEVICE(0x0DF6, 0x0042)}, /* Sitecom 3072 */ + {USB_DEVICE(0x0DF6, 0x0048)}, /* Sitecom 3070 */ + {USB_DEVICE(0x0DF6, 0x0047)}, /* Sitecom 3071 */ {USB_DEVICE(0x14B2, 0x3C12)}, /* AL 3070 */ {USB_DEVICE(0x18C5, 0x0012)}, /* Corega 3070 */ {USB_DEVICE(0x083A, 0x7511)}, /* Arcadyan 3070 */ + {USB_DEVICE(0x083A, 0xA701)}, /* SMC 3070 */ + {USB_DEVICE(0x083A, 0xA702)}, /* SMC 3072 */ {USB_DEVICE(0x1740, 0x9703)}, /* EnGenius 3070 */ {USB_DEVICE(0x1740, 0x9705)}, /* EnGenius 3071 */ {USB_DEVICE(0x1740, 0x9706)}, /* EnGenius 3072 */ + {USB_DEVICE(0x1740, 0x9707)}, /* EnGenius 3070 */ + {USB_DEVICE(0x1740, 0x9708)}, /* EnGenius 3071 */ + {USB_DEVICE(0x1740, 0x9709)}, /* EnGenius 3072 */ {USB_DEVICE(0x13D3, 0x3273)}, /* AzureWave 3070 */ + {USB_DEVICE(0x13D3, 0x3305)}, /* AzureWave 3070*/ {USB_DEVICE(0x1044, 0x800D)}, /* Gigabyte GN-WB32L 3070 */ {USB_DEVICE(0x2019, 0xAB25)}, /* Planex Communications, Inc. RT3070 */ {USB_DEVICE(0x07B8, 0x3070)}, /* AboCom 3070 */ @@ -132,14 +147,36 @@ struct usb_device_id rtusb_usb_id[] = { {USB_DEVICE(0x07D1, 0x3C0D)}, /* D-Link 3070 */ {USB_DEVICE(0x07D1, 0x3C0E)}, /* D-Link 3070 */ {USB_DEVICE(0x07D1, 0x3C0F)}, /* D-Link 3070 */ + {USB_DEVICE(0x07D1, 0x3C16)}, /* D-Link 3070 */ + {USB_DEVICE(0x07D1, 0x3C17)}, /* D-Link 8070 */ {USB_DEVICE(0x1D4D, 0x000C)}, /* Pegatron Corporation 3070 */ {USB_DEVICE(0x1D4D, 0x000E)}, /* Pegatron Corporation 3070 */ {USB_DEVICE(0x5A57, 0x5257)}, /* Zinwell 3070 */ {USB_DEVICE(0x5A57, 0x0283)}, /* Zinwell 3072 */ {USB_DEVICE(0x04BB, 0x0945)}, /* I-O DATA 3072 */ + {USB_DEVICE(0x04BB, 0x0947)}, /* I-O DATA 3070 */ + {USB_DEVICE(0x04BB, 0x0948)}, /* I-O DATA 3072 */ {USB_DEVICE(0x203D, 0x1480)}, /* Encore 3070 */ + {USB_DEVICE(0x20B8, 0x8888)}, /* PARA INDUSTRIAL 3070 */ + {USB_DEVICE(0x0B05, 0x1784)}, /* Asus 3072 */ + {USB_DEVICE(0x203D, 0x14A9)}, /* Encore 3070*/ + {USB_DEVICE(0x0DB0, 0x899A)}, /* MSI 3070*/ + {USB_DEVICE(0x0DB0, 0x3870)}, /* MSI 3070*/ + {USB_DEVICE(0x0DB0, 0x870A)}, /* MSI 3070*/ + {USB_DEVICE(0x0DB0, 0x6899)}, /* MSI 3070 */ + {USB_DEVICE(0x0DB0, 0x3822)}, /* MSI 3070 */ + {USB_DEVICE(0x0DB0, 0x3871)}, /* MSI 3070 */ + {USB_DEVICE(0x0DB0, 0x871A)}, /* MSI 3070 */ + {USB_DEVICE(0x0DB0, 0x822A)}, /* MSI 3070 */ + {USB_DEVICE(0x0DB0, 0x3821)}, /* Ralink 3070 */ + {USB_DEVICE(0x0DB0, 0x821A)}, /* Ralink 3070 */ + {USB_DEVICE(0x083A, 0xA703)}, /* IO-MAGIC */ + {USB_DEVICE(0x13D3, 0x3307)}, /* Azurewave */ + {USB_DEVICE(0x13D3, 0x3321)}, /* Azurewave */ + {USB_DEVICE(0x07FA, 0x7712)}, /* Edimax */ + {USB_DEVICE(0x0789, 0x0166)}, /* Edimax */ + {USB_DEVICE(0x148F, 0x2070)}, /* Edimax */ #endif /* RT3070 // */ - {USB_DEVICE(0x0DF6, 0x003F)}, /* Sitecom WL-608 */ {USB_DEVICE(0x1737, 0x0077)}, /* Linksys WUSB54GC-EU v3 */ {USB_DEVICE(0x2001, 0x3C09)}, /* D-Link */ {USB_DEVICE(0x2001, 0x3C0A)}, /* D-Link 3072 */ -- cgit v1.2.3-59-g8ed1b From 273ad8dcef345cac55a5db910137c10953f81480 Mon Sep 17 00:00:00 2001 From: Shahar Havivi Date: Sat, 28 Aug 2010 10:09:05 +0300 Subject: Staging: zram: free device memory when init fails Signed-off-by: Shahar Havivi Cc: Nitin Gupta Signed-off-by: Greg Kroah-Hartman --- drivers/staging/zram/zram_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 77d4d715a789..722c840ac638 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -769,6 +769,7 @@ static int __init zram_init(void) free_devices: while (dev_id) destroy_device(&devices[--dev_id]); + kfree(devices); unregister: unregister_blkdev(zram_major, "zram"); out: -- cgit v1.2.3-59-g8ed1b From 11ac33a5f29a8e96ec76097ec1b3de3a4045f4b6 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 24 Aug 2010 12:12:26 -0400 Subject: Staging: spectra: depend on X86_MRST lld_nand fails to build on arches without virt_to_bus. Since this driver is specifically for hardware enablment on Moorestown, this patch adds Moorestown MID support as a dependency. Signed-off-by: Jeff Mahoney Cc: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/staging/spectra/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/spectra/Kconfig b/drivers/staging/spectra/Kconfig index 5e2ffefb60af..d231ae27299d 100644 --- a/drivers/staging/spectra/Kconfig +++ b/drivers/staging/spectra/Kconfig @@ -2,6 +2,7 @@ menuconfig SPECTRA tristate "Denali Spectra Flash Translation Layer" depends on BLOCK + depends on X86_MRST default n ---help--- Enable the FTL pseudo-filesystem used with the NAND Flash -- cgit v1.2.3-59-g8ed1b From 95c46ed9c99f9a3fc4954fc1b7cc1509a359efbb Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 24 Aug 2010 14:09:40 -0700 Subject: Staging: octeon: depends on NETDEVICES OCTEON_ETHERNET should depend on NETDEVICES. Fixes this kconfig warning: warning: (NET_DSA && NET && EXPERIMENTAL && NETDEVICES && !S390 || ... || OCTEON_ETHERNET && STAGING && !STAGING_EXCLUDE_BUILD && CPU_CAVIUM_OCTEON) selects PHYLIB which has unmet direct dependencies (!S390 && NETDEVICES) Reported-by: Arnaud Lacombe Signed-off-by: Randy Dunlap Cc: support@caviumnetworks.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/octeon/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/octeon/Kconfig b/drivers/staging/octeon/Kconfig index 638ad6b35891..9493128e5fd2 100644 --- a/drivers/staging/octeon/Kconfig +++ b/drivers/staging/octeon/Kconfig @@ -1,6 +1,6 @@ config OCTEON_ETHERNET tristate "Cavium Networks Octeon Ethernet support" - depends on CPU_CAVIUM_OCTEON + depends on CPU_CAVIUM_OCTEON && NETDEVICES select PHYLIB select MDIO_OCTEON help -- cgit v1.2.3-59-g8ed1b From aff3ea4e5d4b0280d1c631fcce048e7f009bc3e5 Mon Sep 17 00:00:00 2001 From: Karl Relton Date: Wed, 11 Aug 2010 18:16:08 +0100 Subject: Staging: wlan-ng: Explicitly set some fields in cfg80211 interface The cfg80211 api has introduced a few new fields. Rather than assume what cfg80211 api does by default, set these explicitly. Signed-off-by: Karl Relton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/cfg80211.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 368c30a9d5ff..4af83d5318f2 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -219,6 +219,7 @@ int prism2_get_key(struct wiphy *wiphy, struct net_device *dev, return -ENOENT; params.key_len = len; params.key = wlandev->wep_keys[key_index]; + params.seq_len = 0; callback(cookie, ¶ms); @@ -735,6 +736,8 @@ struct wiphy *wlan_create_wiphy(struct device *dev, wlandevice_t *wlandev) priv->band.n_channels = ARRAY_SIZE(prism2_channels); priv->band.bitrates = priv->rates; priv->band.n_bitrates = ARRAY_SIZE(prism2_rates); + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.ht_cap.ht_supported = false; wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; set_wiphy_dev(wiphy, dev); -- cgit v1.2.3-59-g8ed1b From d06563cb860ab594889010889a7111c9e25d1051 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 4 Sep 2010 23:10:48 +0800 Subject: regulator: 88pm8607 - fix value range checking for accessing info->vol_table In choose_voltage(), we use i as array index of info->vol_table. The valid value range for i should be 0 .. ARRAY_SIZE(info->vol_table) - 1. Take LDO1 as example, ARRAY_SIZE(LDO1_table) is 4, vol_nbits of LDO1 is 2. for (i = 0; i < (2 << info->vol_nbits); i++) is equivalent to for (i = 0; i < 8; i++) which is wrong. The same value range checking also applies for index in pm8607_list_voltage(). Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/88pm8607.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 7d149a8d8d9b..2ce2eb71d0f5 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -215,7 +215,7 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); int ret = -EINVAL; - if (info->vol_table && (index < (2 << info->vol_nbits))) { + if (info->vol_table && (index < (1 << info->vol_nbits))) { ret = info->vol_table[index]; if (info->slope_double) ret <<= 1; @@ -233,7 +233,7 @@ static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) max_uV = max_uV >> 1; } if (info->vol_table) { - for (i = 0; i < (2 << info->vol_nbits); i++) { + for (i = 0; i < (1 << info->vol_nbits); i++) { if (!info->vol_table[i]) break; if ((min_uV <= info->vol_table[i]) -- cgit v1.2.3-59-g8ed1b From 49990e6efe576b8707584398f93198b5aa182ab7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 4 Sep 2010 23:06:41 +0800 Subject: regulator: ab8500 - fix off-by-one value range checking for selector selector is used as array index of info->supported_voltages Thus the valid value range should be 0 .. info->voltages_len -1 Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 3d09580dc883..28c7ae67cec9 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -157,7 +157,7 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) if (info->fixed_uV) return info->fixed_uV; - if (selector > info->voltages_len) + if (selector >= info->voltages_len) return -EINVAL; return info->supported_voltages[selector]; -- cgit v1.2.3-59-g8ed1b From cc1a8e523333bc3d990102140f4d12908fa83caf Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 4 Sep 2010 22:56:43 +0200 Subject: x86: Fix the address space annotations of iomap_atomic_prot_pfn() This patch fixes the sparse warnings when the return pointer of iomap_atomic_prot_pfn() is used as an argument of iowrite32() and friends. Signed-off-by: Francisco Jerez LKML-Reference: <1283633804-11749-1-git-send-email-currojerez@riseup.net> Cc: Andrew Morton Signed-off-by: Ingo Molnar --- arch/x86/include/asm/iomap.h | 4 ++-- arch/x86/mm/iomap_32.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/iomap.h b/arch/x86/include/asm/iomap.h index f35eb45d6576..c4191b3b7056 100644 --- a/arch/x86/include/asm/iomap.h +++ b/arch/x86/include/asm/iomap.h @@ -26,11 +26,11 @@ #include #include -void * +void __iomem * iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot); void -iounmap_atomic(void *kvaddr, enum km_type type); +iounmap_atomic(void __iomem *kvaddr, enum km_type type); int iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot); diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c index 84e236ce76ba..72fc70cf6184 100644 --- a/arch/x86/mm/iomap_32.c +++ b/arch/x86/mm/iomap_32.c @@ -74,7 +74,7 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot) /* * Map 'pfn' using fixed map 'type' and protections 'prot' */ -void * +void __iomem * iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot) { /* @@ -86,12 +86,12 @@ iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot) if (!pat_enabled && pgprot_val(prot) == pgprot_val(PAGE_KERNEL_WC)) prot = PAGE_KERNEL_UC_MINUS; - return kmap_atomic_prot_pfn(pfn, type, prot); + return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, type, prot); } EXPORT_SYMBOL_GPL(iomap_atomic_prot_pfn); void -iounmap_atomic(void *kvaddr, enum km_type type) +iounmap_atomic(void __iomem *kvaddr, enum km_type type) { unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); -- cgit v1.2.3-59-g8ed1b From 29bc17ecb856ffb2b47c7009a71971c6f9334205 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sat, 4 Sep 2010 22:56:44 +0200 Subject: io-mapping: Fix the address space annotations Fixes a bunch of sparse warnings in io-mapping.h because of the inconsistent __iomem usage. Signed-off-by: Francisco Jerez LKML-Reference: <1283633804-11749-2-git-send-email-currojerez@riseup.net> Cc: Andrew Morton Signed-off-by: Ingo Molnar --- include/linux/io-mapping.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h index 0a6b3d5c490c..7fb592793738 100644 --- a/include/linux/io-mapping.h +++ b/include/linux/io-mapping.h @@ -79,7 +79,7 @@ io_mapping_free(struct io_mapping *mapping) } /* Atomic map/unmap */ -static inline void * +static inline void __iomem * io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset, int slot) @@ -94,12 +94,12 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping, } static inline void -io_mapping_unmap_atomic(void *vaddr, int slot) +io_mapping_unmap_atomic(void __iomem *vaddr, int slot) { iounmap_atomic(vaddr, slot); } -static inline void * +static inline void __iomem * io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset) { resource_size_t phys_addr; @@ -111,7 +111,7 @@ io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset) } static inline void -io_mapping_unmap(void *vaddr) +io_mapping_unmap(void __iomem *vaddr) { iounmap(vaddr); } @@ -125,38 +125,38 @@ struct io_mapping; static inline struct io_mapping * io_mapping_create_wc(resource_size_t base, unsigned long size) { - return (struct io_mapping *) ioremap_wc(base, size); + return (struct io_mapping __force *) ioremap_wc(base, size); } static inline void io_mapping_free(struct io_mapping *mapping) { - iounmap(mapping); + iounmap((void __force __iomem *) mapping); } /* Atomic map/unmap */ -static inline void * +static inline void __iomem * io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset, int slot) { - return ((char *) mapping) + offset; + return ((char __force __iomem *) mapping) + offset; } static inline void -io_mapping_unmap_atomic(void *vaddr, int slot) +io_mapping_unmap_atomic(void __iomem *vaddr, int slot) { } /* Non-atomic map/unmap */ -static inline void * +static inline void __iomem * io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset) { - return ((char *) mapping) + offset; + return ((char __force __iomem *) mapping) + offset; } static inline void -io_mapping_unmap(void *vaddr) +io_mapping_unmap(void __iomem *vaddr) { } -- cgit v1.2.3-59-g8ed1b From 1389298f7d14f179c2fa4b4b343079bd56082c70 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 27 Aug 2010 11:20:07 +0200 Subject: x86, mcheck: Avoid duplicate sysfs links/files for thresholding banks kobject_add_internal failed for threshold_bank2 with -EEXIST, don't try to register things with the same name in the same directory: Pid: 1, comm: swapper Tainted: G W 2.6.31 #1 Call Trace: [] ? kobject_add_internal+0x156/0x180 [] ? kobject_add+0x66/0x6b [] ? kobject_init+0x42/0x82 [] ? kobject_create_and_add+0x34/0x63 [] ? threshold_create_bank+0x14f/0x259 [] ? mce_create_device+0x8d/0x1b8 [] ? threshold_init_device+0x3f/0x80 [] ? threshold_init_device+0x0/0x80 [] ? do_one_initcall+0x4f/0x143 [] ? kernel_init+0x14c/0x1a2 [] ? child_rip+0xa/0x20 [] ? kernel_init+0x0/0x1a2 [] ? child_rip+0x0/0x20 kobject_create_and_add: kobject_add error: -17 (Probably the for_each_cpu loop should be entirely removed.) Signed-off-by: Andreas Herrmann LKML-Reference: <20100827092006.GB5348@loge.amd.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/mcheck/mce_amd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 224392d8fe8c..5e975298fa81 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -530,7 +530,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) err = -ENOMEM; goto out; } - if (!alloc_cpumask_var(&b->cpus, GFP_KERNEL)) { + if (!zalloc_cpumask_var(&b->cpus, GFP_KERNEL)) { kfree(b); err = -ENOMEM; goto out; @@ -543,7 +543,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank) #ifndef CONFIG_SMP cpumask_setall(b->cpus); #else - cpumask_copy(b->cpus, c->llc_shared_map); + cpumask_set_cpu(cpu, b->cpus); #endif per_cpu(threshold_banks, cpu)[bank] = b; -- cgit v1.2.3-59-g8ed1b From b3bd3de66f60df4c9a2076e2886a622458929056 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 10 Aug 2010 14:17:51 -0700 Subject: gcc-4.6: kernel/*: Fix unused but set warnings No real bugs I believe, just some dead code. Signed-off-by: Andi Kleen Cc: Peter Zijlstra Cc: andi@firstfloor.org Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar --- kernel/debug/kdb/kdb_bp.c | 2 -- kernel/hrtimer.c | 3 +-- kernel/sched_fair.c | 3 +-- kernel/sysctl.c | 5 +---- kernel/trace/ring_buffer.c | 2 -- 5 files changed, 3 insertions(+), 12 deletions(-) diff --git a/kernel/debug/kdb/kdb_bp.c b/kernel/debug/kdb/kdb_bp.c index 75bd9b3ebbb7..20059ef4459a 100644 --- a/kernel/debug/kdb/kdb_bp.c +++ b/kernel/debug/kdb/kdb_bp.c @@ -274,7 +274,6 @@ static int kdb_bp(int argc, const char **argv) int i, bpno; kdb_bp_t *bp, *bp_check; int diag; - int free; char *symname = NULL; long offset = 0ul; int nextarg; @@ -305,7 +304,6 @@ static int kdb_bp(int argc, const char **argv) /* * Find an empty bp structure to allocate */ - free = KDB_MAXBPT; for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT; bpno++, bp++) { if (bp->bp_free) break; diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index ce669174f355..1decafbb6b1a 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1091,11 +1091,10 @@ EXPORT_SYMBOL_GPL(hrtimer_cancel); */ ktime_t hrtimer_get_remaining(const struct hrtimer *timer) { - struct hrtimer_clock_base *base; unsigned long flags; ktime_t rem; - base = lock_hrtimer_base(timer, &flags); + lock_hrtimer_base(timer, &flags); rem = hrtimer_expires_remaining(timer); unlock_hrtimer_base(timer, &flags); diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index ab661ebc4895..134f7edb30c6 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -1313,7 +1313,7 @@ static struct sched_group * find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu, int load_idx) { - struct sched_group *idlest = NULL, *this = NULL, *group = sd->groups; + struct sched_group *idlest = NULL, *group = sd->groups; unsigned long min_load = ULONG_MAX, this_load = 0; int imbalance = 100 + (sd->imbalance_pct-100)/2; @@ -1348,7 +1348,6 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, if (local_group) { this_load = avg_load; - this = group; } else if (avg_load < min_load) { min_load = avg_load; idlest = group; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ca38e8e3e907..f88552c6d227 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1713,10 +1713,7 @@ static __init int sysctl_init(void) { sysctl_set_parent(NULL, root_table); #ifdef CONFIG_SYSCTL_SYSCALL_CHECK - { - int err; - err = sysctl_check_table(current->nsproxy, root_table); - } + sysctl_check_table(current->nsproxy, root_table); #endif return 0; } diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 19cccc3c3028..492197e2f86c 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2985,13 +2985,11 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer) static void rb_advance_iter(struct ring_buffer_iter *iter) { - struct ring_buffer *buffer; struct ring_buffer_per_cpu *cpu_buffer; struct ring_buffer_event *event; unsigned length; cpu_buffer = iter->cpu_buffer; - buffer = cpu_buffer->buffer; /* * Check if we are at the end of the buffer. -- cgit v1.2.3-59-g8ed1b From 73457f0f836956747e0394320be2163c050e96ef Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 6 Aug 2010 01:59:14 +0300 Subject: cgroups: fix API thinko cgroup_attach_task_current_cg API that have upstream is backwards: we really need an API to attach to the cgroups from another process A to the current one. In our case (vhost), a priveledged user wants to attach it's task to cgroups from a less priveledged one, the API makes us run it in the other task's context, and this fails. So let's make the API generic and just pass in 'from' and 'to' tasks. Add an inline wrapper for cgroup_attach_task_current_cg to avoid breaking bisect. Signed-off-by: Michael S. Tsirkin Acked-by: Li Zefan Acked-by: Paul Menage --- include/linux/cgroup.h | 11 ++++++++++- kernel/cgroup.c | 9 +++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index ed3e92e41c6e..5a53d8f039a2 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -578,7 +578,11 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it); int cgroup_scan_tasks(struct cgroup_scanner *scan); int cgroup_attach_task(struct cgroup *, struct task_struct *); -int cgroup_attach_task_current_cg(struct task_struct *); +int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); +static inline int cgroup_attach_task_current_cg(struct task_struct *tsk) +{ + return cgroup_attach_task_all(current, tsk); +} /* * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works @@ -636,6 +640,11 @@ static inline int cgroupstats_build(struct cgroupstats *stats, } /* No cgroups - nothing to do */ +static inline int cgroup_attach_task_all(struct task_struct *from, + struct task_struct *t) +{ + return 0; +} static inline int cgroup_attach_task_current_cg(struct task_struct *t) { return 0; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a8ce09954404..9d90c08f3bde 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1789,10 +1789,11 @@ out: } /** - * cgroup_attach_task_current_cg - attach task 'tsk' to current task's cgroup + * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from' + * @from: attach to all cgroups of a given task * @tsk: the task to be attached */ -int cgroup_attach_task_current_cg(struct task_struct *tsk) +int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk) { struct cgroupfs_root *root; struct cgroup *cur_cg; @@ -1800,7 +1801,7 @@ int cgroup_attach_task_current_cg(struct task_struct *tsk) cgroup_lock(); for_each_active_root(root) { - cur_cg = task_cgroup_from_root(current, root); + cur_cg = task_cgroup_from_root(from, root); retval = cgroup_attach_task(cur_cg, tsk); if (retval) break; @@ -1809,7 +1810,7 @@ int cgroup_attach_task_current_cg(struct task_struct *tsk) return retval; } -EXPORT_SYMBOL_GPL(cgroup_attach_task_current_cg); +EXPORT_SYMBOL_GPL(cgroup_attach_task_all); /* * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex -- cgit v1.2.3-59-g8ed1b From feafb7b1714cf599a6d0fed45801ab3f66046cbd Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Fri, 3 Sep 2010 14:57:00 -0700 Subject: [SCSI] qla2xxx: Fix vport delete issues Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 23 ++++++---- drivers/scsi/qla2xxx/qla_dbg.h | 2 - drivers/scsi/qla2xxx/qla_def.h | 20 +++++++++ drivers/scsi/qla2xxx/qla_init.c | 94 +++++++++++++++++++++++++++++++++++------ drivers/scsi/qla2xxx/qla_mbx.c | 7 ++- drivers/scsi/qla2xxx/qla_mid.c | 67 ++++++++++++++++++++++++++--- drivers/scsi/qla2xxx/qla_os.c | 30 +++++++++++-- 7 files changed, 207 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 420238cc794e..114bc5a81171 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1838,26 +1838,33 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) qla24xx_disable_vp(vha); + vha->flags.delete_progress = 1; + fc_remove_host(vha->host); scsi_remove_host(vha->host); - qla2x00_free_fcports(vha); + if (vha->timer_active) { + qla2x00_vp_stop_timer(vha); + DEBUG15(printk(KERN_INFO "scsi(%ld): timer for the vport[%d]" + " = %p has stopped\n", vha->host_no, vha->vp_idx, vha)); + } qla24xx_deallocate_vp_id(vha); + /* No pending activities shall be there on the vha now */ + DEBUG(msleep(random32()%10)); /* Just to see if something falls on + * the net we have placed below */ + + BUG_ON(atomic_read(&vha->vref_count)); + + qla2x00_free_fcports(vha); + mutex_lock(&ha->vport_lock); ha->cur_vport_count--; clear_bit(vha->vp_idx, ha->vp_idx_map); mutex_unlock(&ha->vport_lock); - if (vha->timer_active) { - qla2x00_vp_stop_timer(vha); - DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p " - "has stopped\n", - vha->host_no, vha->vp_idx, vha)); - } - if (vha->req->id && !ha->flags.cpu_affinity_enabled) { if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) qla_printk(KERN_WARNING, ha, diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 6cfc28a25eb3..b74e6b5743dc 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -29,8 +29,6 @@ /* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */ /* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */ -/* #define QL_PRINTK_BUF */ /* Captures printk to buffer */ - /* * Macros use for debugging the driver. */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3a432ea0c7a3..d2a4e1530708 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2641,6 +2641,7 @@ struct qla_hw_data { #define MBX_UPDATE_FLASH_ACTIVE 3 struct mutex vport_lock; /* Virtual port synchronization */ + spinlock_t vport_slock; /* order is hardware_lock, then vport_slock */ struct completion mbx_cmd_comp; /* Serialize mbx access */ struct completion mbx_intr_comp; /* Used for completion notification */ struct completion dcbx_comp; /* For set port config notification */ @@ -2828,6 +2829,7 @@ typedef struct scsi_qla_host { uint32_t management_server_logged_in :1; uint32_t process_response_queue :1; uint32_t difdix_supported:1; + uint32_t delete_progress:1; } flags; atomic_t loop_state; @@ -2922,6 +2924,8 @@ typedef struct scsi_qla_host { struct req_que *req; int fw_heartbeat_counter; int seconds_since_last_heartbeat; + + atomic_t vref_count; } scsi_qla_host_t; /* @@ -2932,6 +2936,22 @@ typedef struct scsi_qla_host { test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \ atomic_read(&ha->loop_state) == LOOP_DOWN) +#define QLA_VHA_MARK_BUSY(__vha, __bail) do { \ + atomic_inc(&__vha->vref_count); \ + mb(); \ + if (__vha->flags.delete_progress) { \ + atomic_dec(&__vha->vref_count); \ + __bail = 1; \ + } else { \ + __bail = 0; \ + } \ +} while (0) + +#define QLA_VHA_MARK_NOT_BUSY(__vha) do { \ + atomic_dec(&__vha->vref_count); \ +} while (0) + + #define qla_printk(level, ha, format, arg...) \ dev_printk(level , &((ha)->pdev->dev) , format , ## arg) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d863ed2619b5..9c383baebe27 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -69,21 +69,29 @@ qla2x00_ctx_sp_free(srb_t *sp) { struct srb_ctx *ctx = sp->ctx; struct srb_iocb *iocb = ctx->u.iocb_cmd; + struct scsi_qla_host *vha = sp->fcport->vha; del_timer_sync(&iocb->timer); kfree(iocb); kfree(ctx); mempool_free(sp, sp->fcport->vha->hw->srb_mempool); + + QLA_VHA_MARK_NOT_BUSY(vha); } inline srb_t * qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, unsigned long tmo) { - srb_t *sp; + srb_t *sp = NULL; struct qla_hw_data *ha = vha->hw; struct srb_ctx *ctx; struct srb_iocb *iocb; + uint8_t bail; + + QLA_VHA_MARK_BUSY(vha, bail); + if (bail) + return NULL; sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL); if (!sp) @@ -116,6 +124,8 @@ qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size, iocb->timer.function = qla2x00_ctx_sp_timeout; add_timer(&iocb->timer); done: + if (!sp) + QLA_VHA_MARK_NOT_BUSY(vha); return sp; } @@ -1777,11 +1787,15 @@ qla2x00_init_rings(scsi_qla_host_t *vha) qla2x00_init_response_q_entries(rsp); } + spin_lock_irqsave(&ha->vport_slock, flags); /* Clear RSCN queue. */ list_for_each_entry(vp, &ha->vp_list, list) { vp->rscn_in_ptr = 0; vp->rscn_out_ptr = 0; } + + spin_unlock_irqrestore(&ha->vport_slock, flags); + ha->isp_ops->config_rings(vha); spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -3218,12 +3232,17 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, /* Bypass virtual ports of the same host. */ found = 0; if (ha->num_vhosts) { + unsigned long flags; + + spin_lock_irqsave(&ha->vport_slock, flags); list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (new_fcport->d_id.b24 == vp->d_id.b24) { found = 1; break; } } + spin_unlock_irqrestore(&ha->vport_slock, flags); + if (found) continue; } @@ -3343,6 +3362,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp; struct scsi_qla_host *tvp; + unsigned long flags = 0; rval = QLA_SUCCESS; @@ -3367,6 +3387,8 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) /* Check for loop ID being already in use. */ found = 0; fcport = NULL; + + spin_lock_irqsave(&ha->vport_slock, flags); list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { list_for_each_entry(fcport, &vp->vp_fcports, list) { if (fcport->loop_id == dev->loop_id && @@ -3379,6 +3401,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) if (found) break; } + spin_unlock_irqrestore(&ha->vport_slock, flags); /* If not in use then it is free to use. */ if (!found) { @@ -3791,14 +3814,27 @@ void qla2x00_update_fcports(scsi_qla_host_t *base_vha) { fc_port_t *fcport; - struct scsi_qla_host *tvp, *vha; + struct scsi_qla_host *vha; + struct qla_hw_data *ha = base_vha->hw; + unsigned long flags; + spin_lock_irqsave(&ha->vport_slock, flags); /* Go with deferred removal of rport references. */ - list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list) - list_for_each_entry(fcport, &vha->vp_fcports, list) + list_for_each_entry(vha, &base_vha->hw->vp_list, list) { + atomic_inc(&vha->vref_count); + list_for_each_entry(fcport, &vha->vp_fcports, list) { if (fcport && fcport->drport && - atomic_read(&fcport->state) != FCS_UNCONFIGURED) + atomic_read(&fcport->state) != FCS_UNCONFIGURED) { + spin_unlock_irqrestore(&ha->vport_slock, flags); + qla2x00_rport_del(fcport); + + spin_lock_irqsave(&ha->vport_slock, flags); + } + } + atomic_dec(&vha->vref_count); + } + spin_unlock_irqrestore(&ha->vport_slock, flags); } void @@ -3806,7 +3842,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); - struct scsi_qla_host *tvp; + unsigned long flags; vha->flags.online = 0; ha->flags.chip_reset_done = 0; @@ -3824,8 +3860,18 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) if (atomic_read(&vha->loop_state) != LOOP_DOWN) { atomic_set(&vha->loop_state, LOOP_DOWN); qla2x00_mark_all_devices_lost(vha, 0); - list_for_each_entry_safe(vp, tvp, &base_vha->hw->vp_list, list) + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &base_vha->hw->vp_list, list) { + atomic_inc(&vp->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); + qla2x00_mark_all_devices_lost(vp, 0); + + spin_lock_irqsave(&ha->vport_slock, flags); + atomic_dec(&vp->vref_count); + } + spin_unlock_irqrestore(&ha->vport_slock, flags); } else { if (!atomic_read(&vha->loop_down_timer)) atomic_set(&vha->loop_down_timer, @@ -3862,8 +3908,8 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) uint8_t status = 0; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp; - struct scsi_qla_host *tvp; struct req_que *req = ha->req_q_map[0]; + unsigned long flags; if (vha->flags.online) { qla2x00_abort_isp_cleanup(vha); @@ -3970,10 +4016,21 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) DEBUG(printk(KERN_INFO "qla2x00_abort_isp(%ld): succeeded.\n", vha->host_no)); - list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { - if (vp->vp_idx) + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) { + if (vp->vp_idx) { + atomic_inc(&vp->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); + qla2x00_vp_abort_isp(vp); + + spin_lock_irqsave(&ha->vport_slock, flags); + atomic_dec(&vp->vref_count); + } } + spin_unlock_irqrestore(&ha->vport_slock, flags); + } else { qla_printk(KERN_INFO, ha, "qla2x00_abort_isp: **** FAILED ****\n"); @@ -5185,7 +5242,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) struct req_que *req = ha->req_q_map[0]; struct rsp_que *rsp = ha->rsp_q_map[0]; struct scsi_qla_host *vp; - struct scsi_qla_host *tvp; + unsigned long flags; status = qla2x00_init_rings(vha); if (!status) { @@ -5272,10 +5329,21 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) DEBUG(printk(KERN_INFO "qla82xx_restart_isp(%ld): succeeded.\n", vha->host_no)); - list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { - if (vp->vp_idx) + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) { + if (vp->vp_idx) { + atomic_inc(&vp->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); + qla2x00_vp_abort_isp(vp); + + spin_lock_irqsave(&ha->vport_slock, flags); + atomic_dec(&vp->vref_count); + } } + spin_unlock_irqrestore(&ha->vport_slock, flags); + } else { qla_printk(KERN_INFO, ha, "qla82xx_restart_isp: **** FAILED ****\n"); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 6009b0c69488..a595ec8264f8 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2913,7 +2913,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, uint16_t stat = le16_to_cpu(rptid_entry->vp_idx); struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *vp; - scsi_qla_host_t *tvp; + unsigned long flags; if (rptid_entry->entry_status != 0) return; @@ -2945,9 +2945,12 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, return; } - list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) if (vp_idx == vp->vp_idx) break; + spin_unlock_irqrestore(&ha->vport_slock, flags); + if (!vp) return; diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 987c5b0ca78e..bc1a7453c5d8 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -30,6 +30,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) { uint32_t vp_id; struct qla_hw_data *ha = vha->hw; + unsigned long flags; /* Find an empty slot and assign an vp_id */ mutex_lock(&ha->vport_lock); @@ -44,7 +45,11 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) set_bit(vp_id, ha->vp_idx_map); ha->num_vhosts++; vha->vp_idx = vp_id; + + spin_lock_irqsave(&ha->vport_slock, flags); list_add_tail(&vha->list, &ha->vp_list); + spin_unlock_irqrestore(&ha->vport_slock, flags); + mutex_unlock(&ha->vport_lock); return vp_id; } @@ -54,12 +59,31 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) { uint16_t vp_id; struct qla_hw_data *ha = vha->hw; + unsigned long flags = 0; mutex_lock(&ha->vport_lock); + /* + * Wait for all pending activities to finish before removing vport from + * the list. + * Lock needs to be held for safe removal from the list (it + * ensures no active vp_list traversal while the vport is removed + * from the queue) + */ + spin_lock_irqsave(&ha->vport_slock, flags); + while (atomic_read(&vha->vref_count)) { + spin_unlock_irqrestore(&ha->vport_slock, flags); + + msleep(500); + + spin_lock_irqsave(&ha->vport_slock, flags); + } + list_del(&vha->list); + spin_unlock_irqrestore(&ha->vport_slock, flags); + vp_id = vha->vp_idx; ha->num_vhosts--; clear_bit(vp_id, ha->vp_idx_map); - list_del(&vha->list); + mutex_unlock(&ha->vport_lock); } @@ -68,12 +92,17 @@ qla24xx_find_vhost_by_name(struct qla_hw_data *ha, uint8_t *port_name) { scsi_qla_host_t *vha; struct scsi_qla_host *tvha; + unsigned long flags; + spin_lock_irqsave(&ha->vport_slock, flags); /* Locate matching device in database. */ list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { - if (!memcmp(port_name, vha->port_name, WWN_SIZE)) + if (!memcmp(port_name, vha->port_name, WWN_SIZE)) { + spin_unlock_irqrestore(&ha->vport_slock, flags); return vha; + } } + spin_unlock_irqrestore(&ha->vport_slock, flags); return NULL; } @@ -93,6 +122,12 @@ qla24xx_find_vhost_by_name(struct qla_hw_data *ha, uint8_t *port_name) static void qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) { + /* + * !!! NOTE !!! + * This function, if called in contexts other than vp create, disable + * or delete, please make sure this is synchronized with the + * delete thread. + */ fc_port_t *fcport; list_for_each_entry(fcport, &vha->vp_fcports, list) { @@ -194,12 +229,17 @@ qla24xx_configure_vp(scsi_qla_host_t *vha) void qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) { - scsi_qla_host_t *vha, *tvha; + scsi_qla_host_t *vha; struct qla_hw_data *ha = rsp->hw; int i = 0; + unsigned long flags; - list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vha, &ha->vp_list, list) { if (vha->vp_idx) { + atomic_inc(&vha->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); + switch (mb[0]) { case MBA_LIP_OCCURRED: case MBA_LOOP_UP: @@ -215,9 +255,13 @@ qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) qla2x00_async_event(vha, rsp, mb); break; } + + spin_lock_irqsave(&ha->vport_slock, flags); + atomic_dec(&vha->vref_count); } i++; } + spin_unlock_irqrestore(&ha->vport_slock, flags); } int @@ -297,7 +341,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) int ret; struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *vp; - struct scsi_qla_host *tvp; + unsigned long flags = 0; if (vha->vp_idx) return; @@ -309,10 +353,19 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) if (!(ha->current_topology & ISP_CFG_F)) return; - list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { - if (vp->vp_idx) + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) { + if (vp->vp_idx) { + atomic_inc(&vp->vref_count); + spin_unlock_irqrestore(&ha->vport_slock, flags); + ret = qla2x00_do_dpc_vp(vp); + + spin_lock_irqsave(&ha->vport_slock, flags); + atomic_dec(&vp->vref_count); + } } + spin_unlock_irqrestore(&ha->vport_slock, flags); } int diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8c80b49ac1c4..1e4bff695254 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2341,16 +2341,28 @@ probe_out: static void qla2x00_remove_one(struct pci_dev *pdev) { - scsi_qla_host_t *base_vha, *vha, *temp; + scsi_qla_host_t *base_vha, *vha; struct qla_hw_data *ha; + unsigned long flags; base_vha = pci_get_drvdata(pdev); ha = base_vha->hw; - list_for_each_entry_safe(vha, temp, &ha->vp_list, list) { - if (vha && vha->fc_vport) + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vha, &ha->vp_list, list) { + atomic_inc(&vha->vref_count); + + if (vha && vha->fc_vport) { + spin_unlock_irqrestore(&ha->vport_slock, flags); + fc_vport_terminate(vha->fc_vport); + + spin_lock_irqsave(&ha->vport_slock, flags); + } + + atomic_dec(&vha->vref_count); } + spin_unlock_irqrestore(&ha->vport_slock, flags); set_bit(UNLOADING, &base_vha->dpc_flags); @@ -2975,10 +2987,17 @@ static struct qla_work_evt * qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) { struct qla_work_evt *e; + uint8_t bail; + + QLA_VHA_MARK_BUSY(vha, bail); + if (bail) + return NULL; e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); - if (!e) + if (!e) { + QLA_VHA_MARK_NOT_BUSY(vha); return NULL; + } INIT_LIST_HEAD(&e->list); e->type = type; @@ -3135,6 +3154,9 @@ qla2x00_do_work(struct scsi_qla_host *vha) } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); + + /* For each work completed decrement vha ref count */ + QLA_VHA_MARK_NOT_BUSY(vha); } } -- cgit v1.2.3-59-g8ed1b From 970ee0c52a41cf27c1b5c346dd9475e9c236f3c5 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Fri, 3 Sep 2010 14:57:01 -0700 Subject: [SCSI] qla2xxx: make rport deletions explicit during vport removal Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mid.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index bc1a7453c5d8..2b69392a71a1 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -135,7 +135,6 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) "loop_id=0x%04x :%x\n", vha->host_no, fcport->loop_id, fcport->vp_idx)); - atomic_set(&fcport->state, FCS_DEVICE_DEAD); qla2x00_mark_device_lost(vha, fcport, 0, 0); atomic_set(&fcport->state, FCS_UNCONFIGURED); } -- cgit v1.2.3-59-g8ed1b From efa786cc43a114d0bf2e4b95e856ea6911404d58 Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Fri, 3 Sep 2010 14:57:02 -0700 Subject: [SCSI] qla2xxx: Reset seconds_since_last_heartbeat correctly. The seconds_since_last_heartbeat should be checked for consecutive heartbeat checks. Currently it could happen that seconds_since_last_heartbeat gets set to max (2 seconds) for non-consecutive heartbeat checks. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 915b77a6e193..e54d2fa1c9f1 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3316,7 +3316,8 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha) complete(&ha->mbx_intr_comp); } } - } + } else + vha->seconds_since_last_heartbeat = 0; vha->fw_heartbeat_counter = fw_heartbeat_counter; } -- cgit v1.2.3-59-g8ed1b From 4142b1987f1f8ba90589642cb74566eaff3dc2e9 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 3 Sep 2010 14:57:03 -0700 Subject: [SCSI] qla2xxx: Correctly set fw hung and complete only waiting mbx. The fw_hung flag should be set ir-respective of if there is a mbx command pending or not. Also the complete should be called if there is a mbx waiting. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index e54d2fa1c9f1..ad290dc9ba35 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3307,13 +3307,15 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); } qla2xxx_wake_dpc(vha); + ha->flags.fw_hung = 1; if (ha->flags.mbox_busy) { - ha->flags.fw_hung = 1; ha->flags.mbox_int = 1; DEBUG2(qla_printk(KERN_ERR, ha, - "Due to fw hung, doing premature " - "completion of mbx command\n")); - complete(&ha->mbx_intr_comp); + "Due to fw hung, doing premature " + "completion of mbx command\n")); + if (test_bit(MBX_INTR_WAIT, + &ha->mbx_cmd_flags)) + complete(&ha->mbx_intr_comp); } } } else @@ -3419,13 +3421,15 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) "%s(): Adapter reset needed!\n", __func__); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); + ha->flags.fw_hung = 1; if (ha->flags.mbox_busy) { - ha->flags.fw_hung = 1; ha->flags.mbox_int = 1; DEBUG2(qla_printk(KERN_ERR, ha, - "Need reset, doing premature " - "completion of mbx command\n")); - complete(&ha->mbx_intr_comp); + "Need reset, doing premature " + "completion of mbx command\n")); + if (test_bit(MBX_INTR_WAIT, + &ha->mbx_cmd_flags)) + complete(&ha->mbx_intr_comp); } } else { qla82xx_check_fw_alive(vha); -- cgit v1.2.3-59-g8ed1b From 0374f55ed882a46cd4825dde16ca2392d4c367f6 Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Fri, 3 Sep 2010 14:57:04 -0700 Subject: [SCSI] qla2xxx: Cover UNDERRUN case where SCSI status is set. Currently, if target sets the SCSI Status (with Check condition) and there is no FCP residual bit set then driver does not check for dropped frame. This could lead to data corruption. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 6982ba70e12a..28f65be19dad 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1706,19 +1706,20 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) cp->result = DID_ERROR << 16; break; } - } else if (!lscsi_status) { + } else { DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d) Dropped frame(s) detected (0x%x " "of 0x%x bytes).\n", vha->host_no, cp->device->id, cp->device->lun, resid, scsi_bufflen(cp))); - cp->result = DID_ERROR << 16; - break; + cp->result = DID_ERROR << 16 | lscsi_status; + goto check_scsi_status; } cp->result = DID_OK << 16 | lscsi_status; logit = 0; +check_scsi_status: /* * Check to see if SCSI Status is non zero. If so report SCSI * Status. -- cgit v1.2.3-59-g8ed1b From 1bd58b89e84b15283aaa3148fee4969abe19af8d Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 3 Sep 2010 14:57:05 -0700 Subject: [SCSI] qla2xxx: Check for empty slot in request queue before posting Command type 6 request. For ISP82xx, the check for empty slot in request queue before posting command type 6 request was missing. This could lead to request queue entry corruptions causing IO timeouts. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index ad290dc9ba35..0a71cc71eab2 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2672,6 +2672,19 @@ qla82xx_start_scsi(srb_t *sp) sufficient_dsds: req_cnt = 1; + if (req->cnt < (req_cnt + 2)) { + cnt = (uint16_t)RD_REG_DWORD_RELAXED( + ®->req_q_out[0]); + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + } + + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); if (!sp->ctx) { DEBUG(printk(KERN_INFO -- cgit v1.2.3-59-g8ed1b From 0fb576d8251c10f498ed4c6938aeeed8d0c93cfe Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Fri, 3 Sep 2010 14:57:06 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.03.04-k0. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index e75ccb91317d..8edbccb3232d 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.03-k0" +#define QLA2XXX_VERSION "8.03.04-k0" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -#define QLA_DRIVER_PATCH_VER 3 +#define QLA_DRIVER_PATCH_VER 4 #define QLA_DRIVER_BETA_VER 0 -- cgit v1.2.3-59-g8ed1b From 87d6a412bd1ed82c14cabd4b408003b23bbd2880 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 2 Sep 2010 14:05:30 +0300 Subject: vhost: fix attach to cgroups regression Since 2.6.36-rc1, non-root users of vhost-net fail to attach if they are in any cgroups. The reason is that when qemu uses vhost, vhost wants to attach its thread to all cgroups that qemu has. But we got the API backwards, so a non-priveledged process (Qemu) tried to control the priveledged one (vhost), which fails. Fix this by switching to the new cgroup_attach_task_all, and running it from the vhost thread. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 79 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 22 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 4b99117f3ecd..1afa08527e08 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -60,22 +60,25 @@ static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync, return 0; } +static void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn) +{ + INIT_LIST_HEAD(&work->node); + work->fn = fn; + init_waitqueue_head(&work->done); + work->flushing = 0; + work->queue_seq = work->done_seq = 0; +} + /* Init poll structure */ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn, unsigned long mask, struct vhost_dev *dev) { - struct vhost_work *work = &poll->work; - init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup); init_poll_funcptr(&poll->table, vhost_poll_func); poll->mask = mask; poll->dev = dev; - INIT_LIST_HEAD(&work->node); - work->fn = fn; - init_waitqueue_head(&work->done); - work->flushing = 0; - work->queue_seq = work->done_seq = 0; + vhost_work_init(&poll->work, fn); } /* Start polling a file. We add ourselves to file's wait queue. The caller must @@ -95,35 +98,38 @@ void vhost_poll_stop(struct vhost_poll *poll) remove_wait_queue(poll->wqh, &poll->wait); } -/* Flush any work that has been scheduled. When calling this, don't hold any - * locks that are also used by the callback. */ -void vhost_poll_flush(struct vhost_poll *poll) +static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work) { - struct vhost_work *work = &poll->work; unsigned seq; int left; int flushing; - spin_lock_irq(&poll->dev->work_lock); + spin_lock_irq(&dev->work_lock); seq = work->queue_seq; work->flushing++; - spin_unlock_irq(&poll->dev->work_lock); + spin_unlock_irq(&dev->work_lock); wait_event(work->done, ({ - spin_lock_irq(&poll->dev->work_lock); + spin_lock_irq(&dev->work_lock); left = seq - work->done_seq <= 0; - spin_unlock_irq(&poll->dev->work_lock); + spin_unlock_irq(&dev->work_lock); left; })); - spin_lock_irq(&poll->dev->work_lock); + spin_lock_irq(&dev->work_lock); flushing = --work->flushing; - spin_unlock_irq(&poll->dev->work_lock); + spin_unlock_irq(&dev->work_lock); BUG_ON(flushing < 0); } -void vhost_poll_queue(struct vhost_poll *poll) +/* Flush any work that has been scheduled. When calling this, don't hold any + * locks that are also used by the callback. */ +void vhost_poll_flush(struct vhost_poll *poll) +{ + vhost_work_flush(poll->dev, &poll->work); +} + +static inline void vhost_work_queue(struct vhost_dev *dev, + struct vhost_work *work) { - struct vhost_dev *dev = poll->dev; - struct vhost_work *work = &poll->work; unsigned long flags; spin_lock_irqsave(&dev->work_lock, flags); @@ -135,6 +141,11 @@ void vhost_poll_queue(struct vhost_poll *poll) spin_unlock_irqrestore(&dev->work_lock, flags); } +void vhost_poll_queue(struct vhost_poll *poll) +{ + vhost_work_queue(poll->dev, &poll->work); +} + static void vhost_vq_reset(struct vhost_dev *dev, struct vhost_virtqueue *vq) { @@ -236,6 +247,29 @@ long vhost_dev_check_owner(struct vhost_dev *dev) return dev->mm == current->mm ? 0 : -EPERM; } +struct vhost_attach_cgroups_struct { + struct vhost_work work; + struct task_struct *owner; + int ret; +}; + +static void vhost_attach_cgroups_work(struct vhost_work *work) +{ + struct vhost_attach_cgroups_struct *s; + s = container_of(work, struct vhost_attach_cgroups_struct, work); + s->ret = cgroup_attach_task_all(s->owner, current); +} + +static int vhost_attach_cgroups(struct vhost_dev *dev) +{ + struct vhost_attach_cgroups_struct attach; + attach.owner = current; + vhost_work_init(&attach.work, vhost_attach_cgroups_work); + vhost_work_queue(dev, &attach.work); + vhost_work_flush(dev, &attach.work); + return attach.ret; +} + /* Caller should have device mutex */ static long vhost_dev_set_owner(struct vhost_dev *dev) { @@ -255,10 +289,11 @@ static long vhost_dev_set_owner(struct vhost_dev *dev) } dev->worker = worker; - err = cgroup_attach_task_current_cg(worker); + wake_up_process(worker); /* avoid contributing to loadavg */ + + err = vhost_attach_cgroups(dev); if (err) goto err_cgroup; - wake_up_process(worker); /* avoid contributing to loadavg */ return 0; err_cgroup: -- cgit v1.2.3-59-g8ed1b From 615cc2211c17ed05a2a5d94abdac6c340a8ea508 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 2 Sep 2010 14:16:36 +0300 Subject: vhost: error handling fix vhost should set worker to NULL on cgroups attach failure, so that we won't try to destroy the worker again on close. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 1afa08527e08..c579dcc9200c 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -298,6 +298,7 @@ static long vhost_dev_set_owner(struct vhost_dev *dev) return 0; err_cgroup: kthread_stop(worker); + dev->worker = NULL; err_worker: if (dev->mm) mmput(dev->mm); -- cgit v1.2.3-59-g8ed1b From e260999c66768c2fccd9da8c3918b4e0e5121b3a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 6 Sep 2010 16:48:13 +0800 Subject: regulator: wm831x-ldo - fix the logic to set REGULATOR_MODE_IDLE and REGULATOR_MODE_STANDBY modes Problem description in current implementation: When setting REGULATOR_MODE_IDLE mode, current implementation set WM831X_LDO1_LP_MODE bit of ctrl_reg (which is wrong, it should clear the bit). But due to a missing break statement for case REGULATOR_MODE_IDLE, the code fall through to case REGULATOR_MODE_STANDBY and then clear WM831X_LDO1_LP_MODE bit. So it still looks OK when checking the status by wm831x_gp_ldo_get_mode(). When setting REGULATOR_MODE_STANDBY mode, it just does not work. wm831x_gp_ldo_get_mode() will still return REGULATOR_MODE_IDLE because the accordingly WM831X_LDO1_LP_MODE bit is clear. Correct behavior should be: Clear WM831X_LDO1_LP_MODE bit of ctrl_reg for REGULATOR_MODE_IDLE mode. Set WM831X_LDO1_LP_MODE bit of ctrl_reg for REGULATOR_MODE_STANDBY mode. Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm831x-ldo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index e686cdb61b97..9edf8f692341 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -215,8 +215,7 @@ static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev, case REGULATOR_MODE_IDLE: ret = wm831x_set_bits(wm831x, ctrl_reg, - WM831X_LDO1_LP_MODE, - WM831X_LDO1_LP_MODE); + WM831X_LDO1_LP_MODE, 0); if (ret < 0) return ret; @@ -225,10 +224,12 @@ static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev, WM831X_LDO1_ON_MODE); if (ret < 0) return ret; + break; case REGULATOR_MODE_STANDBY: ret = wm831x_set_bits(wm831x, ctrl_reg, - WM831X_LDO1_LP_MODE, 0); + WM831X_LDO1_LP_MODE, + WM831X_LDO1_LP_MODE); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 8ecee36adc9d2cf19471c395af6ef70264dec251 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 6 Sep 2010 14:06:07 +0800 Subject: regulator: wm8350-regulator - fix the logic of checking REGULATOR_MODE_STANDBY mode In wm8350_dcdc_set_mode(), we set DCx_SLEEP bit of WM8350_DCDC_SLEEP_OPTIONS register for REGULATOR_MODE_STANDBY mode. ( DCx_SLEEP bits: 0: Normal DC-DC operation 1: Select LDO mode ) In wm8350_dcdc_get_mode(), current logic to determinate REGULATOR_MODE_STANDBY mode is just reverse. ( sleep is set should mean REGULATOR_MODE_STANDBY mode. ) Signed-off-by: Axel Lin Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm8350-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 0e6ed7db9364..fe4b8a8a9dfd 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1129,7 +1129,7 @@ static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev) mode = REGULATOR_MODE_NORMAL; } else if (!active && !sleep) mode = REGULATOR_MODE_IDLE; - else if (!sleep) + else if (sleep) mode = REGULATOR_MODE_STANDBY; return mode; -- cgit v1.2.3-59-g8ed1b From 7e7b41d2ff30ed7ad4bf401d18566e6f38e42e4f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 2 Sep 2010 21:32:32 -0400 Subject: drm/radeon/kms/evergreen: fix gpu hangs in userspace accel code These VGT regs need to be programmed via the ring rather than MMIO as on previous asics (r6xx/r7xx). Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 39 +++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/radeon/r600.c | 5 +---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index fe31b0db1e9c..b8b7f010b25f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -675,6 +675,43 @@ static int evergreen_cp_load_microcode(struct radeon_device *rdev) return 0; } +static int evergreen_cp_start(struct radeon_device *rdev) +{ + int r; + uint32_t cp_me; + + r = radeon_ring_lock(rdev, 7); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + return r; + } + radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5)); + radeon_ring_write(rdev, 0x1); + radeon_ring_write(rdev, 0x0); + radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1); + radeon_ring_write(rdev, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 0); + radeon_ring_unlock_commit(rdev); + + cp_me = 0xff; + WREG32(CP_ME_CNTL, cp_me); + + r = radeon_ring_lock(rdev, 4); + if (r) { + DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r); + return r; + } + /* init some VGT regs */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2)); + radeon_ring_write(rdev, (VGT_VERTEX_REUSE_BLOCK_CNTL - PACKET3_SET_CONTEXT_REG_START) >> 2); + radeon_ring_write(rdev, 0xe); + radeon_ring_write(rdev, 0x10); + radeon_ring_unlock_commit(rdev); + + return 0; +} + int evergreen_cp_resume(struct radeon_device *rdev) { u32 tmp; @@ -719,7 +756,7 @@ int evergreen_cp_resume(struct radeon_device *rdev) rdev->cp.rptr = RREG32(CP_RB_RPTR); rdev->cp.wptr = RREG32(CP_RB_WPTR); - r600_cp_start(rdev); + evergreen_cp_start(rdev); rdev->cp.ready = true; r = radeon_ring_test(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 04f134d1aae7..afc18d87fdca 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2119,10 +2119,7 @@ int r600_cp_start(struct radeon_device *rdev) } radeon_ring_write(rdev, PACKET3(PACKET3_ME_INITIALIZE, 5)); radeon_ring_write(rdev, 0x1); - if (rdev->family >= CHIP_CEDAR) { - radeon_ring_write(rdev, 0x0); - radeon_ring_write(rdev, rdev->config.evergreen.max_hw_contexts - 1); - } else if (rdev->family >= CHIP_RV770) { + if (rdev->family >= CHIP_RV770) { radeon_ring_write(rdev, 0x0); radeon_ring_write(rdev, rdev->config.rv770.max_hw_contexts - 1); } else { -- cgit v1.2.3-59-g8ed1b From 54bfe496cec7586f76f713a277435dd3ac6fd4c4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 3 Sep 2010 15:52:53 -0400 Subject: drm/radeon/kms: fix tv-out on avivo asics digital underscan support regressed tv-out. fixes: https://bugs.freedesktop.org/show_bug.cgi?id=29985 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 71b31509afc9..464a81a1990f 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -332,6 +332,11 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, args.usV_SyncWidth = cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); + args.ucOverscanRight = radeon_crtc->h_border; + args.ucOverscanLeft = radeon_crtc->h_border; + args.ucOverscanBottom = radeon_crtc->v_border; + args.ucOverscanTop = radeon_crtc->v_border; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) misc |= ATOM_VSYNC_POLARITY; if (mode->flags & DRM_MODE_FLAG_NHSYNC) @@ -1211,8 +1216,18 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder; + bool is_tvcv = false; - /* TODO color tiling */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + /* find tv std */ + if (encoder->crtc == crtc) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->active_device & + (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + is_tvcv = true; + } + } atombios_disable_ss(crtc); /* always set DCPLL */ @@ -1221,9 +1236,14 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, atombios_crtc_set_pll(crtc, adjusted_mode); atombios_enable_ss(crtc); - if (ASIC_IS_AVIVO(rdev)) + if (ASIC_IS_DCE4(rdev)) atombios_set_crtc_dtd_timing(crtc, adjusted_mode); - else { + else if (ASIC_IS_AVIVO(rdev)) { + if (is_tvcv) + atombios_crtc_set_timing(crtc, adjusted_mode); + else + atombios_set_crtc_dtd_timing(crtc, adjusted_mode); + } else { atombios_crtc_set_timing(crtc, adjusted_mode); if (radeon_crtc->crtc_id == 0) atombios_set_crtc_dtd_timing(crtc, adjusted_mode); -- cgit v1.2.3-59-g8ed1b From e58f637bb96d5a0ae0919b9998b891d1ba7e47c9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Aug 2010 09:13:36 +0100 Subject: drm/kms: Add a module parameter to disable polling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Polling for a VGA device on an old system can be quite expensive, causing latencies on the order of 600ms. As we hold the mode mutex for this time and also need the same mutex to move the cursor, we trigger a user-visible stall. The real solution would involve improving the granulatity of the locking and so perhaps performing some of the probing not under the lock or some other updates can be done under different locks. Also reducing the cost of probing for a non-existent monitor would be worthwhile. However, exposing a parameter to disable polling is a simple workaround in the meantime. In order to accommodate users turning polling on and off at runtime, the polling is potentially re-enabled on every probe. This is coupled to the user calling xrandr, which seems to be a vaild time to reset the polling timeout since the information on the connection has just been updated. (The presumption being that all connections are probed in a single xrandr pass, which is currently valid.) References: Bug 29536 - 2.6.35 causes ~600ms latency every 10s https://bugs.freedesktop.org/show_bug.cgi?id=29536 Bug 16265 - Why is kslowd accumulating so much CPU time? https://bugzilla.kernel.org/show_bug.cgi?id=16265 Signed-off-by: Chris Wilson Reported-and-tested-by: Bruno Prémont Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 7e31d4348340..06fc0bccaff7 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -34,6 +34,9 @@ #include "drm_crtc_helper.h" #include "drm_fb_helper.h" +static bool drm_kms_helper_poll = true; +module_param_named(poll, drm_kms_helper_poll, bool, 0600); + static void drm_mode_validate_flag(struct drm_connector *connector, int flags) { @@ -99,8 +102,10 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, connector->status = connector_status_disconnected; if (connector->funcs->force) connector->funcs->force(connector); - } else + } else { connector->status = connector->funcs->detect(connector); + drm_helper_hpd_irq_event(dev); + } if (connector->status == connector_status_disconnected) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", @@ -840,6 +845,9 @@ static void output_poll_execute(struct work_struct *work) enum drm_connector_status old_status, status; bool repoll = false, changed = false; + if (!drm_kms_helper_poll) + return; + mutex_lock(&dev->mode_config.mutex); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -890,6 +898,9 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) bool poll = false; struct drm_connector *connector; + if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) + return; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->polled) poll = true; @@ -919,8 +930,10 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) { if (!dev->mode_config.poll_enabled) return; + /* kill timer and schedule immediate execution, this doesn't block */ cancel_delayed_work(&dev->mode_config.output_poll_work); - queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); + if (drm_kms_helper_poll) + queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0); } EXPORT_SYMBOL(drm_helper_hpd_irq_event); -- cgit v1.2.3-59-g8ed1b From c7ef35a960369bcad733b92868e4befe03ba9234 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Sep 2010 16:55:25 +0100 Subject: drm: Do not force 1024x768 modes on unknown connectors Only fallback to a set of default modes on a connector iff that connector is known to be connected. The issue occurs that with limited hardware which cannot probe a connector and so reports the connector status as unknown will then attempt to retrieve the modes for it during drm_helper_probe_single_connector_modes(). Should that fail, the helper then generates a default set which fools the fb_helper and causes havoc with the console and beyond. Signed-off-by: Chris Wilson Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 06fc0bccaff7..d2ab01e90a96 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -115,11 +115,10 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, } count = (*connector_funcs->get_modes)(connector); - if (!count) { + if (count == 0 && connector->status == connector_status_connected) count = drm_add_modes_noedid(connector, 1024, 768); - if (!count) - return 0; - } + if (count == 0) + goto prune; drm_mode_connector_list_update(connector); -- cgit v1.2.3-59-g8ed1b From e167976ee7f5fe4b80f7e8f55e087f6c67cf9562 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 24 Aug 2010 16:35:52 -0700 Subject: drivers/gpu/drm/i915/intel_overlay.c needs seq_file.h drivers/gpu/drm/i915/intel_overlay.c: In function 'intel_overlay_print_error_state': drivers/gpu/drm/i915/intel_overlay.c:1467: error: implicit declaration of function 'seq_printf' Addresses https://bugzilla.kernel.org/show_bug.cgi?id=16811 Reported-by: Martin Ziegler Cc: Chris Wilson Cc: Daniel Vetter Cc: Eric Anholt Cc: Dave Airlie Cc: Andre Muller Signed-off-by: Andrew Morton Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_overlay.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 4f00390d7c61..1d306a458be6 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -25,6 +25,8 @@ * * Derived from Xorg ddx, xf86-video-intel, src/i830_video.c */ + +#include #include "drmP.h" #include "drm.h" #include "i915_drm.h" -- cgit v1.2.3-59-g8ed1b From 1dfd9754cd55e424f247d9a2e855ad384e3e90ef Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Sep 2010 14:44:14 +0100 Subject: Revert "drm/i915: Unreference object not handle on creation" This reverts commit 86f100b136626e91f4f66f3776303475e2e58998. The kref API requires the handlecount to be initialised to one on object creation (so that kref_get() doesn't complain upon first use) so the dalliance in the drivers is required in order to sink the initial floating reference. Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index df5a7135c261..68526f467c87 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -135,12 +135,15 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, return -ENOMEM; ret = drm_gem_handle_create(file_priv, obj, &handle); - drm_gem_object_unreference_unlocked(obj); - if (ret) + if (ret) { + drm_gem_object_unreference_unlocked(obj); return ret; + } - args->handle = handle; + /* Sink the floating reference from kref_init(handlecount) */ + drm_gem_object_handle_unreference_unlocked(obj); + args->handle = handle; return 0; } -- cgit v1.2.3-59-g8ed1b From c74696b9c890074c1e1ee3d7496fc71eb3680ced Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Thu, 2 Sep 2010 14:46:34 -0400 Subject: i915: revert some checks added by commit 32aad86f This fixes blur-like screen corruption on the following card: VGA compatible controller [0300]: Intel Corporation 82G33/G31 Express Integrated Graphics Controller [8086:29c2] (rev 10) intel_sdvo_mode_set() should not return prematurely just because some features are not supported. https://bugzilla.kernel.org/show_bug.cgi?id=17151 Signed-off-by: Pavel Roskin Reported-by: Jonathan Corbet Reviewed-by: Chris Wilson [ickle: Relax a couple more checks for failing LVDS modesetting] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_sdvo.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 093e914e8a41..62d22ae4a1d1 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1061,8 +1061,9 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) return false; - if (!intel_sdvo_set_input_timings_for_mode(intel_sdvo, mode, adjusted_mode)) - return false; + (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo, + mode, + adjusted_mode); } else if (intel_sdvo->is_lvds) { drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0); @@ -1070,8 +1071,9 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, intel_sdvo->sdvo_lvds_fixed_mode)) return false; - if (!intel_sdvo_set_input_timings_for_mode(intel_sdvo, mode, adjusted_mode)) - return false; + (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo, + mode, + adjusted_mode); } /* Make the CRTC code factor in the SDVO pixel multiplier. The @@ -1108,10 +1110,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, in_out.in0 = intel_sdvo->attached_output; in_out.in1 = 0; - if (!intel_sdvo_set_value(intel_sdvo, - SDVO_CMD_SET_IN_OUT_MAP, - &in_out, sizeof(in_out))) - return; + intel_sdvo_set_value(intel_sdvo, + SDVO_CMD_SET_IN_OUT_MAP, + &in_out, sizeof(in_out)); if (intel_sdvo->is_hdmi) { if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) @@ -1122,11 +1123,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* We have tried to get input timing in mode_fixup, and filled into adjusted_mode */ - if (intel_sdvo->is_tv || intel_sdvo->is_lvds) { - intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); + intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); + if (intel_sdvo->is_tv || intel_sdvo->is_lvds) input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags; - } else - intel_sdvo_get_dtd_from_mode(&input_dtd, mode); /* If it's a TV, we already set the output timing in mode_fixup. * Otherwise, the output timing is equal to the input timing. @@ -1137,8 +1136,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo->attached_output)) return; - if (!intel_sdvo_set_output_timing(intel_sdvo, &input_dtd)) - return; + (void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); } /* Set the input timing to the screen. Assume always input 0. */ @@ -1165,8 +1163,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_input_timing(encoder, &input_dtd); } #else - if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd)) - return; + (void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); #endif sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); -- cgit v1.2.3-59-g8ed1b From 4f233eff6f32745f8894eb513bc59851213c7833 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sat, 4 Sep 2010 19:24:04 +0300 Subject: i915: Fix spurious TV detection after 9d0498a2bf + 9559fcdbff Partial revert of 9d0498a2bf. Signed-off-by: Pekka Enberg Tested-by: Hugh Dickins Tested-by: Sven Joachim Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_tv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index d2029efee982..c671f60ce80b 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1231,7 +1231,6 @@ intel_tv_detect_type (struct intel_tv *intel_tv) struct drm_encoder *encoder = &intel_tv->base.enc; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); unsigned long irqflags; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; @@ -1268,11 +1267,15 @@ intel_tv_detect_type (struct intel_tv *intel_tv) DAC_C_0_7_V); I915_WRITE(TV_CTL, tv_ctl); I915_WRITE(TV_DAC, tv_dac); - intel_wait_for_vblank(dev, intel_crtc->pipe); + POSTING_READ(TV_DAC); + msleep(20); + tv_dac = I915_READ(TV_DAC); I915_WRITE(TV_DAC, save_tv_dac); I915_WRITE(TV_CTL, save_tv_ctl); - intel_wait_for_vblank(dev, intel_crtc->pipe); + POSTING_READ(TV_CTL); + msleep(20); + /* * A B C * 0 1 1 Composite -- cgit v1.2.3-59-g8ed1b From 300387c0b57d75e5218e2881d6ad2720657a8bcf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Sep 2010 20:25:43 +0100 Subject: drm/i915: Clear the vblank status bit before polling for the next vblank The vblank status bit is a sticky bit that must be cleared with a write of '1' prior to polling for the next vblank. Signed-off-by: Chris Wilson Tested-by: Sitsofe Wheeler jbarnes: I'd still rather see a lock, but I think you're right that we don't generally wait in code that needs not to miss an interrupt. Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 11a3394f5fe1..3fc767bcbaa0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -990,6 +990,22 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe) struct drm_i915_private *dev_priv = dev->dev_private; int pipestat_reg = (pipe == 0 ? PIPEASTAT : PIPEBSTAT); + /* Clear existing vblank status. Note this will clear any other + * sticky status fields as well. + * + * This races with i915_driver_irq_handler() with the result + * that either function could miss a vblank event. Here it is not + * fatal, as we will either wait upon the next vblank interrupt or + * timeout. Generally speaking intel_wait_for_vblank() is only + * called during modeset at which time the GPU should be idle and + * should *not* be performing page flips and thus not waiting on + * vblanks... + * Currently, the result of us stealing a vblank from the irq + * handler is that a single frame will be skipped during swapbuffers. + */ + I915_WRITE(pipestat_reg, + I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS); + /* Wait for vblank interrupt bit to set */ if (wait_for((I915_READ(pipestat_reg) & PIPE_VBLANK_INTERRUPT_STATUS), -- cgit v1.2.3-59-g8ed1b From 9f82d23846146990d475f6753be733e55788d88d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 30 Aug 2010 21:25:23 +0200 Subject: drm/i915: overlay on gen2 can't address above 1G So set the coherent dma mask accordingly. This dma mask is only used for physical objects, so it won't really matter allocation-wise. Now this never really surfaced because sane 32bit kernels only have 1G of lowmem. But some eager testers (distros?) still carry around the patch to adjust lowmem via a kconfig option. And the kernel seems to favour high allocations on boot-up, hence the overlay blowing up reliably. Because the patch is tiny and nicely shows how broken gen2 is it's imho worth to merge despite the fact that mucking around with the lowmem/ highmem division is (no longer) supported. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=28318 Cc: stable@kernel.org Signed-off-by: Daniel Vetter Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_dma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a7ec93e62f81..7796f452ed1d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2082,6 +2082,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto free_priv; } + /* overlay on gen2 is broken and can't address above 1G */ + if (IS_GEN2(dev)) + dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30)); + dev_priv->regs = ioremap(base, size); if (!dev_priv->regs) { DRM_ERROR("failed to map registers\n"); -- cgit v1.2.3-59-g8ed1b From df51e7aa2cf204e3a65657a1d60b96cfda133e9b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 4 Sep 2010 14:57:27 +0100 Subject: agp/intel: Promote warning about failure to setup flush to error. Make sure we always detect when we fail to correctly allocate the Isoch Flush Page and print an error to warn the user about the likely memory corruption that will result in invalid rendering or worse. Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/char/agp/intel-gtt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index d22ffb811bf2..ce536e68b6c6 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1068,11 +1068,11 @@ static void intel_i9xx_setup_flush(void) intel_i915_setup_chipset_flush(); } - if (intel_private.ifp_resource.start) { + if (intel_private.ifp_resource.start) intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); - if (!intel_private.i9xx_flush_page) - dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing"); - } + if (!intel_private.i9xx_flush_page) + dev_err(&intel_private.pcidev->dev, + "can't ioremap flush page - no chipset flushing\n"); } static int intel_i9xx_configure(void) -- cgit v1.2.3-59-g8ed1b From 9927a403ca8c97798129953fa9cbb5dc259c7cb9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 19 Jun 2010 15:12:51 +0200 Subject: i915: return -EFAULT if copy_to_user fails copy_to_user returns the number of bytes remaining to be copied, but we want to return a negative error code here. These are returned to userspace. Signed-off-by: Dan Carpenter Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_dma.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7796f452ed1d..051c4db7a1d3 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -620,8 +620,10 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, ret = copy_from_user(cliprects, batch->cliprects, batch->num_cliprects * sizeof(struct drm_clip_rect)); - if (ret != 0) + if (ret != 0) { + ret = -EFAULT; goto fail_free; + } } mutex_lock(&dev->struct_mutex); @@ -662,8 +664,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, return -ENOMEM; ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz); - if (ret != 0) + if (ret != 0) { + ret = -EFAULT; goto fail_batch_free; + } if (cmdbuf->num_cliprects) { cliprects = kcalloc(cmdbuf->num_cliprects, @@ -676,8 +680,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, ret = copy_from_user(cliprects, cmdbuf->cliprects, cmdbuf->num_cliprects * sizeof(struct drm_clip_rect)); - if (ret != 0) + if (ret != 0) { + ret = -EFAULT; goto fail_clip_free; + } } mutex_lock(&dev->struct_mutex); -- cgit v1.2.3-59-g8ed1b From c877cdce93a44eea96f6cf7fc04be7d0372db2be Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 23 Jun 2010 19:03:01 +0200 Subject: i915: return -EFAULT if copy_to_user fails copy_to_user() returns the number of bytes remaining to be copied and I'm pretty sure we want to return a negative error code here. Signed-off-by: Dan Carpenter Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 68526f467c87..748c26340c35 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3588,6 +3588,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret != 0) { DRM_ERROR("copy %d cliprects failed: %d\n", args->num_cliprects, ret); + ret = -EFAULT; goto pre_mutex_err; } } -- cgit v1.2.3-59-g8ed1b From 831853c87fb7234a8650484d30993242ea9ad6d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 6 Sep 2010 16:08:56 +0100 Subject: ALSA: Add more jack button slots Some devices have more flexible microphone detection and can detect a wider range of buttons. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- include/sound/jack.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/sound/jack.h b/include/sound/jack.h index d90b9fa32707..c140fc7cbd3f 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -47,6 +47,9 @@ enum snd_jack_types { SND_JACK_BTN_0 = 0x4000, SND_JACK_BTN_1 = 0x2000, SND_JACK_BTN_2 = 0x1000, + SND_JACK_BTN_3 = 0x0800, + SND_JACK_BTN_4 = 0x0400, + SND_JACK_BTN_5 = 0x0200, }; struct snd_jack { @@ -55,7 +58,7 @@ struct snd_jack { int type; const char *id; char name[100]; - unsigned int key[3]; /* Keep in sync with definitions above */ + unsigned int key[6]; /* Keep in sync with definitions above */ void *private_data; void (*private_free)(struct snd_jack *); }; -- cgit v1.2.3-59-g8ed1b From 9fe856e47e1751204faf3d604c6d20ab24bd3b93 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 4 Sep 2010 18:52:54 -0700 Subject: sound: Remove unnecessary casts of private_data Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/core/oss/mixer_oss.c | 22 +++++++++++----------- sound/core/pcm.c | 3 +-- sound/drivers/virmidi.c | 2 +- sound/i2c/other/ak4xxx-adda.c | 2 +- sound/isa/ad1816a/ad1816a.c | 2 +- sound/isa/azt2320.c | 2 +- sound/isa/gus/gusmax.c | 4 ++-- sound/isa/sb/sb8.c | 2 +- sound/oss/au1550_ac97.c | 18 +++++++++--------- sound/pci/emu10k1/emumpu401.c | 2 +- sound/pci/ice1712/pontis.c | 6 +++--- sound/pci/ice1712/prodigy192.c | 2 +- sound/pci/rme96.c | 8 ++++---- sound/pci/rme9652/hdsp.c | 8 ++++---- 14 files changed, 41 insertions(+), 42 deletions(-) diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index f50ebf20df96..86afb13cd240 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file) struct snd_mixer_oss_file *fmixer; if (file->private_data) { - fmixer = (struct snd_mixer_oss_file *) file->private_data; + fmixer = file->private_data; module_put(fmixer->card->module); snd_card_file_remove(fmixer->card, file); kfree(fmixer); @@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg); + return snd_mixer_oss_ioctl1(file->private_data, cmd, arg); } int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg) @@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int *left, int *right) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; *left = *right = 100; if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { @@ -691,7 +691,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int left, int right) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); @@ -740,7 +740,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int *active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; int left, right; left = right = 1; @@ -753,7 +753,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int *active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; int left, right; left = right = 1; @@ -766,7 +766,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); return 0; @@ -776,7 +776,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer, struct snd_mixer_oss_slot *pslot, int active) { - struct slot *slot = (struct slot *)pslot->private_data; + struct slot *slot = pslot->private_data; snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); return 0; @@ -813,7 +813,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned if (!(mixer->mask_recsrc & (1 << idx))) continue; pslot = &mixer->slots[idx]; - slot = (struct slot *)pslot->private_data; + slot = pslot->private_data; if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) continue; if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) @@ -861,7 +861,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned if (!(mixer->mask_recsrc & (1 << idx))) continue; pslot = &mixer->slots[idx]; - slot = (struct slot *)pslot->private_data; + slot = pslot->private_data; if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE) continue; if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE)) @@ -925,7 +925,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn) { - struct slot *p = (struct slot *)chn->private_data; + struct slot *p = chn->private_data; if (p) { if (p->allocated && p->assigned) { kfree(p->assigned->name); diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 204af48c5cc1..88525a958291 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry, static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data, - buffer); + snd_pcm_proc_info_read(entry->private_data, buffer); } static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 0e631c3221e3..f4cd49336f33 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr) sizeof(struct snd_card_virmidi), &card); if (err < 0) return err; - vmidi = (struct snd_card_virmidi *)card->private_data; + vmidi = card->private_data; vmidi->card = card; if (midi_devs[dev] > MAX_MIDI_DEVICES) { diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 1adb8a3c2b62..ebab6c7aaa81 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) static void proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; + struct snd_akm4xxx *ak = entry->private_data; int reg, val, chip; for (chip = 0; chip < ak->num_chips; chip++) { for (reg = 0; reg < ak->total_regs; reg++) { diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index bbcbf92a8ebe..3cb75bc97699 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard sizeof(struct snd_card_ad1816a), &card); if (error < 0) return error; - acard = (struct snd_card_ad1816a *)card->private_data; + acard = card->private_data; if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) { snd_card_free(card); diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index f7aa637b0d18..aac8dc15c2fe 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev, sizeof(struct snd_card_azt2320), &card); if (error < 0) return error; - acard = (struct snd_card_azt2320 *)card->private_data; + acard = card->private_data; if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) { snd_card_free(card); diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index f26eac8d8110..3e4a58b72913 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip) static void snd_gusmax_free(struct snd_card *card) { - struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data; + struct snd_gusmax *maxcard = card->private_data; if (maxcard == NULL) return; @@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) if (err < 0) return err; card->private_free = snd_gusmax_free; - maxcard = (struct snd_gusmax *)card->private_data; + maxcard = card->private_data; maxcard->card = card; maxcard->irq = -1; diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 81284a8fa0ce..2259e3f726a7 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id) static void snd_sb8_free(struct snd_card *card) { - struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data; + struct snd_sb8 *acard = card->private_data; if (acard == NULL) return; diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index c6f2621221ba..8a12621d8b3a 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c @@ -171,7 +171,7 @@ au1550_delay(int msec) static u16 rdcodec(struct ac97_codec *codec, u8 addr) { - struct au1550_state *s = (struct au1550_state *)codec->private_data; + struct au1550_state *s = codec->private_data; unsigned long flags; u32 cmd, val; u16 data; @@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr) static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) { - struct au1550_state *s = (struct au1550_state *)codec->private_data; + struct au1550_state *s = codec->private_data; unsigned long flags; u32 cmd, val; int i; @@ -820,7 +820,7 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, static long au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct ac97_codec *codec = s->codec; int ret; @@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user) static ssize_t au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct dmabuf *db = &s->dma_adc; DECLARE_WAITQUEUE(wait, current); ssize_t ret; @@ -1111,7 +1111,7 @@ out2: static ssize_t au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct dmabuf *db = &s->dma_dac; DECLARE_WAITQUEUE(wait, current); ssize_t ret = 0; @@ -1211,7 +1211,7 @@ out2: static unsigned int au1550_poll(struct file *file, struct poll_table_struct *wait) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; unsigned long flags; unsigned int mask = 0; @@ -1250,7 +1250,7 @@ au1550_poll(struct file *file, struct poll_table_struct *wait) static int au1550_mmap(struct file *file, struct vm_area_struct *vma) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; struct dmabuf *db; unsigned long size; int ret = 0; @@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db) static int au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; unsigned long flags; audio_buf_info abinfo; count_info cinfo; @@ -1868,7 +1868,7 @@ out2: static int au1550_release(struct inode *inode, struct file *file) { - struct au1550_state *s = (struct au1550_state *)file->private_data; + struct au1550_state *s = file->private_data; lock_kernel(); diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 8578c70c61f2..bab564824efe 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input = static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) { - struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data; + struct snd_emu10k1_midi *midi = rmidi->private_data; midi->interrupt = NULL; midi->rmidi = NULL; } diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 6bc3f91b7281..cdb873f5da50 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = { */ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; char line[64]; unsigned int reg, val; mutex_lock(&ice->gpio_mutex); @@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; int reg, val; mutex_lock(&ice->gpio_mutex); @@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; int reg, val; mutex_lock(&ice->gpio_mutex); diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 2a8e5cd8f2d8..e36ddb94c382 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) static void stac9460_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; + struct snd_ice1712 *ice = entry->private_data; int reg, val; /* registers 0x0 - 0x14 */ for (reg = 0; reg <= 0x15; reg++) { diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index d19dc052c391..d5f5b440fc40 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data) static void snd_rme96_free_spdif_pcm(struct snd_pcm *pcm) { - struct rme96 *rme96 = (struct rme96 *) pcm->private_data; + struct rme96 *rme96 = pcm->private_data; rme96->spdif_pcm = NULL; } static void snd_rme96_free_adat_pcm(struct snd_pcm *pcm) { - struct rme96 *rme96 = (struct rme96 *) pcm->private_data; + struct rme96 *rme96 = pcm->private_data; rme96->adat_pcm = NULL; } @@ -1661,7 +1661,7 @@ static void snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { int n; - struct rme96 *rme96 = (struct rme96 *)entry->private_data; + struct rme96 *rme96 = entry->private_data; rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); @@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci, if (err < 0) return err; card->private_free = snd_rme96_card_free; - rme96 = (struct rme96 *)card->private_data; + rme96 = card->private_data; rme96->card = card; rme96->pci = pci; snd_card_set_dev(card, &pci->dev); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index b92adef8e81e..599e09051663 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) static void snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct hdsp *hdsp = (struct hdsp *) entry->private_data; + struct hdsp *hdsp = entry->private_data; unsigned int status; unsigned int status2; char *pref_sync_ref; @@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) { - struct hdsp *hdsp = (struct hdsp *)hw->private_data; + struct hdsp *hdsp = hw->private_data; void __user *argp = (void __user *)arg; int err; @@ -5155,7 +5155,7 @@ static int snd_hdsp_free(struct hdsp *hdsp) static void snd_hdsp_card_free(struct snd_card *card) { - struct hdsp *hdsp = (struct hdsp *) card->private_data; + struct hdsp *hdsp = card->private_data; if (hdsp) snd_hdsp_free(hdsp); @@ -5181,7 +5181,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, if (err < 0) return err; - hdsp = (struct hdsp *) card->private_data; + hdsp = card->private_data; card->private_free = snd_hdsp_card_free; hdsp->dev = dev; hdsp->pci = pci; -- cgit v1.2.3-59-g8ed1b From add7c0a6a4b8669ebd726f9c08ba6002900ca671 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Jul 2009 18:19:12 +0200 Subject: ALSA: ca0106 - clean up playback pointer callback Clean up the playback pointer callback function a bit, and make the pointer check more strictly to avoid bogus pointers. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0a3d3d6e77b4..8e69620da20b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1002,29 +1002,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ca0106_pcm *epcm = runtime->private_data; - snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; + unsigned int ptr, prev_ptr; int channel = epcm->channel_id; + int timeout = 10; if (!epcm->running) return 0; - ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); - ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); - ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); - if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); - ptr2 = bytes_to_frames(runtime, ptr1); - ptr2+= (ptr4 >> 3) * runtime->period_size; - ptr=ptr2; - if (ptr >= runtime->buffer_size) - ptr -= runtime->buffer_size; - /* - printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " - "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", - ptr1, ptr2, ptr, (int)runtime->buffer_size, - (int)runtime->period_size, (int)runtime->frame_bits, - (int)runtime->rate); - */ - return ptr; + prev_ptr = -1; + do { + ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); + ptr = (ptr >> 3) * runtime->period_size; + ptr += bytes_to_frames(runtime, + snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel)); + if (ptr >= runtime->buffer_size) + ptr -= runtime->buffer_size; + if (prev_ptr == ptr) + return ptr; + prev_ptr = ptr; + } while (--timeout); + snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); + return 0; } /* pointer_capture callback */ -- cgit v1.2.3-59-g8ed1b From 4d155641c81203440da64c4633b4efaab75f63b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Sep 2010 11:58:30 +0200 Subject: ALSA: hda - Add quirk for Lenovo T400s Lenovo T400s requires the quirk to make automatic HP/mic switching working. Reported-by: Frank Becker Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4f0619908a30..71f9d6475b09 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3094,6 +3094,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), -- cgit v1.2.3-59-g8ed1b From c96c3a8cb7fadcb33d9a5ebe35fcee8b7d0a7946 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 11 Aug 2010 09:59:24 +0100 Subject: drm/i915: Include a generation number in the device info To simplify the IS_GEN[234] macros and to enable switching. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.c | 61 +++++++++++++++++++---------------------- drivers/gpu/drm/i915/i915_drv.h | 27 ++++-------------- 2 files changed, 34 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 00befce8fbb7..5363985673a4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -61,91 +61,86 @@ extern int intel_agp_enabled; .driver_data = (unsigned long) info } static const struct intel_device_info intel_i830_info = { - .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_845g_info = { - .is_i8xx = 1, + .gen = 2, .is_i8xx = 1, }; static const struct intel_device_info intel_i85x_info = { - .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, + .gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_i865g_info = { - .is_i8xx = 1, + .gen = 2, .is_i8xx = 1, }; static const struct intel_device_info intel_i915g_info = { - .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, + .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_i915gm_info = { - .is_i9xx = 1, .is_mobile = 1, + .gen = 3, .is_i9xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_i945g_info = { - .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, + .gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_i945gm_info = { - .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, + .gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_hotplug = 1, .cursor_needs_physical = 1, }; static const struct intel_device_info intel_i965g_info = { - .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, + .gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, + .has_hotplug = 1, }; static const struct intel_device_info intel_i965gm_info = { - .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1, - .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, - .has_hotplug = 1, + .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1, + .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_g33_info = { - .is_g33 = 1, .is_i9xx = 1, .need_gfx_hws = 1, - .has_hotplug = 1, + .gen = 3, .is_g33 = 1, .is_i9xx = 1, + .need_gfx_hws = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_g45_info = { - .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1, - .has_pipe_cxsr = 1, - .has_hotplug = 1, + .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1, + .has_pipe_cxsr = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_gm45_info = { - .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, + .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, - .has_pipe_cxsr = 1, - .has_hotplug = 1, + .has_pipe_cxsr = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_pineview_info = { - .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, - .need_gfx_hws = 1, - .has_hotplug = 1, + .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, + .need_gfx_hws = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_ironlake_d_info = { - .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, - .has_pipe_cxsr = 1, - .has_hotplug = 1, + .gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, + .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_ironlake_m_info = { - .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, - .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, - .has_hotplug = 1, + .gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, + .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_sandybridge_d_info = { - .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1, - .has_hotplug = 1, .is_gen6 = 1, + .gen = 6, .is_i965g = 1, .is_i9xx = 1, + .need_gfx_hws = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { - .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1, - .has_hotplug = 1, .is_gen6 = 1, + .gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, + .need_gfx_hws = 1, .has_hotplug = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 047cd7ce7e1b..af4a263cf257 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -191,6 +191,7 @@ struct drm_i915_display_funcs { }; struct intel_device_info { + u8 gen; u8 is_mobile : 1; u8 is_i8xx : 1; u8 is_i85x : 1; @@ -206,7 +207,6 @@ struct intel_device_info { u8 is_broadwater : 1; u8 is_crestline : 1; u8 is_ironlake : 1; - u8 is_gen6 : 1; u8 has_fbc : 1; u8 has_rc6 : 1; u8 has_pipe_cxsr : 1; @@ -1162,7 +1162,6 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove #define IS_845G(dev) ((dev)->pci_device == 0x2562) #define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x) #define IS_I865G(dev) ((dev)->pci_device == 0x2572) -#define IS_GEN2(dev) (INTEL_INFO(dev)->is_i8xx) #define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g) #define IS_I915GM(dev) ((dev)->pci_device == 0x2592) #define IS_I945G(dev) ((dev)->pci_device == 0x2772) @@ -1181,27 +1180,13 @@ extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_ove #define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046) #define IS_IRONLAKE(dev) (INTEL_INFO(dev)->is_ironlake) #define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx) -#define IS_GEN6(dev) (INTEL_INFO(dev)->is_gen6) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) -#define IS_GEN3(dev) (IS_I915G(dev) || \ - IS_I915GM(dev) || \ - IS_I945G(dev) || \ - IS_I945GM(dev) || \ - IS_G33(dev) || \ - IS_PINEVIEW(dev)) -#define IS_GEN4(dev) ((dev)->pci_device == 0x2972 || \ - (dev)->pci_device == 0x2982 || \ - (dev)->pci_device == 0x2992 || \ - (dev)->pci_device == 0x29A2 || \ - (dev)->pci_device == 0x2A02 || \ - (dev)->pci_device == 0x2A12 || \ - (dev)->pci_device == 0x2E02 || \ - (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22 || \ - (dev)->pci_device == 0x2E32 || \ - (dev)->pci_device == 0x2A42 || \ - (dev)->pci_device == 0x2E42) +#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2) +#define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3) +#define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4) +#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5) +#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6) #define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev)) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) -- cgit v1.2.3-59-g8ed1b From 52e68630d13f9668f8f4dd6978fa41039bacfaf6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Aug 2010 10:15:59 +0100 Subject: drm/i915: Fix offset page-flips on i965+ i965 uses the Display Registers to compute the offset from the display base so the new base does not need adjusting when flipping. The older chipsets use a fence to access the display and so do perceive the surface as linear and have a single base register which is reprogrammed using the flip. Signed-off-by: Chris Wilson Cc: Jesse Barnes Reported-by: Marty Jack Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_display.c | 67 ++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3fc767bcbaa0..334665cbe7df 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5042,9 +5042,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; unsigned long flags, offset; - int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC; - int ret, pipesrc; - u32 flip_mask; + int pipe = intel_crtc->pipe; + u32 pf, pipesrc; + int ret; work = kzalloc(sizeof *work, GFP_KERNEL); if (work == NULL) @@ -5093,12 +5093,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, atomic_inc(&obj_priv->pending_flip); work->pending_flip_obj = obj; - if (intel_crtc->plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - if (IS_GEN3(dev) || IS_GEN2(dev)) { + u32 flip_mask; + + if (intel_crtc->plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + BEGIN_LP_RING(2); OUT_RING(MI_WAIT_FOR_EVENT | flip_mask); OUT_RING(0); @@ -5106,29 +5108,56 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, } /* Offset into the new buffer for cases of shared fbs between CRTCs */ - offset = obj_priv->gtt_offset; - offset += (crtc->y * fb->pitch) + (crtc->x * (fb->bits_per_pixel) / 8); + offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; BEGIN_LP_RING(4); - if (IS_I965G(dev)) { + switch(INTEL_INFO(dev)->gen) { + case 2: OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(offset | obj_priv->tiling_mode); - pipesrc = I915_READ(pipesrc_reg); - OUT_RING(pipesrc & 0x0fff0fff); - } else if (IS_GEN3(dev)) { + OUT_RING(obj_priv->gtt_offset + offset); + OUT_RING(MI_NOOP); + break; + + case 3: OUT_RING(MI_DISPLAY_FLIP_I915 | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(offset); + OUT_RING(obj_priv->gtt_offset + offset); OUT_RING(MI_NOOP); - } else { + break; + + case 4: + case 5: + /* i965+ uses the linear or tiled offsets from the + * Display Registers (which do not change across a page-flip) + * so we need only reprogram the base address. + */ OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); OUT_RING(fb->pitch); - OUT_RING(offset); - OUT_RING(MI_NOOP); + OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode); + + /* XXX Enabling the panel-fitter across page-flip is so far + * untested on non-native modes, so ignore it for now. + * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; + */ + pf = 0; + pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff; + OUT_RING(pf | pipesrc); + break; + + case 6: + OUT_RING(MI_DISPLAY_FLIP | + MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); + OUT_RING(fb->pitch | obj_priv->tiling_mode); + OUT_RING(obj_priv->gtt_offset); + + pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; + pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff; + OUT_RING(pf | pipesrc); + break; } ADVANCE_LP_RING(); -- cgit v1.2.3-59-g8ed1b From 4e6cfefc729be2aa20647415317577ed98d4f7bf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 8 Aug 2010 13:20:19 +0100 Subject: drm/i915: Re-use set_base_atomic to share setting of the display registers Lets try to avoid repeating old bugs. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_display.c | 80 ++++-------------------------------- 1 file changed, 9 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 334665cbe7df..cbb509383089 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1502,7 +1502,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, dspcntr &= ~DISPPLANE_TILED; } - if (IS_IRONLAKE(dev)) + if (HAS_PCH_SPLIT(dev)) /* must disable */ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; @@ -1511,20 +1511,19 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, Start = obj_priv->gtt_offset; Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); - DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); + DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", + Start, Offset, x, y, fb->pitch); I915_WRITE(dspstride, fb->pitch); if (IS_I965G(dev)) { - I915_WRITE(dspbase, Offset); - I915_READ(dspbase); I915_WRITE(dspsurf, Start); - I915_READ(dspsurf); I915_WRITE(dsptileoff, (y << 16) | x); + I915_WRITE(dspbase, Offset); } else { I915_WRITE(dspbase, Start + Offset); - I915_READ(dspbase); } + POSTING_READ(dspbase); - if ((IS_I965G(dev) || plane == 0)) + if (IS_I965G(dev) || plane == 0) intel_update_fbc(crtc, &crtc->mode); intel_wait_for_vblank(dev, intel_crtc->pipe); @@ -1538,7 +1537,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_framebuffer *intel_fb; @@ -1546,13 +1544,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_gem_object *obj; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - unsigned long Start, Offset; - int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR); - int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF); - int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; - int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); - int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; - u32 dspcntr; int ret; /* no fb bound */ @@ -1588,71 +1579,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - dspcntr = I915_READ(dspcntr_reg); - /* Mask out pixel format bits in case we change it */ - dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; - switch (crtc->fb->bits_per_pixel) { - case 8: - dspcntr |= DISPPLANE_8BPP; - break; - case 16: - if (crtc->fb->depth == 15) - dspcntr |= DISPPLANE_15_16BPP; - else - dspcntr |= DISPPLANE_16BPP; - break; - case 24: - case 32: - if (crtc->fb->depth == 30) - dspcntr |= DISPPLANE_32BPP_30BIT_NO_ALPHA; - else - dspcntr |= DISPPLANE_32BPP_NO_ALPHA; - break; - default: - DRM_ERROR("Unknown color depth\n"); + ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y); + if (ret) { i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - if (IS_I965G(dev)) { - if (obj_priv->tiling_mode != I915_TILING_NONE) - dspcntr |= DISPPLANE_TILED; - else - dspcntr &= ~DISPPLANE_TILED; - } - - if (HAS_PCH_SPLIT(dev)) - /* must disable */ - dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; - - I915_WRITE(dspcntr_reg, dspcntr); - - Start = obj_priv->gtt_offset; - Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); - - DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", - Start, Offset, x, y, crtc->fb->pitch); - I915_WRITE(dspstride, crtc->fb->pitch); - if (IS_I965G(dev)) { - I915_WRITE(dspsurf, Start); - I915_WRITE(dsptileoff, (y << 16) | x); - I915_WRITE(dspbase, Offset); - } else { - I915_WRITE(dspbase, Start + Offset); + return ret; } - POSTING_READ(dspbase); - - if ((IS_I965G(dev) || plane == 0)) - intel_update_fbc(crtc, &crtc->mode); - - intel_wait_for_vblank(dev, pipe); if (old_fb) { intel_fb = to_intel_framebuffer(old_fb); obj_priv = to_intel_bo(intel_fb->obj); i915_gem_object_unpin(intel_fb->obj); } - intel_increase_pllclock(crtc, true); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3-59-g8ed1b From 0ad6ef2c587dea59212c4e2ab3ec3b0067500a2a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 9 Aug 2010 17:21:44 +0100 Subject: drm/i915/dp: Boost timeout for enabling transcoder to 100ms Adam Hill reported that his Arrandale system required a much longer, up to 200x500us, wait for the panel to initialise or else modesetting would fail. References: https://bugs.freedesktop.org/show_bug.cgi?id=29141 Signed-off-by: Chris Wilson Reported-and-tested-by: Adam Hill --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cbb509383089..83c85450608e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2069,7 +2069,7 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_WRITE(transconf_reg, temp | TRANS_ENABLE); I915_READ(transconf_reg); - if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 10, 0)) + if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1)) DRM_ERROR("failed to enable transcoder\n"); } -- cgit v1.2.3-59-g8ed1b From b66d842467311ac3434aa19c5c41deaab8295bd0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 15:26:41 +0100 Subject: drm/i915/sdvo: Restore guess of the DDC bus in absence of VBIOS If the VBIOS tells us the mapping of the SDVO device onto the DDC bus, use it. However, if there is no VBIOS available that mapping is uninitialised and we should fallback to our earlier guess. Fix regression introduced in b1083333 (which in turn is a fix for the regression caused by the introduction of this guess, 14571b4). References: Bug 29499 - [945GM] Screen disconnected because of missing VBIOS https://bugs.freedesktop.org/show_bug.cgi?id=29499 Bug 15109 - i945GM fails to detect EDID on DVI port https://bugzilla.kernel.org/show_bug.cgi?id=15109 Signed-off-by: Chris Wilson Reported-and-tested-by: Paul Neumann Cc: Adam Jackson Cc: Zhenyu Wang Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_sdvo.c | 40 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 62d22ae4a1d1..e3b7a7ee39cb 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1929,6 +1929,41 @@ static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { .destroy = intel_sdvo_enc_destroy, }; +static void +intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) +{ + uint16_t mask = 0; + unsigned int num_bits; + + /* Make a mask of outputs less than or equal to our own priority in the + * list. + */ + switch (sdvo->controlled_output) { + case SDVO_OUTPUT_LVDS1: + mask |= SDVO_OUTPUT_LVDS1; + case SDVO_OUTPUT_LVDS0: + mask |= SDVO_OUTPUT_LVDS0; + case SDVO_OUTPUT_TMDS1: + mask |= SDVO_OUTPUT_TMDS1; + case SDVO_OUTPUT_TMDS0: + mask |= SDVO_OUTPUT_TMDS0; + case SDVO_OUTPUT_RGB1: + mask |= SDVO_OUTPUT_RGB1; + case SDVO_OUTPUT_RGB0: + mask |= SDVO_OUTPUT_RGB0; + break; + } + + /* Count bits to find what number we are in the priority list. */ + mask &= sdvo->caps.output_flags; + num_bits = hweight16(mask); + /* If more than 3 outputs, default to DDC bus 3 for now. */ + if (num_bits > 3) + num_bits = 3; + + /* Corresponds to SDVO_CONTROL_BUS_DDCx */ + sdvo->ddc_bus = 1 << num_bits; +} /** * Choose the appropriate DDC bus for control bus switch command for this @@ -1948,7 +1983,10 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, else mapping = &(dev_priv->sdvo_mappings[1]); - sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4); + if (mapping->initialized) + sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4); + else + intel_sdvo_guess_ddc_bus(sdvo); } static bool -- cgit v1.2.3-59-g8ed1b From 4f7f7b7eb94bd37c449f06932459bbed78826f8d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Aug 2010 18:12:56 +0100 Subject: drm/i915/dp: Really try 5 times before giving up. Only stop trying if the aux channel sucessfully reports that the transmission was completed, otherwise try again. On the 5th failure, bail and report that something is amiss. This fixes a sporadic failure in reading the EDID for my external panel over DP. Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_dp.c | 58 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9caccd03dccb..51d142939a26 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -239,7 +239,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint32_t ch_data = ch_ctl + 4; int i; int recv_bytes; - uint32_t ctl; uint32_t status; uint32_t aux_clock_divider; int try, precharge; @@ -263,41 +262,43 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, else precharge = 5; + if (I915_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) { + DRM_ERROR("dp_aux_ch not started status 0x%08x\n", + I915_READ(ch_ctl)); + return -EBUSY; + } + /* Must try at least 3 times according to DP spec */ for (try = 0; try < 5; try++) { /* Load the send data into the aux channel data registers */ - for (i = 0; i < send_bytes; i += 4) { - uint32_t d = pack_aux(send + i, send_bytes - i); - - I915_WRITE(ch_data + i, d); - } - - ctl = (DP_AUX_CH_CTL_SEND_BUSY | - DP_AUX_CH_CTL_TIME_OUT_400us | - (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | - (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | - (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | - DP_AUX_CH_CTL_DONE | - DP_AUX_CH_CTL_TIME_OUT_ERROR | - DP_AUX_CH_CTL_RECEIVE_ERROR); + for (i = 0; i < send_bytes; i += 4) + I915_WRITE(ch_data + i, + pack_aux(send + i, send_bytes - i)); /* Send the command and wait for it to complete */ - I915_WRITE(ch_ctl, ctl); - (void) I915_READ(ch_ctl); + I915_WRITE(ch_ctl, + DP_AUX_CH_CTL_SEND_BUSY | + DP_AUX_CH_CTL_TIME_OUT_400us | + (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | + (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | + (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) | + DP_AUX_CH_CTL_DONE | + DP_AUX_CH_CTL_TIME_OUT_ERROR | + DP_AUX_CH_CTL_RECEIVE_ERROR); for (;;) { - udelay(100); status = I915_READ(ch_ctl); if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) break; + udelay(100); } /* Clear done status and any errors */ - I915_WRITE(ch_ctl, (status | - DP_AUX_CH_CTL_DONE | - DP_AUX_CH_CTL_TIME_OUT_ERROR | - DP_AUX_CH_CTL_RECEIVE_ERROR)); - (void) I915_READ(ch_ctl); - if ((status & DP_AUX_CH_CTL_TIME_OUT_ERROR) == 0) + I915_WRITE(ch_ctl, + status | + DP_AUX_CH_CTL_DONE | + DP_AUX_CH_CTL_TIME_OUT_ERROR | + DP_AUX_CH_CTL_RECEIVE_ERROR); + if (status & DP_AUX_CH_CTL_DONE) break; } @@ -324,15 +325,12 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, /* Unload any bytes sent back from the other side */ recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >> DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); - if (recv_bytes > recv_size) recv_bytes = recv_size; - for (i = 0; i < recv_bytes; i += 4) { - uint32_t d = I915_READ(ch_data + i); - - unpack_aux(d, recv + i, recv_bytes - i); - } + for (i = 0; i < recv_bytes; i += 4) + unpack_aux(I915_READ(ch_data + i), + recv + i, recv_bytes - i); return recv_bytes; } -- cgit v1.2.3-59-g8ed1b From a25c25c2a2aa55e609099a9f74453c518aec29a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 20 Aug 2010 14:36:45 +0100 Subject: drm/i915: Allocate the PCI resource for the MCHBAR We were failing when trying to allocate the resource for MMIO of the MCHBAR because we forgot to specify what type of resource we wanted. Signed-off-by: Chris Wilson Cc: Jesse Barnes Cc: stable@kernel.org Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/i915_dma.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 051c4db7a1d3..9d67b4853030 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -891,7 +891,7 @@ intel_alloc_mchbar_resource(struct drm_device *dev) int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; u32 temp_lo, temp_hi = 0; u64 mchbar_addr; - int ret = 0; + int ret; if (IS_I965G(dev)) pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi); @@ -901,22 +901,23 @@ intel_alloc_mchbar_resource(struct drm_device *dev) /* If ACPI doesn't have it, assume we need to allocate it ourselves */ #ifdef CONFIG_PNP if (mchbar_addr && - pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) { - ret = 0; - goto out; - } + pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) + return 0; #endif /* Get some space for it */ - ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res, + dev_priv->mch_res.name = "i915 MCHBAR"; + dev_priv->mch_res.flags = IORESOURCE_MEM; + ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, + &dev_priv->mch_res, MCHBAR_SIZE, MCHBAR_SIZE, PCIBIOS_MIN_MEM, - 0, pcibios_align_resource, + 0, pcibios_align_resource, dev_priv->bridge_dev); if (ret) { DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret); dev_priv->mch_res.start = 0; - goto out; + return ret; } if (IS_I965G(dev)) @@ -925,8 +926,7 @@ intel_alloc_mchbar_resource(struct drm_device *dev) pci_write_config_dword(dev_priv->bridge_dev, reg, lower_32_bits(dev_priv->mch_res.start)); -out: - return ret; + return 0; } /* Setup MCHBAR if possible, return true if we should disable it again */ -- cgit v1.2.3-59-g8ed1b From 8e647a279ca30029f19eca646de08a6338eab924 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 22 Aug 2010 10:54:23 +0100 Subject: drm/i915: Tightly scope intel_encoder to prevent invalid use We reset intel_encoder for every matching encoder whilst iterating over the encoders attached to this crtc when changing mode. As such in a cloned configuration intel_encoder may not correspond to the correct is_edp encoder. By scoping intel_encoder to the loop, not only is the compiler able to spot this mistake, we also improve readiability for ourselves. [It might not be a mistake, within this function it is unclear as to whether it is permissable for eDP to be cloned...] Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 83c85450608e..0b90443f1eb3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3508,10 +3508,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf; bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; - bool is_edp = false; + struct intel_encoder *has_edp_encoder = NULL; struct drm_mode_config *mode_config = &dev->mode_config; struct drm_encoder *encoder; - struct intel_encoder *intel_encoder = NULL; const intel_limit_t *limit; int ret; struct fdi_m_n m_n = {0}; @@ -3532,12 +3531,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, drm_vblank_pre_modeset(dev, pipe); list_for_each_entry(encoder, &mode_config->encoder_list, head) { + struct intel_encoder *intel_encoder; - if (!encoder || encoder->crtc != crtc) + if (encoder->crtc != crtc) continue; intel_encoder = enc_to_intel_encoder(encoder); - switch (intel_encoder->type) { case INTEL_OUTPUT_LVDS: is_lvds = true; @@ -3561,7 +3560,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, is_dp = true; break; case INTEL_OUTPUT_EDP: - is_edp = true; + has_edp_encoder = intel_encoder; break; } @@ -3639,10 +3638,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int lane = 0, link_bw, bpp; /* eDP doesn't require FDI link, so just set DP M/N according to current link config */ - if (is_edp) { + if (has_edp_encoder) { target_clock = mode->clock; - intel_edp_link_config(intel_encoder, - &lane, &link_bw); + intel_edp_link_config(has_edp_encoder, + &lane, &link_bw); } else { /* DP over FDI requires target mode clock instead of link clock */ @@ -3663,7 +3662,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, temp |= PIPE_8BPC; else temp |= PIPE_6BPC; - } else if (is_edp || (is_dp && intel_pch_has_edp(crtc))) { + } else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) { switch (dev_priv->edp_bpp/3) { case 8: temp |= PIPE_8BPC; @@ -3736,7 +3735,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, udelay(200); - if (is_edp) { + if (has_edp_encoder) { if (dev_priv->lvds_use_ssc) { temp |= DREF_SSC1_ENABLE; I915_WRITE(PCH_DREF_CONTROL, temp); @@ -3885,7 +3884,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll_reg = pch_dpll_reg; } - if (!is_edp) { + if (!has_edp_encoder) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); I915_READ(dpll_reg); @@ -3980,7 +3979,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } - if (!is_edp) { + if (!has_edp_encoder) { I915_WRITE(fp_reg, fp); I915_WRITE(dpll_reg, dpll); I915_READ(dpll_reg); @@ -4059,7 +4058,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(link_m1_reg, m_n.link_m); I915_WRITE(link_n1_reg, m_n.link_n); - if (is_edp) { + if (has_edp_encoder) { ironlake_set_pll_edp(crtc, adjusted_mode->clock); } else { /* enable FDI RX PLL too */ -- cgit v1.2.3-59-g8ed1b From 4e5359cd053bfb7d8dabe4a63624a5726848ffbc Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Wed, 1 Sep 2010 17:47:52 +0100 Subject: drm/i915: Avoid pageflipping freeze when we miss the flip prepare interrupt When we miss the flip prepare interrupt, we never get into the software state needed to restart userspace, resulting in a freeze of a full-screen OpenGL application (such as a compositor). Work around this by checking DSPxSURF/DSPxBASE to see if the page flip has actually happened. If it has, do the work we would have done when the flip prepare interrupt comes in. Also, add debugfs information to tell us what's going on (based on the patch from Chris Wilson attached to bugs.fdo bug #29798). Signed-off-by: Simon Farnsworth Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_debugfs.c | 50 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_irq.c | 51 ++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_display.c | 14 +++------- drivers/gpu/drm/i915/intel_drv.h | 10 +++++++ 4 files changed, 113 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 92d5605a34d1..5e43d7076789 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -31,6 +31,7 @@ #include #include "drmP.h" #include "drm.h" +#include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -121,6 +122,54 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) return 0; } +static int i915_gem_pageflip_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + unsigned long flags; + struct intel_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + const char *pipe = crtc->pipe ? "B" : "A"; + const char *plane = crtc->plane ? "B" : "A"; + struct intel_unpin_work *work; + + spin_lock_irqsave(&dev->event_lock, flags); + work = crtc->unpin_work; + if (work == NULL) { + seq_printf(m, "No flip due on pipe %s (plane %s)\n", + pipe, plane); + } else { + if (!work->pending) { + seq_printf(m, "Flip queued on pipe %s (plane %s)\n", + pipe, plane); + } else { + seq_printf(m, "Flip pending (waiting for vsync) on pipe %s (plane %s)\n", + pipe, plane); + } + if (work->enable_stall_check) + seq_printf(m, "Stall check enabled, "); + else + seq_printf(m, "Stall check waiting for page flip ioctl, "); + seq_printf(m, "%d prepares\n", work->pending); + + if (work->old_fb_obj) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(work->old_fb_obj); + if(obj_priv) + seq_printf(m, "Old framebuffer gtt_offset 0x%08x\n", obj_priv->gtt_offset ); + } + if (work->pending_flip_obj) { + struct drm_i915_gem_object *obj_priv = to_intel_bo(work->pending_flip_obj); + if(obj_priv) + seq_printf(m, "New framebuffer gtt_offset 0x%08x\n", obj_priv->gtt_offset ); + } + } + spin_unlock_irqrestore(&dev->event_lock, flags); + } + + return 0; +} + static int i915_gem_request_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -777,6 +826,7 @@ static struct drm_info_list i915_debugfs_list[] = { {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, {"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST}, {"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST}, + {"i915_gem_pageflip", i915_gem_pageflip_info, 0}, {"i915_gem_request", i915_gem_request_info, 0}, {"i915_gem_seqno", i915_gem_seqno_info, 0}, {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0}, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 16861b800fee..59457e83b011 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -887,6 +887,49 @@ static void i915_handle_error(struct drm_device *dev, bool wedged) queue_work(dev_priv->wq, &dev_priv->error_work); } +static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_i915_gem_object *obj_priv; + struct intel_unpin_work *work; + unsigned long flags; + bool stall_detected; + + /* Ignore early vblank irqs */ + if (intel_crtc == NULL) + return; + + spin_lock_irqsave(&dev->event_lock, flags); + work = intel_crtc->unpin_work; + + if (work == NULL || work->pending || !work->enable_stall_check) { + /* Either the pending flip IRQ arrived, or we're too early. Don't check */ + spin_unlock_irqrestore(&dev->event_lock, flags); + return; + } + + /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ + obj_priv = to_intel_bo(work->pending_flip_obj); + if(IS_I965G(dev)) { + int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF; + stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset; + } else { + int dspaddr = intel_crtc->plane == 0 ? DSPAADDR : DSPBADDR; + stall_detected = I915_READ(dspaddr) == (obj_priv->gtt_offset + + crtc->y * crtc->fb->pitch + + crtc->x * crtc->fb->bits_per_pixel/8); + } + + spin_unlock_irqrestore(&dev->event_lock, flags); + + if (stall_detected) { + DRM_DEBUG_DRIVER("Pageflip stall detected\n"); + intel_prepare_page_flip(dev, intel_crtc->plane); + } +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -1004,15 +1047,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if (pipea_stats & vblank_status) { vblank++; drm_handle_vblank(dev, 0); - if (!dev_priv->flip_pending_is_done) + if (!dev_priv->flip_pending_is_done) { + i915_pageflip_stall_check(dev, 0); intel_finish_page_flip(dev, 0); + } } if (pipeb_stats & vblank_status) { vblank++; drm_handle_vblank(dev, 1); - if (!dev_priv->flip_pending_is_done) + if (!dev_priv->flip_pending_is_done) { + i915_pageflip_stall_check(dev, 1); intel_finish_page_flip(dev, 1); + } } if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b90443f1eb3..1bd0c672ec90 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4864,15 +4864,6 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) kfree(intel_crtc); } -struct intel_unpin_work { - struct work_struct work; - struct drm_device *dev; - struct drm_gem_object *old_fb_obj; - struct drm_gem_object *pending_flip_obj; - struct drm_pending_vblank_event *event; - int pending; -}; - static void intel_unpin_work_fn(struct work_struct *__work) { struct intel_unpin_work *work = @@ -4960,7 +4951,8 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane) spin_lock_irqsave(&dev->event_lock, flags); if (intel_crtc->unpin_work) { - intel_crtc->unpin_work->pending = 1; + if ((++intel_crtc->unpin_work->pending) > 1) + DRM_ERROR("Prepared flip multiple times\n"); } else { DRM_DEBUG_DRIVER("preparing flip with no unpin work?\n"); } @@ -5044,6 +5036,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, ADVANCE_LP_RING(); } + work->enable_stall_check = true; + /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitch + crtc->x * fb->bits_per_pixel/8; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0e92aa07b382..ad312ca6b3e5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -176,6 +176,16 @@ struct intel_crtc { #define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) +struct intel_unpin_work { + struct work_struct work; + struct drm_device *dev; + struct drm_gem_object *old_fb_obj; + struct drm_gem_object *pending_flip_obj; + struct drm_pending_vblank_event *event; + int pending; + bool enable_stall_check; +}; + struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg, const char *name); void intel_i2c_destroy(struct i2c_adapter *adapter); -- cgit v1.2.3-59-g8ed1b From 52be11964869c948fbbb9ec7845f9c52b0d3dc09 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 5 Sep 2010 10:01:13 +0100 Subject: drm/i915: Avoid use of uninitialised values when disabling panel-fitter We were passing garbage values into the panel-fitter control register when disabling it on Ironlake - those values (filter modes and reserved MBZ bits) would have then be re-used the next time panel-fitting was enabled. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1bd0c672ec90..cf8d5e5a286e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1865,9 +1865,6 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; - int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1; - int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ; - int pf_win_pos = (pipe == 0) ? PFA_WIN_POS : PFB_WIN_POS; int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; @@ -1936,15 +1933,19 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) } /* Enable panel fitting for LVDS */ - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) - || HAS_eDP || intel_pch_has_edp(crtc)) { - if (dev_priv->pch_pf_size) { - temp = I915_READ(pf_ctl_reg); - I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); - I915_WRITE(pf_win_pos, dev_priv->pch_pf_pos); - I915_WRITE(pf_win_size, dev_priv->pch_pf_size); - } else - I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); + if (dev_priv->pch_pf_size && + (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) + || HAS_eDP || intel_pch_has_edp(crtc))) { + /* Force use of hard-coded filter coefficients + * as some pre-programmed values are broken, + * e.g. x201. + */ + I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, + PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS, + dev_priv->pch_pf_pos); + I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, + dev_priv->pch_pf_size); } /* Enable CPU pipe */ @@ -2109,14 +2110,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) udelay(100); /* Disable PF */ - temp = I915_READ(pf_ctl_reg); - if ((temp & PF_ENABLE) != 0) { - I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); - I915_READ(pf_ctl_reg); - } - I915_WRITE(pf_win_size, 0); - POSTING_READ(pf_win_size); - + I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0); + I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0); /* disable CPU FDI tx and PCH FDI rx */ temp = I915_READ(fdi_tx_reg); -- cgit v1.2.3-59-g8ed1b From 032d2a0d068b0368296a56469761394ef03207c3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Sep 2010 16:17:22 +0100 Subject: drm/i915: Prevent double dpms on Arguably this is a bug in drm-core in that we should not be called twice in succession with DPMS_ON, however this is still occuring and we see FDI link training failures on the second call leading to the occassional blank display. For the time being ignore the repeated call. Original patch by Dave Airlie Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cf8d5e5a286e..40cc5da264a9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2370,6 +2370,9 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) int pipe = intel_crtc->pipe; bool enabled; + if (intel_crtc->dpms_mode == mode) + return; + intel_crtc->dpms_mode = mode; intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON; @@ -5164,7 +5167,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; intel_crtc->cursor_addr = 0; - intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; + intel_crtc->dpms_mode = -1; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); intel_crtc->busy = false; -- cgit v1.2.3-59-g8ed1b From 8dfc2b14ebf538f28a05565f34913ecffedf5024 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Mon, 23 Aug 2010 14:37:52 +0800 Subject: agp/intel: fix physical address mask bits for sandybridge It should shift bit 39-32 into pte's bit 11-4. Reported-by:Takashi Iwai Signed-off-by: Zhenyu Wang Cc: stable@kernel.org Signed-off-by: Chris Wilson --- drivers/char/agp/intel-gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index ce536e68b6c6..7f35854d33a3 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1333,8 +1333,8 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr, int type) { - /* Shift high bits down */ - addr |= (addr >> 28) & 0xff; + /* gen6 has bit11-4 for physical addr bit39-32 */ + addr |= (addr >> 28) & 0xff0; /* Type checking must be done elsewhere */ return addr | bridge->driver->masks[type].mask; -- cgit v1.2.3-59-g8ed1b From 93f5f7f1249e76a5e8afbdab53f90b10c41fdb61 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 27 Aug 2010 11:06:48 +0800 Subject: agp/intel: use #ifdef idiom for intel-agp.h Signed-off-by: Zhenyu Wang Cc: stable@kernel.org Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 08d47532e605..78124a8402e5 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -1,6 +1,8 @@ /* * Common Intel AGPGART and GTT definitions. */ +#ifndef _INTEL_AGP_H +#define _INTEL_AGP_H /* Intel registers */ #define INTEL_APSIZE 0xb4 @@ -244,3 +246,5 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \ IS_SNB) + +#endif -- cgit v1.2.3-59-g8ed1b From f8f235e5bbf4e61f3e0886a44afb1dc4cfe8f337 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 27 Aug 2010 11:08:57 +0800 Subject: agp/intel: Fix cache control for Sandybridge Sandybridge GTT has new cache control bits in PTE, which controls graphics page cache in LLC or LLC/MLC, so we need to extend the mask function to respect the new bits. And set cache control to always LLC only by default on Gen6. Signed-off-by: Zhenyu Wang Cc: stable@kernel.org Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.c | 1 + drivers/char/agp/intel-gtt.c | 50 ++++++++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/i915_gem.c | 1 + include/linux/intel-gtt.h | 20 +++++++++++++++++ 4 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 include/linux/intel-gtt.h diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 710af89b176d..74461d177baf 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -12,6 +12,7 @@ #include #include "agp.h" #include "intel-agp.h" +#include #include "intel-gtt.c" diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 7f35854d33a3..64b10551a3f8 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -49,6 +49,26 @@ static struct gatt_mask intel_i810_masks[] = .type = INTEL_AGP_CACHED_MEMORY} }; +#define INTEL_AGP_UNCACHED_MEMORY 0 +#define INTEL_AGP_CACHED_MEMORY_LLC 1 +#define INTEL_AGP_CACHED_MEMORY_LLC_GFDT 2 +#define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3 +#define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4 + +static struct gatt_mask intel_gen6_masks[] = +{ + {.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED, + .type = INTEL_AGP_UNCACHED_MEMORY }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC, + .type = INTEL_AGP_CACHED_MEMORY_LLC }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT, + .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC, + .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT, + .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT }, +}; + static struct _intel_private { struct pci_dev *pcidev; /* device one */ u8 __iomem *registers; @@ -178,13 +198,6 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem, off_t pg_start, int mask_type) { int i, j; - u32 cache_bits = 0; - - if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) - { - cache_bits = GEN6_PTE_LLC_MLC; - } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, @@ -317,6 +330,23 @@ static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge, return 0; } +static int intel_gen6_type_to_mask_type(struct agp_bridge_data *bridge, + int type) +{ + unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT; + unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT; + + if (type_mask == AGP_USER_UNCACHED_MEMORY) + return INTEL_AGP_UNCACHED_MEMORY; + else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) + return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT : + INTEL_AGP_CACHED_MEMORY_LLC_MLC; + else /* set 'normal'/'cached' to LLC by default */ + return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT : + INTEL_AGP_CACHED_MEMORY_LLC; +} + + static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -1163,7 +1193,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + if (!IS_SNB && mask_type != 0 && mask_type != AGP_PHYS_MEMORY && mask_type != INTEL_AGP_CACHED_MEMORY) goto out_err; @@ -1563,7 +1593,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .fetch_size = intel_i9xx_fetch_size, .cleanup = intel_i915_cleanup, .mask_memory = intel_gen6_mask_memory, - .masks = intel_i810_masks, + .masks = intel_gen6_masks, .agp_enable = intel_i810_agp_enable, .cache_flush = global_cache_flush, .create_gatt_table = intel_i965_create_gatt_table, @@ -1576,7 +1606,7 @@ static const struct agp_bridge_driver intel_gen6_driver = { .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, - .agp_type_to_mask_type = intel_i830_type_to_mask_type, + .agp_type_to_mask_type = intel_gen6_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, #ifdef USE_PCI_DMA_API .agp_map_page = intel_agp_map_page, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 748c26340c35..16fca1d1799a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -34,6 +34,7 @@ #include #include #include +#include static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj); static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); diff --git a/include/linux/intel-gtt.h b/include/linux/intel-gtt.h new file mode 100644 index 000000000000..1d19ab2afa39 --- /dev/null +++ b/include/linux/intel-gtt.h @@ -0,0 +1,20 @@ +/* + * Common Intel AGPGART and GTT definitions. + */ +#ifndef _INTEL_GTT_H +#define _INTEL_GTT_H + +#include + +/* This is for Intel only GTT controls. + * + * Sandybridge: AGP_USER_CACHED_MEMORY default to LLC only + */ + +#define AGP_USER_CACHED_MEMORY_LLC_MLC (AGP_USER_TYPES + 2) +#define AGP_USER_UNCACHED_MEMORY (AGP_USER_TYPES + 4) + +/* flag for GFDT type */ +#define AGP_USER_CACHED_MEMORY_GFDT (1 << 3) + +#endif -- cgit v1.2.3-59-g8ed1b From a69ffdbfcba8eabf2ca9d384b578e6f28b339c61 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Mon, 30 Aug 2010 16:12:42 +0800 Subject: drm/i915: Enable MI_FLUSH on Sandybridge MI_FLUSH is being deprecated, but still available on Sandybridge. Make sure it's enabled as userspace still uses MI_FLUSH. Signed-off-by: Zhenyu Wang Cc: stable@kernel.org Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 67e3ec1a6af9..d094e9129223 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -319,6 +319,7 @@ #define MI_MODE 0x0209c # define VS_TIMER_DISPATCH (1 << 6) +# define MI_FLUSH_ENABLE (1 << 11) #define SCPD0 0x0209c /* 915+ only */ #define IER 0x020a0 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 51e9c9e718c4..cb3508f78bc3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -220,9 +220,13 @@ static int init_render_ring(struct drm_device *dev, { drm_i915_private_t *dev_priv = dev->dev_private; int ret = init_ring_common(dev, ring); + int mode; + if (IS_I9XX(dev) && !IS_GEN3(dev)) { - I915_WRITE(MI_MODE, - (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH); + mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; + if (IS_GEN6(dev)) + mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE; + I915_WRITE(MI_MODE, mode); } return ret; } -- cgit v1.2.3-59-g8ed1b From 8554048070906579ec9fa19ac381deddd2d7b155 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Tue, 7 Sep 2010 13:45:32 +0800 Subject: intel_agp,i915: Add more sandybridge graphics device ids New pci ids for GT2 and GT2+ on desktop and mobile sandybridge, and graphics device ids for server sandybridge. Also rename original ids string to reflect GT1 version. Signed-off-by: Zhenyu Wang Cc: stable@kernel.org Signed-off-by: Chris Wilson --- drivers/char/agp/intel-agp.c | 15 ++++++++++++--- drivers/char/agp/intel-agp.h | 18 ++++++++++++------ drivers/char/agp/intel-gtt.c | 4 ++-- drivers/gpu/drm/i915/i915_drv.c | 4 ++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 74461d177baf..eab58db5f91c 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -816,11 +816,19 @@ static const struct intel_driver_description { "HD Graphics", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, "HD Graphics", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, "Sandybridge", NULL, &intel_gen6_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, "Sandybridge", NULL, &intel_gen6_driver }, { 0, 0, NULL, NULL, NULL } }; @@ -1045,6 +1053,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB), + ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB), { } }; diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 78124a8402e5..ee189c74d345 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -202,11 +202,16 @@ #define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062 #define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB 0x006a #define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG 0x0046 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB 0x0100 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG 0x0126 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB 0x0100 /* Desktop */ +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG 0x0102 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG 0x0112 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG 0x0122 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 /* Mobile */ +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG 0x0106 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG 0x0116 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG 0x0126 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */ +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A /* cover 915 and 945 variants */ #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ @@ -233,7 +238,8 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB) #define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB) #define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \ diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 64b10551a3f8..75e0a3497888 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -618,8 +618,7 @@ static void intel_i830_init_gtt_entries(void) gtt_entries = 0; break; } - } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) { + } else if (IS_SNB) { /* * SandyBridge has new memory control reg at 0x50.w */ @@ -1389,6 +1388,7 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) break; case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB: case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB: + case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB: *gtt_offset = MB(2); pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 5363985673a4..216deb579785 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -175,8 +175,12 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info), INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info), INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info), + INTEL_VGA_DEVICE(0x0112, &intel_sandybridge_d_info), + INTEL_VGA_DEVICE(0x0122, &intel_sandybridge_d_info), INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info), + INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info), INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info), + INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info), {0, 0, 0} }; -- cgit v1.2.3-59-g8ed1b From 595afaf9e6ee1b48e13ec4b8bcc8c7dee888161a Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 7 Sep 2010 13:42:41 +0200 Subject: fuse: flush background queue on connection close David Bartly reported that fuse can hang in fuse_get_req_nofail() when the connection to the filesystem server is no longer active. If bg_queue is not empty then flush_bg_queue() called from request_end() can put more requests on to the pending queue. If this happens while ending requests on the processing queue then those background requests will be queued to the pending list and never ended. Another problem is that fuse_dev_release() didn't wake up processes sleeping on blocked_waitq. Solve this by: a) flushing the background queue before calling end_requests() on the pending and processing queues b) setting blocked = 0 and waking up processes waiting on blocked_waitq() Thanks to David for an excellent bug report. Reported-by: David Bartley Signed-off-by: Miklos Szeredi CC: stable@kernel.org --- fs/fuse/dev.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 69ad053ffd78..b4fc47ff4bc2 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1769,6 +1769,14 @@ __acquires(&fc->lock) } } +static void end_queued_requests(struct fuse_conn *fc) +{ + fc->max_background = UINT_MAX; + flush_bg_queue(fc); + end_requests(fc, &fc->pending); + end_requests(fc, &fc->processing); +} + /* * Abort all requests. * @@ -1795,8 +1803,7 @@ void fuse_abort_conn(struct fuse_conn *fc) fc->connected = 0; fc->blocked = 0; end_io_requests(fc); - end_requests(fc, &fc->pending); - end_requests(fc, &fc->processing); + end_queued_requests(fc); wake_up_all(&fc->waitq); wake_up_all(&fc->blocked_waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); @@ -1811,8 +1818,9 @@ int fuse_dev_release(struct inode *inode, struct file *file) if (fc) { spin_lock(&fc->lock); fc->connected = 0; - end_requests(fc, &fc->pending); - end_requests(fc, &fc->processing); + fc->blocked = 0; + end_queued_requests(fc); + wake_up_all(&fc->blocked_waitq); spin_unlock(&fc->lock); fuse_conn_put(fc); } -- cgit v1.2.3-59-g8ed1b From b9ca67b2ddf021491a3741d9555e8ff59b2175ba Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 7 Sep 2010 13:42:41 +0200 Subject: fuse: fix lock annotations Sparse doesn't understand lock annotations of the form __releases(&foo->lock). Change them to __releases(foo->lock). Same for __acquires(). Signed-off-by: Miklos Szeredi --- fs/fuse/dev.c | 26 ++++++++++++++------------ fs/fuse/file.c | 8 ++++---- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index b4fc47ff4bc2..d367af1514ef 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -276,7 +276,7 @@ static void flush_bg_queue(struct fuse_conn *fc) * Called with fc->lock, unlocks it */ static void request_end(struct fuse_conn *fc, struct fuse_req *req) -__releases(&fc->lock) +__releases(fc->lock) { void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; req->end = NULL; @@ -306,8 +306,8 @@ __releases(&fc->lock) static void wait_answer_interruptible(struct fuse_conn *fc, struct fuse_req *req) -__releases(&fc->lock) -__acquires(&fc->lock) +__releases(fc->lock) +__acquires(fc->lock) { if (signal_pending(current)) return; @@ -325,8 +325,8 @@ static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req) } static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) -__releases(&fc->lock) -__acquires(&fc->lock) +__releases(fc->lock) +__acquires(fc->lock) { if (!fc->no_interrupt) { /* Any signal may interrupt this */ @@ -905,8 +905,8 @@ static int request_pending(struct fuse_conn *fc) /* Wait until a request is available on the pending list */ static void request_wait(struct fuse_conn *fc) -__releases(&fc->lock) -__acquires(&fc->lock) +__releases(fc->lock) +__acquires(fc->lock) { DECLARE_WAITQUEUE(wait, current); @@ -934,7 +934,7 @@ __acquires(&fc->lock) */ static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_copy_state *cs, size_t nbytes, struct fuse_req *req) -__releases(&fc->lock) +__releases(fc->lock) { struct fuse_in_header ih; struct fuse_interrupt_in arg; @@ -1720,8 +1720,8 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait) * This function releases and reacquires fc->lock */ static void end_requests(struct fuse_conn *fc, struct list_head *head) -__releases(&fc->lock) -__acquires(&fc->lock) +__releases(fc->lock) +__acquires(fc->lock) { while (!list_empty(head)) { struct fuse_req *req; @@ -1744,8 +1744,8 @@ __acquires(&fc->lock) * locked). */ static void end_io_requests(struct fuse_conn *fc) -__releases(&fc->lock) -__acquires(&fc->lock) +__releases(fc->lock) +__acquires(fc->lock) { while (!list_empty(&fc->io)) { struct fuse_req *req = @@ -1770,6 +1770,8 @@ __acquires(&fc->lock) } static void end_queued_requests(struct fuse_conn *fc) +__releases(fc->lock) +__acquires(fc->lock) { fc->max_background = UINT_MAX; flush_bg_queue(fc); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 147c1f71bdb9..c8224587123f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1144,8 +1144,8 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) /* Called under fc->lock, may release and reacquire it */ static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req) -__releases(&fc->lock) -__acquires(&fc->lock) +__releases(fc->lock) +__acquires(fc->lock) { struct fuse_inode *fi = get_fuse_inode(req->inode); loff_t size = i_size_read(req->inode); @@ -1183,8 +1183,8 @@ __acquires(&fc->lock) * Called with fc->lock */ void fuse_flush_writepages(struct inode *inode) -__releases(&fc->lock) -__acquires(&fc->lock) +__releases(fc->lock) +__acquires(fc->lock) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_inode *fi = get_fuse_inode(inode); -- cgit v1.2.3-59-g8ed1b From 7e443312403ad1ff40ef3177590e96d1fe747c79 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 7 Sep 2010 11:27:52 -0400 Subject: [SCSI] sd: fix medium-removal bug Commit 409f3499a2cfcd1e9c2857c53af7fcce069f027f (scsi/sd: remove big kernel lock) introduced a bug in the sd_release routine. Medium removal should be allowed when the number of open file references drops to 0, not when it becomes non-zero. This patch (as1414) adjusts the test to fix the bug. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index cd71f46a3d47..ffa0689ee840 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -870,7 +870,7 @@ static int sd_release(struct gendisk *disk, fmode_t mode) SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n")); - if (atomic_dec_return(&sdkp->openers) && sdev->removable) { + if (atomic_dec_return(&sdkp->openers) == 0 && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); } -- cgit v1.2.3-59-g8ed1b From 8d2602e0778299e2d6084f03086b716d6e7a1e1e Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 20 Aug 2010 16:44:33 +0200 Subject: AT91: change dma resource index Reported-by: Dan Liang Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91sam9g45_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 809114d5a5a6..501ac6fae2e7 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -46,7 +46,7 @@ static struct resource hdmac_resources[] = { .end = AT91_BASE_SYS + AT91_DMA + SZ_512 - 1, .flags = IORESOURCE_MEM, }, - [2] = { + [1] = { .start = AT91SAM9G45_ID_DMA, .end = AT91SAM9G45_ID_DMA, .flags = IORESOURCE_IRQ, -- cgit v1.2.3-59-g8ed1b From 7a2e8a8faab76386d8eaae9ded739ee5615be174 Mon Sep 17 00:00:00 2001 From: Valerie Aurora Date: Thu, 26 Aug 2010 11:07:22 -0700 Subject: VFS: Sanity check mount flags passed to change_mnt_propagation() Sanity check the flags passed to change_mnt_propagation(). Exactly one flag should be set. Return EINVAL otherwise. Userspace can pass in arbitrary combinations of MS_* flags to mount(). do_change_type() is called if any of MS_SHARED, MS_PRIVATE, MS_SLAVE, or MS_UNBINDABLE is set. do_change_type() clears MS_REC and then calls change_mnt_propagation() with the rest of the user-supplied flags. change_mnt_propagation() clearly assumes only one flag is set but do_change_type() does not check that this is true. For example, mount() with flags MS_SHARED | MS_RDONLY does not actually make the mount shared or read-only but does clear MNT_UNBINDABLE. Signed-off-by: Valerie Aurora Signed-off-by: Linus Torvalds --- fs/namespace.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/namespace.c b/fs/namespace.c index de402eb6eafb..a72eaabfe8f2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1483,6 +1483,23 @@ out_unlock: return err; } +/* + * Sanity check the flags to change_mnt_propagation. + */ + +static int flags_to_propagation_type(int flags) +{ + int type = flags & ~MS_REC; + + /* Fail if any non-propagation flags are set */ + if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) + return 0; + /* Only one propagation flag should be set */ + if (!is_power_of_2(type)) + return 0; + return type; +} + /* * recursively change the type of the mountpoint. */ @@ -1490,7 +1507,7 @@ static int do_change_type(struct path *path, int flag) { struct vfsmount *m, *mnt = path->mnt; int recurse = flag & MS_REC; - int type = flag & ~MS_REC; + int type; int err = 0; if (!capable(CAP_SYS_ADMIN)) @@ -1499,6 +1516,10 @@ static int do_change_type(struct path *path, int flag) if (path->dentry != path->mnt->mnt_root) return -EINVAL; + type = flags_to_propagation_type(flag); + if (!type) + return -EINVAL; + down_write(&namespace_sem); if (type == MS_SHARED) { err = invent_group_ids(mnt, recurse); -- cgit v1.2.3-59-g8ed1b From 3ab61eb9fd751336d1b3ad50ec7704bd3b62213f Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 31 Aug 2010 16:52:11 +0100 Subject: h8300: IRQ flags should be stored in an unsigned long Fix h8300's asm/atomic.h to store the IRQ flags in an unsigned long to deal with warnings of the following type: arch/h8300/include/asm/atomic.h: In function 'atomic_add_return': arch/h8300/include/asm/atomic.h:22: warning: comparison of distinct pointer types lacks a cast arch/h8300/include/asm/atomic.h:24: warning: comparison of distinct pointer types lacks a cast Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/h8300/include/asm/atomic.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index e936804b7508..984221abb66d 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -18,7 +18,8 @@ static __inline__ int atomic_add_return(int i, atomic_t *v) { - int ret,flags; + unsigned long flags; + int ret; local_irq_save(flags); ret = v->counter += i; local_irq_restore(flags); @@ -30,7 +31,8 @@ static __inline__ int atomic_add_return(int i, atomic_t *v) static __inline__ int atomic_sub_return(int i, atomic_t *v) { - int ret,flags; + unsigned long flags; + int ret; local_irq_save(flags); ret = v->counter -= i; local_irq_restore(flags); @@ -42,7 +44,8 @@ static __inline__ int atomic_sub_return(int i, atomic_t *v) static __inline__ int atomic_inc_return(atomic_t *v) { - int ret,flags; + unsigned long flags; + int ret; local_irq_save(flags); v->counter++; ret = v->counter; @@ -64,7 +67,8 @@ static __inline__ int atomic_inc_return(atomic_t *v) static __inline__ int atomic_dec_return(atomic_t *v) { - int ret,flags; + unsigned long flags; + int ret; local_irq_save(flags); --v->counter; ret = v->counter; @@ -76,7 +80,8 @@ static __inline__ int atomic_dec_return(atomic_t *v) static __inline__ int atomic_dec_and_test(atomic_t *v) { - int ret,flags; + unsigned long flags; + int ret; local_irq_save(flags); --v->counter; ret = v->counter; -- cgit v1.2.3-59-g8ed1b From b857189d94e0d8a05943349618c4f84dbc57144c Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 31 Aug 2010 16:52:16 +0100 Subject: h8300: Fix die() Fix h8300's die() to take care of a number of problems: CC arch/h8300/kernel/traps.o In file included from arch/h8300/include/asm/bitops.h:10, from include/linux/bitops.h:22, from include/linux/kernel.h:17, from include/linux/sched.h:54, from arch/h8300/kernel/traps.c:18: arch/h8300/include/asm/system.h:136: warning: 'struct pt_regs' declared inside parameter list arch/h8300/include/asm/system.h:136: warning: its scope is only this definition or declaration, which is probably not what you want arch/h8300/kernel/traps.c:100: error: conflicting types for 'die' arch/h8300/include/asm/system.h:136: error: previous declaration of 'die' was here make[2]: *** [arch/h8300/kernel/traps.o] Error 1 Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/h8300/include/asm/system.h | 4 +++- arch/h8300/kernel/traps.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/h8300/include/asm/system.h b/arch/h8300/include/asm/system.h index d98d97685f06..16bf1560ff68 100644 --- a/arch/h8300/include/asm/system.h +++ b/arch/h8300/include/asm/system.h @@ -3,6 +3,8 @@ #include +struct pt_regs; + /* * switch_to(n) should switch tasks to task ptr, first checking that * ptr isn't the current task, in which case it does nothing. This @@ -155,6 +157,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz #define arch_align_stack(x) (x) -void die(char *str, struct pt_regs *fp, unsigned long err); +extern void die(const char *str, struct pt_regs *fp, unsigned long err); #endif /* _H8300_SYSTEM_H */ diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c index 3c0b66bc669e..dfa05bd908b6 100644 --- a/arch/h8300/kernel/traps.c +++ b/arch/h8300/kernel/traps.c @@ -96,7 +96,7 @@ static void dump(struct pt_regs *fp) printk("\n\n"); } -void die(char *str, struct pt_regs *fp, unsigned long err) +void die(const char *str, struct pt_regs *fp, unsigned long err) { static int diecount; -- cgit v1.2.3-59-g8ed1b From 1e72910e248fb94839cd63c0c62107b1f15716f9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 31 Aug 2010 16:52:21 +0100 Subject: h8300: Fix missing consts in kernel_execve() Fix missing consts in h8300's kernel_execve(): arch/h8300/kernel/sys_h8300.c: In function 'kernel_execve': arch/h8300/kernel/sys_h8300.c:59: warning: initialization from incompatible pointer type arch/h8300/kernel/sys_h8300.c:60: warning: initialization from incompatible pointer type Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/h8300/kernel/sys_h8300.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c index dc1ac0243b78..aaf5e5a48f93 100644 --- a/arch/h8300/kernel/sys_h8300.c +++ b/arch/h8300/kernel/sys_h8300.c @@ -56,8 +56,8 @@ int kernel_execve(const char *filename, const char *const envp[]) { register long res __asm__("er0"); - register char *const *_c __asm__("er3") = envp; - register char *const *_b __asm__("er2") = argv; + register const char *const *_c __asm__("er3") = envp; + register const char *const *_b __asm__("er2") = argv; register const char * _a __asm__("er1") = filename; __asm__ __volatile__ ("mov.l %1,er0\n\t" "trapa #0\n\t" -- cgit v1.2.3-59-g8ed1b From e6ba59bcae6968ee18ef5a237a8020a0ea331ae1 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Fri, 3 Sep 2010 11:15:19 +1000 Subject: m68knommu: fix missing linker segments Recent changes to linker segments that hold per-cpu data broke linking for m68knommu targets: LD vmlinux /usr/local/bin/m68k-uclinux-ld.real: error: no memory region specified for loadable section `.data..shared_aligned' Add missing segments into the m68knommu linker script. Signed-off-by: Greg Ungerer Signed-off-by: Linus Torvalds --- arch/m68knommu/kernel/vmlinux.lds.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S index a91b2713451d..ef332136f96d 100644 --- a/arch/m68knommu/kernel/vmlinux.lds.S +++ b/arch/m68knommu/kernel/vmlinux.lds.S @@ -150,6 +150,8 @@ SECTIONS { _sdata = . ; DATA_DATA CACHELINE_ALIGNED_DATA(32) + PAGE_ALIGNED_DATA(PAGE_SIZE) + *(.data..shared_aligned) INIT_TASK_DATA(THREAD_SIZE) _edata = . ; } > DATA -- cgit v1.2.3-59-g8ed1b From bc41606aefa8b17000619f510d5809e6c4003d65 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Sep 2010 21:51:02 +0100 Subject: Revert "drm/i915: Enable RC6 on Ironlake." This reverts commit ce17178094f368d9e3f39b2cb4303da5ed633dd4. This commit has been independently bisected a few times as being the cause of a s2ram failure. Reported-and-tested-by: Kyle McMartin Reported-and-tested-by: Andy Isaacson Cc: Zou Nan hai Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 40cc5da264a9..e0d1952fd3ce 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5696,8 +5696,7 @@ void intel_init_clock_gating(struct drm_device *dev) ILK_DPFC_DIS2 | ILK_CLK_FBC); } - if (IS_GEN6(dev)) - return; + return; } else if (IS_G4X(dev)) { uint32_t dspclk_gate; I915_WRITE(RENCLK_GATE_D1, 0); @@ -5758,11 +5757,9 @@ void intel_init_clock_gating(struct drm_device *dev) OUT_RING(MI_FLUSH); ADVANCE_LP_RING(); } - } else { + } else DRM_DEBUG_KMS("Failed to allocate render context." - "Disable RC6\n"); - return; - } + "Disable RC6\n"); } if (I915_HAS_RC6(dev) && drm_core_check_feature(dev, DRIVER_MODESET)) { -- cgit v1.2.3-59-g8ed1b From c4433be6e19e3680727f3f89c938a22e7b789b43 Mon Sep 17 00:00:00 2001 From: Giuseppe Cavallaro Date: Mon, 6 Sep 2010 05:02:11 +0200 Subject: stmmac: fix sleep inside atomic We cannot use spinlock when kmalloc is invoked with GFP_KERNEL flag because it can sleep. So this patch reviews the usage of spinlock within the stmmac_resume function avoing this bug. Signed-off-by: Giuseppe Cavallaro Reported-by: Jiri Slaby Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index bbb7951b9c4c..ea0461eb2dbe 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -1865,15 +1865,15 @@ static int stmmac_resume(struct platform_device *pdev) if (!netif_running(dev)) return 0; - spin_lock(&priv->lock); - if (priv->shutdown) { /* Re-open the interface and re-init the MAC/DMA - and the rings. */ + and the rings (i.e. on hibernation stage) */ stmmac_open(dev); - goto out_resume; + return 0; } + spin_lock(&priv->lock); + /* Power Down bit, into the PM register, is cleared * automatically as soon as a magic packet or a Wake-up frame * is received. Anyway, it's better to manually clear @@ -1901,7 +1901,6 @@ static int stmmac_resume(struct platform_device *pdev) netif_start_queue(dev); -out_resume: spin_unlock(&priv->lock); return 0; } -- cgit v1.2.3-59-g8ed1b From cb32f2a0d194212e4e750a8cdedcc610c9ca4876 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Thu, 2 Sep 2010 05:45:54 +0000 Subject: bonding: Fix jiffies overflow problems (again) The time_before_eq()/time_after_eq() functions operate on unsigned long and only work if the difference between the two compared values is smaller than half the range of unsigned long (31 bits on i386). Some of the variables (slave->jiffies, dev->trans_start, dev->last_rx) used by bonding store a copy of jiffies and may not be updated for a long time. With HZ=1000, time_before_eq()/time_after_eq() will start giving bad results after ~25 days. jiffies will never be before slave->jiffies, dev->trans_start, dev->last_rx by more than possibly a couple ticks caused by preemption of this code. This allows us to detect/prevent these overflows by replacing time_before_eq()/time_after_eq() with time_in_range(). Signed-off-by: Jiri Bohac Signed-off-by: Jean Delvare Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 56 ++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2cc4cfc31892..3b16f62d5606 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2797,9 +2797,15 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * so it can wait */ bond_for_each_slave(bond, slave, i) { + unsigned long trans_start = dev_trans_start(slave->dev); + if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, dev_trans_start(slave->dev) + delta_in_ticks) && - time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) { + if (time_in_range(jiffies, + trans_start - delta_in_ticks, + trans_start + delta_in_ticks) && + time_in_range(jiffies, + slave->dev->last_rx - delta_in_ticks, + slave->dev->last_rx + delta_in_ticks)) { slave->link = BOND_LINK_UP; slave->state = BOND_STATE_ACTIVE; @@ -2827,8 +2833,12 @@ void bond_loadbalance_arp_mon(struct work_struct *work) * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (time_after_eq(jiffies, dev_trans_start(slave->dev) + 2*delta_in_ticks) || - (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) { + if (!time_in_range(jiffies, + trans_start - delta_in_ticks, + trans_start + 2 * delta_in_ticks) || + !time_in_range(jiffies, + slave->dev->last_rx - delta_in_ticks, + slave->dev->last_rx + 2 * delta_in_ticks)) { slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; @@ -2883,13 +2893,16 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) { struct slave *slave; int i, commit = 0; + unsigned long trans_start; bond_for_each_slave(bond, slave, i) { slave->new_link = BOND_LINK_NOCHANGE; if (slave->link != BOND_LINK_UP) { - if (time_before_eq(jiffies, slave_last_rx(bond, slave) + - delta_in_ticks)) { + if (time_in_range(jiffies, + slave_last_rx(bond, slave) - delta_in_ticks, + slave_last_rx(bond, slave) + delta_in_ticks)) { + slave->new_link = BOND_LINK_UP; commit++; } @@ -2902,8 +2915,9 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) * active. This avoids bouncing, as the last receive * times need a full ARP monitor cycle to be updated. */ - if (!time_after_eq(jiffies, slave->jiffies + - 2 * delta_in_ticks)) + if (time_in_range(jiffies, + slave->jiffies - delta_in_ticks, + slave->jiffies + 2 * delta_in_ticks)) continue; /* @@ -2921,8 +2935,10 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) */ if (slave->state == BOND_STATE_BACKUP && !bond->current_arp_slave && - time_after(jiffies, slave_last_rx(bond, slave) + - 3 * delta_in_ticks)) { + !time_in_range(jiffies, + slave_last_rx(bond, slave) - delta_in_ticks, + slave_last_rx(bond, slave) + 3 * delta_in_ticks)) { + slave->new_link = BOND_LINK_DOWN; commit++; } @@ -2933,11 +2949,15 @@ static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks) * - (more than 2*delta since receive AND * the bond has an IP address) */ + trans_start = dev_trans_start(slave->dev); if ((slave->state == BOND_STATE_ACTIVE) && - (time_after_eq(jiffies, dev_trans_start(slave->dev) + - 2 * delta_in_ticks) || - (time_after_eq(jiffies, slave_last_rx(bond, slave) - + 2 * delta_in_ticks)))) { + (!time_in_range(jiffies, + trans_start - delta_in_ticks, + trans_start + 2 * delta_in_ticks) || + !time_in_range(jiffies, + slave_last_rx(bond, slave) - delta_in_ticks, + slave_last_rx(bond, slave) + 2 * delta_in_ticks))) { + slave->new_link = BOND_LINK_DOWN; commit++; } @@ -2956,6 +2976,7 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) { struct slave *slave; int i; + unsigned long trans_start; bond_for_each_slave(bond, slave, i) { switch (slave->new_link) { @@ -2963,10 +2984,11 @@ static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks) continue; case BOND_LINK_UP: + trans_start = dev_trans_start(slave->dev); if ((!bond->curr_active_slave && - time_before_eq(jiffies, - dev_trans_start(slave->dev) + - delta_in_ticks)) || + time_in_range(jiffies, + trans_start - delta_in_ticks, + trans_start + delta_in_ticks)) || bond->curr_active_slave != slave) { slave->link = BOND_LINK_UP; bond->current_arp_slave = NULL; -- cgit v1.2.3-59-g8ed1b From deabc772f39405054a438d711f408d2d94d26d96 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 3 Sep 2010 02:39:56 +0000 Subject: net: fix tx queue selection for bridged devices implementing select_queue When a net device is implementing the select_queue callback and is part of a bridge, frames coming from the bridge already have a tx queue associated to the socket (introduced in commit a4ee3ce3293dc931fab19beb472a8bde1295aebe, "net: Use sk_tx_queue_mapping for connected sockets"). The call to sk_tx_queue_get will then return the tx queue used by the bridge instead of calling the select_queue callback. In case of mac80211 this broke QoS which is implemented by using the select_queue callback. Furthermore it introduced problems with rt2x00 because frames with the same TID and RA sometimes appeared on different tx queues which the hw cannot handle correctly. Fix this by always calling select_queue first if it is available and only afterwards use the socket tx queue mapping. Signed-off-by: Helmut Schaa Signed-off-by: David S. Miller --- net/core/dev.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 3721fbb9a83c..b9b22a3c4c8f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2058,16 +2058,16 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev, struct sk_buff *skb) { int queue_index; - struct sock *sk = skb->sk; + const struct net_device_ops *ops = dev->netdev_ops; - queue_index = sk_tx_queue_get(sk); - if (queue_index < 0) { - const struct net_device_ops *ops = dev->netdev_ops; + if (ops->ndo_select_queue) { + queue_index = ops->ndo_select_queue(dev, skb); + queue_index = dev_cap_txqueue(dev, queue_index); + } else { + struct sock *sk = skb->sk; + queue_index = sk_tx_queue_get(sk); + if (queue_index < 0) { - if (ops->ndo_select_queue) { - queue_index = ops->ndo_select_queue(dev, skb); - queue_index = dev_cap_txqueue(dev, queue_index); - } else { queue_index = 0; if (dev->real_num_tx_queues > 1) queue_index = skb_tx_hash(dev, skb); -- cgit v1.2.3-59-g8ed1b From 70789d7052239992824628db8133de08dc78e593 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 3 Sep 2010 05:13:05 +0000 Subject: ipv6: discard overlapping fragment RFC5722 prohibits reassembling fragments when some data overlaps. Bug spotted by Zhang Zuotao . Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv6/reassembly.c | 71 +++++++++++---------------------------------------- 1 file changed, 15 insertions(+), 56 deletions(-) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 545c4141b755..64cfef1b0a4c 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -149,13 +149,6 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a) } EXPORT_SYMBOL(ip6_frag_match); -/* Memory Tracking Functions. */ -static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb) -{ - atomic_sub(skb->truesize, &nf->mem); - kfree_skb(skb); -} - void ip6_frag_init(struct inet_frag_queue *q, void *a) { struct frag_queue *fq = container_of(q, struct frag_queue, q); @@ -346,58 +339,22 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, } found: - /* We found where to put this one. Check for overlap with - * preceding fragment, and, if needed, align things so that - * any overlaps are eliminated. + /* RFC5722, Section 4: + * When reassembling an IPv6 datagram, if + * one or more its constituent fragments is determined to be an + * overlapping fragment, the entire datagram (and any constituent + * fragments, including those not yet received) MUST be silently + * discarded. */ - if (prev) { - int i = (FRAG6_CB(prev)->offset + prev->len) - offset; - if (i > 0) { - offset += i; - if (end <= offset) - goto err; - if (!pskb_pull(skb, i)) - goto err; - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->ip_summed = CHECKSUM_NONE; - } - } + /* Check for overlap with preceding fragment. */ + if (prev && + (FRAG6_CB(prev)->offset + prev->len) - offset > 0) + goto discard_fq; - /* Look for overlap with succeeding segments. - * If we can merge fragments, do it. - */ - while (next && FRAG6_CB(next)->offset < end) { - int i = end - FRAG6_CB(next)->offset; /* overlap is 'i' bytes */ - - if (i < next->len) { - /* Eat head of the next overlapped fragment - * and leave the loop. The next ones cannot overlap. - */ - if (!pskb_pull(next, i)) - goto err; - FRAG6_CB(next)->offset += i; /* next fragment */ - fq->q.meat -= i; - if (next->ip_summed != CHECKSUM_UNNECESSARY) - next->ip_summed = CHECKSUM_NONE; - break; - } else { - struct sk_buff *free_it = next; - - /* Old fragment is completely overridden with - * new one drop it. - */ - next = next->next; - - if (prev) - prev->next = next; - else - fq->q.fragments = next; - - fq->q.meat -= free_it->len; - frag_kfree_skb(fq->q.net, free_it); - } - } + /* Look for overlap with succeeding segment. */ + if (next && FRAG6_CB(next)->offset < end) + goto discard_fq; FRAG6_CB(skb)->offset = offset; @@ -436,6 +393,8 @@ found: write_unlock(&ip6_frags.lock); return -1; +discard_fq: + fq_kill(fq); err: IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS); -- cgit v1.2.3-59-g8ed1b From 1ee89bd0fe72e381c8e4ef887d53c19c8adc6c93 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 3 Sep 2010 05:13:07 +0000 Subject: netfilter: discard overlapping IPv6 fragment RFC5722 prohibits reassembling IPv6 fragments when some data overlaps. Bug spotted by Zhang Zuotao . Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv6/netfilter/nf_conntrack_reasm.c | 80 +++++++-------------------------- 1 file changed, 15 insertions(+), 65 deletions(-) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 13ef5bc05cf5..578f3c1a16db 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -113,14 +113,6 @@ static void nf_skb_free(struct sk_buff *skb) kfree_skb(NFCT_FRAG6_CB(skb)->orig); } -/* Memory Tracking Functions. */ -static void frag_kfree_skb(struct sk_buff *skb) -{ - atomic_sub(skb->truesize, &nf_init_frags.mem); - nf_skb_free(skb); - kfree_skb(skb); -} - /* Destruction primitives. */ static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) @@ -282,66 +274,22 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, } found: - /* We found where to put this one. Check for overlap with - * preceding fragment, and, if needed, align things so that - * any overlaps are eliminated. - */ - if (prev) { - int i = (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset; - - if (i > 0) { - offset += i; - if (end <= offset) { - pr_debug("overlap\n"); - goto err; - } - if (!pskb_pull(skb, i)) { - pr_debug("Can't pull\n"); - goto err; - } - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->ip_summed = CHECKSUM_NONE; - } - } - - /* Look for overlap with succeeding segments. - * If we can merge fragments, do it. + /* RFC5722, Section 4: + * When reassembling an IPv6 datagram, if + * one or more its constituent fragments is determined to be an + * overlapping fragment, the entire datagram (and any constituent + * fragments, including those not yet received) MUST be silently + * discarded. */ - while (next && NFCT_FRAG6_CB(next)->offset < end) { - /* overlap is 'i' bytes */ - int i = end - NFCT_FRAG6_CB(next)->offset; - - if (i < next->len) { - /* Eat head of the next overlapped fragment - * and leave the loop. The next ones cannot overlap. - */ - pr_debug("Eat head of the overlapped parts.: %d", i); - if (!pskb_pull(next, i)) - goto err; - /* next fragment */ - NFCT_FRAG6_CB(next)->offset += i; - fq->q.meat -= i; - if (next->ip_summed != CHECKSUM_UNNECESSARY) - next->ip_summed = CHECKSUM_NONE; - break; - } else { - struct sk_buff *free_it = next; - - /* Old fragmnet is completely overridden with - * new one drop it. - */ - next = next->next; + /* Check for overlap with preceding fragment. */ + if (prev && + (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset > 0) + goto discard_fq; - if (prev) - prev->next = next; - else - fq->q.fragments = next; - - fq->q.meat -= free_it->len; - frag_kfree_skb(free_it); - } - } + /* Look for overlap with succeeding segment. */ + if (next && NFCT_FRAG6_CB(next)->offset < end) + goto discard_fq; NFCT_FRAG6_CB(skb)->offset = offset; @@ -371,6 +319,8 @@ found: write_unlock(&nf_frags.lock); return 0; +discard_fq: + fq_kill(fq); err: return -1; } -- cgit v1.2.3-59-g8ed1b From 89b12faba4f3441c9457c5278851e8a93ffd008d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 6 Sep 2010 18:28:56 -0700 Subject: 3c59x: Fix deadlock in vortex_error() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug introduced in commit de847272149365363a6043a963a6f42fb91566e2 "3c59x: Use fine-grained locks for MII and windowed register access". vortex_interrupt() holds vp->window_lock over multiple register accesses to reduce locking overhead. However it also needs to call vortex_error() sometimes, and that uses the regular functions for access to windowed registers, which will try to acquire window_lock again. Therefore, drop window_lock around the call to vortex_error() and set the window afterward reacquiring the lock. Since vortex_error() may call vortex_rx(), which *does* require its caller to hold window_lock, lift that call up into vortex_interrupt(). This also removes the potential for calling vortex_rx() on a later-generation NIC. Reported-and-tested-by: Jens Schüßler [in Debian's 2.6.32] Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index a045559c81cf..85671adae455 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1994,10 +1994,9 @@ vortex_error(struct net_device *dev, int status) } } - if (status & RxEarly) { /* Rx early is unused. */ - vortex_rx(dev); + if (status & RxEarly) /* Rx early is unused. */ iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD); - } + if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat; if (vortex_debug > 4) @@ -2298,7 +2297,12 @@ vortex_interrupt(int irq, void *dev_id) if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { if (status == 0xffff) break; + if (status & RxEarly) + vortex_rx(dev); + spin_unlock(&vp->window_lock); vortex_error(dev, status); + spin_lock(&vp->window_lock); + window_set(vp, 7); } if (--work_done < 0) { -- cgit v1.2.3-59-g8ed1b From cf9b94f88bdbe8a02015fc30d7c232b2d262d4ad Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 4 Sep 2010 03:14:35 +0000 Subject: irda: off by one This is an off by one. We would go past the end when we NUL terminate the "value" string at end of the function. The "value" buffer is allocated in irlan_client_parse_response() or irlan_provider_parse_command(). CC: stable@kernel.org Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/irda/irlan/irlan_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index a788f9e9427d..6130f9d9dbe1 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -1102,7 +1102,7 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */ le16_to_cpus(&val_len); n+=2; - if (val_len > 1016) { + if (val_len >= 1016) { IRDA_DEBUG(2, "%s(), parameter length to long\n", __func__ ); return -RSP_INVALID_COMMAND_FORMAT; } -- cgit v1.2.3-59-g8ed1b From 32737e934a952c1b0c744f2a78d80089d15c7ee3 Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Sat, 4 Sep 2010 14:17:59 +0000 Subject: PATCH: b44 Handle RX FIFO overflow better (simplified) This patch is a simplified version of the original patch from James Courtier-Dutton. >From: James Courtier-Dutton >Subject: [PATCH] Fix b44 RX FIFO overflow recovery. >Date: Wednesday, June 30, 2010 - 1:11 pm > >This patch improves the recovery after a RX FIFO overflow on the b44 >Ethernet NIC. >Before it would do a complete chip reset, resulting is loss of link >for a few seconds. >This patch improves this to do recovery in about 20ms without loss of link. > >Signed off by: James@superbug.co.uk Signed-off-by: Mark Lord Signed-off-by: David S. Miller --- drivers/net/b44.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 37617abc1647..1e620e287ae0 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -848,6 +848,15 @@ static int b44_poll(struct napi_struct *napi, int budget) b44_tx(bp); /* spin_unlock(&bp->tx_lock); */ } + if (bp->istat & ISTAT_RFO) { /* fast recovery, in ~20msec */ + bp->istat &= ~ISTAT_RFO; + b44_disable_ints(bp); + ssb_device_enable(bp->sdev, 0); /* resets ISTAT_RFO */ + b44_init_rings(bp); + b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY); + netif_wake_queue(bp->dev); + } + spin_unlock_irqrestore(&bp->lock, flags); work_done = 0; -- cgit v1.2.3-59-g8ed1b From 8df73ff90f00f14d2c7ff7156f7ef153f7e9d3b7 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sat, 4 Sep 2010 01:34:28 +0000 Subject: UNIX: Do not loop forever at unix_autobind(). We assumed that unix_autobind() never fails if kzalloc() succeeded. But unix_autobind() allows only 1048576 names. If /proc/sys/fs/file-max is larger than 1048576 (e.g. systems with more than 10GB of RAM), a local user can consume all names using fork()/socket()/bind(). If all names are in use, those who call bind() with addr_len == sizeof(short) or connect()/sendmsg() with setsockopt(SO_PASSCRED) will continue while (1) yield(); loop at unix_autobind() till a name becomes available. This patch adds a loop counter in order to give up after 1048576 attempts. Calling yield() for once per 256 attempts may not be sufficient when many names are already in use, for __unix_find_socket_byname() can take long time under such circumstance. Therefore, this patch also adds cond_resched() call. Note that currently a local user can consume 2GB of kernel memory if the user is allowed to create and autobind 1048576 UNIX domain sockets. We should consider adding some restriction for autobind operation. Signed-off-by: Tetsuo Handa Signed-off-by: David S. Miller --- net/unix/af_unix.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 4414a18c63b4..0b39b2451ea5 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -692,6 +692,7 @@ static int unix_autobind(struct socket *sock) static u32 ordernum = 1; struct unix_address *addr; int err; + unsigned int retries = 0; mutex_lock(&u->readlock); @@ -717,9 +718,17 @@ retry: if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type, addr->hash)) { spin_unlock(&unix_table_lock); - /* Sanity yield. It is unusual case, but yet... */ - if (!(ordernum&0xFF)) - yield(); + /* + * __unix_find_socket_byname() may take long time if many names + * are already in use. + */ + cond_resched(); + /* Give up if all names seems to be in use. */ + if (retries++ == 0xFFFFF) { + err = -ENOSPC; + kfree(addr); + goto out; + } goto retry; } addr->hash ^= sk->sk_type; -- cgit v1.2.3-59-g8ed1b From 6f86b325189e0a53c97bf86cff0c8b02ff624934 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 6 Sep 2010 22:36:19 -0700 Subject: ipv4: Fix reverse path filtering with multipath routing. Actually iterate over the next-hops to make sure we have a device match. Otherwise RP filtering is always elided when the route matched has multiple next-hops. Reported-by: Igor M Podlesny Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index a43968918350..7d02a9f999fa 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -246,6 +246,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, struct fib_result res; int no_addr, rpf, accept_local; + bool dev_match; int ret; struct net *net; @@ -273,12 +274,22 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, } *spec_dst = FIB_RES_PREFSRC(res); fib_combine_itag(itag, &res); + dev_match = false; + #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1) + for (ret = 0; ret < res.fi->fib_nhs; ret++) { + struct fib_nh *nh = &res.fi->fib_nh[ret]; + + if (nh->nh_dev == dev) { + dev_match = true; + break; + } + } #else if (FIB_RES_DEV(res) == dev) + dev_match = true; #endif - { + if (dev_match) { ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; fib_res_put(&res); return ret; -- cgit v1.2.3-59-g8ed1b From de2b96f1212722eb0af80bf9a029d03d8fc673a9 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 7 Sep 2010 13:49:44 -0700 Subject: via-velocity: Turn scatter-gather support back off. It causes all kinds of DMA API debugging assertions and all straight-forward attempts to fix it have failed. So turn off SG, and we'll tackle making this work properly in net-next-2.6 Reported-by: Dave Jones Tested-by: Dave Jones Signed-off-by: David S. Miller --- drivers/net/via-velocity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index fd69095ef6e3..f53412368ce1 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2824,7 +2824,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM | NETIF_F_SG; + NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM; ret = register_netdev(dev); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From e819ff519b2d74373eca4a9a2b417ebf4c1e1b29 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 27 Aug 2010 18:33:26 -0700 Subject: AppArmor: Drop hack to remove appended " (deleted)" string The 2.6.36 kernel has refactored __d_path() so that it no longer appends " (deleted)" to unlinked paths. So drop the hack that was used to detect and remove the appended string. Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/path.c | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 19358dc14605..82396050f186 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -59,8 +59,7 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, { struct path root, tmp; char *res; - int deleted, connected; - int error = 0; + int connected, error = 0; /* Get the root we want to resolve too, released below */ if (flags & PATH_CHROOT_REL) { @@ -74,19 +73,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, } spin_lock(&dcache_lock); - /* There is a race window between path lookup here and the - * need to strip the " (deleted) string that __d_path applies - * Detect the race and relookup the path - * - * The stripping of (deleted) is a hack that could be removed - * with an updated __d_path - */ - do { - tmp = root; - deleted = d_unlinked(path->dentry); - res = __d_path(path, &tmp, buf, buflen); - - } while (deleted != d_unlinked(path->dentry)); + tmp = root; + res = __d_path(path, &tmp, buf, buflen); spin_unlock(&dcache_lock); *name = res; @@ -98,21 +86,17 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, *name = buf; goto out; } - if (deleted) { - /* On some filesystems, newly allocated dentries appear to the - * security_path hooks as a deleted dentry except without an - * inode allocated. - * - * Remove the appended deleted text and return as string for - * normal mediation, or auditing. The (deleted) string is - * guaranteed to be added in this case, so just strip it. - */ - buf[buflen - 11] = 0; /* - (len(" (deleted)") +\0) */ - if (path->dentry->d_inode && !(flags & PATH_MEDIATE_DELETED)) { + /* Handle two cases: + * 1. A deleted dentry && profile is not allowing mediation of deleted + * 2. On some filesystems, newly allocated dentries appear to the + * security_path hooks as a deleted dentry except without an inode + * allocated. + */ + if (d_unlinked(path->dentry) && path->dentry->d_inode && + !(flags & PATH_MEDIATE_DELETED)) { error = -ENOENT; goto out; - } } /* Determine if the path is connected to the expected root */ -- cgit v1.2.3-59-g8ed1b From 3a2dc8382a3e85a51ed9c6f57ea80665ea7a0c95 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 6 Sep 2010 10:10:20 -0700 Subject: AppArmor: Fix security_task_setrlimit logic for 2.6.36 changes 2.6.36 introduced the abilitiy to specify the task that is having its rlimits set. Update mediation to ensure that confined tasks can only set their own group_leader as expected by current policy. Add TODO note about extending policy to support setting other tasks rlimits. Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/include/resource.h | 4 ++-- security/apparmor/lsm.c | 2 +- security/apparmor/resource.c | 20 ++++++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/security/apparmor/include/resource.h b/security/apparmor/include/resource.h index 3c88be946494..02baec732bb5 100644 --- a/security/apparmor/include/resource.h +++ b/security/apparmor/include/resource.h @@ -33,8 +33,8 @@ struct aa_rlimit { }; int aa_map_resource(int resource); -int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource, - struct rlimit *new_rlim); +int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, + unsigned int resource, struct rlimit *new_rlim); void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f73e2c204218..cf1de4462ccd 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -614,7 +614,7 @@ static int apparmor_task_setrlimit(struct task_struct *task, int error = 0; if (!unconfined(profile)) - error = aa_task_setrlimit(profile, resource, new_rlim); + error = aa_task_setrlimit(profile, task, resource, new_rlim); return error; } diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 4a368f1fd36d..a4136c10b1c6 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -72,6 +72,7 @@ int aa_map_resource(int resource) /** * aa_task_setrlimit - test permission to set an rlimit * @profile - profile confining the task (NOT NULL) + * @task - task the resource is being set on * @resource - the resource being set * @new_rlim - the new resource limit (NOT NULL) * @@ -79,18 +80,21 @@ int aa_map_resource(int resource) * * Returns: 0 or error code if setting resource failed */ -int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource, - struct rlimit *new_rlim) +int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, + unsigned int resource, struct rlimit *new_rlim) { int error = 0; - if (profile->rlimits.mask & (1 << resource) && - new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max) - - error = audit_resource(profile, resource, new_rlim->rlim_max, - -EACCES); + /* TODO: extend resource control to handle other (non current) + * processes. AppArmor rules currently have the implicit assumption + * that the task is setting the resource of the current process + */ + if ((task != current->group_leader) || + (profile->rlimits.mask & (1 << resource) && + new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) + error = -EACCES; - return error; + return audit_resource(profile, resource, new_rlim->rlim_max, error); } /** -- cgit v1.2.3-59-g8ed1b From 04ccd53f09741c4bc54ab36db000bc1383e4812e Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 27 Aug 2010 18:33:28 -0700 Subject: AppArmor: Fix splitting an fqname into separate namespace and profile names As per Dan Carpenter If we have a ns name without a following profile then in the original code it did "*ns_name = &name[1];". "name" is NULL so "*ns_name" is 0x1. That isn't useful and could cause an oops when this function is called from aa_remove_profiles(). Beyond this the assignment of the namespace name was wrong in the case where the profile name was provided as it was being set to &name[1] after name = skip_spaces(split + 1); Move the ns_name assignment before updating name for the split and also add skip_spaces, making the interface more robust. Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 6e85cdb4303f..506d2baf6147 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -40,6 +40,7 @@ char *aa_split_fqname(char *fqname, char **ns_name) *ns_name = NULL; if (name[0] == ':') { char *split = strchr(&name[1], ':'); + *ns_name = skip_spaces(&name[1]); if (split) { /* overwrite ':' with \0 */ *split = 0; @@ -47,7 +48,6 @@ char *aa_split_fqname(char *fqname, char **ns_name) } else /* a ns name without a following profile is allowed */ name = NULL; - *ns_name = &name[1]; } if (name && *name == 0) name = NULL; -- cgit v1.2.3-59-g8ed1b From 999b4f0aa2314b76857775334cb94bafa053db64 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 27 Aug 2010 18:33:29 -0700 Subject: AppArmor: Fix locking from removal of profile namespace The locking for profile namespace removal is wrong, when removing a profile namespace, it needs to be removed from its parent's list. Lock the parent of namespace list instead of the namespace being removed. Signed-off-by: John Johansen Signed-off-by: James Morris --- security/apparmor/policy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 3cdc1ad0787e..52cc865f1464 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -1151,12 +1151,14 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) /* released below */ ns = aa_get_namespace(root); - write_lock(&ns->lock); if (!name) { /* remove namespace - can only happen if fqname[0] == ':' */ + write_lock(&ns->parent->lock); __remove_namespace(ns); + write_unlock(&ns->parent->lock); } else { /* remove profile */ + write_lock(&ns->lock); profile = aa_get_profile(__lookup_profile(&ns->base, name)); if (!profile) { error = -ENOENT; @@ -1165,8 +1167,8 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) } name = profile->base.hname; __remove_profile(profile); + write_unlock(&ns->lock); } - write_unlock(&ns->lock); /* don't fail removal if audit fails */ (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); -- cgit v1.2.3-59-g8ed1b From e950598d43dce8d97e7d5270808393425d1e5cbd Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Tue, 31 Aug 2010 09:38:51 -0400 Subject: ima: always maintain counters commit 8262bb85da allocated the inode integrity struct (iint) before any inodes were created. Only after IMA was initialized in late_initcall were the counters updated. This patch updates the counters, whether or not IMA has been initialized, to resolve 'imbalance' messages. This patch fixes the bug as reported in bugzilla: 15673. When the i915 is builtin, the ring_buffer is initialized before IMA, causing the imbalance message on suspend. Reported-by: Thomas Meyer Signed-off-by: Mimi Zohar Tested-by: Thomas Meyer Tested-by: David Safford Cc: Stable Kernel Signed-off-by: James Morris --- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_iint.c | 4 +++- security/integrity/ima/ima_main.c | 8 +++++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 16d100d3fc38..3fbcd1dda0ef 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -35,6 +35,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 }; #define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS) /* set during initialization */ +extern int iint_initialized; extern int ima_initialized; extern int ima_used_chip; extern char *ima_hash; diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index 7625b85c2274..afba4aef812f 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c @@ -22,9 +22,10 @@ RADIX_TREE(ima_iint_store, GFP_ATOMIC); DEFINE_SPINLOCK(ima_iint_lock); - static struct kmem_cache *iint_cache __read_mostly; +int iint_initialized = 0; + /* ima_iint_find_get - return the iint associated with an inode * * ima_iint_find_get gets a reference to the iint. Caller must @@ -141,6 +142,7 @@ static int __init ima_iintcache_init(void) iint_cache = kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, SLAB_PANIC, init_once); + iint_initialized = 1; return 0; } security_initcall(ima_iintcache_init); diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index f93641382e9f..e662b89d4079 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -148,12 +148,14 @@ void ima_counts_get(struct file *file) struct ima_iint_cache *iint; int rc; - if (!ima_initialized || !S_ISREG(inode->i_mode)) + if (!iint_initialized || !S_ISREG(inode->i_mode)) return; iint = ima_iint_find_get(inode); if (!iint) return; mutex_lock(&iint->mutex); + if (!ima_initialized) + goto out; rc = ima_must_measure(iint, inode, MAY_READ, FILE_CHECK); if (rc < 0) goto out; @@ -213,7 +215,7 @@ void ima_file_free(struct file *file) struct inode *inode = file->f_dentry->d_inode; struct ima_iint_cache *iint; - if (!ima_initialized || !S_ISREG(inode->i_mode)) + if (!iint_initialized || !S_ISREG(inode->i_mode)) return; iint = ima_iint_find_get(inode); if (!iint) @@ -230,7 +232,7 @@ static int process_measurement(struct file *file, const unsigned char *filename, { struct inode *inode = file->f_dentry->d_inode; struct ima_iint_cache *iint; - int rc; + int rc = 0; if (!ima_initialized || !S_ISREG(inode->i_mode)) return 0; -- cgit v1.2.3-59-g8ed1b From dc696aced9f09f05b1f927b93f5a7918017a3e49 Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Thu, 12 Aug 2010 16:24:25 -0700 Subject: ocfs2: Fix metaecc error messages Like tools, the checksum validate function now prints the values in hex. Signed-off-by: Sunil Mushran Singed-off-by: Tao Ma --- fs/ocfs2/blockcheck.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c index ec6d12339593..c7ee03c22226 100644 --- a/fs/ocfs2/blockcheck.c +++ b/fs/ocfs2/blockcheck.c @@ -439,7 +439,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, ocfs2_blockcheck_inc_failure(stats); mlog(ML_ERROR, - "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", + "CRC32 failed: stored: 0x%x, computed 0x%x. Applying ECC.\n", (unsigned int)check.bc_crc32e, (unsigned int)crc); /* Ok, try ECC fixups */ @@ -453,7 +453,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, goto out; } - mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", + mlog(ML_ERROR, "Fixed CRC32 failed: stored: 0x%x, computed 0x%x\n", (unsigned int)check.bc_crc32e, (unsigned int)crc); rc = -EIO; -- cgit v1.2.3-59-g8ed1b From f5ce5a08a40f2086435858ddc80cb40394b082eb Mon Sep 17 00:00:00 2001 From: Sunil Mushran Date: Thu, 12 Aug 2010 16:24:26 -0700 Subject: ocfs2: Fix incorrect checksum validation error For local mounts, ocfs2_read_locked_inode() calls ocfs2_read_blocks_sync() to read the inode off the disk. The latter first checks to see if that block is cached in the journal, and, if so, returns that block. That is ok. But ocfs2_read_locked_inode() goes wrong when it tries to validate the checksum of such blocks. Blocks that are cached in the journal may not have had their checksum computed as yet. We should not validate the checksums of such blocks. Fixes ossbz#1282 http://oss.oracle.com/bugzilla/show_bug.cgi?id=1282 Signed-off-by: Sunil Mushran Cc: stable@kernel.org Singed-off-by: Tao Ma --- fs/ocfs2/inode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 0492464916b1..eece3e05d9d0 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -488,7 +488,11 @@ static int ocfs2_read_locked_inode(struct inode *inode, OCFS2_BH_IGNORE_CACHE); } else { status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); - if (!status) + /* + * If buffer is in jbd, then its checksum may not have been + * computed as yet. + */ + if (!status && !buffer_jbd(bh)) status = ocfs2_validate_inode_block(osb->sb, bh); } if (status < 0) { -- cgit v1.2.3-59-g8ed1b From f63afdb2c32db850fa1bfccf84643a8885cbeb61 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Sat, 17 Jul 2010 21:45:49 +0800 Subject: ocfs2: make __ocfs2_page_mkwrite handle file end properly. __ocfs2_page_mkwrite now is broken in handling file end. 1. the last page should be the page contains i_size - 1. 2. the len in the last page is also calculated wrong. So change them accordingly. Acked-by: Mark Fasheh Signed-off-by: Tao Ma --- fs/ocfs2/mmap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c index af2b8fe1f139..4c18f4ad93b4 100644 --- a/fs/ocfs2/mmap.c +++ b/fs/ocfs2/mmap.c @@ -74,9 +74,11 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh, /* * Another node might have truncated while we were waiting on * cluster locks. + * We don't check size == 0 before the shift. This is borrowed + * from do_generic_file_read. */ - last_index = size >> PAGE_CACHE_SHIFT; - if (page->index > last_index) { + last_index = (size - 1) >> PAGE_CACHE_SHIFT; + if (unlikely(!size || page->index > last_index)) { ret = -EINVAL; goto out; } @@ -107,7 +109,7 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh, * because the "write" would invalidate their data. */ if (page->index == last_index) - len = size & ~PAGE_CACHE_MASK; + len = ((size - 1) & ~PAGE_CACHE_MASK) + 1; ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page, &fsdata, di_bh, page); -- cgit v1.2.3-59-g8ed1b From 04eda1a18019bb387dc7e97ee99979dd88dc608a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 5 Aug 2010 20:32:45 +0200 Subject: ocfs2: Flush drive's caches on fdatasync When 'barrier' mount option is specified, we have to issue a cache flush during fdatasync(2). We have to do this even if inode doesn't have I_DIRTY_DATASYNC set because we still have to get written *data* to disk so that they are not lost in case of crash. Acked-by: Tao Ma Signed-off-by: Jan Kara Singed-off-by: Tao Ma --- fs/ocfs2/file.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 81296b4e3646..6b2be0f2eacd 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -36,6 +36,7 @@ #include #include #include +#include #define MLOG_MASK_PREFIX ML_INODE #include @@ -190,8 +191,16 @@ static int ocfs2_sync_file(struct file *file, int datasync) if (err) goto bail; - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) { + /* + * We still have to flush drive's caches to get data to the + * platter + */ + if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER) + blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, + NULL, BLKDEV_IFL_WAIT); goto bail; + } journal = osb->journal->j_journal; err = jbd2_journal_force_commit(journal); -- cgit v1.2.3-59-g8ed1b From 889f004a8c83d515f275078687f859bc0d5ede9d Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Thu, 2 Sep 2010 13:10:10 +0800 Subject: ocfs2: Use the right group in nfs sync check. We have added discontig block group now, and now an inode can be allocated in an discontig block group. So get it in ocfs2_get_suballoc_slot_bit. The old ocfs2_test_suballoc_bit gets group block no from the allocation inode which is wrong. Fix it by passing the right group. Acked-by: Mark Fasheh Signed-off-by: Tao Ma --- fs/ocfs2/suballoc.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index a8e6a95a353f..8a009ee1f7fd 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -2567,7 +2567,8 @@ out: * suballoc_bit. */ static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno, - u16 *suballoc_slot, u16 *suballoc_bit) + u16 *suballoc_slot, u64 *group_blkno, + u16 *suballoc_bit) { int status; struct buffer_head *inode_bh = NULL; @@ -2604,6 +2605,8 @@ static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno, *suballoc_slot = le16_to_cpu(inode_fe->i_suballoc_slot); if (suballoc_bit) *suballoc_bit = le16_to_cpu(inode_fe->i_suballoc_bit); + if (group_blkno) + *group_blkno = le64_to_cpu(inode_fe->i_suballoc_loc); bail: brelse(inode_bh); @@ -2621,7 +2624,8 @@ bail: */ static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, struct inode *suballoc, - struct buffer_head *alloc_bh, u64 blkno, + struct buffer_head *alloc_bh, + u64 group_blkno, u64 blkno, u16 bit, int *res) { struct ocfs2_dinode *alloc_di; @@ -2642,10 +2646,8 @@ static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, goto bail; } - if (alloc_di->i_suballoc_loc) - bg_blkno = le64_to_cpu(alloc_di->i_suballoc_loc); - else - bg_blkno = ocfs2_which_suballoc_group(blkno, bit); + bg_blkno = group_blkno ? group_blkno : + ocfs2_which_suballoc_group(blkno, bit); status = ocfs2_read_group_descriptor(suballoc, alloc_di, bg_blkno, &group_bh); if (status < 0) { @@ -2680,6 +2682,7 @@ bail: int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) { int status; + u64 group_blkno = 0; u16 suballoc_bit = 0, suballoc_slot = 0; struct inode *inode_alloc_inode; struct buffer_head *alloc_bh = NULL; @@ -2687,7 +2690,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) mlog_entry("blkno: %llu", (unsigned long long)blkno); status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot, - &suballoc_bit); + &group_blkno, &suballoc_bit); if (status < 0) { mlog(ML_ERROR, "get alloc slot and bit failed %d\n", status); goto bail; @@ -2715,7 +2718,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) } status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh, - blkno, suballoc_bit, res); + group_blkno, blkno, suballoc_bit, res); if (status < 0) mlog(ML_ERROR, "test suballoc bit failed %d\n", status); -- cgit v1.2.3-59-g8ed1b From b2b6ebf5f740e015b2155343958f067e594323ea Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Thu, 26 Aug 2010 13:06:50 -0700 Subject: ocfs2: properly set and use inode group alloc hint We were setting ac->ac_last_group in ocfs2_claim_suballoc_bits from res->sr_bg_blkno. Unfortunately, res->sr_bg_blkno is going to be zero under normal (non-fragmented) circumstances. The discontig block group patches effectively turned off that feature. Fix this by correctly calculating what the next group hint should be. Acked-by: Tao Ma Signed-off-by: Mark Fasheh Tested-by: Goldwyn Rodrigues Signed-off-by: Tao Ma --- fs/ocfs2/suballoc.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 8a009ee1f7fd..b93d7e72175a 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -62,6 +62,17 @@ struct ocfs2_suballoc_result { unsigned int sr_bits; /* How many bits we claimed */ }; +static u64 ocfs2_group_from_res(struct ocfs2_suballoc_result *res) +{ + if (res->sr_blkno == 0) + return 0; + + if (res->sr_bg_blkno) + return res->sr_bg_blkno; + + return ocfs2_which_suballoc_group(res->sr_blkno, res->sr_bit_offset); +} + static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg); static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe); static inline u16 ocfs2_find_victim_chain(struct ocfs2_chain_list *cl); @@ -1845,6 +1856,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, int status; u16 victim, i; u16 bits_left = 0; + u64 hint = ac->ac_last_group; struct ocfs2_chain_list *cl; struct ocfs2_dinode *fe; @@ -1872,7 +1884,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, goto bail; } - res->sr_bg_blkno = ac->ac_last_group; + res->sr_bg_blkno = hint; if (res->sr_bg_blkno) { /* Attempt to short-circuit the usual search mechanism * by jumping straight to the most recently used @@ -1896,8 +1908,10 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, res, &bits_left); - if (!status) + if (!status) { + hint = ocfs2_group_from_res(res); goto set_hint; + } if (status < 0 && status != -ENOSPC) { mlog_errno(status); goto bail; @@ -1920,8 +1934,10 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, ac->ac_chain = i; status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, res, &bits_left); - if (!status) + if (!status) { + hint = ocfs2_group_from_res(res); break; + } if (status < 0 && status != -ENOSPC) { mlog_errno(status); goto bail; @@ -1936,7 +1952,7 @@ set_hint: if (bits_left < min_bits) ac->ac_last_group = 0; else - ac->ac_last_group = res->sr_bg_blkno; + ac->ac_last_group = hint; } bail: -- cgit v1.2.3-59-g8ed1b From 9b4c0ff32ccd87ab52d4c5bd0a0536febce11370 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 24 Aug 2010 14:28:03 +0200 Subject: ocfs2: Fix deadlock when allocating page We cannot call grab_cache_page() when holding filesystem locks or with a transaction started as grab_cache_page() calls page allocation with GFP_KERNEL flag and thus page reclaim can recurse back into the filesystem causing deadlocks or various assertion failures. We have to use find_or_create_page() instead and pass it GFP_NOFS as we do with other allocations. Acked-by: Mark Fasheh Signed-off-by: Jan Kara Signed-off-by: Tao Ma --- fs/ocfs2/alloc.c | 2 +- fs/ocfs2/file.c | 2 +- fs/ocfs2/refcounttree.c | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 215e12ce1d85..592fae5007d1 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -6672,7 +6672,7 @@ int ocfs2_grab_pages(struct inode *inode, loff_t start, loff_t end, last_page_bytes = PAGE_ALIGN(end); index = start >> PAGE_CACHE_SHIFT; do { - pages[numpages] = grab_cache_page(mapping, index); + pages[numpages] = find_or_create_page(mapping, index, GFP_NOFS); if (!pages[numpages]) { ret = -ENOMEM; mlog_errno(ret); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 6b2be0f2eacd..2caa3a7a1a39 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -783,7 +783,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from, BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT)); BUG_ON(abs_from & (inode->i_blkbits - 1)); - page = grab_cache_page(mapping, index); + page = find_or_create_page(mapping, index, GFP_NOFS); if (!page) { ret = -ENOMEM; mlog_errno(ret); diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 73a11ccfd4c2..0afeda83120f 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -2960,7 +2960,7 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle, if (map_end & (PAGE_CACHE_SIZE - 1)) to = map_end & (PAGE_CACHE_SIZE - 1); - page = grab_cache_page(mapping, page_index); + page = find_or_create_page(mapping, page_index, GFP_NOFS); /* * In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page @@ -3179,7 +3179,8 @@ static int ocfs2_cow_sync_writeback(struct super_block *sb, if (map_end > end) map_end = end; - page = grab_cache_page(context->inode->i_mapping, page_index); + page = find_or_create_page(context->inode->i_mapping, + page_index, GFP_NOFS); BUG_ON(!page); wait_on_page_writeback(page); -- cgit v1.2.3-59-g8ed1b From 81c8c82b5a39f9127e8b239e9b406a6c3a41b228 Mon Sep 17 00:00:00 2001 From: Tristan Ye Date: Thu, 19 Aug 2010 15:15:00 +0800 Subject: Ocfs2: Fix a regression bug from mainline commit(6b933c8e6f1a2f3118082c455eef25f9b1ac7b45). The patch is to fix the regression bug brought from commit 6b933c8...( 'ocfs2: Avoid direct write if we fall back to buffered I/O'): http://oss.oracle.com/bugzilla/show_bug.cgi?id=1285 The commit 6b933c8e6f1a2f3118082c455eef25f9b1ac7b45 changed __generic_file_aio_write to generic_file_buffered_write, which didn't call filemap_{write,wait}_range to flush the pagecaches when we were falling O_DIRECT writes back to buffered ones. it did hurt the O_DIRECT semantics somehow in extented odirect writes. This patch tries to guarantee O_DIRECT writes of 'fall back to buffered' to be correctly flushed. Signed-off-by: Tristan Ye Signed-off-by: Tao Ma --- fs/ocfs2/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 2caa3a7a1a39..9a03c151b5ce 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2338,7 +2338,7 @@ out_dio: BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || - ((file->f_flags & O_DIRECT) && has_refcount)) { + ((file->f_flags & O_DIRECT) && !direct_io)) { ret = filemap_fdatawrite_range(file->f_mapping, pos, pos + count - 1); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From 021960cab320ae3cc4e9aba9cca42f9f5ce785f3 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 13 Aug 2010 15:15:15 -0700 Subject: ocfs2: split out inode alloc code from ocfs2_mknod_locked Do this by splitting the bulk of the function away from the inode allocation code at the very tom of ocfs2_mknod_locked(). Existing callers don't need to change and won't see any difference. The new function created, __ocfs2_mknod_locked() will be used shortly. Signed-off-by: Mark Fasheh Signed-off-by: Tao Ma --- fs/ocfs2/namei.c | 55 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index f171b51a74f7..2aa66b695fab 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -472,32 +472,23 @@ leave: return status; } -static int ocfs2_mknod_locked(struct ocfs2_super *osb, - struct inode *dir, - struct inode *inode, - dev_t dev, - struct buffer_head **new_fe_bh, - struct buffer_head *parent_fe_bh, - handle_t *handle, - struct ocfs2_alloc_context *inode_ac) +static int __ocfs2_mknod_locked(struct inode *dir, + struct inode *inode, + dev_t dev, + struct buffer_head **new_fe_bh, + struct buffer_head *parent_fe_bh, + handle_t *handle, + struct ocfs2_alloc_context *inode_ac, + u64 fe_blkno, u64 suballoc_loc, u16 suballoc_bit) { int status = 0; + struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); struct ocfs2_dinode *fe = NULL; struct ocfs2_extent_list *fel; - u64 suballoc_loc, fe_blkno = 0; - u16 suballoc_bit; u16 feat; *new_fe_bh = NULL; - status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh, - inode_ac, &suballoc_loc, - &suballoc_bit, &fe_blkno); - if (status < 0) { - mlog_errno(status); - goto leave; - } - /* populate as many fields early on as possible - many of * these are used by the support functions here and in * callers. */ @@ -591,6 +582,34 @@ leave: return status; } +static int ocfs2_mknod_locked(struct ocfs2_super *osb, + struct inode *dir, + struct inode *inode, + dev_t dev, + struct buffer_head **new_fe_bh, + struct buffer_head *parent_fe_bh, + handle_t *handle, + struct ocfs2_alloc_context *inode_ac) +{ + int status = 0; + u64 suballoc_loc, fe_blkno = 0; + u16 suballoc_bit; + + *new_fe_bh = NULL; + + status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh, + inode_ac, &suballoc_loc, + &suballoc_bit, &fe_blkno); + if (status < 0) { + mlog_errno(status); + return status; + } + + return __ocfs2_mknod_locked(dir, inode, dev, new_fe_bh, + parent_fe_bh, handle, inode_ac, + fe_blkno, suballoc_loc, suballoc_bit); +} + static int ocfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode) -- cgit v1.2.3-59-g8ed1b From d51349829c378c06ba4aa7d4b16ca23739858608 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 13 Aug 2010 15:15:16 -0700 Subject: ocfs2: use ocfs2_alloc_dinode_update_counts() instead of open coding ocfs2_search_chain() makes the same updates as ocfs2_alloc_dinode_update_counts to the alloc inode. Instead of open coding the bitmap update, use our helper function. Signed-off-by: Mark Fasheh Signed-off-by: Tao Ma --- fs/ocfs2/suballoc.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index b93d7e72175a..e7edda8c6a11 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -1719,7 +1719,6 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, { int status; u16 chain; - u32 tmp_used; u64 next_group; struct inode *alloc_inode = ac->ac_inode; struct buffer_head *group_bh = NULL; @@ -1807,22 +1806,14 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, } } - /* Ok, claim our bits now: set the info on dinode, chainlist - * and then the group */ - status = ocfs2_journal_access_di(handle, - INODE_CACHE(alloc_inode), - ac->ac_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (status < 0) { + status = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, + ac->ac_bh, res->sr_bits, + chain); + if (status) { mlog_errno(status); goto bail; } - tmp_used = le32_to_cpu(fe->id1.bitmap1.i_used); - fe->id1.bitmap1.i_used = cpu_to_le32(res->sr_bits + tmp_used); - le32_add_cpu(&cl->cl_recs[chain].c_free, -res->sr_bits); - ocfs2_journal_dirty(handle, ac->ac_bh); - status = ocfs2_block_group_set_bits(handle, alloc_inode, bg, -- cgit v1.2.3-59-g8ed1b From e49e27674d1dd2717ad90b21ece8f83102153315 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 13 Aug 2010 15:15:17 -0700 Subject: ocfs2: allow return of new inode block location before allocation of the inode This allows code which needs to know the eventual block number of an inode but can't allocate it yet due to transaction or lock ordering. For example, ocfs2_create_inode_in_orphan() currently gives a junk blkno for preparation of the orphan dir because it can't yet know where the actual inode is placed - that code is actually in ocfs2_mknod_locked. This is a problem when the orphan dirs are indexed as the junk inode number will create an index entry which goes unused (and fails the later removal from the orphan dir). Now with these interfaces, ocfs2_create_inode_in_orphan() can run the block group search (and get back the inode block number) *before* any actual allocation occurs. Signed-off-by: Mark Fasheh Signed-off-by: Tao Ma --- fs/ocfs2/suballoc.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/suballoc.h | 21 +++++++ 2 files changed, 180 insertions(+) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index e7edda8c6a11..8a286f54dca1 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -57,6 +57,12 @@ struct ocfs2_suballoc_result { u64 sr_bg_blkno; /* The bg we allocated from. Set to 0 when a block group is contiguous. */ + u64 sr_bg_stable_blkno; /* + * Doesn't change, always + * set to target block + * group descriptor + * block. + */ u64 sr_blkno; /* The first allocated block */ unsigned int sr_bit_offset; /* The bit in the bg */ unsigned int sr_bits; /* How many bits we claimed */ @@ -149,6 +155,10 @@ void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) brelse(ac->ac_bh); ac->ac_bh = NULL; ac->ac_resv = NULL; + if (ac->ac_find_loc_priv) { + kfree(ac->ac_find_loc_priv); + ac->ac_find_loc_priv = NULL; + } } void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac) @@ -1689,6 +1699,15 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, if (!ret) ocfs2_bg_discontig_fix_result(ac, gd, res); + /* + * sr_bg_blkno might have been changed by + * ocfs2_bg_discontig_fix_result + */ + res->sr_bg_stable_blkno = group_bh->b_blocknr; + + if (ac->ac_find_loc_only) + goto out_loc_only; + ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh, res->sr_bits, le16_to_cpu(gd->bg_chain)); @@ -1702,6 +1721,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, if (ret < 0) mlog_errno(ret); +out_loc_only: *bits_left = le16_to_cpu(gd->bg_free_bits_count); out: @@ -1780,6 +1800,11 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, if (!status) ocfs2_bg_discontig_fix_result(ac, bg, res); + /* + * sr_bg_blkno might have been changed by + * ocfs2_bg_discontig_fix_result + */ + res->sr_bg_stable_blkno = group_bh->b_blocknr; /* * Keep track of previous block descriptor read. When @@ -1806,6 +1831,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, } } + if (ac->ac_find_loc_only) + goto out_loc_only; + status = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh, res->sr_bits, chain); @@ -1828,6 +1856,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits, (unsigned long long)le64_to_cpu(fe->i_blkno)); +out_loc_only: *bits_left = le16_to_cpu(bg->bg_free_bits_count); bail: brelse(group_bh); @@ -2023,6 +2052,136 @@ static inline void ocfs2_save_inode_ac_group(struct inode *dir, OCFS2_I(dir)->ip_last_used_slot = ac->ac_alloc_slot; } +int ocfs2_find_new_inode_loc(struct inode *dir, + struct buffer_head *parent_fe_bh, + struct ocfs2_alloc_context *ac, + u64 *fe_blkno) +{ + int ret; + handle_t *handle = NULL; + struct ocfs2_suballoc_result *res; + + BUG_ON(!ac); + BUG_ON(ac->ac_bits_given != 0); + BUG_ON(ac->ac_bits_wanted != 1); + BUG_ON(ac->ac_which != OCFS2_AC_USE_INODE); + + res = kzalloc(sizeof(*res), GFP_NOFS); + if (res == NULL) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; + } + + ocfs2_init_inode_ac_group(dir, parent_fe_bh, ac); + + /* + * The handle started here is for chain relink. Alternatively, + * we could just disable relink for these calls. + */ + handle = ocfs2_start_trans(OCFS2_SB(dir->i_sb), OCFS2_SUBALLOC_ALLOC); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + handle = NULL; + mlog_errno(ret); + goto out; + } + + /* + * This will instruct ocfs2_claim_suballoc_bits and + * ocfs2_search_one_group to search but save actual allocation + * for later. + */ + ac->ac_find_loc_only = 1; + + ret = ocfs2_claim_suballoc_bits(ac, handle, 1, 1, res); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + + ac->ac_find_loc_priv = res; + *fe_blkno = res->sr_blkno; + +out: + if (handle) + ocfs2_commit_trans(OCFS2_SB(dir->i_sb), handle); + + if (ret) + kfree(res); + + return ret; +} + +int ocfs2_claim_new_inode_at_loc(handle_t *handle, + struct inode *dir, + struct ocfs2_alloc_context *ac, + u64 *suballoc_loc, + u16 *suballoc_bit, + u64 di_blkno) +{ + int ret; + u16 chain; + struct ocfs2_suballoc_result *res = ac->ac_find_loc_priv; + struct buffer_head *bg_bh = NULL; + struct ocfs2_group_desc *bg; + struct ocfs2_dinode *di = (struct ocfs2_dinode *) ac->ac_bh->b_data; + + /* + * Since di_blkno is being passed back in, we check for any + * inconsistencies which may have happened between + * calls. These are code bugs as di_blkno is not expected to + * change once returned from ocfs2_find_new_inode_loc() + */ + BUG_ON(res->sr_blkno != di_blkno); + + ret = ocfs2_read_group_descriptor(ac->ac_inode, di, + res->sr_bg_stable_blkno, &bg_bh); + if (ret) { + mlog_errno(ret); + goto out; + } + + bg = (struct ocfs2_group_desc *) bg_bh->b_data; + chain = le16_to_cpu(bg->bg_chain); + + ret = ocfs2_alloc_dinode_update_counts(ac->ac_inode, handle, + ac->ac_bh, res->sr_bits, + chain); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_block_group_set_bits(handle, + ac->ac_inode, + bg, + bg_bh, + res->sr_bit_offset, + res->sr_bits); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + + mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits, + (unsigned long long)di_blkno); + + atomic_inc(&OCFS2_SB(ac->ac_inode->i_sb)->alloc_stats.bg_allocs); + + BUG_ON(res->sr_bits != 1); + + *suballoc_loc = res->sr_bg_blkno; + *suballoc_bit = res->sr_bit_offset; + ac->ac_bits_given++; + ocfs2_save_inode_ac_group(dir, ac); + +out: + brelse(bg_bh); + + return ret; +} + int ocfs2_claim_new_inode(handle_t *handle, struct inode *dir, struct buffer_head *parent_fe_bh, diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index a017dd3ee7d9..b8afabfeede4 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h @@ -56,6 +56,9 @@ struct ocfs2_alloc_context { u64 ac_max_block; /* Highest block number to allocate. 0 is is the same as ~0 - unlimited */ + int ac_find_loc_only; /* hack for reflink operation ordering */ + struct ocfs2_suballoc_result *ac_find_loc_priv; /* */ + struct ocfs2_alloc_reservation *ac_resv; }; @@ -197,4 +200,22 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et, struct ocfs2_alloc_context **meta_ac); int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res); + + + +/* + * The following two interfaces are for ocfs2_create_inode_in_orphan(). + */ +int ocfs2_find_new_inode_loc(struct inode *dir, + struct buffer_head *parent_fe_bh, + struct ocfs2_alloc_context *ac, + u64 *fe_blkno); + +int ocfs2_claim_new_inode_at_loc(handle_t *handle, + struct inode *dir, + struct ocfs2_alloc_context *ac, + u64 *suballoc_loc, + u16 *suballoc_bit, + u64 di_blkno); + #endif /* _CHAINALLOC_H_ */ -- cgit v1.2.3-59-g8ed1b From dd43bcde23c527f64897eef41aa1fed2c9905ea9 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 13 Aug 2010 15:15:18 -0700 Subject: ocfs2: split out ocfs2_prepare_orphan_dir() into locking and prep functions We do this because ocfs2_create_inode_in_orphan() wants to order locking of the orphan dir with respect to locking of the inode allocator *before* making any changes to the directory. Signed-off-by: Mark Fasheh Signed-off-by: Tao Ma --- fs/ocfs2/namei.c | 120 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 2aa66b695fab..54c629855357 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1871,61 +1871,117 @@ bail: return status; } -static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, - struct inode **ret_orphan_dir, - u64 blkno, - char *name, - struct ocfs2_dir_lookup_result *lookup) +static int ocfs2_lookup_lock_orphan_dir(struct ocfs2_super *osb, + struct inode **ret_orphan_dir, + struct buffer_head **ret_orphan_dir_bh) { struct inode *orphan_dir_inode; struct buffer_head *orphan_dir_bh = NULL; - int status = 0; - - status = ocfs2_blkno_stringify(blkno, name); - if (status < 0) { - mlog_errno(status); - return status; - } + int ret = 0; orphan_dir_inode = ocfs2_get_system_file_inode(osb, ORPHAN_DIR_SYSTEM_INODE, osb->slot_num); if (!orphan_dir_inode) { - status = -ENOENT; - mlog_errno(status); - return status; + ret = -ENOENT; + mlog_errno(ret); + return ret; } mutex_lock(&orphan_dir_inode->i_mutex); - status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); - if (status < 0) { - mlog_errno(status); - goto leave; + ret = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); + if (ret < 0) { + mutex_unlock(&orphan_dir_inode->i_mutex); + iput(orphan_dir_inode); + + mlog_errno(ret); + return ret; } - status = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode, - orphan_dir_bh, name, - OCFS2_ORPHAN_NAMELEN, lookup); - if (status < 0) { - ocfs2_inode_unlock(orphan_dir_inode, 1); + *ret_orphan_dir = orphan_dir_inode; + *ret_orphan_dir_bh = orphan_dir_bh; - mlog_errno(status); - goto leave; + return 0; +} + +static int __ocfs2_prepare_orphan_dir(struct inode *orphan_dir_inode, + struct buffer_head *orphan_dir_bh, + u64 blkno, + char *name, + struct ocfs2_dir_lookup_result *lookup) +{ + int ret; + struct ocfs2_super *osb = OCFS2_SB(orphan_dir_inode->i_sb); + + ret = ocfs2_blkno_stringify(blkno, name); + if (ret < 0) { + mlog_errno(ret); + return ret; + } + + ret = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode, + orphan_dir_bh, name, + OCFS2_ORPHAN_NAMELEN, lookup); + if (ret < 0) { + mlog_errno(ret); + return ret; + } + + return 0; +} + +/** + * ocfs2_prepare_orphan_dir() - Prepare an orphan directory for + * insertion of an orphan. + * @osb: ocfs2 file system + * @ret_orphan_dir: Orphan dir inode - returned locked! + * @blkno: Actual block number of the inode to be inserted into orphan dir. + * @lookup: dir lookup result, to be passed back into functions like + * ocfs2_orphan_add + * + * Returns zero on success and the ret_orphan_dir, name and lookup + * fields will be populated. + * + * Returns non-zero on failure. + */ +static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, + struct inode **ret_orphan_dir, + u64 blkno, + char *name, + struct ocfs2_dir_lookup_result *lookup) +{ + struct inode *orphan_dir_inode = NULL; + struct buffer_head *orphan_dir_bh = NULL; + int ret = 0; + + ret = ocfs2_lookup_lock_orphan_dir(osb, &orphan_dir_inode, + &orphan_dir_bh); + if (ret < 0) { + mlog_errno(ret); + return ret; + } + + ret = __ocfs2_prepare_orphan_dir(orphan_dir_inode, orphan_dir_bh, + blkno, name, lookup); + if (ret < 0) { + mlog_errno(ret); + goto out; } *ret_orphan_dir = orphan_dir_inode; -leave: - if (status) { +out: + brelse(orphan_dir_bh); + + if (ret) { + ocfs2_inode_unlock(orphan_dir_inode, 1); mutex_unlock(&orphan_dir_inode->i_mutex); iput(orphan_dir_inode); } - brelse(orphan_dir_bh); - - mlog_exit(status); - return status; + mlog_exit(ret); + return ret; } static int ocfs2_orphan_add(struct ocfs2_super *osb, -- cgit v1.2.3-59-g8ed1b From 97b8f4a9dfd932997677136e11980eb2fafea91d Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Fri, 13 Aug 2010 15:15:19 -0700 Subject: ocfs2: Fix orphan add in ocfs2_create_inode_in_orphan ocfs2_create_inode_in_orphan() is used by reflink to create the newly reflinked inode simultaneously in the orphan dir. This allows us to easily handle partially-reflinked files during recovery cleanup. We have a problem though - the orphan dir stringifies inode # to determine a unique name under which the orphan entry dirent can be created. Since ocfs2_create_inode_in_orphan() needs the space allocated in the orphan dir before it can allocate the inode, we currently call into the orphan code: /* * We give the orphan dir the root blkno to fake an orphan name, * and allocate enough space for our insertion. */ status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, osb->root_blkno, orphan_name, &orphan_insert); Using osb->root_blkno might work fine on unindexed directories, but the orphan dir can have an index. When it has that index, the above code fails to allocate the proper index entry. Later, when we try to remove the file from the orphan dir (using the actual inode #), the reflink operation will fail. To fix this, I created a function ocfs2_alloc_orphaned_file() which uses the newly split out orphan and inode alloc code to figure out what the inode block number will be (once allocated) and then prepare the orphan dir from that data. Signed-off-by: Mark Fasheh Signed-off-by: Tao Ma --- fs/ocfs2/namei.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 20 deletions(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 54c629855357..a00dda2e4f16 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -2128,6 +2128,99 @@ leave: return status; } +/** + * ocfs2_prep_new_orphaned_file() - Prepare the orphan dir to recieve a newly + * allocated file. This is different from the typical 'add to orphan dir' + * operation in that the inode does not yet exist. This is a problem because + * the orphan dir stringifies the inode block number to come up with it's + * dirent. Obviously if the inode does not yet exist we have a chicken and egg + * problem. This function works around it by calling deeper into the orphan + * and suballoc code than other callers. Use this only by necessity. + * @dir: The directory which this inode will ultimately wind up under - not the + * orphan dir! + * @dir_bh: buffer_head the @dir inode block + * @orphan_name: string of length (CFS2_ORPHAN_NAMELEN + 1). Will be filled + * with the string to be used for orphan dirent. Pass back to the orphan dir + * code. + * @ret_orphan_dir: orphan dir inode returned to be passed back into orphan + * dir code. + * @ret_di_blkno: block number where the new inode will be allocated. + * @orphan_insert: Dir insert context to be passed back into orphan dir code. + * @ret_inode_ac: Inode alloc context to be passed back to the allocator. + * + * Returns zero on success and the ret_orphan_dir, name and lookup + * fields will be populated. + * + * Returns non-zero on failure. + */ +static int ocfs2_prep_new_orphaned_file(struct inode *dir, + struct buffer_head *dir_bh, + char *orphan_name, + struct inode **ret_orphan_dir, + u64 *ret_di_blkno, + struct ocfs2_dir_lookup_result *orphan_insert, + struct ocfs2_alloc_context **ret_inode_ac) +{ + int ret; + u64 di_blkno; + struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); + struct inode *orphan_dir = NULL; + struct buffer_head *orphan_dir_bh = NULL; + struct ocfs2_alloc_context *inode_ac = NULL; + + ret = ocfs2_lookup_lock_orphan_dir(osb, &orphan_dir, &orphan_dir_bh); + if (ret < 0) { + mlog_errno(ret); + return ret; + } + + /* reserve an inode spot */ + ret = ocfs2_reserve_new_inode(osb, &inode_ac); + if (ret < 0) { + if (ret != -ENOSPC) + mlog_errno(ret); + goto out; + } + + ret = ocfs2_find_new_inode_loc(dir, dir_bh, inode_ac, + &di_blkno); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = __ocfs2_prepare_orphan_dir(orphan_dir, orphan_dir_bh, + di_blkno, orphan_name, orphan_insert); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + +out: + if (ret == 0) { + *ret_orphan_dir = orphan_dir; + *ret_di_blkno = di_blkno; + *ret_inode_ac = inode_ac; + /* + * orphan_name and orphan_insert are already up to + * date via prepare_orphan_dir + */ + } else { + /* Unroll reserve_new_inode* */ + if (inode_ac) + ocfs2_free_alloc_context(inode_ac); + + /* Unroll orphan dir locking */ + mutex_unlock(&orphan_dir->i_mutex); + ocfs2_inode_unlock(orphan_dir, 1); + iput(orphan_dir); + } + + brelse(orphan_dir_bh); + + return 0; +} + int ocfs2_create_inode_in_orphan(struct inode *dir, int mode, struct inode **new_inode) @@ -2143,6 +2236,8 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, struct buffer_head *new_di_bh = NULL; struct ocfs2_alloc_context *inode_ac = NULL; struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; + u64 uninitialized_var(di_blkno), suballoc_loc; + u16 suballoc_bit; status = ocfs2_inode_lock(dir, &parent_di_bh, 1); if (status < 0) { @@ -2151,20 +2246,9 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, return status; } - /* - * We give the orphan dir the root blkno to fake an orphan name, - * and allocate enough space for our insertion. - */ - status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, - osb->root_blkno, - orphan_name, &orphan_insert); - if (status < 0) { - mlog_errno(status); - goto leave; - } - - /* reserve an inode spot */ - status = ocfs2_reserve_new_inode(osb, &inode_ac); + status = ocfs2_prep_new_orphaned_file(dir, parent_di_bh, + orphan_name, &orphan_dir, + &di_blkno, &orphan_insert, &inode_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -2191,17 +2275,20 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, goto leave; did_quota_inode = 1; - inode->i_nlink = 0; - /* do the real work now. */ - status = ocfs2_mknod_locked(osb, dir, inode, - 0, &new_di_bh, parent_di_bh, handle, - inode_ac); + status = ocfs2_claim_new_inode_at_loc(handle, dir, inode_ac, + &suballoc_loc, + &suballoc_bit, di_blkno); if (status < 0) { mlog_errno(status); goto leave; } - status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, orphan_name); + inode->i_nlink = 0; + /* do the real work now. */ + status = __ocfs2_mknod_locked(dir, inode, + 0, &new_di_bh, parent_di_bh, handle, + inode_ac, di_blkno, suballoc_loc, + suballoc_bit); if (status < 0) { mlog_errno(status); goto leave; -- cgit v1.2.3-59-g8ed1b From 4c25b93223340deff73381cc47f9244fb379a74d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 7 Sep 2010 13:37:10 +0200 Subject: ALSA: virtuoso: work around missing reset in the Xonar DS Windows driver For the WM8776 chip, this driver uses a different sample format and more features than the Windows driver. When rebooting from Linux into Windows, the latter driver does not reset the chip but assumes all its registers have their default settings, so we get garbled sound or, if the output happened to be muted before rebooting, no sound. To make that driver happy, hook our driver's cleanup function into the shutdown notifier and ensure that the chip gets reset. Signed-off-by: Clemens Ladisch Reported-and-tested-by: Nathan Schagen Cc: Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.h | 1 + sound/pci/oxygen/oxygen_lib.c | 21 ++++++++++++++++++--- sound/pci/oxygen/virtuoso.c | 1 + sound/pci/oxygen/xonar_wm87x6.c | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 6147216af744..a3409edcfb50 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -155,6 +155,7 @@ void oxygen_pci_remove(struct pci_dev *pci); int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state); int oxygen_pci_resume(struct pci_dev *pci); #endif +void oxygen_pci_shutdown(struct pci_dev *pci); /* oxygen_mixer.c */ diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index fad03d64e3ad..7e93cf884437 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -519,16 +519,21 @@ static void oxygen_init(struct oxygen *chip) } } -static void oxygen_card_free(struct snd_card *card) +static void oxygen_shutdown(struct oxygen *chip) { - struct oxygen *chip = card->private_data; - spin_lock_irq(&chip->reg_lock); chip->interrupt_mask = 0; chip->pcm_running = 0; oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); spin_unlock_irq(&chip->reg_lock); +} + +static void oxygen_card_free(struct snd_card *card) +{ + struct oxygen *chip = card->private_data; + + oxygen_shutdown(chip); if (chip->irq >= 0) free_irq(chip->irq, chip); flush_scheduled_work(); @@ -778,3 +783,13 @@ int oxygen_pci_resume(struct pci_dev *pci) } EXPORT_SYMBOL(oxygen_pci_resume); #endif /* CONFIG_PM */ + +void oxygen_pci_shutdown(struct pci_dev *pci) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct oxygen *chip = card->private_data; + + oxygen_shutdown(chip); + chip->model.cleanup(chip); +} +EXPORT_SYMBOL(oxygen_pci_shutdown); diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index f03a2f2cffee..06c863e86e3d 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -95,6 +95,7 @@ static struct pci_driver xonar_driver = { .suspend = oxygen_pci_suspend, .resume = oxygen_pci_resume, #endif + .shutdown = oxygen_pci_shutdown, }; static int __init alsa_card_xonar_init(void) diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index dbc4b89d74e4..0b89932fb8c4 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -193,6 +193,7 @@ static void xonar_ds_init(struct oxygen *chip) static void xonar_ds_cleanup(struct oxygen *chip) { xonar_disable_output(chip); + wm8776_write(chip, WM8776_RESET, 0); } static void xonar_ds_suspend(struct oxygen *chip) -- cgit v1.2.3-59-g8ed1b From fe6ce80ae25953d95ebaf9bce27b585218cda25c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 7 Sep 2010 13:38:49 +0200 Subject: ALSA: virtuoso: fix setting of Xonar DS line-in/mic-in controls The Line and Mic inputs cannot be used at the same time, so the driver has to automatically disable one of them if both are set. However, it forgot to notify userspace about this change, so the mixer state would be inconsistent. To fix this, check if the other control gets muted, and send a notification event in this case. Signed-off-by: Clemens Ladisch Reported-and-tested-by: Nathan Schagen Cc: Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_wm87x6.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 0b89932fb8c4..b82c1cfa96f5 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -53,6 +53,8 @@ struct xonar_wm87x6 { struct xonar_generic generic; u16 wm8776_regs[0x17]; u16 wm8766_regs[0x10]; + struct snd_kcontrol *line_adcmux_control; + struct snd_kcontrol *mic_adcmux_control; struct snd_kcontrol *lc_controls[13]; }; @@ -604,6 +606,7 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl, { struct oxygen *chip = ctl->private_data; struct xonar_wm87x6 *data = chip->model_data; + struct snd_kcontrol *other_ctl; unsigned int mux_bit = ctl->private_value; u16 reg; int changed; @@ -611,8 +614,18 @@ static int wm8776_input_mux_put(struct snd_kcontrol *ctl, mutex_lock(&chip->mutex); reg = data->wm8776_regs[WM8776_ADCMUX]; if (value->value.integer.value[0]) { - reg &= ~0x003; reg |= mux_bit; + /* line-in and mic-in are exclusive */ + mux_bit ^= 3; + if (reg & mux_bit) { + reg &= ~mux_bit; + if (mux_bit == 1) + other_ctl = data->line_adcmux_control; + else + other_ctl = data->mic_adcmux_control; + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, + &other_ctl->id); + } } else reg &= ~mux_bit; changed = reg != data->wm8776_regs[WM8776_ADCMUX]; @@ -964,7 +977,13 @@ static int xonar_ds_mixer_init(struct oxygen *chip) err = snd_ctl_add(chip->card, ctl); if (err < 0) return err; + if (!strcmp(ctl->id.name, "Line Capture Switch")) + data->line_adcmux_control = ctl; + else if (!strcmp(ctl->id.name, "Mic Capture Switch")) + data->mic_adcmux_control = ctl; } + if (!data->line_adcmux_control || !data->mic_adcmux_control) + return -ENXIO; BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { ctl = snd_ctl_new1(&lc_controls[i], chip); -- cgit v1.2.3-59-g8ed1b From 76195fb096ca6db2f8bbaffb96e3025aaf1649a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 08:27:02 +0200 Subject: ALSA: usb - Release capture substream URBs properly Due to the wrong "return" in the loop, a capture substream won't be released at disconnection properly if the device is capture only and has no playback substream. This caused Oops occasionally at the device reconnection. Reported-by: Kim Minhyoung Cc: Signed-off-by: Takashi Iwai --- sound/usb/card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 32e4be8a187c..4eabafa5b037 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -126,7 +126,7 @@ static void snd_usb_stream_disconnect(struct list_head *head) for (idx = 0; idx < 2; idx++) { subs = &as->substream[idx]; if (!subs->num_formats) - return; + continue; snd_usb_release_substream_urbs(subs, 1); subs->interface = -1; } -- cgit v1.2.3-59-g8ed1b From a769cbcf60cee51f4431c0938acd39e7e5b76b8d Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Tue, 7 Sep 2010 14:36:22 -0500 Subject: ALSA: hda - Add errata initverb sequence for CS42xx codecs Add init verb sequence for errata ER880C3 http://www.cirrus.com/en/pubs/errata/ER880C3.pdf Signed-off-by: Brian Austin Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 4ef5efaaaef1..488fd9ade1ba 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -972,6 +972,53 @@ static struct hda_verb cs_coef_init_verbs[] = { {} /* terminator */ }; +/* Errata: CS4207 rev C0/C1/C2 Silicon + * + * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf + * + * 6. At high temperature (TA > +85°C), the digital supply current (IVD) + * may be excessive (up to an additional 200 μA), which is most easily + * observed while the part is being held in reset (RESET# active low). + * + * Root Cause: At initial powerup of the device, the logic that drives + * the clock and write enable to the S/PDIF SRC RAMs is not properly + * initialized. + * Certain random patterns will cause a steady leakage current in those + * RAM cells. The issue will resolve once the SRCs are used (turned on). + * + * Workaround: The following verb sequence briefly turns on the S/PDIF SRC + * blocks, which will alleviate the issue. + */ + +static struct hda_verb cs_errata_init_verbs[] = { + {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */ + {0x11, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ + + {0x11, AC_VERB_SET_COEF_INDEX, 0x0008}, + {0x11, AC_VERB_SET_PROC_COEF, 0x9999}, + {0x11, AC_VERB_SET_COEF_INDEX, 0x0017}, + {0x11, AC_VERB_SET_PROC_COEF, 0xa412}, + {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, + {0x11, AC_VERB_SET_PROC_COEF, 0x0009}, + + {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */ + {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */ + + {0x11, AC_VERB_SET_COEF_INDEX, 0x0017}, + {0x11, AC_VERB_SET_PROC_COEF, 0x2412}, + {0x11, AC_VERB_SET_COEF_INDEX, 0x0008}, + {0x11, AC_VERB_SET_PROC_COEF, 0x0000}, + {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, + {0x11, AC_VERB_SET_PROC_COEF, 0x0008}, + {0x11, AC_VERB_SET_PROC_STATE, 0x00}, + + {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */ + {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */ + /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */ + + {} /* terminator */ +}; + /* SPDIF setup */ static void init_digital(struct hda_codec *codec) { @@ -991,6 +1038,9 @@ static int cs_init(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; + /* init_verb sequence for C0/C1/C2 errata*/ + snd_hda_sequence_write(codec, cs_errata_init_verbs); + snd_hda_sequence_write(codec, cs_coef_init_verbs); if (spec->gpio_mask) { -- cgit v1.2.3-59-g8ed1b From 080dc7bc2562615a5be0a705a9d1a8c24eb198d4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 08:38:41 +0200 Subject: ALSA: hda - Enable PC-beep for EeePC with ALC269 codec EeePC 1001HAG has a similar problem like other ASUS machine, which doesn't set the codec SSID properly for indicating the beep capability. To enable PC-beep again, put this to the whitelist. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 627bf9963368..bcbf9160ed81 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5334,6 +5334,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids, static struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), {} }; -- cgit v1.2.3-59-g8ed1b From ab5a6ebee38f3ed311f0565ecd3fba5cf111564a Mon Sep 17 00:00:00 2001 From: Vitaliy Kulikov Date: Wed, 8 Sep 2010 09:00:17 +0200 Subject: ALSA: hda - Adding support for new IDT 92HD90BXX and 92HD91BXX codecs Adding support for digital MIC in 92HD83/90/91XXX codecs family. Signed-off-by: Vitaliy Kulikov Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 79 ++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d226edd1e143..82d1e4378621 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -382,6 +382,11 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = { 0x03, 0x0c, 0x20, 0x40, }; +#define STAC92HD83XXX_NUM_DMICS 2 +static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { + 0x11, 0x20, 0 +}; + #define STAC92HD83XXX_NUM_CAPS 2 static unsigned long stac92hd83xxx_capvols[] = { HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), @@ -4695,6 +4700,36 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) } } +/* get the pin connection (fixed, none, etc) */ +static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int cfg; + + cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]); + return get_defcfg_connect(cfg); +} + +static int stac92xx_connected_ports(struct hda_codec *codec, + hda_nid_t *nids, int num_nids) +{ + struct sigmatel_spec *spec = codec->spec; + int idx, num; + unsigned int def_conf; + + for (num = 0; num < num_nids; num++) { + for (idx = 0; idx < spec->num_pins; idx++) + if (spec->pin_nids[idx] == nids[num]) + break; + if (idx >= spec->num_pins) + break; + def_conf = stac_get_defcfg_connect(codec, idx); + if (def_conf == AC_JACK_PORT_NONE) + break; + } + return num; +} + static void stac92xx_mic_detect(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -5325,6 +5360,8 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->linear_tone_beep = 1; codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; spec->digbeep_nid = 0x21; + spec->dmic_nids = stac92hd83xxx_dmic_nids; + spec->dmux_nids = stac92hd83xxx_mux_nids; spec->mux_nids = stac92hd83xxx_mux_nids; spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids); spec->adc_nids = stac92hd83xxx_adc_nids; @@ -5370,9 +5407,13 @@ again: case 0x111d76d4: case 0x111d7605: case 0x111d76d5: + case 0x111d76e7: if (spec->board_config == STAC_92HD83XXX_PWR_REF) break; spec->num_pwrs = 0; + spec->num_dmics = stac92xx_connected_ports(codec, + stac92hd83xxx_dmic_nids, + STAC92HD83XXX_NUM_DMICS); break; } @@ -5431,36 +5472,6 @@ again: return 0; } -/* get the pin connection (fixed, none, etc) */ -static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int cfg; - - cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]); - return get_defcfg_connect(cfg); -} - -static int stac92hd71bxx_connected_ports(struct hda_codec *codec, - hda_nid_t *nids, int num_nids) -{ - struct sigmatel_spec *spec = codec->spec; - int idx, num; - unsigned int def_conf; - - for (num = 0; num < num_nids; num++) { - for (idx = 0; idx < spec->num_pins; idx++) - if (spec->pin_nids[idx] == nids[num]) - break; - if (idx >= spec->num_pins) - break; - def_conf = stac_get_defcfg_connect(codec, idx); - if (def_conf == AC_JACK_PORT_NONE) - break; - } - return num; -} - static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, hda_nid_t dig0pin) { @@ -5599,7 +5610,7 @@ again: case 0x111d76b5: spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; - spec->num_dmics = stac92hd71bxx_connected_ports(codec, + spec->num_dmics = stac92xx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS); break; @@ -5631,7 +5642,7 @@ again: snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0; - spec->num_dmics = stac92hd71bxx_connected_ports(codec, + spec->num_dmics = stac92xx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS - 1); break; @@ -5645,7 +5656,7 @@ again: default: spec->init = stac92hd71bxx_core_init; codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; - spec->num_dmics = stac92hd71bxx_connected_ports(codec, + spec->num_dmics = stac92xx_connected_ports(codec, stac92hd71bxx_dmic_nids, STAC92HD71BXX_NUM_DMICS); break; @@ -6327,6 +6338,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx }, { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx }, { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx }, + { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx}, {} /* terminator */ }; -- cgit v1.2.3-59-g8ed1b From 263d0328c46995d8e4fb478005177839104483d2 Mon Sep 17 00:00:00 2001 From: Vitaliy Kulikov Date: Wed, 8 Sep 2010 08:56:03 +0200 Subject: ALSA: hda - Improve input control names for IDT/STAC codecs Changing the way the input controls are named using port connection type and jack location info. Signed-off-by: Vitaliy Kulikov Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 107 +++++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 19 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 82d1e4378621..7f09e140953e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -191,6 +191,11 @@ struct sigmatel_mic_route { signed char dmux_idx; }; +struct unique_input_names { + int num; + char uname[HDA_MAX_NUM_INPUTS][32]; +}; + struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -307,6 +312,7 @@ struct sigmatel_spec { struct hda_input_mux private_imux; struct hda_input_mux private_smux; struct hda_input_mux private_mono_mux; + struct unique_input_names private_u_inp_names; }; static hda_nid_t stac9200_adc_nids[1] = { @@ -3452,6 +3458,76 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, return 1; } +static const char *get_input_src_label(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int def_conf; + + def_conf = snd_hda_codec_get_pincfg(codec, nid); + + switch (get_defcfg_device(def_conf)) { + case AC_JACK_MIC_IN: + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || + ((get_defcfg_location(def_conf) & 0xf0) + == AC_JACK_LOC_INTERNAL)) + return "Internal Mic"; + if ((get_defcfg_location(def_conf) & 0xf0) + == AC_JACK_LOC_SEPARATE) + return "Dock Mic"; + if (get_defcfg_location(def_conf) == AC_JACK_LOC_REAR) + return "Rear Mic"; + return "Mic"; + case AC_JACK_LINE_IN: + if ((get_defcfg_location(def_conf) & 0xf0) + == AC_JACK_LOC_SEPARATE) + return "Dock Line"; + return "Line"; + case AC_JACK_AUX: + return "Aux"; + case AC_JACK_CD: + return "CD"; + case AC_JACK_SPDIF_IN: + return "SPDIF In"; + case AC_JACK_DIG_OTHER_IN: + return "Digital In"; + } + + snd_printd("invalid inp pin %02x device config %08x", nid, def_conf); + return NULL; +} + +static const char *get_unique_inp_src_label(struct hda_codec *codec, + hda_nid_t nid) +{ + int i, n; + const char *label; + struct sigmatel_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->private_imux; + struct hda_input_mux *dimux = &spec->private_dimux; + struct unique_input_names *unames = &spec->private_u_inp_names; + + label = get_input_src_label(codec, nid); + n = 0; + + for (i = 0; i < imux->num_items; i++) { + if (!strncmp(label, imux->items[i].label, strlen(label))) + n++; + } + if (snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { + for (i = 0; i < dimux->num_items; i++) { + if (!strncmp(label, dimux->items[i].label, + strlen(label))) + n++; + } + } + if (n > 0 && unames->num < HDA_MAX_NUM_INPUTS) { + sprintf(&unames->uname[unames->num][0], "%.28s %d", label, n); + label = &unames->uname[unames->num][0]; + unames->num++; + } + + return label; +} + /* create playback/capture controls for input pins on dmic capable codecs */ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) @@ -3459,24 +3535,13 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux; struct hda_input_mux *dimux = &spec->private_dimux; - int err, i, active_mics; + int err, i; unsigned int def_conf; dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; dimux->items[dimux->num_items].index = 0; dimux->num_items++; - active_mics = 0; - for (i = 0; i < spec->num_dmics; i++) { - /* check the validity: sometimes it's a dead vendor-spec node */ - if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i])) - != AC_WID_PIN) - continue; - def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]); - if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) - active_mics++; - } - for (i = 0; i < spec->num_dmics; i++) { hda_nid_t nid; int index; @@ -3493,10 +3558,9 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, if (index < 0) continue; - if (active_mics == 1) - label = "Digital Mic"; - else - label = stac92xx_dmic_labels[dimux->num_items]; + label = get_unique_inp_src_label(codec, nid); + if (label == NULL) + return -EINVAL; err = create_elem_capture_vol(codec, nid, label, 0, HDA_INPUT); if (err < 0) @@ -3618,6 +3682,7 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux; int i, j, type_idx = 0; + const char *label; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; @@ -3637,14 +3702,18 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const type_idx++; else type_idx = 0; + + label = get_unique_inp_src_label(codec, nid); + if (label == NULL) + return -EINVAL; + err = create_elem_capture_vol(codec, nid, - auto_pin_cfg_labels[i], type_idx, + label, type_idx, HDA_INPUT); if (err < 0) return err; - imux->items[imux->num_items].label = - snd_hda_get_input_pin_label(cfg, i); + imux->items[imux->num_items].label = label; imux->items[imux->num_items].index = index; imux->num_items++; } -- cgit v1.2.3-59-g8ed1b From 12e8ba25ef52f19e7a42e61aecb3c1fef83b2a82 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 7 Sep 2010 23:39:28 +0100 Subject: Revert "drm/i915: Allow LVDS on pipe A on gen4+" This reverts commit 0f3ee801b332d6ff22285386675fe5aaedf035c3. Enabling LVDS on pipe A was causing excessive wakeups on otherwise idle systems due to i915 interrupts. So restrict the LVDS to pipe B once more, whilst the issue is properly diagnosed. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16307 Reported-and-tested-by: Enrico Bandiello Poked-by: Florian Mickler Signed-off-by: Chris Wilson Cc: Adam Jackson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_lvds.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index b819c1081147..4fbb0165b26f 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -875,8 +875,6 @@ void intel_lvds_init(struct drm_device *dev) intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT); intel_encoder->crtc_mask = (1 << 1); - if (IS_I965G(dev)) - intel_encoder->crtc_mask |= (1 << 0); drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; -- cgit v1.2.3-59-g8ed1b From e4ee8dd8afcbcbe502fa8a3d3af6eb09c96dd806 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 09:58:12 +0200 Subject: ALSA: msnd-classic: Fix invalid cfg parameter The driver doesn't probe the device properly because of left-over cfg[] that isn't used at all for msnd-classic device. This is only for msnd- pinnacle. Signed-off-by: Takashi Iwai --- sound/isa/msnd/msnd_pinnacle.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 5f3e68401f90..91d6023a63e5 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c @@ -764,9 +764,9 @@ static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +#ifndef MSND_CLASSIC static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; -#ifndef MSND_CLASSIC /* Extra Peripheral Configuration (Default: Disable) */ static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; @@ -894,7 +894,11 @@ static int __devinit snd_msnd_isa_probe(struct device *pdev, unsigned int idx) struct snd_card *card; struct snd_msnd *chip; - if (has_isapnp(idx) || cfg[idx] == SNDRV_AUTO_PORT) { + if (has_isapnp(idx) +#ifndef MSND_CLASSIC + || cfg[idx] == SNDRV_AUTO_PORT +#endif + ) { printk(KERN_INFO LOGNAME ": Assuming PnP mode\n"); return -ENODEV; } -- cgit v1.2.3-59-g8ed1b From c3add4b63438555d5e88c5893d238ab80d1f5959 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 8 Sep 2010 09:14:08 +0100 Subject: Revert "drm/i915: Warn if we run out of FIFO space for a mode" This reverts commit b9421ae8f30958deea98d71477b4a77a066856b4. This warning was so prelevant, even for apparently working machines, that it was just causing fear, anxiety and panic. The root cause still remains, so we will add some better debugging when we focus on fixing it. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=17021 Reported-by: Maciej Rutecki Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e0d1952fd3ce..7c9103030036 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2767,14 +2767,8 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, /* Don't promote wm_size to unsigned... */ if (wm_size > (long)wm->max_wm) wm_size = wm->max_wm; - if (wm_size <= 0) { + if (wm_size <= 0) wm_size = wm->default_wm; - DRM_ERROR("Insufficient FIFO for plane, expect flickering:" - " entries required = %ld, available = %lu.\n", - entries_required + wm->guard_size, - wm->fifo_size); - } - return wm_size; } -- cgit v1.2.3-59-g8ed1b From 27f7ad53829f79e799a253285318bff79ece15bd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Sep 2010 09:13:45 +0200 Subject: ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open() The error handling in snd_seq_oss_open() has several bad codes that do dereferecing released pointers and double-free of kmalloc'ed data. The object dp is release in free_devinfo() that is called via private_free callback. The rest shouldn't touch this object any more. The patch changes delete_port() to call kfree() in any case, and gets rid of unnecessary calls of destructors in snd_seq_oss_open(). Fixes CVE-2010-3080. Reported-and-tested-by: Tavis Ormandy Cc: Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_init.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 685712276ac9..69cd7b3c362d 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -281,13 +281,10 @@ snd_seq_oss_open(struct file *file, int level) return 0; _error: - snd_seq_oss_writeq_delete(dp->writeq); - snd_seq_oss_readq_delete(dp->readq); snd_seq_oss_synth_cleanup(dp); snd_seq_oss_midi_cleanup(dp); - delete_port(dp); delete_seq_queue(dp->queue); - kfree(dp); + delete_port(dp); return rc; } @@ -350,8 +347,10 @@ create_port(struct seq_oss_devinfo *dp) static int delete_port(struct seq_oss_devinfo *dp) { - if (dp->port < 0) + if (dp->port < 0) { + kfree(dp); return 0; + } debug_printk(("delete_port %i\n", dp->port)); return snd_seq_event_port_detach(dp->cseq, dp->port); -- cgit v1.2.3-59-g8ed1b From 1d220334d6a8a711149234dc5f98d34ae02226b8 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 8 Sep 2010 00:10:26 +0400 Subject: apm_power: Add missing break statement The missing break statement causes wrong capacity calculation for batteries that report energy. Reported-by: d binderman Cc: Signed-off-by: Anton Vorontsov --- drivers/power/apm_power.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index 936bae560fa1..dc628cb2e762 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c @@ -233,6 +233,7 @@ static int calculate_capacity(enum apm_source source) empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; + break; case SOURCE_VOLTAGE: full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; -- cgit v1.2.3-59-g8ed1b From 0485e18bc4112a3b548baa314c24bfbece4d156b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 5 Sep 2010 12:19:50 +0100 Subject: Revert "[ARM] pxa: remove now unnecessary dma_needs_bounce()" This reverts commit 4fa5518, which causes a compilation regression for IXP4xx platforms. Reported-by: Richard Cochran Acked-by: Eric Miao Signed-off-by: Russell King --- arch/arm/common/it8152.c | 8 ++++++++ arch/arm/include/asm/dma-mapping.h | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index 6c0913562455..7974baacafce 100644 --- a/arch/arm/common/it8152.c +++ b/arch/arm/common/it8152.c @@ -263,6 +263,14 @@ static int it8152_pci_platform_notify_remove(struct device *dev) return 0; } +int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", + __func__, dma_addr, size); + return (dev->bus == &pci_bus_type) && + ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); +} + int __init it8152_pci_setup(int nr, struct pci_sys_data *sys) { it8152_io.start = IT8152_IO_BASE + 0x12000; diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index c226fe10553e..c568da7dcae4 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -288,15 +288,7 @@ extern void dmabounce_unregister_dev(struct device *); * DMA access and 1 if the buffer needs to be bounced. * */ -#ifdef CONFIG_SA1111 extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); -#else -static inline int dma_needs_bounce(struct device *dev, dma_addr_t addr, - size_t size) -{ - return 0; -} -#endif /* * The DMA API, implemented by dmabounce.c. See below for descriptions. -- cgit v1.2.3-59-g8ed1b From a387f0f5409276c5cf75eecb61ef6e6896f851b4 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 3 Sep 2010 17:14:54 +0100 Subject: ARM: 6359/1: ep93xx: move clock initialization earlier Commit 7cfe24947 ("ARM: AMBA: Add pclk support to AMBA bus infrastructure") changed AMBA bus to handle the PCLK automatically. However, in EP93xx clock initialization is arch_initcall which is done later than AMBA device identification. This causes amba_get_enable_pclk() to fail resulting device where UARTs are not functional. So change ep93xx_clock_init() to be postcore_initcall. Signed-off-by: Mika Westerberg Acked-by: H Hartley Sweeten Signed-off-by: Russell King --- arch/arm/mach-ep93xx/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 8bf3cec98cfa..4566bd1c8660 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -560,4 +560,4 @@ static int __init ep93xx_clock_init(void) clkdev_add_table(clocks, ARRAY_SIZE(clocks)); return 0; } -arch_initcall(ep93xx_clock_init); +postcore_initcall(ep93xx_clock_init); -- cgit v1.2.3-59-g8ed1b From cec15a0ece19116b6c2c53fedf9696c20124d491 Mon Sep 17 00:00:00 2001 From: Roland Baum Date: Wed, 8 Sep 2010 14:27:55 +0200 Subject: HID: add device ID for new Asus Multitouch Controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following patch instructs usbhid/hid-mosart to handle a new multitouch controller, built-in by some Asus EeePC T101MT models. Signed-off-by: Roland Baum Tested-by: Roland Baum Acked-by: Stéphane Chatty CC: Stéphane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-mosart.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b2b3bb90dd64..2baf959301b1 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1285,6 +1285,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7c69f1ebb390..765a4f53eb5c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -105,6 +105,7 @@ #define USB_VENDOR_ID_ASUS 0x0486 #define USB_DEVICE_ID_ASUS_T91MT 0x0185 +#define USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO 0x0186 #define USB_VENDOR_ID_ASUSTEK 0x0b05 #define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index e91437c18906..ac5421d568f1 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -239,6 +239,7 @@ static void mosart_remove(struct hid_device *hdev) static const struct hid_device_id mosart_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, { } }; MODULE_DEVICE_TABLE(hid, mosart_devices); -- cgit v1.2.3-59-g8ed1b From eaca1386207a9e0314647d3a88967acb17cc30e3 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 8 Sep 2010 14:31:47 +0200 Subject: HID: fixup blacklist entry for Asus T91MT The device is handled by hid-mosart driver, and therefore should be present in hid_blacklist[], not hid_ignore_list[]. Cc: Stephane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2baf959301b1..3f7292486024 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1285,6 +1285,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, @@ -1580,7 +1581,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)}, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, -- cgit v1.2.3-59-g8ed1b From 122661b67899980f1372812d907e73ebcfb3d037 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 14:57:04 +0200 Subject: ALSA: hda - Fix wrong HP pin detection in snd_hda_parse_pin_def_config() snd_hda_parse_pin_def_config() has some workaround for re-assigning some pins declared as headphones to line-outs. This didn't work properly for some cases because it used memmove() stupidly wrongly. Reference: Novell bnc#637263 https://bugzilla.novell.com/show_bug.cgi?id=637263 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3827092cc1d2..14829210ef0b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4536,7 +4536,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, cfg->hp_outs--; memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); - memmove(sequences_hp + i - 1, sequences_hp + i, + memmove(sequences_hp + i, sequences_hp + i + 1, sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); } } -- cgit v1.2.3-59-g8ed1b From febc88c5948f81114f64c3412011d695aecae233 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Sep 2010 14:46:37 +0200 Subject: semaphore: Add DEFINE_SEMAPHORE The full cleanup of init_MUTEX[_LOCKED] and DECLARE_MUTEX has not been done. Some of the users are real semaphores and we should name them as such instead of confusing everyone with "MUTEX". Provide the infrastructure to get finally rid of init_MUTEX[_LOCKED] and DECLARE_MUTEX. Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Cc: Christoph Hellwig LKML-Reference: <20100907125054.795929962@linutronix.de> --- include/linux/semaphore.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index 7415839ac890..5310d27abd2a 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h @@ -26,6 +26,9 @@ struct semaphore { .wait_list = LIST_HEAD_INIT((name).wait_list), \ } +#define DEFINE_SEMAPHORE(name) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) + #define DECLARE_MUTEX(name) \ struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) -- cgit v1.2.3-59-g8ed1b From 03642c9a444079aa13f0864383a8f9ca04bfd198 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 15:28:19 +0200 Subject: ALSA: hda - Clear left-over hp_pins in snd_hda_parse_pin_def_config() In snd_hda_parse_def_config(), some unused values may remain in hp_pins[] array during the headphone-reassignment workaround. This patch clears the unused array members. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2980c277847a..bfdde7b0bafb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4558,6 +4558,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, memmove(sequences_hp + i, sequences_hp + i + 1, sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); } + memset(cfg->hp_pins + cfg->hp_outs, 0, + sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); } /* sort by sequence */ -- cgit v1.2.3-59-g8ed1b From bb35febd16fe5ac8c30f9116a25210c4f63a5267 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 15:30:49 +0200 Subject: ALSA: hda - Support multiple headphone auto-mute Currently headphone auto-mute using alc_automute_pin() assumes only the single pin used for the headphone output. Since there are devices with multiple headphone jacks, we need to check all these pins there, too. Also this patch merges the common code between alc_automute_pin() and alc_automute_amp() helper functions. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 92 +++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 81e4b1d957c5..ee59df7a41f8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -990,25 +990,46 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -static void alc_automute_pin(struct hda_codec *codec) +static void alc_automute_speaker(struct hda_codec *codec, int pinctl) { struct alc_spec *spec = codec->spec; - unsigned int nid = spec->autocfg.hp_pins[0]; + unsigned int mute; + hda_nid_t nid; int i; - if (!nid) - return; - spec->jack_present = snd_hda_jack_detect(codec, nid); + spec->jack_present = 0; + for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { + nid = spec->autocfg.hp_pins[i]; + if (!nid) + break; + if (snd_hda_jack_detect(codec, nid)) { + spec->jack_present = 1; + break; + } + } + + mute = spec->jack_present ? HDA_AMP_MUTE : 0; + /* Toggle internal speakers muting */ for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { nid = spec->autocfg.speaker_pins[i]; if (!nid) break; - snd_hda_codec_write(codec, nid, 0, + if (pinctl) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->jack_present ? 0 : PIN_OUT); + } else { + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } } } +static void alc_automute_pin(struct hda_codec *codec) +{ + alc_automute_speaker(codec, 1); +} + static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid) { @@ -1236,24 +1257,35 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) static void alc_init_auto_hp(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; - if (!spec->autocfg.hp_pins[0]) - return; + if (!cfg->hp_pins[0]) { + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + return; + } - if (!spec->autocfg.speaker_pins[0]) { - if (spec->autocfg.line_out_pins[0] && - spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - spec->autocfg.speaker_pins[0] = - spec->autocfg.line_out_pins[0]; - else + if (!cfg->speaker_pins[0]) { + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) return; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = cfg->line_outs; + } + + if (!cfg->hp_pins[0]) { + memcpy(cfg->hp_pins, cfg->line_out_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = cfg->line_outs; } - snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", - spec->autocfg.hp_pins[0]); - snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0, + for (i = 0; i < cfg->hp_outs; i++) { + snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", + cfg->hp_pins[i]); + snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT); + } spec->unsol_event = alc_sku_unsol_event; } @@ -1711,31 +1743,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { static void alc_automute_amp(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; - unsigned int mute; - hda_nid_t nid; - int i; - - spec->jack_present = 0; - for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { - nid = spec->autocfg.hp_pins[i]; - if (!nid) - break; - if (snd_hda_jack_detect(codec, nid)) { - spec->jack_present = 1; - break; - } - } - - mute = spec->jack_present ? HDA_AMP_MUTE : 0; - /* Toggle internal speakers muting */ - for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { - nid = spec->autocfg.speaker_pins[i]; - if (!nid) - break; - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); - } + alc_automute_speaker(codec, 0); } static void alc_automute_amp_unsol_event(struct hda_codec *codec, -- cgit v1.2.3-59-g8ed1b From 033688a5a80f9d56b2e7d56c4cb8188ae1448919 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 15:47:09 +0200 Subject: ALSA: hda - Add multiple headphone support to ALC262 codec This patch changes the alc262 auto-parser to allow multiple pins assigned for a single purpose (line-out, headphone or speaker). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 71 +++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ee59df7a41f8..26069e397fc9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11824,7 +11824,7 @@ static int alc262_check_volbit(hda_nid_t nid) } static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, - const char *pfx, int *vbits) + const char *pfx, int *vbits, int idx) { unsigned long val; int vbit; @@ -11839,11 +11839,11 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT); else val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT); - return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val); + return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val); } static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, - const char *pfx) + const char *pfx, int idx) { unsigned long val; @@ -11853,7 +11853,7 @@ static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); else val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val); + return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val); } /* add playback controls from the parsed DAC table */ @@ -11862,7 +11862,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, { const char *pfx; int vbits; - int err; + int i, err; spec->multiout.num_dacs = 1; /* only use one dac */ spec->multiout.dac_nids = spec->private_dac_nids; @@ -11872,39 +11872,52 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, pfx = "Master"; else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) pfx = "Speaker"; + else if (cfg->line_out_type == AUTO_PIN_HP_OUT) + pfx = "Headphone"; else pfx = "Front"; - err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx); - if (err < 0) - return err; - err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker"); - if (err < 0) - return err; - err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone"); - if (err < 0) - return err; + for (i = 0; i < 2; i++) { + err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i); + if (err < 0) + return err; + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i], + "Speaker", i); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i], + "Headphone", i); + if (err < 0) + return err; + } + } vbits = alc262_check_volbit(cfg->line_out_pins[0]) | alc262_check_volbit(cfg->speaker_pins[0]) | alc262_check_volbit(cfg->hp_pins[0]); if (vbits == 1 || vbits == 2) pfx = "Master"; /* only one mixer is used */ - else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - pfx = "Speaker"; - else - pfx = "Front"; vbits = 0; - err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits); - if (err < 0) - return err; - err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker", - &vbits); - if (err < 0) - return err; - err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone", - &vbits); - if (err < 0) - return err; + for (i = 0; i < 2; i++) { + err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx, + &vbits, i); + if (err < 0) + return err; + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i], + "Speaker", &vbits, i); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i], + "Headphone", &vbits, i); + if (err < 0) + return err; + } + } return 0; } -- cgit v1.2.3-59-g8ed1b From 18675e4283f575594d55ef1239c14ab5b4de53b6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Sep 2010 15:55:44 +0200 Subject: ALSA: hda - Add fixup for FSC Celsius H270 Added a fixup table for ALC262 codec containing the entry for FSC Celsius H270. Now both headphone jacks are detected properly as headphones. Reference: Novell bnc637263 https://bugzilla.novell.com/show_bug.cgi?id=637263 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 26069e397fc9..f11a9ca2c4b2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -12205,6 +12205,35 @@ static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = { {} }; +/* + * Pin config fixes + */ +enum { + PINFIX_FSC_H270, +}; + +static const struct alc_fixup alc262_fixups[] = { + [PINFIX_FSC_H270] = { + .pins = (const struct alc_pincfg[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x15, 0x0221142f }, /* front HP */ + { 0x1b, 0x0121141f }, /* rear HP */ + { } + } + }, + [PINFIX_PB_M5210] = { + .verbs = (const struct hda_verb[]) { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + {} + } + }, +}; + +static struct snd_pci_quirk alc262_fixup_tbl[] = { + SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270), + {} +}; + #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc262_loopbacks alc880_loopbacks @@ -12628,6 +12657,9 @@ static int patch_alc262(struct hda_codec *codec) board_config = ALC262_AUTO; } + if (board_config == ALC262_AUTO) + alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1); + if (board_config == ALC262_AUTO) { /* automatic parse from the BIOS config */ err = alc262_parse_auto_config(codec); @@ -12696,6 +12728,9 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->no_analog && has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); + if (board_config == ALC262_AUTO) + alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0); + spec->vmaster_nid = 0x0c; codec->patch_ops = alc_patch_ops; -- cgit v1.2.3-59-g8ed1b From 9c55cb12c1c172e2d51e85fbb5a4796ca86b77e7 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 8 Sep 2010 11:20:37 -0400 Subject: tracing: Do not allow llseek to set_ftrace_filter Reading the file set_ftrace_filter does three things. 1) shows whether or not filters are set for the function tracer 2) shows what functions are set for the function tracer 3) shows what triggers are set on any functions 3 is independent from 1 and 2. The way this file currently works is that it is a state machine, and as you read it, it may change state. But this assumption breaks when you use lseek() on the file. The state machine gets out of sync and the t_show() may use the wrong pointer and cause a kernel oops. Luckily, this will only kill the app that does the lseek, but the app dies while holding a mutex. This prevents anyone else from using the set_ftrace_filter file (or any other function tracing file for that matter). A real fix for this is to rewrite the code, but that is too much for a -rc release or stable. This patch simply disables llseek on the set_ftrace_filter() file for now, and we can do the proper fix for the next major release. Reported-by: Robert Swiecki Cc: Chris Wright Cc: Tavis Ormandy Cc: Eugene Teo Cc: vendor-sec@lst.de Cc: Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 7cb1f45a1de1..83a16e9ee518 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2416,7 +2416,7 @@ static const struct file_operations ftrace_filter_fops = { .open = ftrace_filter_open, .read = seq_read, .write = ftrace_filter_write, - .llseek = ftrace_regex_lseek, + .llseek = no_llseek, .release = ftrace_filter_release, }; -- cgit v1.2.3-59-g8ed1b From 61a527362234ac3352a91ac67c50c6f7cd248eb1 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 27 Aug 2010 20:38:46 +0900 Subject: tracing/kprobe: Fix a memory leak in error case Fix a memory leak which happens when a field name conflicts with others. In error case, free_trace_probe() will free all arguments until nr_args, so this increments nr_args the begining of the loop instead of the end. Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mathieu Desnoyers LKML-Reference: <20100827113846.22882.12670.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- kernel/trace/trace_kprobe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 8b27c9849b42..0116c038b0bc 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -992,6 +992,9 @@ static int create_trace_probe(int argc, char **argv) /* parse arguments */ ret = 0; for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { + /* Increment count for freeing args in error case */ + tp->nr_args++; + /* Parse argument name */ arg = strchr(argv[i], '='); if (arg) @@ -1021,11 +1024,8 @@ static int create_trace_probe(int argc, char **argv) ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); if (ret) { pr_info("Parse error at argument%d. (%d)\n", i, ret); - kfree(tp->args[i].name); goto error; } - - tp->nr_args++; } ret = register_trace_probe(tp); -- cgit v1.2.3-59-g8ed1b From 04ddd04b044d8896a4f8a921b23ba09d365df196 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 27 Aug 2010 20:38:53 +0900 Subject: perf probe: Fix return probe support Fix a bug to support %return probe syntax again. Previous commit 4235b04 has a bug which disables the %return syntax on perf probe. Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <20100827113852.22882.87447.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 1 + tools/perf/util/probe-finder.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index e72f05c3bef0..fcc16e4349df 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1539,6 +1539,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, goto error; } tev->point.offset = pev->point.offset; + tev->point.retprobe = pev->point.retprobe; tev->nargs = pev->nargs; if (tev->nargs) { tev->args = zalloc(sizeof(struct probe_trace_arg) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 525136684d4e..9b0e1b1f9755 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -783,6 +783,16 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) /* This function has no name. */ tev->point.offset = (unsigned long)pf->addr; + /* Return probe must be on the head of a subprogram */ + if (pf->pev->point.retprobe) { + if (tev->point.offset != 0) { + pr_warning("Return probe must be on the head of" + " a real function\n"); + return -EINVAL; + } + tev->point.retprobe = true; + } + pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, tev->point.offset); -- cgit v1.2.3-59-g8ed1b From 367e94c10092469c896a226a77ef13cf6da757e4 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 27 Aug 2010 20:38:59 +0900 Subject: perf probe: Fix handling of arguments names Don't make argument names from raw parameters (means the parameters are written in kprobe-tracer syntax), because the argument syntax may include special characters. Just leave it, then kprobe-tracer gives a new name. Reported-by: Srikar Dronamraju Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker LKML-Reference: <20100827113859.22882.75598.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 9b0e1b1f9755..32b81f707ff5 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -686,6 +686,25 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) char buf[32], *ptr; int ret, nscopes; + if (!is_c_varname(pf->pvar->var)) { + /* Copy raw parameters */ + pf->tvar->value = strdup(pf->pvar->var); + if (pf->tvar->value == NULL) + return -ENOMEM; + if (pf->pvar->type) { + pf->tvar->type = strdup(pf->pvar->type); + if (pf->tvar->type == NULL) + return -ENOMEM; + } + if (pf->pvar->name) { + pf->tvar->name = strdup(pf->pvar->name); + if (pf->tvar->name == NULL) + return -ENOMEM; + } else + pf->tvar->name = NULL; + return 0; + } + if (pf->pvar->name) pf->tvar->name = strdup(pf->pvar->name); else { @@ -700,19 +719,6 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) if (pf->tvar->name == NULL) return -ENOMEM; - if (!is_c_varname(pf->pvar->var)) { - /* Copy raw parameters */ - pf->tvar->value = strdup(pf->pvar->var); - if (pf->tvar->value == NULL) - return -ENOMEM; - if (pf->pvar->type) { - pf->tvar->type = strdup(pf->pvar->type); - if (pf->tvar->type == NULL) - return -ENOMEM; - } - return 0; - } - pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); /* Search child die for local variables and parameters. */ -- cgit v1.2.3-59-g8ed1b From aba91595cfcebd193425e20aabc407531526a1c5 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 27 Aug 2010 20:39:06 +0900 Subject: tracing/kprobes: Fix handling of argument names Set "argN" name for each argument automatically if it has no specified name. Since dynamic trace event(kprobe_events) accepts special characters for its argument, its format can show those special characters (e.g. '$', '%', '+'). However, perf can't parse those format because of the character (especially '%') mess up the format. This sets "argX" name for those arguments if user omitted the argument names. E.g. # echo 'p do_fork %ax IP=%ip $stack' > tracing/kprobe_events # cat tracing/kprobe_events p:kprobes/p_do_fork_0 do_fork arg1=%ax IP=%ip arg3=$stack Reported-by: Srikar Dronamraju Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mathieu Desnoyers LKML-Reference: <20100827113906.22882.59312.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- kernel/trace/trace_kprobe.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 0116c038b0bc..a39251ef1a7b 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -997,15 +997,18 @@ static int create_trace_probe(int argc, char **argv) /* Parse argument name */ arg = strchr(argv[i], '='); - if (arg) + if (arg) { *arg++ = '\0'; - else + tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); + } else { arg = argv[i]; + /* If argument name is omitted, set "argN" */ + snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1); + tp->args[i].name = kstrdup(buf, GFP_KERNEL); + } - tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); if (!tp->args[i].name) { - pr_info("Failed to allocate argument%d name '%s'.\n", - i, argv[i]); + pr_info("Failed to allocate argument[%d] name.\n", i); ret = -ENOMEM; goto error; } @@ -1014,7 +1017,7 @@ static int create_trace_probe(int argc, char **argv) *tmp = '_'; /* convert : to _ */ if (conflict_field_name(tp->args[i].name, tp->args, i)) { - pr_info("Argument%d name '%s' conflicts with " + pr_info("Argument[%d] name '%s' conflicts with " "another field.\n", i, argv[i]); ret = -EINVAL; goto error; @@ -1023,7 +1026,7 @@ static int create_trace_probe(int argc, char **argv) /* Parse fetch argument */ ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); if (ret) { - pr_info("Parse error at argument%d. (%d)\n", i, ret); + pr_info("Parse error at argument[%d]. (%d)\n", i, ret); goto error; } } -- cgit v1.2.3-59-g8ed1b From da34634fd39958725310d2c30c9b4543945f968b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 27 Aug 2010 20:39:12 +0900 Subject: tracing/kprobe: Fix handling of C-unlike argument names Check the argument name whether it is invalid (not C-like symbol name). This makes event format simple. Reported-by: Srikar Dronamraju Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mathieu Desnoyers LKML-Reference: <20100827113912.22882.62313.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu Signed-off-by: Arnaldo Carvalho de Melo --- kernel/trace/trace_kprobe.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index a39251ef1a7b..544301d29dee 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -514,8 +514,8 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); static int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs); -/* Check the name is good for event/group */ -static int check_event_name(const char *name) +/* Check the name is good for event/group/fields */ +static int is_good_name(const char *name) { if (!isalpha(*name) && *name != '_') return 0; @@ -557,7 +557,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, else tp->rp.kp.pre_handler = kprobe_dispatcher; - if (!event || !check_event_name(event)) { + if (!event || !is_good_name(event)) { ret = -EINVAL; goto error; } @@ -567,7 +567,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, if (!tp->call.name) goto error; - if (!group || !check_event_name(group)) { + if (!group || !is_good_name(group)) { ret = -EINVAL; goto error; } @@ -883,7 +883,7 @@ static int create_trace_probe(int argc, char **argv) int i, ret = 0; int is_return = 0, is_delete = 0; char *symbol = NULL, *event = NULL, *group = NULL; - char *arg, *tmp; + char *arg; unsigned long offset = 0; void *addr = NULL; char buf[MAX_EVENT_NAME_LEN]; @@ -1012,9 +1012,13 @@ static int create_trace_probe(int argc, char **argv) ret = -ENOMEM; goto error; } - tmp = strchr(tp->args[i].name, ':'); - if (tmp) - *tmp = '_'; /* convert : to _ */ + + if (!is_good_name(tp->args[i].name)) { + pr_info("Invalid argument[%d] name: %s\n", + i, tp->args[i].name); + ret = -EINVAL; + goto error; + } if (conflict_field_name(tp->args[i].name, tp->args, i)) { pr_info("Argument[%d] name '%s' conflicts with " -- cgit v1.2.3-59-g8ed1b From 2be23c475af8ae4e25f8bab08d815b17593bd547 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 8 Sep 2010 16:27:56 +0100 Subject: ARM: Ensure PTE modifications via dma_alloc_coherent are visible Dave Hylands reports: | We've observed a problem with dma_alloc_writecombine when the system | is under heavy load (heavy bus traffic). We've managed to reduce the | problem to the following snippet, which is run from a kthread in a | continuous loop: | | void *virtAddr; | dma_addr_t physAddr; | unsigned int numBytes = 256; | | for (;;) { | virtAddr = dma_alloc_writecombine(NULL, | numBytes, &physAddr, GFP_KERNEL); | if (virtAddr == NULL) { | printk(KERN_ERR "Running out of memory\n"); | break; | } | | /* access DMA memory allocated */ | tmp = virtAddr; | *tmp = 0x77; | | /* free DMA memory */ | dma_free_writecombine(NULL, | numBytes, virtAddr, physAddr); | | ...sleep here... | } | | By itself, the code will run forever with no issues. However, as we | increase our bus traffic (typically using DMA) then the *tmp = 0x77 | line will eventually cause a page fault. If we add a small delay (a | few microseconds) before the *tmp = 0x77, then we don't see a page | fault, even under heavy load. A dsb() is required after modifying the PTE entries to ensure that they will always be visible. Add this dsb(). Reported-by: Dave Hylands Tested-by: Dave Hylands Signed-off-by: Russell King --- arch/arm/mm/dma-mapping.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index c704eed63c5d..4bc43e535d3b 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -229,6 +229,8 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot) } } while (size -= PAGE_SIZE); + dsb(); + return (void *)c->vm_start; } return NULL; -- cgit v1.2.3-59-g8ed1b From d2a787fc57142ba8757142f1569603b4d0b714a4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Sep 2010 11:29:17 +0100 Subject: spi/spi_s3c64xx: Move to subsys_initcall() Allow the use of the S3C64xx SPI controller with things like PMICs by moving the init up to subsys_initcall(). Signed-off-by: Mark Brown Acked-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 7e627f73bc6c..a4c480551e5f 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -1175,7 +1175,7 @@ static int __init s3c64xx_spi_init(void) { return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe); } -module_init(s3c64xx_spi_init); +subsys_initcall(s3c64xx_spi_init); static void __exit s3c64xx_spi_exit(void) { -- cgit v1.2.3-59-g8ed1b From 9d8f86b56093d7b06d81d4063d5b9a4cbf887e75 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Sep 2010 16:37:52 +0100 Subject: spi/spi_s3c64xx: Increase dead reckoning time in wait_for_xfer() For small transfers at high speeds the expected transfer time can easily be well under 1ms, causing the delay in wait_for_xfer() to be only the dead reckoning fudge factor of 5ms currently included. Experiments on some of my systems shows that this is marginal for some transfers so double it to 10ms. Signed-off-by: Mark Brown Acked-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index a4c480551e5f..8130f02dc466 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -320,7 +320,7 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, /* millisecs to xfer 'len' bytes @ 'cur_speed' */ ms = xfer->len * 8 * 1000 / sdd->cur_speed; - ms += 5; /* some tolerance */ + ms += 10; /* some tolerance */ if (dma_mode) { val = msecs_to_jiffies(ms) + 10; -- cgit v1.2.3-59-g8ed1b From cbcc062abb16d39839b3d8d4e3d20360fc21eb58 Mon Sep 17 00:00:00 2001 From: Yong Wang Date: Tue, 7 Sep 2010 15:27:27 +0800 Subject: spi/dw_spi: Allow interrupt sharing Allow interrupt sharing since exclusive interrupt line for DW SPI controller is not provided on every platform. Signed-off-by: Yong Wang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index d256cb00604c..11fbbf6fb07b 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -396,6 +396,11 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) static irqreturn_t dw_spi_irq(int irq, void *dev_id) { struct dw_spi *dws = dev_id; + u16 irq_status, irq_mask = 0x3f; + + irq_status = dw_readw(dws, isr) & irq_mask; + if (!irq_status) + return IRQ_NONE; if (!dws->cur_msg) { spi_mask_intr(dws, SPI_INT_TXEI); @@ -883,7 +888,7 @@ int __devinit dw_spi_add_host(struct dw_spi *dws) dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); - ret = request_irq(dws->irq, dw_spi_irq, 0, + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, "dw_spi", dws); if (ret < 0) { dev_err(&master->dev, "can not get IRQ\n"); -- cgit v1.2.3-59-g8ed1b From e3e55ff5854655d8723ad8b307f02515aecc3df5 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Tue, 7 Sep 2010 15:52:06 +0800 Subject: spi/dw_spi: clean the cs_control code commit 052dc7c45i "spi/dw_spi: conditional transfer mode change" introduced cs_control code, which has a bug by using bit offset for spi mode to set transfer mode in control register. Also it forces devices who don't need cs_control to re-configure the control registers for each spi transfer. This patch will fix them Signed-off-by: Feng Tang Signed-off-by: Grant Likely --- drivers/spi/dw_spi.c | 17 +++++------------ include/linux/spi/dw_spi.h | 2 ++ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 11fbbf6fb07b..56247853c298 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -181,10 +181,6 @@ static void flush(struct dw_spi *dws) wait_till_not_busy(dws); } -static void null_cs_control(u32 command) -{ -} - static int null_writer(struct dw_spi *dws) { u8 n_bytes = dws->n_bytes; @@ -322,7 +318,7 @@ static void giveback(struct dw_spi *dws) struct spi_transfer, transfer_list); - if (!last_transfer->cs_change) + if (!last_transfer->cs_change && dws->cs_control) dws->cs_control(MRST_SPI_DEASSERT); msg->state = NULL; @@ -549,13 +545,13 @@ static void pump_transfers(unsigned long data) */ if (dws->cs_control) { if (dws->rx && dws->tx) - chip->tmode = 0x00; + chip->tmode = SPI_TMOD_TR; else if (dws->rx) - chip->tmode = 0x02; + chip->tmode = SPI_TMOD_RO; else - chip->tmode = 0x01; + chip->tmode = SPI_TMOD_TO; - cr0 &= ~(0x3 << SPI_MODE_OFFSET); + cr0 &= ~SPI_TMOD_MASK; cr0 |= (chip->tmode << SPI_TMOD_OFFSET); } @@ -704,9 +700,6 @@ static int dw_spi_setup(struct spi_device *spi) chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); if (!chip) return -ENOMEM; - - chip->cs_control = null_cs_control; - chip->enable_dma = 0; } /* diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h index cc813f95a2f2..c91302f3a257 100644 --- a/include/linux/spi/dw_spi.h +++ b/include/linux/spi/dw_spi.h @@ -14,7 +14,9 @@ #define SPI_MODE_OFFSET 6 #define SPI_SCPH_OFFSET 6 #define SPI_SCOL_OFFSET 7 + #define SPI_TMOD_OFFSET 8 +#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET) #define SPI_TMOD_TR 0x0 /* xmit & recv */ #define SPI_TMOD_TO 0x1 /* xmit only */ #define SPI_TMOD_RO 0x2 /* recv only */ -- cgit v1.2.3-59-g8ed1b From 64289c8e6851bca0e589e064c9a5c9fbd6ae5dd4 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Sat, 4 Sep 2010 10:34:29 +0000 Subject: gro: Re-fix different skb headrooms The patch: "gro: fix different skb headrooms" in its part: "2) allocate a minimal skb for head of frag_list" is buggy. The copied skb has p->data set at the ip header at the moment, and skb_gro_offset is the length of ip + tcp headers. So, after the change the length of mac header is skipped. Later skb_set_mac_header() sets it into the NET_SKB_PAD area (if it's long enough) and ip header is misaligned at NET_SKB_PAD + NET_IP_ALIGN offset. There is no reason to assume the original skb was wrongly allocated, so let's copy it as it was. bugzilla : https://bugzilla.kernel.org/show_bug.cgi?id=16626 fixes commit: 3d3be4333fdf6faa080947b331a6a19bce1a4f57 Reported-by: Plamen Petrov Signed-off-by: Jarek Poplawski CC: Eric Dumazet Acked-by: Eric Dumazet Tested-by: Plamen Petrov Signed-off-by: David S. Miller --- net/core/skbuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 26396ff67cf9..c83b421341c0 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2706,7 +2706,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) } else if (skb_gro_len(p) != pinfo->gso_size) return -E2BIG; - headroom = NET_SKB_PAD + NET_IP_ALIGN; + headroom = skb_headroom(p); nskb = alloc_skb(headroom + skb_gro_offset(p), GFP_ATOMIC); if (unlikely(!nskb)) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 6523ce1525e88c598c75a1a6b8c4edddfa9defe8 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sun, 5 Sep 2010 18:02:29 +0000 Subject: ipvs: fix active FTP - Do not create expectation when forwarding the PORT command to avoid blocking the connection. The problem is that nf_conntrack_ftp.c:help() tries to create the same expectation later in POST_ROUTING and drops the packet with "dropping packet" message after failure in nf_ct_expect_related. - Change ip_vs_update_conntrack to alter the conntrack for related connections from real server. If we do not alter the reply in this direction the next packet from client sent to vport 20 comes as NEW connection. We alter it but may be some collision happens for both conntracks and the second conntrack gets destroyed immediately. The connection stucks too. Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- include/net/ip_vs.h | 3 +++ net/netfilter/ipvs/ip_vs_core.c | 1 + net/netfilter/ipvs/ip_vs_ftp.c | 6 ------ net/netfilter/ipvs/ip_vs_xmit.c | 18 ++++++++++++------ 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index a4747a0f7303..f976885f686f 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -955,6 +955,9 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum) return csum_partial(diff, sizeof(diff), oldsum); } +extern void ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, + int outin); + #endif /* __KERNEL__ */ #endif /* _NET_IP_VS_H */ diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 4f8ddba48011..4c2f89df5cce 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -924,6 +924,7 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, ip_vs_out_stats(cp, skb); ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp); + ip_vs_update_conntrack(skb, cp, 0); ip_vs_conn_put(cp); skb->ipvs_property = 1; diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 33b329bfc2d2..7e9af5b76d9e 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -410,7 +410,6 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, union nf_inet_addr to; __be16 port; struct ip_vs_conn *n_cp; - struct nf_conn *ct; #ifdef CONFIG_IP_VS_IPV6 /* This application helper doesn't work with IPv6 yet, @@ -497,11 +496,6 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, ip_vs_control_add(n_cp, cp); } - ct = (struct nf_conn *)skb->nfct; - if (ct && ct != &nf_conntrack_untracked) - ip_vs_expect_related(skb, ct, n_cp, - IPPROTO_TCP, &n_cp->dport, 1); - /* * Move tunnel to listen state */ diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 21e1a5e9b9d3..49df6bea6a2d 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -349,8 +349,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, } #endif -static void -ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp) +void +ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin) { struct nf_conn *ct = (struct nf_conn *)skb->nfct; struct nf_conntrack_tuple new_tuple; @@ -365,11 +365,17 @@ ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp) * real-server we will see RIP->DIP. */ new_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; - new_tuple.src.u3 = cp->daddr; + if (outin) + new_tuple.src.u3 = cp->daddr; + else + new_tuple.dst.u3 = cp->vaddr; /* * This will also take care of UDP and other protocols. */ - new_tuple.src.u.tcp.port = cp->dport; + if (outin) + new_tuple.src.u.tcp.port = cp->dport; + else + new_tuple.dst.u.tcp.port = cp->vport; nf_conntrack_alter_reply(ct, &new_tuple); } @@ -428,7 +434,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT"); - ip_vs_update_conntrack(skb, cp); + ip_vs_update_conntrack(skb, cp, 1); /* FIXME: when application helper enlarges the packet and the length is larger than the MTU of outgoing device, there will be still @@ -506,7 +512,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT"); - ip_vs_update_conntrack(skb, cp); + ip_vs_update_conntrack(skb, cp, 1); /* FIXME: when application helper enlarges the packet and the length is larger than the MTU of outgoing device, there will be still -- cgit v1.2.3-59-g8ed1b From 915b96191f01d53e30d74083dcf4aebfb5b7ce10 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 4 Sep 2010 09:13:17 +0200 Subject: powerpc/5200: efika.c: Add of_node_put to avoid memory leak This function is implemented as though the function of_get_next_child does not increment the reference count of its result, but actually it does. Thus the patch adds of_node_put in error handling code and drops a call to of_node_get. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ local idexpression x; expression E1; position p1,p2; @@ x@p1 = of_get_next_child(...); ... when != x = E1 of_node_get@p2(x) @script:python@ p1 << r.p1; p2 << r.p2; @@ cocci.print_main("call",p1) cocci.print_secs("get",p2) // Signed-off-by: Julia Lawall Signed-off-by: Grant Likely --- arch/powerpc/platforms/52xx/efika.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 45c0cb9b67e6..18c104820198 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -99,7 +99,7 @@ static void __init efika_pcisetup(void) if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Can't get bus-range for %s\n", pcictrl->full_name); - return; + goto out_put; } if (bus_range[1] == bus_range[0]) @@ -111,12 +111,12 @@ static void __init efika_pcisetup(void) printk(" controlled by %s\n", pcictrl->full_name); printk("\n"); - hose = pcibios_alloc_controller(of_node_get(pcictrl)); + hose = pcibios_alloc_controller(pcictrl); if (!hose) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Can't allocate PCI controller structure for %s\n", pcictrl->full_name); - return; + goto out_put; } hose->first_busno = bus_range[0]; @@ -124,6 +124,9 @@ static void __init efika_pcisetup(void) hose->ops = &rtas_pci_ops; pci_process_bridge_OF_ranges(hose, pcictrl, 0); + return; +out_put: + of_node_put(pcictrl); } #else -- cgit v1.2.3-59-g8ed1b From 16518d5ada690643453eb0aef3cc7841d3623c2d Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 26 Aug 2010 14:31:30 +0300 Subject: KVM: x86 emulator: fix regression with cmpxchg8b on i386 hosts operand::val and operand::orig_val are 32-bit on i386, whereas cmpxchg8b operands are 64-bit. Fix by adding val64 and orig_val64 union members to struct operand, and using them where needed. Signed-off-by: Avi Kivity Signed-off-by: Marcelo Tosatti --- arch/x86/include/asm/kvm_emulate.h | 7 ++++++- arch/x86/kvm/emulate.c | 9 ++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index 51cfd730ac5d..1f99ecfc48e1 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -152,9 +152,14 @@ struct x86_emulate_ops { struct operand { enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type; unsigned int bytes; - unsigned long orig_val, *ptr; + union { + unsigned long orig_val; + u64 orig_val64; + }; + unsigned long *ptr; union { unsigned long val; + u64 val64; char valptr[sizeof(unsigned long) + 2]; }; }; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index b38bd8b92aa6..66ca98aafdd6 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1870,17 +1870,16 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { struct decode_cache *c = &ctxt->decode; - u64 old = c->dst.orig_val; + u64 old = c->dst.orig_val64; if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) || ((u32) (old >> 32) != (u32) c->regs[VCPU_REGS_RDX])) { - c->regs[VCPU_REGS_RAX] = (u32) (old >> 0); c->regs[VCPU_REGS_RDX] = (u32) (old >> 32); ctxt->eflags &= ~EFLG_ZF; } else { - c->dst.val = ((u64)c->regs[VCPU_REGS_RCX] << 32) | - (u32) c->regs[VCPU_REGS_RBX]; + c->dst.val64 = ((u64)c->regs[VCPU_REGS_RCX] << 32) | + (u32) c->regs[VCPU_REGS_RBX]; ctxt->eflags |= EFLG_ZF; } @@ -2616,7 +2615,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) c->src.valptr, c->src.bytes); if (rc != X86EMUL_CONTINUE) goto done; - c->src.orig_val = c->src.val; + c->src.orig_val64 = c->src.val64; } if (c->src2.type == OP_MEM) { -- cgit v1.2.3-59-g8ed1b From ae0635b3580844e320a253a16985f4ce8b5bd0b6 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 27 Jul 2010 14:51:44 +0300 Subject: KVM: fix i8259 oops when no vcpus are online If there are no vcpus, found will be NULL. Check before doing anything with it. Signed-off-by: Avi Kivity --- arch/x86/kvm/i8259.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 8d10c063d7f2..4b7b73ce2098 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c @@ -64,6 +64,9 @@ static void pic_unlock(struct kvm_pic *s) if (!found) found = s->kvm->bsp_vcpu; + if (!found) + return; + kvm_vcpu_kick(found); } } -- cgit v1.2.3-59-g8ed1b From eebb5f31b8d9a2620dcf32297096f8ce1240b179 Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Mon, 30 Aug 2010 12:49:13 +0300 Subject: KVM: i8259: fix migration Top of kvm_kpic_state structure should have the same memory layout as kvm_pic_state since it is copied by memcpy. Signed-off-by: Gleb Natapov Signed-off-by: Avi Kivity --- arch/x86/kvm/irq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index ffed06871c5c..63c314502993 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -43,7 +43,6 @@ struct kvm_kpic_state { u8 irr; /* interrupt request register */ u8 imr; /* interrupt mask register */ u8 isr; /* interrupt service register */ - u8 isr_ack; /* interrupt ack detection */ u8 priority_add; /* highest irq priority */ u8 irq_base; u8 read_reg_select; @@ -56,6 +55,7 @@ struct kvm_kpic_state { u8 init4; /* true if 4 byte init */ u8 elcr; /* PIIX edge/trigger selection */ u8 elcr_mask; + u8 isr_ack; /* interrupt ack detection */ struct kvm_pic *pics_state; }; -- cgit v1.2.3-59-g8ed1b From fa32154e47a203688453e53c1369fcbc63b06a21 Mon Sep 17 00:00:00 2001 From: Eric Millbrandt Date: Fri, 3 Sep 2010 13:27:38 -0400 Subject: powerpc/5200: tighten up ac97 reset timing Tighten up time timing around the gpio reset functionality. Add a 200ns delay before remuxing the pins back to ac97 to comply with the ac97 spec. Signed-off-by: Eric Millbrandt Signed-off-by: Grant Likely --- arch/powerpc/platforms/52xx/mpc52xx_common.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 6e905314ad5d..41f3a7eda1de 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -325,12 +325,16 @@ int mpc5200_psc_ac97_gpio_reset(int psc_number) clrbits32(&simple_gpio->simple_dvo, sync | out); clrbits8(&wkup_gpio->wkup_dvo, reset); - /* wait at lease 1 us */ - udelay(2); + /* wait for 1 us */ + udelay(1); /* Deassert reset */ setbits8(&wkup_gpio->wkup_dvo, reset); + /* wait at least 200ns */ + /* 7 ~= (200ns * timebase) / ns2sec */ + __delay(7); + /* Restore pin-muxing */ out_be32(&simple_gpio->port_config, mux); -- cgit v1.2.3-59-g8ed1b From 251ee478f2c877a9a80362e094c542fbac7f5651 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Fri, 3 Sep 2010 10:36:26 +0900 Subject: spi/s3c64xx: Fix compilation warning Fix compilation warning by typecasting the tx_buf pointer. [I'm not thrilled with resorting to a cast; but I cannot see a better way to go about this. I don't want to drop the const from struct spi_transfer ~~glikely] Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 8130f02dc466..240b690a8a6f 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -508,8 +508,9 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (xfer->tx_buf != NULL) { - xfer->tx_dma = dma_map_single(dev, xfer->tx_buf, - xfer->len, DMA_TO_DEVICE); + xfer->tx_dma = dma_map_single(dev, + (void *)xfer->tx_buf, xfer->len, + DMA_TO_DEVICE); if (dma_mapping_error(dev, xfer->tx_dma)) { dev_err(dev, "dma_map_single Tx failed\n"); xfer->tx_dma = XFER_DMAADDR_INVALID; -- cgit v1.2.3-59-g8ed1b From c3f139b65585a5f29df47b2302ff8dbd9bdad0b0 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Fri, 3 Sep 2010 10:36:46 +0900 Subject: spi/s3c64xx: Fix incorrect reuse of 'val' local variable. Instead of, wrongly, reusing the 'val' variable, use a dedicated one for reading the status register. Signed-off-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index 240b690a8a6f..ef9dacabe062 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -326,10 +326,11 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, val = msecs_to_jiffies(ms) + 10; val = wait_for_completion_timeout(&sdd->xfer_completion, val); } else { + u32 status; val = msecs_to_loops(ms); do { - val = readl(regs + S3C64XX_SPI_STATUS); - } while (RX_FIFO_LVL(val, sci) < xfer->len && --val); + status = readl(regs + S3C64XX_SPI_STATUS); + } while (RX_FIFO_LVL(status, sci) < xfer->len && --val); } if (!val) -- cgit v1.2.3-59-g8ed1b From be7852a839b6dcd86db1a2d25b9a1a99f38db2db Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 23 Aug 2010 17:40:56 +0100 Subject: spi/spi_s3c64xx: Warn if PIO transfers time out When using PIO we have a timeout for the TX and RX FIFOs to ensure that the data actually gets transferred. Warn if we hit that timeout - it should never happen, but this makes sure we'll find out if it does. Signed-off-by: Mark Brown Acked-by: Jassi Brar Signed-off-by: Grant Likely --- drivers/spi/spi_s3c64xx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/spi/spi_s3c64xx.c b/drivers/spi/spi_s3c64xx.c index ef9dacabe062..c3038da2648a 100644 --- a/drivers/spi/spi_s3c64xx.c +++ b/drivers/spi/spi_s3c64xx.c @@ -200,6 +200,9 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) val = readl(regs + S3C64XX_SPI_STATUS); } while (TX_FIFO_LVL(val, sci) && loops--); + if (loops == 0) + dev_warn(&sdd->pdev->dev, "Timed out flushing TX FIFO\n"); + /* Flush RxFIFO*/ loops = msecs_to_loops(1); do { @@ -210,6 +213,9 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) break; } while (loops--); + if (loops == 0) + dev_warn(&sdd->pdev->dev, "Timed out flushing RX FIFO\n"); + val = readl(regs + S3C64XX_SPI_CH_CFG); val &= ~S3C64XX_SPI_CH_SW_RST; writel(val, regs + S3C64XX_SPI_CH_CFG); -- cgit v1.2.3-59-g8ed1b From 545074fb953e1753f6b8409db533ad7998789efb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 21 Aug 2010 11:07:36 +0200 Subject: spi/pl022: fix APB pclk power regression on U300 With the introduction of an AMBA PrimeCell per-cell block clock, the pclk was left on after probe() unless explicitly disabled. This clock is wired to the same clock on PL022 causing it to stay always on since. Fix this up properly by clocking the pclk whenever we want to write into any PL022 registers and clocking the external clock whenever we want to transmit messages on the bus. Signed-off-by: Linus Walleij Tested-by : Kevin Wells Signed-off-by: Grant Likely --- drivers/spi/amba-pl022.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index acd35d1ebd12..80613abe961d 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -503,8 +503,9 @@ static void giveback(struct pl022 *pl022) msg->state = NULL; if (msg->complete) msg->complete(msg->context); - /* This message is completed, so let's turn off the clock! */ + /* This message is completed, so let's turn off the clocks! */ clk_disable(pl022->clk); + amba_pclk_disable(pl022->adev); } /** @@ -1139,9 +1140,10 @@ static void pump_messages(struct work_struct *work) /* Setup the SPI using the per chip configuration */ pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi); /* - * We enable the clock here, then the clock will be disabled when + * We enable the clocks here, then the clocks will be disabled when * giveback() is called in each method (poll/interrupt/DMA) */ + amba_pclk_enable(pl022->adev); clk_enable(pl022->clk); restore_state(pl022); flush(pl022); @@ -1786,11 +1788,9 @@ pl022_probe(struct amba_device *adev, struct amba_id *id) } /* Disable SSP */ - clk_enable(pl022->clk); writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); load_ssp_default_config(pl022); - clk_disable(pl022->clk); status = request_irq(adev->irq[0], pl022_interrupt_handler, 0, "pl022", pl022); @@ -1818,6 +1818,8 @@ pl022_probe(struct amba_device *adev, struct amba_id *id) goto err_spi_register; } dev_dbg(dev, "probe succeded\n"); + /* Disable the silicon block pclk and clock it when needed */ + amba_pclk_disable(adev); return 0; err_spi_register: @@ -1879,9 +1881,9 @@ static int pl022_suspend(struct amba_device *adev, pm_message_t state) return status; } - clk_enable(pl022->clk); + amba_pclk_enable(adev); load_ssp_default_config(pl022); - clk_disable(pl022->clk); + amba_pclk_disable(adev); dev_dbg(&adev->dev, "suspended\n"); return 0; } -- cgit v1.2.3-59-g8ed1b From 970f4be85ae6ecf97b711a3a2a1d5cecd3ea0534 Mon Sep 17 00:00:00 2001 From: Heikki Lindholm Date: Mon, 6 Sep 2010 22:30:45 +0300 Subject: firewire: ohci: activate cycle timer register quirk on Ricoh chips The Ricoh FireWire controllers appear to have the non-atomic cycle timer register access bug, so, activate the driver workaround by default. The behaviour was observed on: Ricoh Co Ltd R5C552 IEEE 1394 Controller [1180:0552] and Ricoh Co Ltd R5C832 IEEE 1394 Controller [1180:0832] (rev 04). Signed-off-by: Heikki Lindholm Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index be29b0bb2471..1b05896648bc 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -263,6 +263,7 @@ static const struct { {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI}, {PCI_VENDOR_ID_NEC, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, {PCI_VENDOR_ID_VIA, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, + {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, {PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS}, }; -- cgit v1.2.3-59-g8ed1b From 05f25abcf6043952fb2a2d98735dec58ba1fcadb Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 29 Aug 2010 11:52:41 +0200 Subject: powerpc/5200: mpc52xx_uart.c: Add of_node_put to avoid memory leak Add a call to of_node_put in the error handling code following a call to of_find_compatible_node. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ local idexpression x; expression E,E1; statement S; @@ *x = (of_find_node_by_path |of_find_node_by_name |of_find_node_by_phandle |of_get_parent |of_get_next_parent |of_get_next_child |of_find_compatible_node |of_match_node )(...); ... if (x == NULL) S <... when != x = E *if (...) { ... when != of_node_put(x) when != if (...) { ... of_node_put(x); ... } ( return <+...x...+>; | * return ...; ) } ...> of_node_put(x); // Signed-off-by: Julia Lawall Acked-by: Wolfram Sang Signed-off-by: Grant Likely --- drivers/serial/mpc52xx_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 8dedb266f143..c4399e23565a 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -500,6 +500,7 @@ static int __init mpc512x_psc_fifoc_init(void) psc_fifoc = of_iomap(np, 0); if (!psc_fifoc) { pr_err("%s: Can't map FIFOC\n", __func__); + of_node_put(np); return -ENODEV; } -- cgit v1.2.3-59-g8ed1b From 7100ae97266e387d25d0c8a5d9934931f0b07dbc Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 8 Sep 2010 20:54:49 +0000 Subject: Revert "[CIFS] Eliminate unused variable warning" The change to kernel crypto and fixes to ntlvm2 and ntlmssp series, introduced a regression. Deferring this patch series to 2.6.37 after Shirish fixes it. This reverts commit c89e5198b26a869ce2842bad8519264f3394dee9. Signed-off-by: Steve French Acked-by: Jeff Layton CC: Shirish Pargaonkar --- fs/cifs/sess.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 795095f4eac6..4788e16a02cc 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -620,6 +620,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, struct key *spnego_key = NULL; __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ bool first_time; + char *ntlmsspblob; if (ses == NULL) return -EINVAL; @@ -867,8 +868,6 @@ ssetup_ntlmssp_authenticate: iov[1].iov_base = &pSMB->req.SecurityBlob[0]; } else if (phase == NtLmAuthenticate) { int blob_len; - char *ntlmsspblob; - ntlmsspblob = kmalloc(5 * sizeof(struct _AUTHENTICATE_MESSAGE), GFP_KERNEL); -- cgit v1.2.3-59-g8ed1b From 56234e2767496c125a858f880f1b3a62e04a3406 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 8 Sep 2010 20:57:05 +0000 Subject: Revert "Eliminate sparse warning - bad constant expression" This reverts commit 2d20ca835867d93ead6ce61780d883a4b128106d. The change to kernel crypto and fixes to ntlvm2 and ntlmssp series, introduced a regression. Deferring this patch series to 2.6.37 after Shirish fixes it. Signed-off-by: Steve French Acked-by: Jeff Layton CC: Shirish Pargaonkar --- fs/cifs/cifsencrypt.c | 193 +++++++++++++++++++------------------------------- fs/cifs/cifsglob.h | 7 -- 2 files changed, 72 insertions(+), 128 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 709f2296bdb4..eef78c24e0cc 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -45,38 +45,39 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, char *signature) { - int rc; + int rc = 0; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; + } sdesc; if (cifs_pdu == NULL || server == NULL || signature == NULL) return -EINVAL; - if (!server->ntlmssp.sdescmd5) { - cERROR(1, - "cifs_calculate_signature: can't generate signature\n"); - return -1; - } + sdesc.shash.tfm = server->ntlmssp.md5; + sdesc.shash.flags = 0x0; - rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash); + rc = crypto_shash_init(&sdesc.shash); if (rc) { - cERROR(1, "cifs_calculate_signature: oould not init md5\n"); + cERROR(1, "could not initialize master crypto API hmacmd5\n"); return rc; } if (server->secType == RawNTLMSSP) - crypto_shash_update(&server->ntlmssp.sdescmd5->shash, + crypto_shash_update(&sdesc.shash, server->session_key.data.ntlmv2.key, CIFS_NTLMV2_SESSKEY_SIZE); else - crypto_shash_update(&server->ntlmssp.sdescmd5->shash, + crypto_shash_update(&sdesc.shash, (char *)&server->session_key.data, server->session_key.len); - crypto_shash_update(&server->ntlmssp.sdescmd5->shash, + crypto_shash_update(&sdesc.shash, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); - rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature); + rc = crypto_shash_final(&sdesc.shash, signature); - return rc; + return 0; } @@ -114,28 +115,30 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, struct TCP_Server_Info *server, char *signature) { int i; - int rc; + int rc = 0; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; + } sdesc; if (iov == NULL || server == NULL || signature == NULL) return -EINVAL; - if (!server->ntlmssp.sdescmd5) { - cERROR(1, "cifs_calc_signature2: can't generate signature\n"); - return -1; - } + sdesc.shash.tfm = server->ntlmssp.md5; + sdesc.shash.flags = 0x0; - rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash); + rc = crypto_shash_init(&sdesc.shash); if (rc) { - cERROR(1, "cifs_calc_signature2: oould not init md5\n"); + cERROR(1, "could not initialize master crypto API hmacmd5\n"); return rc; } if (server->secType == RawNTLMSSP) - crypto_shash_update(&server->ntlmssp.sdescmd5->shash, + crypto_shash_update(&sdesc.shash, server->session_key.data.ntlmv2.key, CIFS_NTLMV2_SESSKEY_SIZE); else - crypto_shash_update(&server->ntlmssp.sdescmd5->shash, + crypto_shash_update(&sdesc.shash, (char *)&server->session_key.data, server->session_key.len); @@ -143,7 +146,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, if (iov[i].iov_len == 0) continue; if (iov[i].iov_base == NULL) { - cERROR(1, "cifs_calc_signature2: null iovec entry"); + cERROR(1, "null iovec entry"); return -EIO; } /* The first entry includes a length field (which does not get @@ -151,16 +154,16 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, if (i == 0) { if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ break; /* nothing to sign or corrupt header */ - crypto_shash_update(&server->ntlmssp.sdescmd5->shash, + crypto_shash_update(&sdesc.shash, iov[i].iov_base + 4, iov[i].iov_len - 4); } else - crypto_shash_update(&server->ntlmssp.sdescmd5->shash, + crypto_shash_update(&sdesc.shash, iov[i].iov_base, iov[i].iov_len); } - rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature); + rc = crypto_shash_final(&sdesc.shash, signature); - return rc; + return 0; } int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, @@ -310,48 +313,43 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, wchar_t *user; wchar_t *domain; wchar_t *server; - - if (!ses->server->ntlmssp.sdeschmacmd5) { - cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); - return -1; - } + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; + } sdesc; /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); + sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; + sdesc.shash.flags = 0x0; + crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, nt_hash, CIFS_NTHASH_SIZE); - rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash); + rc = crypto_shash_init(&sdesc.shash); if (rc) { - cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); + cERROR(1, "could not initialize master crypto API hmacmd5\n"); return rc; } /* convert ses->userName to unicode and uppercase */ len = strlen(ses->userName); user = kmalloc(2 + (len * 2), GFP_KERNEL); - if (user == NULL) { - cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); - rc = -ENOMEM; + if (user == NULL) goto calc_exit_2; - } len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); - crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, - (char *)user, 2 * len); + crypto_shash_update(&sdesc.shash, (char *)user, 2 * len); /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { len = strlen(ses->domainName); domain = kmalloc(2 + (len * 2), GFP_KERNEL); - if (domain == NULL) { - cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); - rc = -ENOMEM; + if (domain == NULL) goto calc_exit_1; - } len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, nls_cp); /* the following line was removed since it didn't work well @@ -359,19 +357,15 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, Maybe converting the domain name earlier makes sense */ /* UniStrupr(domain); */ - crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, - (char *)domain, 2 * len); + crypto_shash_update(&sdesc.shash, (char *)domain, 2 * len); kfree(domain); } else if (ses->serverName) { len = strlen(ses->serverName); server = kmalloc(2 + (len * 2), GFP_KERNEL); - if (server == NULL) { - cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); - rc = -ENOMEM; + if (server == NULL) goto calc_exit_1; - } len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, nls_cp); /* the following line was removed since it didn't work well @@ -379,20 +373,16 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, Maybe converting the domain name earlier makes sense */ /* UniStrupr(domain); */ - crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, - (char *)server, 2 * len); + crypto_shash_update(&sdesc.shash, (char *)server, 2 * len); kfree(server); } - - rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash, - ses->server->ntlmv2_hash); - calc_exit_1: kfree(user); calc_exit_2: /* BB FIXME what about bytes 24 through 40 of the signing key? compare with the NTLM example */ + rc = crypto_shash_final(&sdesc.shash, ses->server->ntlmv2_hash); return rc; } @@ -452,33 +442,34 @@ CalcNTLMv2_response(const struct TCP_Server_Info *server, char *v2_session_response) { int rc; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(server->ntlmssp.hmacmd5)]; + } sdesc; - if (!server->ntlmssp.sdeschmacmd5) { - cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); - return -1; - } + sdesc.shash.tfm = server->ntlmssp.hmacmd5; + sdesc.shash.flags = 0x0; crypto_shash_setkey(server->ntlmssp.hmacmd5, server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - rc = crypto_shash_init(&server->ntlmssp.sdeschmacmd5->shash); + rc = crypto_shash_init(&sdesc.shash); if (rc) { - cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); + cERROR(1, "could not initialize master crypto API hmacmd5\n"); return rc; } memcpy(v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, server->cryptKey, CIFS_SERVER_CHALLENGE_SIZE); - crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash, + crypto_shash_update(&sdesc.shash, v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, sizeof(struct ntlmv2_resp) - CIFS_SERVER_CHALLENGE_SIZE); if (server->tilen) - crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash, + crypto_shash_update(&sdesc.shash, server->tiblob, server->tilen); - rc = crypto_shash_final(&server->ntlmssp.sdeschmacmd5->shash, - v2_session_response); + rc = crypto_shash_final(&sdesc.shash, v2_session_response); return rc; } @@ -489,6 +480,10 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, { int rc = 0; struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; + } sdesc; buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; @@ -516,24 +511,21 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, return rc; } - if (!ses->server->ntlmssp.sdeschmacmd5) { - cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); - return -1; - } - crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, ses->server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash); + sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; + sdesc.shash.flags = 0x0; + + rc = crypto_shash_init(&sdesc.shash); if (rc) { - cERROR(1, "setup_ntlmv2_rsp: could not init hmacmd5\n"); + cERROR(1, "could not initialize master crypto API hmacmd5\n"); return rc; } - crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, - resp_buf, CIFS_HMAC_MD5_HASH_SIZE); + crypto_shash_update(&sdesc.shash, resp_buf, CIFS_HMAC_MD5_HASH_SIZE); - rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash, + rc = crypto_shash_final(&sdesc.shash, ses->server->session_key.data.ntlmv2.key); memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, @@ -586,65 +578,24 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server) if (server->ntlmssp.hmacmd5) crypto_free_shash(server->ntlmssp.hmacmd5); - - kfree(server->ntlmssp.sdeschmacmd5); - - kfree(server->ntlmssp.sdescmd5); } int cifs_crypto_shash_allocate(struct TCP_Server_Info *server) { - int rc; - unsigned int size; - server->ntlmssp.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); if (!server->ntlmssp.hmacmd5 || IS_ERR(server->ntlmssp.hmacmd5)) { - cERROR(1, "could not allocate crypto hmacmd5\n"); + cERROR(1, "could not allocate master crypto API hmacmd5\n"); return 1; } server->ntlmssp.md5 = crypto_alloc_shash("md5", 0, 0); if (!server->ntlmssp.md5 || IS_ERR(server->ntlmssp.md5)) { - cERROR(1, "could not allocate crypto md5\n"); - rc = 1; - goto cifs_crypto_shash_allocate_ret1; - } - - size = sizeof(struct shash_desc) + - crypto_shash_descsize(server->ntlmssp.hmacmd5); - server->ntlmssp.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); - if (!server->ntlmssp.sdeschmacmd5) { - cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); - rc = -ENOMEM; - goto cifs_crypto_shash_allocate_ret2; - } - server->ntlmssp.sdeschmacmd5->shash.tfm = server->ntlmssp.hmacmd5; - server->ntlmssp.sdeschmacmd5->shash.flags = 0x0; - - - size = sizeof(struct shash_desc) + - crypto_shash_descsize(server->ntlmssp.md5); - server->ntlmssp.sdescmd5 = kmalloc(size, GFP_KERNEL); - if (!server->ntlmssp.sdescmd5) { - cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); - rc = -ENOMEM; - goto cifs_crypto_shash_allocate_ret3; + crypto_free_shash(server->ntlmssp.hmacmd5); + cERROR(1, "could not allocate master crypto API md5\n"); + return 1; } - server->ntlmssp.sdescmd5->shash.tfm = server->ntlmssp.md5; - server->ntlmssp.sdescmd5->shash.flags = 0x0; return 0; - -cifs_crypto_shash_allocate_ret3: - kfree(server->ntlmssp.sdeschmacmd5); - -cifs_crypto_shash_allocate_ret2: - crypto_free_shash(server->ntlmssp.md5); - -cifs_crypto_shash_allocate_ret1: - crypto_free_shash(server->ntlmssp.hmacmd5); - - return rc; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c9d0cfc086eb..49563e0c1725 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -123,19 +123,12 @@ struct cifs_cred { struct cifs_ace *aces; }; -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - struct ntlmssp_auth { __u32 client_flags; __u32 server_flags; unsigned char ciphertext[CIFS_CPHTXT_SIZE]; struct crypto_shash *hmacmd5; struct crypto_shash *md5; - struct sdesc *sdeschmacmd5; - struct sdesc *sdescmd5; }; /* -- cgit v1.2.3-59-g8ed1b From ee9c5cfad29c8a13199962614b9b16f1c4137ac9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 7 Sep 2010 04:35:19 +0000 Subject: niu: Fix kernel buffer overflow for ETHTOOL_GRXCLSRLALL niu_get_ethtool_tcam_all() assumes that its output buffer is the right size, and warns before returning if it is not. However, the output buffer size is under user control and ETHTOOL_GRXCLSRLALL is an unprivileged ethtool command. Therefore this is at least a local denial-of-service vulnerability. Change it to check before writing each entry and to return an error if the buffer is already full. Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/niu.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/niu.c b/drivers/net/niu.c index b9b950845b0e..340cbec48943 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -7272,32 +7272,28 @@ static int niu_get_ethtool_tcam_all(struct niu *np, struct niu_parent *parent = np->parent; struct niu_tcam_entry *tp; int i, idx, cnt; - u16 n_entries; unsigned long flags; - + int ret = 0; /* put the tcam size here */ nfc->data = tcam_get_size(np); niu_lock_parent(np, flags); - n_entries = nfc->rule_cnt; for (cnt = 0, i = 0; i < nfc->data; i++) { idx = tcam_get_index(np, i); tp = &parent->tcam[idx]; if (!tp->valid) continue; + if (cnt == nfc->rule_cnt) { + ret = -EMSGSIZE; + break; + } rule_locs[cnt] = i; cnt++; } niu_unlock_parent(np, flags); - if (n_entries != cnt) { - /* print warning, this should not happen */ - netdev_info(np->dev, "niu%d: In %s(): n_entries[%d] != cnt[%d]!!!\n", - np->parent->index, __func__, n_entries, cnt); - } - - return 0; + return ret; } static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd, -- cgit v1.2.3-59-g8ed1b From 745e507a9c79c6e1385d3414d5e56f3d4621a375 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 8 Sep 2010 21:09:27 +0000 Subject: Revert "missing changes during ntlmv2/ntlmssp auth and sign" This reverts commit 3ec6bbcdb4e85403f2c5958876ca9492afdf4031. The change to kernel crypto and fixes to ntlvm2 and ntlmssp series, introduced a regression. Deferring this patch series to 2.6.37 after Shirish fixes it. Signed-off-by: Steve French Acked-by: Jeff Layton CC: Shirish Pargaonkar --- fs/cifs/cifsencrypt.c | 2 -- fs/cifs/sess.c | 13 +++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index eef78c24e0cc..051d00011ca3 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -553,8 +553,6 @@ calc_seckey(struct TCP_Server_Info *server) return 1; } - desc.tfm = tfm_arc4; - crypto_blkcipher_setkey(tfm_arc4, server->session_key.data.ntlmv2.key, CIFS_CPHTXT_SIZE); sg_init_one(&sgin, sec_key, CIFS_CPHTXT_SIZE); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 4788e16a02cc..41fc5328120d 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -408,8 +408,6 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ - ses->server->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags); - tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); tilen = cpu_to_le16(pblob->TargetInfoArray.Length); ses->server->tilen = tilen; @@ -442,13 +440,12 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, /* BB is NTLMV2 session security format easier to use here? */ flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NTLM; + NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { - flags |= NTLMSSP_NEGOTIATE_SIGN | - NTLMSSP_NEGOTIATE_KEY_XCH | - NTLMSSP_NEGOTIATE_EXTENDED_SEC; - } + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + flags |= NTLMSSP_NEGOTIATE_SIGN; + if (ses->server->secMode & SECMODE_SIGN_REQUIRED) + flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; sec_blob->NegotiateFlags |= cpu_to_le32(flags); -- cgit v1.2.3-59-g8ed1b From c8e56f1f4fb9f82f63e4ce6d73a14501d0432c76 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 8 Sep 2010 21:10:58 +0000 Subject: Revert "[CIFS] Fix ntlmv2 auth with ntlmssp" This reverts commit 9fbc590860e75785bdaf8b83e48fabfe4d4f7d58. The change to kernel crypto and fixes to ntlvm2 and ntlmssp series, introduced a regression. Deferring this patch series to 2.6.37 after Shirish fixes it. Signed-off-by: Steve French Acked-by: Jeff Layton CC: Shirish Pargaonkar --- fs/cifs/Kconfig | 2 - fs/cifs/asn1.c | 6 +- fs/cifs/cifsencrypt.c | 416 +++++++++++++++----------------------------------- fs/cifs/cifsglob.h | 18 +-- fs/cifs/cifspdu.h | 7 +- fs/cifs/cifsproto.h | 12 +- fs/cifs/cifssmb.c | 13 +- fs/cifs/connect.c | 13 +- fs/cifs/ntlmssp.h | 13 -- fs/cifs/sess.c | 118 ++++---------- fs/cifs/transport.c | 6 +- 11 files changed, 172 insertions(+), 452 deletions(-) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 0da1debd499d..917b7d449bb2 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -2,8 +2,6 @@ config CIFS tristate "CIFS support (advanced network filesystem, SMBFS successor)" depends on INET select NLS - select CRYPTO_MD5 - select CRYPTO_ARC4 help This is the client VFS module for the Common Internet File System (CIFS) protocol which is the successor to the Server Message Block diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 21f0fbd86989..cfd1ce34e0bc 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -597,13 +597,13 @@ decode_negTokenInit(unsigned char *security_blob, int length, if (compare_oid(oid, oidlen, MSKRB5_OID, MSKRB5_OID_LEN)) server->sec_mskerberos = true; - if (compare_oid(oid, oidlen, KRB5U2U_OID, + else if (compare_oid(oid, oidlen, KRB5U2U_OID, KRB5U2U_OID_LEN)) server->sec_kerberosu2u = true; - if (compare_oid(oid, oidlen, KRB5_OID, + else if (compare_oid(oid, oidlen, KRB5_OID, KRB5_OID_LEN)) server->sec_kerberos = true; - if (compare_oid(oid, oidlen, NTLMSSP_OID, + else if (compare_oid(oid, oidlen, NTLMSSP_OID, NTLMSSP_OID_LEN)) server->sec_ntlmssp = true; diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 051d00011ca3..847628dfdc44 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -27,7 +27,6 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" -#include "ntlmssp.h" #include #include @@ -43,44 +42,21 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, - struct TCP_Server_Info *server, char *signature) + const struct mac_key *key, char *signature) { - int rc = 0; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; - } sdesc; + struct MD5Context context; - if (cifs_pdu == NULL || server == NULL || signature == NULL) + if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) return -EINVAL; - sdesc.shash.tfm = server->ntlmssp.md5; - sdesc.shash.flags = 0x0; - - rc = crypto_shash_init(&sdesc.shash); - if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); - return rc; - } - - if (server->secType == RawNTLMSSP) - crypto_shash_update(&sdesc.shash, - server->session_key.data.ntlmv2.key, - CIFS_NTLMV2_SESSKEY_SIZE); - else - crypto_shash_update(&sdesc.shash, - (char *)&server->session_key.data, - server->session_key.len); - - crypto_shash_update(&sdesc.shash, - cifs_pdu->Protocol, cifs_pdu->smb_buf_length); - - rc = crypto_shash_final(&sdesc.shash, signature); + cifs_MD5_init(&context); + cifs_MD5_update(&context, (char *)&key->data, key->len); + cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); + cifs_MD5_final(signature, &context); return 0; } - int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, __u32 *pexpected_response_sequence_number) { @@ -102,7 +78,8 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); + rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, + smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else @@ -112,36 +89,16 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, } static int cifs_calc_signature2(const struct kvec *iov, int n_vec, - struct TCP_Server_Info *server, char *signature) + const struct mac_key *key, char *signature) { + struct MD5Context context; int i; - int rc = 0; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(server->ntlmssp.md5)]; - } sdesc; - if (iov == NULL || server == NULL || signature == NULL) + if ((iov == NULL) || (signature == NULL) || (key == NULL)) return -EINVAL; - sdesc.shash.tfm = server->ntlmssp.md5; - sdesc.shash.flags = 0x0; - - rc = crypto_shash_init(&sdesc.shash); - if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); - return rc; - } - - if (server->secType == RawNTLMSSP) - crypto_shash_update(&sdesc.shash, - server->session_key.data.ntlmv2.key, - CIFS_NTLMV2_SESSKEY_SIZE); - else - crypto_shash_update(&sdesc.shash, - (char *)&server->session_key.data, - server->session_key.len); - + cifs_MD5_init(&context); + cifs_MD5_update(&context, (char *)&key->data, key->len); for (i = 0; i < n_vec; i++) { if (iov[i].iov_len == 0) continue; @@ -154,18 +111,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, if (i == 0) { if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ break; /* nothing to sign or corrupt header */ - crypto_shash_update(&sdesc.shash, - iov[i].iov_base + 4, iov[i].iov_len - 4); + cifs_MD5_update(&context, iov[0].iov_base+4, + iov[0].iov_len-4); } else - crypto_shash_update(&sdesc.shash, - iov[i].iov_base, iov[i].iov_len); + cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); } - rc = crypto_shash_final(&sdesc.shash, signature); + cifs_MD5_final(signature, &context); return 0; } + int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, __u32 *pexpected_response_sequence_number) { @@ -188,7 +145,8 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, server->sequence_number++; spin_unlock(&GlobalMid_Lock); - rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); + rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, + smb_signature); if (rc) memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else @@ -198,14 +156,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, } int cifs_verify_signature(struct smb_hdr *cifs_pdu, - struct TCP_Server_Info *server, + const struct mac_key *mac_key, __u32 expected_sequence_number) { - int rc; + unsigned int rc; char server_response_sig[8]; char what_we_think_sig_should_be[20]; - if (cifs_pdu == NULL || server == NULL) + if ((cifs_pdu == NULL) || (mac_key == NULL)) return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) @@ -234,7 +192,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; - rc = cifs_calculate_signature(cifs_pdu, server, + rc = cifs_calculate_signature(cifs_pdu, mac_key, what_we_think_sig_should_be); if (rc) @@ -251,7 +209,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, } /* We fill in key by putting in 40 byte array which was allocated by caller */ -int cifs_calculate_session_key(struct session_key *key, const char *rn, +int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *password) { char temp_key[16]; @@ -265,6 +223,63 @@ int cifs_calculate_session_key(struct session_key *key, const char *rn, return 0; } +int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses, + const struct nls_table *nls_info) +{ + char temp_hash[16]; + struct HMACMD5Context ctx; + char *ucase_buf; + __le16 *unicode_buf; + unsigned int i, user_name_len, dom_name_len; + + if (ses == NULL) + return -EINVAL; + + E_md4hash(ses->password, temp_hash); + + hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); + user_name_len = strlen(ses->userName); + if (user_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + if (ses->domainName == NULL) + return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ + dom_name_len = strlen(ses->domainName); + if (dom_name_len > MAX_USERNAME_SIZE) + return -EINVAL; + + ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); + if (ucase_buf == NULL) + return -ENOMEM; + unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); + if (unicode_buf == NULL) { + kfree(ucase_buf); + return -ENOMEM; + } + + for (i = 0; i < user_name_len; i++) + ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; + ucase_buf[i] = 0; + user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, + MAX_USERNAME_SIZE*2, nls_info); + unicode_buf[user_name_len] = 0; + user_name_len++; + + for (i = 0; i < dom_name_len; i++) + ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; + ucase_buf[i] = 0; + dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, + MAX_USERNAME_SIZE*2, nls_info); + + unicode_buf[user_name_len + dom_name_len] = 0; + hmac_md5_update((const unsigned char *) unicode_buf, + (user_name_len+dom_name_len)*2, &ctx); + + hmac_md5_final(ses->server->ntlmv2_hash, &ctx); + kfree(ucase_buf); + kfree(unicode_buf); + return 0; +} + #ifdef CONFIG_CIFS_WEAK_PW_HASH void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key) @@ -309,29 +324,21 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, { int rc = 0; int len; - char nt_hash[CIFS_NTHASH_SIZE]; + char nt_hash[16]; + struct HMACMD5Context *pctxt; wchar_t *user; wchar_t *domain; - wchar_t *server; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; - } sdesc; - /* calculate md4 hash of password */ - E_md4hash(ses->password, nt_hash); + pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); - sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; - sdesc.shash.flags = 0x0; + if (pctxt == NULL) + return -ENOMEM; - crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, nt_hash, - CIFS_NTHASH_SIZE); + /* calculate md4 hash of password */ + E_md4hash(ses->password, nt_hash); - rc = crypto_shash_init(&sdesc.shash); - if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); - return rc; - } + /* convert Domainname to unicode and uppercase */ + hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); /* convert ses->userName to unicode and uppercase */ len = strlen(ses->userName); @@ -340,8 +347,7 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, goto calc_exit_2; len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); - - crypto_shash_update(&sdesc.shash, (char *)user, 2 * len); + hmac_md5_update((char *)user, 2*len, pctxt); /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { @@ -357,243 +363,65 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, Maybe converting the domain name earlier makes sense */ /* UniStrupr(domain); */ - crypto_shash_update(&sdesc.shash, (char *)domain, 2 * len); + hmac_md5_update((char *)domain, 2*len, pctxt); kfree(domain); - } else if (ses->serverName) { - len = strlen(ses->serverName); - - server = kmalloc(2 + (len * 2), GFP_KERNEL); - if (server == NULL) - goto calc_exit_1; - len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, - nls_cp); - /* the following line was removed since it didn't work well - with lower cased domain name that passed as an option. - Maybe converting the domain name earlier makes sense */ - /* UniStrupr(domain); */ - - crypto_shash_update(&sdesc.shash, (char *)server, 2 * len); - - kfree(server); } calc_exit_1: kfree(user); calc_exit_2: /* BB FIXME what about bytes 24 through 40 of the signing key? compare with the NTLM example */ - rc = crypto_shash_final(&sdesc.shash, ses->server->ntlmv2_hash); - - return rc; -} - -static int -find_domain_name(struct cifsSesInfo *ses) -{ - int rc = 0; - unsigned int attrsize; - unsigned int type; - unsigned char *blobptr; - struct ntlmssp2_name *attrptr; - - if (ses->server->tiblob) { - blobptr = ses->server->tiblob; - attrptr = (struct ntlmssp2_name *) blobptr; - - while ((type = attrptr->type) != 0) { - blobptr += 2; /* advance attr type */ - attrsize = attrptr->length; - blobptr += 2; /* advance attr size */ - if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { - if (!ses->domainName) { - ses->domainName = - kmalloc(attrptr->length + 1, - GFP_KERNEL); - if (!ses->domainName) - return -ENOMEM; - cifs_from_ucs2(ses->domainName, - (__le16 *)blobptr, - attrptr->length, - attrptr->length, - load_nls_default(), false); - } - } - blobptr += attrsize; /* advance attr value */ - attrptr = (struct ntlmssp2_name *) blobptr; - } - } else { - ses->server->tilen = 2 * sizeof(struct ntlmssp2_name); - ses->server->tiblob = kmalloc(ses->server->tilen, GFP_KERNEL); - if (!ses->server->tiblob) { - ses->server->tilen = 0; - cERROR(1, "Challenge target info allocation failure"); - return -ENOMEM; - } - memset(ses->server->tiblob, 0x0, ses->server->tilen); - attrptr = (struct ntlmssp2_name *) ses->server->tiblob; - attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); - } + hmac_md5_final(ses->server->ntlmv2_hash, pctxt); + kfree(pctxt); return rc; } -static int -CalcNTLMv2_response(const struct TCP_Server_Info *server, - char *v2_session_response) -{ - int rc; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(server->ntlmssp.hmacmd5)]; - } sdesc; - - sdesc.shash.tfm = server->ntlmssp.hmacmd5; - sdesc.shash.flags = 0x0; - - crypto_shash_setkey(server->ntlmssp.hmacmd5, server->ntlmv2_hash, - CIFS_HMAC_MD5_HASH_SIZE); - - rc = crypto_shash_init(&sdesc.shash); - if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); - return rc; - } - - memcpy(v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, - server->cryptKey, CIFS_SERVER_CHALLENGE_SIZE); - crypto_shash_update(&sdesc.shash, - v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, - sizeof(struct ntlmv2_resp) - CIFS_SERVER_CHALLENGE_SIZE); - - if (server->tilen) - crypto_shash_update(&sdesc.shash, - server->tiblob, server->tilen); - - rc = crypto_shash_final(&sdesc.shash, v2_session_response); - - return rc; -} - -int -setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, +void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, const struct nls_table *nls_cp) { - int rc = 0; + int rc; struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; - struct { - struct shash_desc shash; - char ctx[crypto_shash_descsize(ses->server->ntlmssp.hmacmd5)]; - } sdesc; + struct HMACMD5Context context; buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; - - if (!ses->domainName) { - rc = find_domain_name(ses); - if (rc) { - cERROR(1, "could not get domain/server name rc %d", rc); - return rc; - } - } + buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); + buf->names[0].length = 0; + buf->names[1].type = 0; + buf->names[1].length = 0; /* calculate buf->ntlmv2_hash */ rc = calc_ntlmv2_hash(ses, nls_cp); - if (rc) { - cERROR(1, "could not get v2 hash rc %d", rc); - return rc; - } - rc = CalcNTLMv2_response(ses->server, resp_buf); - if (rc) { + if (rc) cERROR(1, "could not get v2 hash rc %d", rc); - return rc; - } - - crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, - ses->server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); - - sdesc.shash.tfm = ses->server->ntlmssp.hmacmd5; - sdesc.shash.flags = 0x0; - - rc = crypto_shash_init(&sdesc.shash); - if (rc) { - cERROR(1, "could not initialize master crypto API hmacmd5\n"); - return rc; - } - - crypto_shash_update(&sdesc.shash, resp_buf, CIFS_HMAC_MD5_HASH_SIZE); + CalcNTLMv2_response(ses, resp_buf); - rc = crypto_shash_final(&sdesc.shash, - ses->server->session_key.data.ntlmv2.key); + /* now calculate the MAC key for NTLMv2 */ + hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); + hmac_md5_update(resp_buf, 16, &context); + hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); - memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, - sizeof(struct ntlmv2_resp)); - ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); - - return rc; + memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, + sizeof(struct ntlmv2_resp)); + ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); } -int -calc_seckey(struct TCP_Server_Info *server) -{ - int rc; - unsigned char sec_key[CIFS_NTLMV2_SESSKEY_SIZE]; - struct crypto_blkcipher *tfm_arc4; - struct scatterlist sgin, sgout; - struct blkcipher_desc desc; - - get_random_bytes(sec_key, CIFS_NTLMV2_SESSKEY_SIZE); - - tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", - 0, CRYPTO_ALG_ASYNC); - if (!tfm_arc4 || IS_ERR(tfm_arc4)) { - cERROR(1, "could not allocate " "master crypto API arc4\n"); - return 1; - } - - crypto_blkcipher_setkey(tfm_arc4, - server->session_key.data.ntlmv2.key, CIFS_CPHTXT_SIZE); - sg_init_one(&sgin, sec_key, CIFS_CPHTXT_SIZE); - sg_init_one(&sgout, server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); - rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); - - if (!rc) - memcpy(server->session_key.data.ntlmv2.key, - sec_key, CIFS_NTLMV2_SESSKEY_SIZE); - - crypto_free_blkcipher(tfm_arc4); - - return 0; -} - -void -cifs_crypto_shash_release(struct TCP_Server_Info *server) -{ - if (server->ntlmssp.md5) - crypto_free_shash(server->ntlmssp.md5); - - if (server->ntlmssp.hmacmd5) - crypto_free_shash(server->ntlmssp.hmacmd5); -} - -int -cifs_crypto_shash_allocate(struct TCP_Server_Info *server) +void CalcNTLMv2_response(const struct cifsSesInfo *ses, + char *v2_session_response) { - server->ntlmssp.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); - if (!server->ntlmssp.hmacmd5 || - IS_ERR(server->ntlmssp.hmacmd5)) { - cERROR(1, "could not allocate master crypto API hmacmd5\n"); - return 1; - } + struct HMACMD5Context context; + /* rest of v2 struct already generated */ + memcpy(v2_session_response + 8, ses->server->cryptKey, 8); + hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); - server->ntlmssp.md5 = crypto_alloc_shash("md5", 0, 0); - if (!server->ntlmssp.md5 || IS_ERR(server->ntlmssp.md5)) { - crypto_free_shash(server->ntlmssp.hmacmd5); - cERROR(1, "could not allocate master crypto API md5\n"); - return 1; - } + hmac_md5_update(v2_session_response+8, + sizeof(struct ntlmv2_resp) - 8, &context); - return 0; + hmac_md5_final(v2_session_response, &context); +/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 49563e0c1725..0cdfb8c32ac6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -25,9 +25,6 @@ #include #include "cifs_fs_sb.h" #include "cifsacl.h" -#include -#include - /* * The sizes of various internal tables and strings */ @@ -100,7 +97,7 @@ enum protocolEnum { /* Netbios frames protocol not supported at this time */ }; -struct session_key { +struct mac_key { unsigned int len; union { char ntlm[CIFS_SESS_KEY_SIZE + 16]; @@ -123,14 +120,6 @@ struct cifs_cred { struct cifs_ace *aces; }; -struct ntlmssp_auth { - __u32 client_flags; - __u32 server_flags; - unsigned char ciphertext[CIFS_CPHTXT_SIZE]; - struct crypto_shash *hmacmd5; - struct crypto_shash *md5; -}; - /* ***************************************************************** * Except the CIFS PDUs themselves all the @@ -193,14 +182,11 @@ struct TCP_Server_Info { /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ - struct session_key session_key; + struct mac_key mac_signing_key; char ntlmv2_hash[16]; unsigned long lstrp; /* when we got last response from this server */ u16 dialect; /* dialect index that server chose */ /* extended security flavors that server supports */ - unsigned int tilen; /* length of the target info blob */ - unsigned char *tiblob; /* target info blob in challenge response */ - struct ntlmssp_auth ntlmssp; /* various keys, ciphers, flags */ bool sec_kerberos; /* supports plain Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_kerberosu2u; /* supports U2U Kerberos */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 320e0fd0ba7b..14d036d8db11 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -134,12 +134,6 @@ * Size of the session key (crypto key encrypted with the password */ #define CIFS_SESS_KEY_SIZE (24) -#define CIFS_CLIENT_CHALLENGE_SIZE (8) -#define CIFS_SERVER_CHALLENGE_SIZE (8) -#define CIFS_HMAC_MD5_HASH_SIZE (16) -#define CIFS_CPHTXT_SIZE (16) -#define CIFS_NTLMV2_SESSKEY_SIZE (16) -#define CIFS_NTHASH_SIZE (16) /* * Maximum user name length @@ -669,6 +663,7 @@ struct ntlmv2_resp { __le64 time; __u64 client_chal; /* random */ __u32 reserved2; + struct ntlmssp2_name names[2]; /* array of name entries could follow ending in minimum 4 byte struct */ } __attribute__((packed)); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1378d9133844..1f5450814087 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -361,15 +361,15 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, __u32 *); extern int cifs_verify_signature(struct smb_hdr *, - struct TCP_Server_Info *server, + const struct mac_key *mac_key, __u32 expected_sequence_number); -extern int cifs_calculate_session_key(struct session_key *key, const char *rn, +extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *pass); -extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *, +extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, + const struct nls_table *); +extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); +extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, const struct nls_table *); -extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); -extern void cifs_crypto_shash_release(struct TCP_Server_Info *); -extern int calc_seckey(struct TCP_Server_Info *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4bda920d1f75..c65c3419dd37 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -604,14 +604,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) else rc = -EINVAL; - if (server->secType == Kerberos) { - if (!server->sec_kerberos && - !server->sec_mskerberos) - rc = -EOPNOTSUPP; - } else if (server->secType == RawNTLMSSP) { - if (!server->sec_ntlmssp) - rc = -EOPNOTSUPP; - } else + if (server->sec_kerberos || server->sec_mskerberos) + server->secType = Kerberos; + else if (server->sec_ntlmssp) + server->secType = RawNTLMSSP; + else rc = -EOPNOTSUPP; } } else diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ec0ea4a43bdb..0ea52e9f9065 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1708,7 +1708,6 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) CIFSSMBLogoff(xid, ses); _FreeXid(xid); } - cifs_crypto_shash_release(server); sesInfoFree(ses); cifs_put_tcp_session(server); } @@ -1788,23 +1787,13 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ses->linux_uid = volume_info->linux_uid; ses->overrideSecFlg = volume_info->secFlg; - rc = cifs_crypto_shash_allocate(server); - if (rc) { - cERROR(1, "could not setup hash structures rc %d", rc); - goto get_ses_fail; - } - server->tilen = 0; - server->tiblob = NULL; - mutex_lock(&ses->session_mutex); rc = cifs_negotiate_protocol(xid, ses); if (!rc) rc = cifs_setup_session(xid, ses, volume_info->local_nls); mutex_unlock(&ses->session_mutex); - if (rc) { - cifs_crypto_shash_release(ses->server); + if (rc) goto get_ses_fail; - } /* success, put it on the list */ write_lock(&cifs_tcp_ses_lock); diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 1db0f0746a5b..49c9a4e75319 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h @@ -61,19 +61,6 @@ #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 #define NTLMSSP_NEGOTIATE_56 0x80000000 -/* Define AV Pair Field IDs */ -#define NTLMSSP_AV_EOL 0 -#define NTLMSSP_AV_NB_COMPUTER_NAME 1 -#define NTLMSSP_AV_NB_DOMAIN_NAME 2 -#define NTLMSSP_AV_DNS_COMPUTER_NAME 3 -#define NTLMSSP_AV_DNS_DOMAIN_NAME 4 -#define NTLMSSP_AV_DNS_TREE_NAME 5 -#define NTLMSSP_AV_FLAGS 6 -#define NTLMSSP_AV_TIMESTAMP 7 -#define NTLMSSP_AV_RESTRICTION 8 -#define NTLMSSP_AV_TARGET_NAME 9 -#define NTLMSSP_AV_CHANNEL_BINDINGS 10 - /* Although typedefs are not commonly used for structure definitions */ /* in the Linux kernel, in this particular case they are useful */ /* to more closely match the standards document for NTLMSSP from */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 41fc5328120d..0a57cb7db5dd 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -383,9 +383,6 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifsSesInfo *ses) { - unsigned int tioffset; /* challeng message target info area */ - unsigned int tilen; /* challeng message target info area length */ - CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; if (blob_len < sizeof(CHALLENGE_MESSAGE)) { @@ -408,18 +405,6 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ - tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); - tilen = cpu_to_le16(pblob->TargetInfoArray.Length); - ses->server->tilen = tilen; - if (tilen) { - ses->server->tiblob = kmalloc(tilen, GFP_KERNEL); - if (!ses->server->tiblob) { - cERROR(1, "Challenge target info allocation failure"); - return -ENOMEM; - } - memcpy(ses->server->tiblob, bcc_ptr + tioffset, tilen); - } - return 0; } @@ -466,12 +451,10 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, struct cifsSesInfo *ses, const struct nls_table *nls_cp, bool first) { - int rc; - unsigned int size; AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; __u32 flags; unsigned char *tmp; - struct ntlmv2_resp ntlmv2_response = {}; + char ntlm_session_key[CIFS_SESS_KEY_SIZE]; memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); sec_blob->MessageType = NtLmAuthenticate; @@ -494,25 +477,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->LmChallengeResponse.Length = 0; sec_blob->LmChallengeResponse.MaximumLength = 0; - sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); - rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); - if (rc) { - cERROR(1, "error rc: %d during ntlmssp ntlmv2 setup", rc); - goto setup_ntlmv2_ret; - } - size = sizeof(struct ntlmv2_resp); - memcpy(tmp, (char *)&ntlmv2_response, size); - tmp += size; - if (ses->server->tilen > 0) { - memcpy(tmp, ses->server->tiblob, ses->server->tilen); - tmp += ses->server->tilen; - } else - ses->server->tilen = 0; + /* calculate session key, BB what about adding similar ntlmv2 path? */ + SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); + if (first) + cifs_calculate_mac_key(&ses->server->mac_signing_key, + ntlm_session_key, ses->password); - sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + - ses->server->tilen); + memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); + sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); + sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); sec_blob->NtChallengeResponse.MaximumLength = - cpu_to_le16(size + ses->server->tilen); + cpu_to_le16(CIFS_SESS_KEY_SIZE); + + tmp += CIFS_SESS_KEY_SIZE; if (ses->domainName == NULL) { sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); @@ -524,6 +501,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ + len += 2; /* trailing null */ sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.Length = cpu_to_le16(len); sec_blob->DomainName.MaximumLength = cpu_to_le16(len); @@ -540,6 +518,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, len = cifs_strtoUCS((__le16 *)tmp, ses->userName, MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ + len += 2; /* trailing null */ sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.Length = cpu_to_le16(len); sec_blob->UserName.MaximumLength = cpu_to_le16(len); @@ -551,26 +530,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, sec_blob->WorkstationName.MaximumLength = 0; tmp += 2; - if ((ses->server->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && - !calc_seckey(ses->server)) { - memcpy(tmp, ses->server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); - sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); - sec_blob->SessionKey.MaximumLength = - cpu_to_le16(CIFS_CPHTXT_SIZE); - tmp += CIFS_CPHTXT_SIZE; - } else { - sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); - sec_blob->SessionKey.Length = 0; - sec_blob->SessionKey.MaximumLength = 0; - } - - ses->server->sequence_number = 0; - -setup_ntlmv2_ret: - if (ses->server->tilen > 0) - kfree(ses->server->tiblob); - + sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); + sec_blob->SessionKey.Length = 0; + sec_blob->SessionKey.MaximumLength = 0; return tmp - pbuffer; } @@ -584,14 +546,15 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, return; } -static int setup_ntlmssp_auth_req(char *ntlmsspblob, +static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, struct cifsSesInfo *ses, const struct nls_table *nls, bool first_time) { int bloblen; - bloblen = build_ntlmssp_auth_blob(ntlmsspblob, ses, nls, + bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, first_time); + pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); return bloblen; } @@ -617,7 +580,6 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, struct key *spnego_key = NULL; __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ bool first_time; - char *ntlmsspblob; if (ses == NULL) return -EINVAL; @@ -728,7 +690,7 @@ ssetup_ntlmssp_authenticate: if (first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_session_key(&ses->server->session_key, + cifs_calculate_mac_key(&ses->server->mac_signing_key, ntlm_session_key, ses->password); /* copy session key */ @@ -767,21 +729,12 @@ ssetup_ntlmssp_authenticate: cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); - if (rc) { - kfree(v2_sess_key); - goto ssetup_exit; - } + setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); /* FIXME: calculate MAC key */ memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); - if (ses->server->tilen > 0) { - memcpy(bcc_ptr, ses->server->tiblob, - ses->server->tilen); - bcc_ptr += ses->server->tilen; - } if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; @@ -812,15 +765,15 @@ ssetup_ntlmssp_authenticate: } /* bail out if key is too long */ if (msg->sesskey_len > - sizeof(ses->server->session_key.data.krb5)) { + sizeof(ses->server->mac_signing_key.data.krb5)) { cERROR(1, "Kerberos signing key too long (%u bytes)", msg->sesskey_len); rc = -EOVERFLOW; goto ssetup_exit; } if (first_time) { - ses->server->session_key.len = msg->sesskey_len; - memcpy(ses->server->session_key.data.krb5, + ses->server->mac_signing_key.len = msg->sesskey_len; + memcpy(ses->server->mac_signing_key.data.krb5, msg->data, msg->sesskey_len); } pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; @@ -862,26 +815,12 @@ ssetup_ntlmssp_authenticate: if (phase == NtLmNegotiate) { setup_ntlmssp_neg_req(pSMB, ses); iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); - iov[1].iov_base = &pSMB->req.SecurityBlob[0]; } else if (phase == NtLmAuthenticate) { int blob_len; - ntlmsspblob = kmalloc(5 * - sizeof(struct _AUTHENTICATE_MESSAGE), - GFP_KERNEL); - if (!ntlmsspblob) { - cERROR(1, "Can't allocate NTLMSSP"); - rc = -ENOMEM; - goto ssetup_exit; - } - - blob_len = setup_ntlmssp_auth_req(ntlmsspblob, - ses, - nls_cp, - first_time); + blob_len = setup_ntlmssp_auth_req(pSMB, ses, + nls_cp, + first_time); iov[1].iov_len = blob_len; - iov[1].iov_base = ntlmsspblob; - pSMB->req.SecurityBlobLength = - cpu_to_le16(blob_len); /* Make sure that we tell the server that we are using the uid that it just gave us back on the response (challenge) */ @@ -891,6 +830,7 @@ ssetup_ntlmssp_authenticate: rc = -ENOSYS; goto ssetup_exit; } + iov[1].iov_base = &pSMB->req.SecurityBlob[0]; /* unicode strings must be word aligned */ if ((iov[0].iov_len + iov[1].iov_len) % 2) { *bcc_ptr = 0; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e0588cdf4cc5..82f78c4d6978 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -543,7 +543,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(midQ->resp_buf, - ses->server, + &ses->server->mac_signing_key, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -731,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - ses->server, + &ses->server->mac_signing_key, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); @@ -981,7 +981,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { rc = cifs_verify_signature(out_buf, - ses->server, + &ses->server->mac_signing_key, midQ->sequence_number+1); if (rc) { cERROR(1, "Unexpected SMB signature"); -- cgit v1.2.3-59-g8ed1b From 639e7a913d81f918bfbf506e6ecd54664f787cbd Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 3 Sep 2010 11:50:09 -0400 Subject: cifs: eliminate redundant xdev check in cifs_rename The VFS always checks that the source and target of a rename are on the same vfsmount, and hence have the same superblock. So, this check is redundant. Remove it and simplify the error handling. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 86a164f08a74..93f77d438d3c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1462,28 +1462,17 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, { char *fromName = NULL; char *toName = NULL; - struct cifs_sb_info *cifs_sb_source; - struct cifs_sb_info *cifs_sb_target; + struct cifs_sb_info *cifs_sb; struct cifsTconInfo *tcon; FILE_UNIX_BASIC_INFO *info_buf_source = NULL; FILE_UNIX_BASIC_INFO *info_buf_target; int xid, rc, tmprc; - cifs_sb_target = CIFS_SB(target_dir->i_sb); - cifs_sb_source = CIFS_SB(source_dir->i_sb); - tcon = cifs_sb_source->tcon; + cifs_sb = CIFS_SB(source_dir->i_sb); + tcon = cifs_sb->tcon; xid = GetXid(); - /* - * BB: this might be allowed if same server, but different share. - * Consider adding support for this - */ - if (tcon != cifs_sb_target->tcon) { - rc = -EXDEV; - goto cifs_rename_exit; - } - /* * we already have the rename sem so we do not need to * grab it again here to protect the path integrity @@ -1519,17 +1508,16 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, info_buf_target = info_buf_source + 1; tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, info_buf_source, - cifs_sb_source->local_nls, - cifs_sb_source->mnt_cifs_flags & + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (tmprc != 0) goto unlink_target; - tmprc = CIFSSMBUnixQPathInfo(xid, tcon, - toName, info_buf_target, - cifs_sb_target->local_nls, - /* remap based on source sb */ - cifs_sb_source->mnt_cifs_flags & + tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName, + info_buf_target, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (tmprc == 0 && (info_buf_source->UniqueId == -- cgit v1.2.3-59-g8ed1b From f6b085b69d1cbbd62f49f34e71a3d58cb6d34b7e Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Tue, 7 Sep 2010 07:51:17 +0000 Subject: ipv4: Suppress lockdep-RCU false positive in FIB trie (3) Hi, Here is one more of these warnings and a patch below: Sep 5 23:52:33 del kernel: [46044.244833] =================================================== Sep 5 23:52:33 del kernel: [46044.269681] [ INFO: suspicious rcu_dereference_check() usage. ] Sep 5 23:52:33 del kernel: [46044.277000] --------------------------------------------------- Sep 5 23:52:33 del kernel: [46044.285185] net/ipv4/fib_trie.c:1756 invoked rcu_dereference_check() without protection! Sep 5 23:52:33 del kernel: [46044.293627] Sep 5 23:52:33 del kernel: [46044.293632] other info that might help us debug this: Sep 5 23:52:33 del kernel: [46044.293634] Sep 5 23:52:33 del kernel: [46044.325333] Sep 5 23:52:33 del kernel: [46044.325335] rcu_scheduler_active = 1, debug_locks = 0 Sep 5 23:52:33 del kernel: [46044.348013] 1 lock held by pppd/1717: Sep 5 23:52:33 del kernel: [46044.357548] #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0xf/0x20 Sep 5 23:52:33 del kernel: [46044.367647] Sep 5 23:52:33 del kernel: [46044.367652] stack backtrace: Sep 5 23:52:33 del kernel: [46044.387429] Pid: 1717, comm: pppd Not tainted 2.6.35.4.4a #3 Sep 5 23:52:33 del kernel: [46044.398764] Call Trace: Sep 5 23:52:33 del kernel: [46044.409596] [] ? printk+0x18/0x1e Sep 5 23:52:33 del kernel: [46044.420761] [] lockdep_rcu_dereference+0xa9/0xb0 Sep 5 23:52:33 del kernel: [46044.432229] [] trie_firstleaf+0x65/0x70 Sep 5 23:52:33 del kernel: [46044.443941] [] fib_table_flush+0x14/0x170 Sep 5 23:52:33 del kernel: [46044.455823] [] ? local_bh_enable_ip+0x62/0xd0 Sep 5 23:52:33 del kernel: [46044.467995] [] ? _raw_spin_unlock_bh+0x2f/0x40 Sep 5 23:52:33 del kernel: [46044.480404] [] ? fib_sync_down_dev+0x120/0x180 Sep 5 23:52:33 del kernel: [46044.493025] [] fib_flush+0x2d/0x60 Sep 5 23:52:33 del kernel: [46044.505796] [] fib_disable_ip+0x25/0x50 Sep 5 23:52:33 del kernel: [46044.518772] [] fib_netdev_event+0x73/0xd0 Sep 5 23:52:33 del kernel: [46044.531918] [] notifier_call_chain+0x2d/0x70 Sep 5 23:52:33 del kernel: [46044.545358] [] raw_notifier_call_chain+0x1a/0x20 Sep 5 23:52:33 del kernel: [46044.559092] [] call_netdevice_notifiers+0x27/0x60 Sep 5 23:52:33 del kernel: [46044.573037] [] __dev_notify_flags+0x5c/0x80 Sep 5 23:52:33 del kernel: [46044.586489] [] dev_change_flags+0x37/0x60 Sep 5 23:52:33 del kernel: [46044.599394] [] devinet_ioctl+0x54d/0x630 Sep 5 23:52:33 del kernel: [46044.612277] [] inet_ioctl+0x97/0xc0 Sep 5 23:52:34 del kernel: [46044.625208] [] sock_ioctl+0x6f/0x270 Sep 5 23:52:34 del kernel: [46044.638046] [] ? handle_mm_fault+0x420/0x6c0 Sep 5 23:52:34 del kernel: [46044.650968] [] ? sock_ioctl+0x0/0x270 Sep 5 23:52:34 del kernel: [46044.663865] [] vfs_ioctl+0x28/0xa0 Sep 5 23:52:34 del kernel: [46044.676556] [] do_vfs_ioctl+0x6a/0x5c0 Sep 5 23:52:34 del kernel: [46044.688989] [] ? up_read+0x16/0x30 Sep 5 23:52:34 del kernel: [46044.701411] [] ? do_page_fault+0x1d6/0x3a0 Sep 5 23:52:34 del kernel: [46044.714223] [] ? fget_light+0xf8/0x2f0 Sep 5 23:52:34 del kernel: [46044.726601] [] ? sys_socketcall+0x208/0x2c0 Sep 5 23:52:34 del kernel: [46044.739140] [] sys_ioctl+0x63/0x70 Sep 5 23:52:34 del kernel: [46044.751967] [] syscall_call+0x7/0xb Sep 5 23:52:34 del kernel: [46044.764734] [] ? cookie_v6_check+0x3d0/0x630 --------------> This patch fixes the warning: =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- net/ipv4/fib_trie.c:1756 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 1 lock held by pppd/1717: #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0xf/0x20 stack backtrace: Pid: 1717, comm: pppd Not tainted 2.6.35.4a #3 Call Trace: [] ? printk+0x18/0x1e [] lockdep_rcu_dereference+0xa9/0xb0 [] trie_firstleaf+0x65/0x70 [] fib_table_flush+0x14/0x170 ... Allow trie_firstleaf() to be called either under rcu_read_lock() protection or with RTNL held. The same annotation is added to node_parent_rcu() to prevent a similar warning a bit later. Followup of commits 634a4b20 and 4eaa0e3c. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 79d057a939ba..4a8e370862bc 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -186,7 +186,9 @@ static inline struct tnode *node_parent_rcu(struct node *node) { struct tnode *ret = node_parent(node); - return rcu_dereference(ret); + return rcu_dereference_check(ret, + rcu_read_lock_held() || + lockdep_rtnl_is_held()); } /* Same as rcu_assign_pointer @@ -1753,7 +1755,9 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c) static struct leaf *trie_firstleaf(struct trie *t) { - struct tnode *n = (struct tnode *) rcu_dereference(t->trie); + struct tnode *n = (struct tnode *) rcu_dereference_check(t->trie, + rcu_read_lock_held() || + lockdep_rtnl_is_held()); if (!n) return NULL; -- cgit v1.2.3-59-g8ed1b From 4266d9118f85b050a341992f0cfab40d392ef32c Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 8 Sep 2010 21:17:29 +0000 Subject: [CIFS] ntlmv2/ntlmssp remove-unused-function CalcNTLMv2_partial_mac_key This function is not used, so remove the definition and declaration. Reviewed-by: Jeff Layton Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 57 --------------------------------------------------- fs/cifs/cifsproto.h | 2 -- 2 files changed, 59 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 847628dfdc44..35042d8f7338 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -223,63 +223,6 @@ int cifs_calculate_mac_key(struct mac_key *key, const char *rn, return 0; } -int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses, - const struct nls_table *nls_info) -{ - char temp_hash[16]; - struct HMACMD5Context ctx; - char *ucase_buf; - __le16 *unicode_buf; - unsigned int i, user_name_len, dom_name_len; - - if (ses == NULL) - return -EINVAL; - - E_md4hash(ses->password, temp_hash); - - hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); - user_name_len = strlen(ses->userName); - if (user_name_len > MAX_USERNAME_SIZE) - return -EINVAL; - if (ses->domainName == NULL) - return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ - dom_name_len = strlen(ses->domainName); - if (dom_name_len > MAX_USERNAME_SIZE) - return -EINVAL; - - ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); - if (ucase_buf == NULL) - return -ENOMEM; - unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); - if (unicode_buf == NULL) { - kfree(ucase_buf); - return -ENOMEM; - } - - for (i = 0; i < user_name_len; i++) - ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; - ucase_buf[i] = 0; - user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, - MAX_USERNAME_SIZE*2, nls_info); - unicode_buf[user_name_len] = 0; - user_name_len++; - - for (i = 0; i < dom_name_len; i++) - ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; - ucase_buf[i] = 0; - dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, - MAX_USERNAME_SIZE*2, nls_info); - - unicode_buf[user_name_len + dom_name_len] = 0; - hmac_md5_update((const unsigned char *) unicode_buf, - (user_name_len+dom_name_len)*2, &ctx); - - hmac_md5_final(ses->server->ntlmv2_hash, &ctx); - kfree(ucase_buf); - kfree(unicode_buf); - return 0; -} - #ifdef CONFIG_CIFS_WEAK_PW_HASH void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, char *lnm_session_key) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1f5450814087..f399b16cb7d5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -365,8 +365,6 @@ extern int cifs_verify_signature(struct smb_hdr *, __u32 expected_sequence_number); extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *pass); -extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, - const struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, const struct nls_table *); -- cgit v1.2.3-59-g8ed1b From 522bbe65a2415fabce618186fc7777eb4c502989 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 3 Sep 2010 12:00:49 -0400 Subject: cifs: prevent cifsd from exiting prematurely When cifs_demultiplex_thread exits, it does a number of cleanup tasks including freeing the TCP_Server_Info struct. Much of the existing code in cifs assumes that when there is a cisfSesInfo struct, that it holds a reference to a valid TCP_Server_Info struct. We can never allow cifsd to exit when a cifsSesInfo struct is still holding a reference to the server. The server pointers will then point to freed memory. This patch eliminates a couple of questionable conditions where it does this. The idea here is to make an -EINTR return from kernel_recvmsg behave the same way as -ERESTARTSYS or -EAGAIN. If the task was signalled from cifs_put_tcp_session, then tcpStatus will be CifsExiting, and the kernel_recvmsg call will return quickly. There's also another condition where this can occur too -- if the tcpStatus is still in CifsNew, then it will also exit if the server closes the socket prematurely. I think we'll probably also need to fix that situation, but that requires a bit more consideration. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0ea52e9f9065..5f68b968faa7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -400,7 +400,9 @@ incomplete_rcv: cFYI(1, "call to reconnect done"); csocket = server->ssocket; continue; - } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { + } else if (length == -ERESTARTSYS || + length == -EAGAIN || + length == -EINTR) { msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ @@ -422,10 +424,6 @@ incomplete_rcv: and so simply return error to mount */ break; } - if (!try_to_freeze() && (length == -EINTR)) { - cFYI(1, "cifsd thread killed"); - break; - } cFYI(1, "Reconnect after unexpected peek error %d", length); cifs_reconnect(server); @@ -522,8 +520,7 @@ incomplete_rcv: total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); - if ((server->tcpStatus == CifsExiting) || - (length == -EINTR)) { + if (server->tcpStatus == CifsExiting) { /* then will exit */ reconnect = 2; break; @@ -534,8 +531,9 @@ incomplete_rcv: /* Now we will reread sock */ reconnect = 1; break; - } else if ((length == -ERESTARTSYS) || - (length == -EAGAIN)) { + } else if (length == -ERESTARTSYS || + length == -EAGAIN || + length == -EINTR) { msleep(1); /* minimum sleep to prevent looping, allowing socket to clear and app threads to set tcpStatus -- cgit v1.2.3-59-g8ed1b From 7332f2a6217ee6925f83ef0e725013067ed316ba Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 3 Sep 2010 12:00:49 -0400 Subject: cifs: eliminate some more premature cifsd exits If the tcpStatus is still CifsNew, the main cifs_demultiplex_loop can break out prematurely in some cases. This is wrong as we will almost always have other structures with pointers to the TCP_Server_Info. If the main loop breaks under any other condition other than tcpStatus == CifsExiting, then it'll face a use-after-free situation. I don't see any reason to treat a CifsNew tcpStatus differently than CifsGood. I believe we'll still want to attempt to reconnect in either case. What should happen in those situations is that the MIDs get marked as MID_RETRY_NEEDED. This will make CIFSSMBNegotiate return -EAGAIN, and then the caller can retry the whole thing on a newly reconnected socket. If that fails again in the same way, the caller of cifs_get_smb_ses should tear down the TCP_Server_Info struct. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5f68b968faa7..5fde83f0c75e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -416,14 +416,6 @@ incomplete_rcv: } else continue; } else if (length <= 0) { - if (server->tcpStatus == CifsNew) { - cFYI(1, "tcp session abend after SMBnegprot"); - /* some servers kill the TCP session rather than - returning an SMB negprot error, in which - case reconnecting here is not going to help, - and so simply return error to mount */ - break; - } cFYI(1, "Reconnect after unexpected peek error %d", length); cifs_reconnect(server); @@ -464,27 +456,18 @@ incomplete_rcv: an error on SMB negprot response */ cFYI(1, "Negative RFC1002 Session Response Error 0x%x)", pdu_length); - if (server->tcpStatus == CifsNew) { - /* if nack on negprot (rather than - ret of smb negprot error) reconnecting - not going to help, ret error to mount */ - break; - } else { - /* give server a second to - clean up before reconnect attempt */ - msleep(1000); - /* always try 445 first on reconnect - since we get NACK on some if we ever - connected to port 139 (the NACK is - since we do not begin with RFC1001 - session initialize frame) */ - server->addr.sockAddr.sin_port = - htons(CIFS_PORT); - cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; - } + /* give server a second to clean up */ + msleep(1000); + /* always try 445 first on reconnect since we get NACK + * on some if we ever connected to port 139 (the NACK + * is since we do not begin with RFC1001 session + * initialize frame) + */ + server->addr.sockAddr.sin_port = htons(CIFS_PORT); + cifs_reconnect(server); + csocket = server->ssocket; + wake_up(&server->response_q); + continue; } else if (temp != (char) 0) { cERROR(1, "Unknown RFC 1002 frame"); cifs_dump_mem(" Received Data: ", (char *)smb_buffer, -- cgit v1.2.3-59-g8ed1b From 32670396e7fc6e4f37451a69339968985461a374 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 3 Sep 2010 12:00:50 -0400 Subject: cifs: prevent possible memory corruption in cifs_demultiplex_thread cifs_demultiplex_thread sets the addr.sockAddr.sin_port without any regard for the socket family. While it may be that the error in question here never occurs on an IPv6 socket, it's probably best to be safe and set the port properly if it ever does. Break the port setting code out of cifs_fill_sockaddr and into a new function, and call that from cifs_demultiplex_thread. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 3 ++- fs/cifs/connect.c | 3 ++- fs/cifs/netmisc.c | 22 +++++++++++++--------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f399b16cb7d5..1d60c655e3e0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -87,8 +87,9 @@ extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, struct TCP_Server_Info *server); extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); +extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, - unsigned short int port); + const unsigned short int port); extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); extern void header_assemble(struct smb_hdr *, char /* command */ , const struct cifsTconInfo *, int /* length of diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5fde83f0c75e..67dad54fbfa1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -463,7 +463,8 @@ incomplete_rcv: * is since we do not begin with RFC1001 session * initialize frame) */ - server->addr.sockAddr.sin_port = htons(CIFS_PORT); + cifs_set_port((struct sockaddr *) + &server->addr.sockAddr, CIFS_PORT); cifs_reconnect(server); csocket = server->ssocket; wake_up(&server->response_q); diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index f97851119e6c..9aad47a2d62f 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -206,26 +206,30 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len) } int -cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, - const unsigned short int port) +cifs_set_port(struct sockaddr *addr, const unsigned short int port) { - if (!cifs_convert_address(dst, src, len)) - return 0; - - switch (dst->sa_family) { + switch (addr->sa_family) { case AF_INET: - ((struct sockaddr_in *)dst)->sin_port = htons(port); + ((struct sockaddr_in *)addr)->sin_port = htons(port); break; case AF_INET6: - ((struct sockaddr_in6 *)dst)->sin6_port = htons(port); + ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); break; default: return 0; } - return 1; } +int +cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, + const unsigned short int port) +{ + if (!cifs_convert_address(dst, src, len)) + return 0; + return cifs_set_port(dst, port); +} + /***************************************************************************** convert a NT status code to a dos class/code *****************************************************************************/ -- cgit v1.2.3-59-g8ed1b From 70c9db0fdfd703781c3b8c2caf9287806f642e02 Mon Sep 17 00:00:00 2001 From: Chien Tung Date: Tue, 7 Sep 2010 16:31:20 +0000 Subject: RDMA/nes: Write correct register write to set TX pause param Setting TX pause param writes to the wrong register location causing the adapter to hang. Correct the define used to write the reigster. Addresses: https://bugs.openfabrics.org/show_bug.cgi?id=2116 Reported-by: Shiri Franchi Signed-off-by: Chien Tung Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_nic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 6dfdd49cdbcf..10560c796fd6 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1446,14 +1446,14 @@ static int nes_netdev_set_pauseparam(struct net_device *netdev, NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200)); u32temp |= NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE; nes_write_indexed(nesdev, - NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp); + NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200), u32temp); nesdev->disable_tx_flow_control = 0; } else if ((et_pauseparam->tx_pause == 0) && (nesdev->disable_tx_flow_control == 0)) { u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200)); u32temp &= ~NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE; nes_write_indexed(nesdev, - NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp); + NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200), u32temp); nesdev->disable_tx_flow_control = 1; } if ((et_pauseparam->rx_pause == 1) && (nesdev->disable_rx_flow_control == 1)) { -- cgit v1.2.3-59-g8ed1b From ae2688d59b5f861dc70a091d003773975d2ae7fb Mon Sep 17 00:00:00 2001 From: Jianzhao Wang Date: Wed, 8 Sep 2010 14:35:43 -0700 Subject: net: blackhole route should always be recalculated Blackhole routes are used when xfrm_lookup() returns -EREMOTE (error triggered by IKE for example), hence this kind of route is always temporary and so we should check if a better route exists for next packets. Bug has been introduced by commit d11a4dc18bf41719c9f0d7ed494d295dd2973b92. Signed-off-by: Jianzhao Wang Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv4/route.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 3f56b6e6c6aa..6298f75d5e93 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2738,6 +2738,11 @@ slow_output: } EXPORT_SYMBOL_GPL(__ip_route_output_key); +static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 cookie) +{ + return NULL; +} + static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) { } @@ -2746,7 +2751,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { .family = AF_INET, .protocol = cpu_to_be16(ETH_P_IP), .destroy = ipv4_dst_destroy, - .check = ipv4_dst_check, + .check = ipv4_blackhole_dst_check, .update_pmtu = ipv4_rt_blackhole_update_pmtu, .entries = ATOMIC_INIT(0), }; -- cgit v1.2.3-59-g8ed1b From dae58728dc64e9ad71c40ac90b463bff6ecce271 Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Sat, 14 Aug 2010 21:04:56 +0000 Subject: RDMA/nes: Fix double CLOSE event indication crash During a stress testing in a large cluster, multiple close event are detected and BUG() is hit in the iWARP core. The cause is that the active node gave up while waiting for an MPA response from the peer and tried to close the connection by sending RST. The passive node driver receives the RST but is waiting for MPA response from the user. When the MPA accept is received, the driver offloads the connection and sends a CLOSE event. The driver gets an AE indicating RESET received and also sends a CLOSE event, hitting a BUG(). Fix this by correcting RESET handling and sending CLOSE events. Signed-off-by: Faisal Latif Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 443cea55daac..61e0efd4ccfb 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -502,7 +502,9 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb, static void nes_retrans_expired(struct nes_cm_node *cm_node) { struct iw_cm_id *cm_id = cm_node->cm_id; - switch (cm_node->state) { + enum nes_cm_node_state state = cm_node->state; + cm_node->state = NES_CM_STATE_CLOSED; + switch (state) { case NES_CM_STATE_SYN_RCVD: case NES_CM_STATE_CLOSING: rem_ref_cm_node(cm_node->cm_core, cm_node); @@ -511,7 +513,6 @@ static void nes_retrans_expired(struct nes_cm_node *cm_node) case NES_CM_STATE_FIN_WAIT1: if (cm_node->cm_id) cm_id->rem_ref(cm_id); - cm_node->state = NES_CM_STATE_CLOSED; send_reset(cm_node, NULL); break; default: @@ -1439,9 +1440,6 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, break; case NES_CM_STATE_MPAREQ_RCVD: passive_state = atomic_add_return(1, &cm_node->passive_state); - if (passive_state == NES_SEND_RESET_EVENT) - create_event(cm_node, NES_CM_EVENT_RESET); - cm_node->state = NES_CM_STATE_CLOSED; dev_kfree_skb_any(skb); break; case NES_CM_STATE_ESTABLISHED: @@ -1456,6 +1454,7 @@ static void handle_rst_pkt(struct nes_cm_node *cm_node, struct sk_buff *skb, case NES_CM_STATE_CLOSED: drop_packet(skb); break; + case NES_CM_STATE_FIN_WAIT2: case NES_CM_STATE_FIN_WAIT1: case NES_CM_STATE_LAST_ACK: cm_node->cm_id->rem_ref(cm_node->cm_id); @@ -2777,6 +2776,12 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) return -EINVAL; } + passive_state = atomic_add_return(1, &cm_node->passive_state); + if (passive_state == NES_SEND_RESET_EVENT) { + rem_ref_cm_node(cm_node->cm_core, cm_node); + return -ECONNRESET; + } + /* associate the node with the QP */ nesqp->cm_node = (void *)cm_node; cm_node->nesqp = nesqp; @@ -2979,9 +2984,6 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) printk(KERN_ERR "%s[%u] OFA CM event_handler returned, " "ret=%d\n", __func__, __LINE__, ret); - passive_state = atomic_add_return(1, &cm_node->passive_state); - if (passive_state == NES_SEND_RESET_EVENT) - create_event(cm_node, NES_CM_EVENT_RESET); return 0; } -- cgit v1.2.3-59-g8ed1b From 67d70721151726286763209ecadc3fce86abfdce Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Sat, 14 Aug 2010 21:05:04 +0000 Subject: RDMA/nes: Change state to closing after FIN When the driver receives an AE for FIN received, it closes the connection without changing the state of the connection in the hardware to closing. By changing the state to closing, hardware will do a normal close sequence. Signed-off-by: Faisal Latif Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_hw.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index f8233c851c69..ba93a8be6bf6 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -3468,6 +3468,18 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, return; /* Ignore it, wait for close complete */ if (atomic_inc_return(&nesqp->close_timer_started) == 1) { + if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) && + (nesqp->ibqp_state == IB_QPS_RTS)) { + spin_lock_irqsave(&nesqp->lock, flags); + nesqp->hw_iwarp_state = iwarp_state; + nesqp->hw_tcp_state = tcp_state; + nesqp->last_aeq = async_event_id; + next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING; + nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING; + spin_unlock_irqrestore(&nesqp->lock, flags); + nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 0); + nes_cm_disconn(nesqp); + } nesqp->cm_id->add_ref(nesqp->cm_id); schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp, NES_TIMER_TYPE_CLOSE, 1, 0); @@ -3477,7 +3489,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount), async_event_id, nesqp->last_aeq, tcp_state); } - break; case NES_AEQE_AEID_LLP_CLOSE_COMPLETE: if (nesqp->term_flags) { -- cgit v1.2.3-59-g8ed1b From 29da03b9d1c6f24548d98cebda1e15a25d80ee1b Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Wed, 1 Sep 2010 15:43:11 +0000 Subject: RDMA/nes: Fix hang with modified FIN handling on A0 cards Changing state to CLOSING when FIN is received causes A0 cards to hang. Fix this by checking for A0 cards in FIN handling. Signed-off-by: Faisal Latif Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_hw.c | 3 ++- drivers/infiniband/hw/nes/nes_hw.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index ba93a8be6bf6..1980a461c499 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -3469,7 +3469,8 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, if (atomic_inc_return(&nesqp->close_timer_started) == 1) { if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) && - (nesqp->ibqp_state == IB_QPS_RTS)) { + (nesqp->ibqp_state == IB_QPS_RTS) && + ((nesadapter->eeprom_version >> 16) != NES_A0)) { spin_lock_irqsave(&nesqp->lock, flags); nesqp->hw_iwarp_state = iwarp_state; nesqp->hw_tcp_state = tcp_state; diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index aa9183db32b1..1204c3432b63 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -45,6 +45,7 @@ #define NES_PHY_TYPE_KR 9 #define NES_MULTICAST_PF_MAX 8 +#define NES_A0 3 enum pci_regs { NES_INT_STAT = 0x0000, -- cgit v1.2.3-59-g8ed1b From 152e1d592071c8b312bb898bc1118b64e4aea535 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 3 Sep 2010 01:24:07 +0200 Subject: PM: Prevent waiting forever on asynchronous resume after failing suspend During suspend, the power.completion is expected to be set when a device has not yet started suspending. Set it on init to fix a corner case where a device is resumed when its parent has never suspended. Consider three drivers, A, B, and C. The parent of A is C, and C has async_suspend set. On boot, C->power.completion is initialized to 0. During the first suspend: suspend_devices_and_enter(...) dpm_resume(...) device_suspend(A) device_suspend(B) returns error, aborts suspend dpm_resume_end(...) dpm_resume(...) device_resume(A) dpm_wait(A->parent == C) wait_for_completion(C->power.completion) The wait_for_completion will never complete, because complete_all(C->power.completion) will only be called from device_suspend(C) or device_resume(C), neither of which is called if suspend is aborted before C. After a successful suspend->resume cycle, where B doesn't abort suspend, C->power.completion is left in the completed state by the call to device_resume(C), and the same call path will work if B aborts suspend. Signed-off-by: Colin Cross Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5419a49ff135..276d5a701dc3 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -59,6 +59,7 @@ void device_pm_init(struct device *dev) { dev->power.status = DPM_ON; init_completion(&dev->power.completion); + complete_all(&dev->power.completion); dev->power.wakeup_count = 0; pm_runtime_init(dev); } -- cgit v1.2.3-59-g8ed1b From b19f8200392db88d529576a4f8178d08b70047be Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 8 Sep 2010 20:57:59 -0700 Subject: sparc: Kill all BKL usage. They were all bogus artifacts and completely unnecessary. Signed-off-by: David S. Miller --- arch/sparc/kernel/sys_sparc_32.c | 2 -- arch/sparc/kernel/unaligned_32.c | 3 +-- arch/sparc/kernel/windows.c | 2 -- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index ee995b7dae7e..de45de4851e9 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -166,7 +166,6 @@ sparc_breakpoint (struct pt_regs *regs) { siginfo_t info; - lock_kernel(); #ifdef DEBUG_SPARC_BREAKPOINT printk ("TRAP: Entering kernel PC=%x, nPC=%x\n", regs->pc, regs->npc); #endif @@ -180,7 +179,6 @@ sparc_breakpoint (struct pt_regs *regs) #ifdef DEBUG_SPARC_BREAKPOINT printk ("TRAP: Returning to space: PC=%x nPC=%x\n", regs->pc, regs->npc); #endif - unlock_kernel(); } asmlinkage int diff --git a/arch/sparc/kernel/unaligned_32.c b/arch/sparc/kernel/unaligned_32.c index f8514e291e15..12b9f352595f 100644 --- a/arch/sparc/kernel/unaligned_32.c +++ b/arch/sparc/kernel/unaligned_32.c @@ -323,7 +323,6 @@ asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) { enum direction dir; - lock_kernel(); if(!(current->thread.flags & SPARC_FLAG_UNALIGNED) || (((insn >> 30) & 3) != 3)) goto kill_user; @@ -377,5 +376,5 @@ asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn) kill_user: user_mna_trap_fault(regs, insn); out: - unlock_kernel(); + ; } diff --git a/arch/sparc/kernel/windows.c b/arch/sparc/kernel/windows.c index f24d298bda29..b351770cbdd6 100644 --- a/arch/sparc/kernel/windows.c +++ b/arch/sparc/kernel/windows.c @@ -112,7 +112,6 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who) struct thread_info *tp = current_thread_info(); int window; - lock_kernel(); flush_user_windows(); for(window = 0; window < tp->w_saved; window++) { unsigned long sp = tp->rwbuf_stkptrs[window]; @@ -123,5 +122,4 @@ void try_to_clear_window_buffer(struct pt_regs *regs, int who) do_exit(SIGILL); } tp->w_saved = 0; - unlock_kernel(); } -- cgit v1.2.3-59-g8ed1b From 719f835853a92f6090258114a72ffe41f09155cd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Sep 2010 05:08:44 +0000 Subject: udp: add rehash on connect() commit 30fff923 introduced in linux-2.6.33 (udp: bind() optimisation) added a secondary hash on UDP, hashed on (local addr, local port). Problem is that following sequence : fd = socket(...) connect(fd, &remote, ...) not only selects remote end point (address and port), but also sets local address, while UDP stack stored in secondary hash table the socket while its local address was INADDR_ANY (or ipv6 equivalent) Sequence is : - autobind() : choose a random local port, insert socket in hash tables [while local address is INADDR_ANY] - connect() : set remote address and port, change local address to IP given by a route lookup. When an incoming UDP frame comes, if more than 10 sockets are found in primary hash table, we switch to secondary table, and fail to find socket because its local address changed. One solution to this problem is to rehash datagram socket if needed. We add a new rehash(struct socket *) method in "struct proto", and implement this method for UDP v4 & v6, using a common helper. This rehashing only takes care of secondary hash table, since primary hash (based on local port only) is not changed. Reported-by: Krzysztof Piotr Oledzki Signed-off-by: Eric Dumazet Tested-by: Krzysztof Piotr Oledzki Signed-off-by: David S. Miller --- include/net/sock.h | 1 + include/net/udp.h | 1 + net/ipv4/datagram.c | 5 ++++- net/ipv4/udp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/datagram.c | 7 ++++++- net/ipv6/udp.c | 10 ++++++++++ 6 files changed, 66 insertions(+), 2 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index ac53bfbdfe16..adab9dc58183 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -752,6 +752,7 @@ struct proto { /* Keeping track of sk's, looking them up, and port selection methods. */ void (*hash)(struct sock *sk); void (*unhash)(struct sock *sk); + void (*rehash)(struct sock *sk); int (*get_port)(struct sock *sk, unsigned short snum); /* Keeping track of sockets in use */ diff --git a/include/net/udp.h b/include/net/udp.h index 7abdf305da50..a184d3496b13 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -151,6 +151,7 @@ static inline void udp_lib_hash(struct sock *sk) } extern void udp_lib_unhash(struct sock *sk); +extern void udp_lib_rehash(struct sock *sk, u16 new_hash); static inline void udp_lib_close(struct sock *sk, long timeout) { diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index f0550941df7b..721a8a37b45c 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -62,8 +62,11 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } if (!inet->inet_saddr) inet->inet_saddr = rt->rt_src; /* Update source address */ - if (!inet->inet_rcv_saddr) + if (!inet->inet_rcv_saddr) { inet->inet_rcv_saddr = rt->rt_src; + if (sk->sk_prot->rehash) + sk->sk_prot->rehash(sk); + } inet->inet_daddr = rt->rt_dst; inet->inet_dport = usin->sin_port; sk->sk_state = TCP_ESTABLISHED; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 32e0bef60d0a..fb23c2e63b52 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1260,6 +1260,49 @@ void udp_lib_unhash(struct sock *sk) } EXPORT_SYMBOL(udp_lib_unhash); +/* + * inet_rcv_saddr was changed, we must rehash secondary hash + */ +void udp_lib_rehash(struct sock *sk, u16 newhash) +{ + if (sk_hashed(sk)) { + struct udp_table *udptable = sk->sk_prot->h.udp_table; + struct udp_hslot *hslot, *hslot2, *nhslot2; + + hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); + nhslot2 = udp_hashslot2(udptable, newhash); + udp_sk(sk)->udp_portaddr_hash = newhash; + if (hslot2 != nhslot2) { + hslot = udp_hashslot(udptable, sock_net(sk), + udp_sk(sk)->udp_port_hash); + /* we must lock primary chain too */ + spin_lock_bh(&hslot->lock); + + spin_lock(&hslot2->lock); + hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node); + hslot2->count--; + spin_unlock(&hslot2->lock); + + spin_lock(&nhslot2->lock); + hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node, + &nhslot2->head); + nhslot2->count++; + spin_unlock(&nhslot2->lock); + + spin_unlock_bh(&hslot->lock); + } + } +} +EXPORT_SYMBOL(udp_lib_rehash); + +static void udp_v4_rehash(struct sock *sk) +{ + u16 new_hash = udp4_portaddr_hash(sock_net(sk), + inet_sk(sk)->inet_rcv_saddr, + inet_sk(sk)->inet_num); + udp_lib_rehash(sk, new_hash); +} + static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { int rc; @@ -1843,6 +1886,7 @@ struct proto udp_prot = { .backlog_rcv = __udp_queue_rcv_skb, .hash = udp_lib_hash, .unhash = udp_lib_unhash, + .rehash = udp_v4_rehash, .get_port = udp_v4_get_port, .memory_allocated = &udp_memory_allocated, .sysctl_mem = sysctl_udp_mem, diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 7d929a22cbc2..ef371aa01ac5 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -105,9 +105,12 @@ ipv4_connected: if (ipv6_addr_any(&np->saddr)) ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); - if (ipv6_addr_any(&np->rcv_saddr)) + if (ipv6_addr_any(&np->rcv_saddr)) { ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, &np->rcv_saddr); + if (sk->sk_prot->rehash) + sk->sk_prot->rehash(sk); + } goto out; } @@ -181,6 +184,8 @@ ipv4_connected: if (ipv6_addr_any(&np->rcv_saddr)) { ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); inet->inet_rcv_saddr = LOOPBACK4_IPV6; + if (sk->sk_prot->rehash) + sk->sk_prot->rehash(sk); } ip6_dst_store(sk, dst, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 1dd1affdead2..5acb3560ff15 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -111,6 +111,15 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr); } +static void udp_v6_rehash(struct sock *sk) +{ + u16 new_hash = udp6_portaddr_hash(sock_net(sk), + &inet6_sk(sk)->rcv_saddr, + inet_sk(sk)->inet_num); + + udp_lib_rehash(sk, new_hash); +} + static inline int compute_score(struct sock *sk, struct net *net, unsigned short hnum, struct in6_addr *saddr, __be16 sport, @@ -1447,6 +1456,7 @@ struct proto udpv6_prot = { .backlog_rcv = udpv6_queue_rcv_skb, .hash = udp_lib_hash, .unhash = udp_lib_unhash, + .rehash = udp_v6_rehash, .get_port = udp_v6_get_port, .memory_allocated = &udp_memory_allocated, .sysctl_mem = sysctl_udp_mem, -- cgit v1.2.3-59-g8ed1b From 972c40b5bee429c84ba727f8ac0a08292bc5dc3d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Sep 2010 13:26:55 +0000 Subject: KS8851: Correct RX packet allocation Use netdev_alloc_skb_ip_align() helper and do correct allocation Tested-by: Abraham Arce Signed-off-by: Abraham Arce Signed-off-by: David S. Miller --- drivers/net/ks8851.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index b4fb07a6f13f..51919fcd50c2 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -503,30 +503,33 @@ static void ks8851_rx_pkts(struct ks8851_net *ks) ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr | RXQCR_SDA | RXQCR_ADRFE); - if (rxlen > 0) { - skb = netdev_alloc_skb(ks->netdev, rxlen + 2 + 8); - if (!skb) { - /* todo - dump frame and move on */ - } + if (rxlen > 4) { + unsigned int rxalign; + + rxlen -= 4; + rxalign = ALIGN(rxlen, 4); + skb = netdev_alloc_skb_ip_align(ks->netdev, rxalign); + if (skb) { - /* two bytes to ensure ip is aligned, and four bytes - * for the status header and 4 bytes of garbage */ - skb_reserve(skb, 2 + 4 + 4); + /* 4 bytes of status header + 4 bytes of + * garbage: we put them before ethernet + * header, so that they are copied, + * but ignored. + */ - rxpkt = skb_put(skb, rxlen - 4) - 8; + rxpkt = skb_put(skb, rxlen) - 8; - /* align the packet length to 4 bytes, and add 4 bytes - * as we're getting the rx status header as well */ - ks8851_rdfifo(ks, rxpkt, ALIGN(rxlen, 4) + 8); + ks8851_rdfifo(ks, rxpkt, rxalign + 8); - if (netif_msg_pktdata(ks)) - ks8851_dbg_dumpkkt(ks, rxpkt); + if (netif_msg_pktdata(ks)) + ks8851_dbg_dumpkkt(ks, rxpkt); - skb->protocol = eth_type_trans(skb, ks->netdev); - netif_rx(skb); + skb->protocol = eth_type_trans(skb, ks->netdev); + netif_rx(skb); - ks->netdev->stats.rx_packets++; - ks->netdev->stats.rx_bytes += rxlen - 4; + ks->netdev->stats.rx_packets++; + ks->netdev->stats.rx_bytes += rxlen; + } } ks8851_wrreg16(ks, KS_RXQCR, ks->rc_rxqcr); -- cgit v1.2.3-59-g8ed1b From 25c8e03bdb769dfe2381f8b7942f05b0eb4bdf31 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 6 Sep 2010 11:02:12 +0200 Subject: spi/pl022: move probe call to subsys_initcall() The PL022 SPI bus is sometimes used for early stuff like regulators that need to be present at module_init() time, so we move this to a subsys_initcall(). Signed-off-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/spi/amba-pl022.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 80613abe961d..4c37c4e28647 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -1983,7 +1983,7 @@ static int __init pl022_init(void) return amba_driver_register(&pl022_driver); } -module_init(pl022_init); +subsys_initcall(pl022_init); static void __exit pl022_exit(void) { -- cgit v1.2.3-59-g8ed1b From a7a13d0676335a7dc9dd72264cca02606e43aaba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Sep 2010 00:11:41 +0200 Subject: ALSA: rawmidi: fix the get next midi device ioctl If we pass in a device which is higher than SNDRV_RAWMIDI_DEVICES then the "next device" should be -1. This function just returns device + 1. But the main thing is that "device + 1" can lead to a (harmless) integer overflow and that annoys static analysis tools. [fix the case for device == SNDRV_RAWMIDI_DEVICE by tiwai] Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index eb68326c37d4..a7868ad4d530 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -829,6 +829,8 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)argp)) return -EFAULT; + if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ + device = SNDRV_RAWMIDI_DEVICES - 1; mutex_lock(®ister_mutex); device = device < 0 ? 0 : device + 1; while (device < SNDRV_RAWMIDI_DEVICES) { -- cgit v1.2.3-59-g8ed1b From 6cb3b707f95954ac18f19b4b3919af235738371a Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 9 Sep 2010 08:51:44 +0200 Subject: ALSA: HDA: Add fixup pins for Ideapad Y550 By adding the subwoofer as a speaker pin, it is treated correctly when auto-muting. BugLink: https://launchpad.net/bugs/611803 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f11a9ca2c4b2..0c25d22be875 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -18963,6 +18963,26 @@ static void alc662_auto_init(struct hda_codec *codec) alc_inithook(codec); } +enum { + ALC662_FIXUP_IDEAPAD, +}; + +static const struct alc_fixup alc662_fixups[] = { + [ALC662_FIXUP_IDEAPAD] = { + .pins = (const struct alc_pincfg[]) { + { 0x17, 0x99130112 }, /* subwoofer */ + { } + } + }, +}; + +static struct snd_pci_quirk alc662_fixup_tbl[] = { + SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), + {} +}; + + + static int patch_alc662(struct hda_codec *codec) { struct alc_spec *spec; @@ -18995,6 +19015,7 @@ static int patch_alc662(struct hda_codec *codec) } if (board_config == ALC662_AUTO) { + alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1); /* automatic parse from the BIOS config */ err = alc662_parse_auto_config(codec); if (err < 0) { @@ -19053,8 +19074,11 @@ static int patch_alc662(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; - if (board_config == ALC662_AUTO) + if (board_config == ALC662_AUTO) { spec->init_hook = alc662_auto_init; + alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0); + } + #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) spec->loopback.amplist = alc662_loopbacks; -- cgit v1.2.3-59-g8ed1b From 7839d956fc6aecbb66d645b4050e8e88e2e821cd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 00:02:03 +0100 Subject: drm/i915: Double check that the wait_request is not pending before warning If we are busy, then we may have woken up the wait_request handler but not yet serviced it before the hang check fires. So in hang check, double check that the i915_gem_do_wait_request() is still pending the wake-up before declaring all hope lost. Fixes regression with e78d73b16bcde921c9cf458d2e4de8e4fc2518f3. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30073 Reported-and-tested-by: Sitsofe Wheeler Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 59457e83b011..744225ebb4b2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1350,17 +1350,25 @@ void i915_hangcheck_elapsed(unsigned long data) i915_seqno_passed(i915_get_gem_seqno(dev, &dev_priv->render_ring), i915_get_tail_request(dev)->seqno)) { + bool missed_wakeup = false; + dev_priv->hangcheck_count = 0; /* Issue a wake-up to catch stuck h/w. */ - if (dev_priv->render_ring.waiting_gem_seqno | - dev_priv->bsd_ring.waiting_gem_seqno) { - DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n"); - if (dev_priv->render_ring.waiting_gem_seqno) - DRM_WAKEUP(&dev_priv->render_ring.irq_queue); - if (dev_priv->bsd_ring.waiting_gem_seqno) - DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + if (dev_priv->render_ring.waiting_gem_seqno && + waitqueue_active(&dev_priv->render_ring.irq_queue)) { + DRM_WAKEUP(&dev_priv->render_ring.irq_queue); + missed_wakeup = true; + } + + if (dev_priv->bsd_ring.waiting_gem_seqno && + waitqueue_active(&dev_priv->bsd_ring.irq_queue)) { + DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue); + missed_wakeup = true; } + + if (missed_wakeup) + DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n"); return; } -- cgit v1.2.3-59-g8ed1b From da0dab5ecb5001f76e739e71ee199db4c61e7af2 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:18:35 +0200 Subject: ALSA: virtuoso: fix WM8766 register writes with MSB The check for the volume update latch bit was accidentally in the wrong function, where it would prevent the MSB from being written, instead of correctly ignoring it for cached values. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_wm87x6.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index b82c1cfa96f5..4346006df3ec 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -97,8 +97,12 @@ static void wm8766_write(struct oxygen *chip, (0 << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, (reg << 9) | value); - if (reg < ARRAY_SIZE(data->wm8766_regs)) + if (reg < ARRAY_SIZE(data->wm8766_regs)) { + if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || + (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) + value &= ~WM8766_UPDATE; data->wm8766_regs[reg] = value; + } } static void wm8766_write_cached(struct oxygen *chip, @@ -107,12 +111,8 @@ static void wm8766_write_cached(struct oxygen *chip, struct xonar_wm87x6 *data = chip->model_data; if (reg >= ARRAY_SIZE(data->wm8766_regs) || - value != data->wm8766_regs[reg]) { - if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || - (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) - value &= ~WM8766_UPDATE; + value != data->wm8766_regs[reg]) wm8766_write(chip, reg, value); - } } static void wm8776_registers_init(struct oxygen *chip) -- cgit v1.2.3-59-g8ed1b From 9bac84edf0360ac94a27308778ef98dc9068777c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:19:21 +0200 Subject: ALSA: virtuoso: fix Xonar DS input switches Use the correct number, register bits, and names for the input switches. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_wm87x6.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 4346006df3ec..fb3f95ccafa1 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -29,6 +29,13 @@ * GPIO 6 -> route input jack to input 1/2 (1/0) * GPIO 7 -> enable output to speakers * GPIO 8 -> enable output to speakers + * + * WM8766: + * + * input 1 <- line + * input 2 <- mic + * input 3 <- front mic + * input 4 <- aux */ #include @@ -896,7 +903,10 @@ static const struct snd_kcontrol_new ds_controls[] = { .put = wm8776_input_mux_put, .private_value = 1 << 1, }, - WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), + WM8776_BIT_SWITCH("Front Mic Capture Switch", + WM8776_ADCMUX, 1 << 2, 0, 0), + WM8776_BIT_SWITCH("Aux Capture Switch", + WM8776_ADCMUX, 1 << 3, 0, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "ADC Filter Capture Enum", -- cgit v1.2.3-59-g8ed1b From 435feac648cab190990aa0bf9355f77d1f082db3 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:20:29 +0200 Subject: ALSA: virtuoso: add Xonar DS headphone jack detection Now that the polarity of the headphone detection pin is known, replace the debugging message with a proper jack plug input device. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 1 + sound/pci/oxygen/xonar_wm87x6.c | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index e7a8cd058efb..b40f2b8df536 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -817,6 +817,7 @@ config SND_VIA82XX_MODEM config SND_VIRTUOSO tristate "Asus Virtuoso 100/200 (Xonar)" select SND_OXYGEN_LIB + select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index fb3f95ccafa1..9d57b5eee3f5 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -25,8 +25,8 @@ * SPI 0 -> WM8766 (surround, center/LFE, back) * SPI 1 -> WM8776 (front, input) * - * GPIO 4 <- headphone detect - * GPIO 6 -> route input jack to input 1/2 (1/0) + * GPIO 4 <- headphone detect, 0 = plugged + * GPIO 6 -> route input jack to mic-in (0) or line-in (1) * GPIO 7 -> enable output to speakers * GPIO 8 -> enable output to speakers * @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ struct xonar_wm87x6 { struct snd_kcontrol *line_adcmux_control; struct snd_kcontrol *mic_adcmux_control; struct snd_kcontrol *lc_controls[13]; + struct snd_jack *hp_jack; }; static void wm8776_write(struct oxygen *chip, @@ -177,6 +179,16 @@ static void wm8776_init(struct oxygen *chip) wm8776_registers_init(chip); } +static void xonar_ds_report_hp_jack(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + u16 bits; + + bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); + snd_jack_report(data->hp_jack, + bits & GPIO_DS_HP_DETECT ? 0 : SND_JACK_HEADPHONE); +} + static void xonar_ds_init(struct oxygen *chip) { struct xonar_wm87x6 *data = chip->model_data; @@ -195,6 +207,10 @@ static void xonar_ds_init(struct oxygen *chip) xonar_enable_output(chip); + snd_jack_new(chip->card, "Headphone", + SND_JACK_HEADPHONE, &data->hp_jack); + xonar_ds_report_hp_jack(chip); + snd_component_add(chip->card, "WM8776"); snd_component_add(chip->card, "WM8766"); } @@ -332,10 +348,7 @@ static void update_wm87x6_mute(struct oxygen *chip) static void xonar_ds_gpio_changed(struct oxygen *chip) { - u16 bits; - - bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); - snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); + xonar_ds_report_hp_jack(chip); } static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, -- cgit v1.2.3-59-g8ed1b From 84cf83a28d4a3cd1fac1384cbaa4ed0ba650d309 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:23:06 +0200 Subject: ALSA: virtuoso: automatically handle Xonar DS headphone routing Automatically mute the speaker outputs as long as a headphone is plugged. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_wm87x6.c | 57 +++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 9d57b5eee3f5..cee07fe3aa36 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -27,8 +27,8 @@ * * GPIO 4 <- headphone detect, 0 = plugged * GPIO 6 -> route input jack to mic-in (0) or line-in (1) - * GPIO 7 -> enable output to speakers - * GPIO 8 -> enable output to speakers + * GPIO 7 -> enable output to front L/R speaker channels + * GPIO 8 -> enable output to other speaker channels and front panel headphone * * WM8766: * @@ -52,7 +52,8 @@ #define GPIO_DS_HP_DETECT 0x0010 #define GPIO_DS_INPUT_ROUTE 0x0040 -#define GPIO_DS_OUTPUT_ENABLE 0x0180 +#define GPIO_DS_OUTPUT_FRONTLR 0x0080 +#define GPIO_DS_OUTPUT_ENABLE 0x0100 #define LC_CONTROL_LIMITER 0x40000000 #define LC_CONTROL_ALC 0x20000000 @@ -150,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip) static void wm8766_registers_init(struct oxygen *chip) { + struct xonar_wm87x6 *data = chip->model_data; + wm8766_write(chip, WM8766_RESET, 0); + wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]); wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); wm8766_write(chip, WM8766_DAC_CTRL2, WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); @@ -179,14 +183,38 @@ static void wm8776_init(struct oxygen *chip) wm8776_registers_init(chip); } -static void xonar_ds_report_hp_jack(struct oxygen *chip) +static void wm8766_init(struct oxygen *chip) { struct xonar_wm87x6 *data = chip->model_data; - u16 bits; - bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); - snd_jack_report(data->hp_jack, - bits & GPIO_DS_HP_DETECT ? 0 : SND_JACK_HEADPHONE); + data->wm8766_regs[WM8766_DAC_CTRL] = + WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; + wm8766_registers_init(chip); +} + +static void xonar_ds_handle_hp_jack(struct oxygen *chip) +{ + struct xonar_wm87x6 *data = chip->model_data; + bool hp_plugged; + unsigned int reg; + + mutex_lock(&chip->mutex); + + hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) & + GPIO_DS_HP_DETECT); + + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR, + GPIO_DS_OUTPUT_FRONTLR); + + reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL; + if (hp_plugged) + reg |= WM8766_MUTEALL; + wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); + + snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0); + + mutex_unlock(&chip->mutex); } static void xonar_ds_init(struct oxygen *chip) @@ -197,10 +225,12 @@ static void xonar_ds_init(struct oxygen *chip) data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; wm8776_init(chip); - wm8766_registers_init(chip); + wm8766_init(chip); - oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, - GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR); + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_DS_HP_DETECT); oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); chip->interrupt_mask |= OXYGEN_INT_GPIO; @@ -209,7 +239,7 @@ static void xonar_ds_init(struct oxygen *chip) snd_jack_new(chip->card, "Headphone", SND_JACK_HEADPHONE, &data->hp_jack); - xonar_ds_report_hp_jack(chip); + xonar_ds_handle_hp_jack(chip); snd_component_add(chip->card, "WM8776"); snd_component_add(chip->card, "WM8766"); @@ -231,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip) wm8776_registers_init(chip); wm8766_registers_init(chip); xonar_enable_output(chip); + xonar_ds_handle_hp_jack(chip); } static void wm8776_adc_hardware_filter(unsigned int channel, @@ -348,7 +379,7 @@ static void update_wm87x6_mute(struct oxygen *chip) static void xonar_ds_gpio_changed(struct oxygen *chip) { - xonar_ds_report_hp_jack(chip); + xonar_ds_handle_hp_jack(chip); } static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, -- cgit v1.2.3-59-g8ed1b From 2dbf0ea29c1e4dff4ee5f0c59b367168fa2e5a40 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:24:35 +0200 Subject: ALSA: virtuoso: Xonar DS: add stereo upmixing to center/LFE channels Add the possibility to route a mix of the two channels of stereo data to the center and LFE outputs. Due to a WM8766 restriction, all surround and back channels also get the mixed L/R signal in this case. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_wm87x6.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index cee07fe3aa36..aceaaa036da6 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -377,6 +377,24 @@ static void update_wm87x6_mute(struct oxygen *chip) (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); } +static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed) +{ + struct xonar_wm87x6 *data = chip->model_data; + unsigned int reg; + + /* + * The WM8766 can mix left and right channels, but this setting + * applies to all three stereo pairs. + */ + reg = data->wm8766_regs[WM8766_DAC_CTRL] & + ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK); + if (mixed) + reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX; + else + reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT; + wm8766_write_cached(chip, WM8766_DAC_CTRL, reg); +} + static void xonar_ds_gpio_changed(struct oxygen *chip) { xonar_ds_handle_hp_jack(chip); @@ -1067,6 +1085,7 @@ static const struct oxygen_model model_xonar_ds = { .set_adc_params = set_wm8776_adc_params, .update_dac_volume = update_wm87x6_volume, .update_dac_mute = update_wm87x6_mute, + .update_center_lfe_mix = update_wm8766_center_lfe_mix, .gpio_changed = xonar_ds_gpio_changed, .dac_tlv = wm87x6_dac_db_scale, .model_data_size = sizeof(struct xonar_wm87x6), -- cgit v1.2.3-59-g8ed1b From 99f08bf59019ca6c9056f10ee8f7e1ba6663251c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:25:29 +0200 Subject: ALSA: oxygen: fix CONFIG_SND_OXYGEN_LIB dependency selection As the select directive does not handle indirect dependencies, select those explicitly in the driver sections. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index b40f2b8df536..0e75d558f303 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -207,12 +207,12 @@ config SND_CMIPCI config SND_OXYGEN_LIB tristate - select SND_PCM - select SND_MPU401_UART config SND_OXYGEN tristate "C-Media 8788 (Oxygen)" select SND_OXYGEN_LIB + select SND_PCM + select SND_MPU401_UART help Say Y here to include support for sound cards based on the C-Media CMI8788 (Oxygen HD Audio) chip: @@ -581,6 +581,8 @@ config SND_HDSPM config SND_HIFIER tristate "TempoTec HiFier Fantasia" select SND_OXYGEN_LIB + select SND_PCM + select SND_MPU401_UART help Say Y here to include support for the MediaTek/TempoTec HiFier Fantasia sound card. @@ -817,6 +819,8 @@ config SND_VIA82XX_MODEM config SND_VIRTUOSO tristate "Asus Virtuoso 100/200 (Xonar)" select SND_OXYGEN_LIB + select SND_PCM + select SND_MPU401_UART select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the -- cgit v1.2.3-59-g8ed1b From 51485e8e24919be10bd61dba1dede0032de2d952 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 9 Sep 2010 12:26:52 +0200 Subject: ALSA: virtuoso: update Kconfig text Update the Xonar config texts with the latest information about the Xonar DS, HDAV1.3 Slim, and Xense. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 0e75d558f303..12e34653b8a8 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -817,17 +817,17 @@ config SND_VIA82XX_MODEM will be called snd-via82xx-modem. config SND_VIRTUOSO - tristate "Asus Virtuoso 100/200 (Xonar)" + tristate "Asus Virtuoso 66/100/200 (Xonar)" select SND_OXYGEN_LIB select SND_PCM select SND_MPU401_UART select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for sound cards based on the - Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, + Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, Essence ST (Deluxe), and Essence STX. - Support for the DS is experimental. - Support for the HDAV1.3 (Deluxe) is very experimental. + Support for the HDAV1.3 (Deluxe) is incomplete; for the + HDAV1.3 Slim and Xense, missing. To compile this driver as a module, choose M here: the module will be called snd-virtuoso. -- cgit v1.2.3-59-g8ed1b From d530148ae8bffe1b33f50d1776d185a6e85dc774 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 20 Aug 2010 16:49:43 +0800 Subject: dquot: do full inode dirty in allocating space Alex Shi found a regression when doing ffsb test. The test has several threads, and each thread creates a small file, write to it and then delete it. ffsb reports about 20% regression and Alex bisected it to 43d2932d88e4. The test will call __mark_inode_dirty 3 times. without this commit, we only take inode_lock one time, while with it, we take the lock 3 times with flags ( I_DIRTY_SYNC,I_DIRTY_PAGES,I_DIRTY). Perf shows the lock contention increased too much. Below proposed patch fixes it. fs is allocating blocks, which usually means file writes and the inode will be dirtied soon. We fully dirty the inode to reduce some inode_lock contention in several calls of __mark_inode_dirty. Jan Kara: Added comment. Signed-off-by: Shaohua Li Signed-off-by: Alex Shi Signed-off-by: Jan Kara --- include/linux/quotaops.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index d50ba858cfe0..d1a9193960f1 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -274,8 +274,14 @@ static inline int dquot_alloc_space(struct inode *inode, qsize_t nr) int ret; ret = dquot_alloc_space_nodirty(inode, nr); - if (!ret) - mark_inode_dirty_sync(inode); + if (!ret) { + /* + * Mark inode fully dirty. Since we are allocating blocks, inode + * would become fully dirty soon anyway and it reportedly + * reduces inode_lock contention. + */ + mark_inode_dirty(inode); + } return ret; } -- cgit v1.2.3-59-g8ed1b From b5786e85cb2ffd0b07e86dec38a442bd20765ad8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 14:21:17 +0200 Subject: ALSA: hda - Keep char arrays in input_mux items Keep char array in the input_mux item itself instead of pointing to an external string. This is a preliminary work for improving the input-mux name based on the pin role. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 18 ++++++------------ sound/pci/hda/hda_generic.c | 2 +- sound/pci/hda/hda_local.h | 6 +++--- sound/pci/hda/patch_analog.c | 6 +++--- sound/pci/hda/patch_realtek.c | 10 +++++----- sound/pci/hda/patch_sigmatel.c | 16 ++++++++-------- sound/pci/hda/patch_via.c | 15 ++++++++------- 7 files changed, 34 insertions(+), 39 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index bfdde7b0bafb..4348c33c6b85 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4662,17 +4662,8 @@ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { }; EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); -static const char *input_labels[AUTO_PIN_LAST][4] = { - { "Mic", "Mic 2", "Mic 3", "Mic 4" }, - { "Front Mic", "Front Mic 2", "Front Mic 3", "Front Mic 4" }, - { "Line", "Line 2", "Line 3", "Line 4" }, - { "Front Line", "Front Line 2", "Front Line 3", "Front Line 4" }, - { "CD", "CD 2", "CD 3", "CD 4" }, - { "Aux", "Aux 2", "Aux 3", "Aux 4" }, -}; - -const char *snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, - int input) +void snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, + int input, char *str) { int type = cfg->inputs[input].type; int idx; @@ -4681,7 +4672,10 @@ const char *snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, if (type != cfg->inputs[input].type) break; } - return input_labels[type][idx]; + if (idx > 0) + sprintf(str, "%s %d", auto_pin_cfg_labels[type], idx); + else + strcpy(str, auto_pin_cfg_labels[type]); } EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_label); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 5ea21285ee1f..cce18ba8b5a1 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -566,7 +566,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, } label = spec->cap_labels[spec->input_mux.num_items]; strcpy(label, type); - spec->input_mux.items[spec->input_mux.num_items].label = label; + strcpy(spec->input_mux.items[spec->input_mux.num_items].label, label); /* unmute the PIN external input */ unmute_input(codec, node, 0); /* index = 0? */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index fb561748adb8..b448b0a997b1 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -215,7 +215,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); */ #define HDA_MAX_NUM_INPUTS 16 struct hda_input_mux_item { - const char *label; + char label[32]; unsigned int index; }; struct hda_input_mux { @@ -391,8 +391,8 @@ struct auto_pin_cfg_item { }; struct auto_pin_cfg; -const char *snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, - int input); +void snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, + int input, char *label); struct auto_pin_cfg { int line_outs; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 3409d315f507..8de3a0dc45e4 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2926,13 +2926,13 @@ static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec, type <= AUTO_PIN_FRONT_MIC); if (err < 0) return err; - imux->items[imux->num_items].label = - snd_hda_get_input_pin_label(cfg, i); + snd_hda_get_input_pin_label(cfg, i, + imux->items[imux->num_items].label); imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->inputs[i].pin); imux->num_items++; } - imux->items[imux->num_items].label = "Mix"; + strcpy(imux->items[imux->num_items].label, "Mix"); imux->items[imux->num_items].index = 9; imux->num_items++; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0c25d22be875..0a7d9d5ea40e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4974,8 +4974,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, if (idx < 0 && cap2) idx = get_connection_index(codec, cap2, pin); if (idx >= 0) { - imux->items[imux->num_items].label = - snd_hda_get_input_pin_label(cfg, i); + snd_hda_get_input_pin_label(cfg, i, + imux->items[imux->num_items].label); imux->items[imux->num_items].index = idx; imux->num_items++; } @@ -10626,9 +10626,9 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) break; nid = cfg->inputs[i].pin; if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - char label[32]; - snprintf(label, sizeof(label), "%s Boost", - snd_hda_get_input_pin_label(cfg, i)); + char pinname[32], label[32]; + snd_hda_get_input_pin_label(cfg, i, pinname); + snprintf(label, sizeof(label), "%s Boost", pinname); err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); if (err < 0) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7f09e140953e..852dae91edb1 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1116,7 +1116,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) struct hda_input_mux *smux = &spec->private_smux; /* check for mute support on SPDIF out */ if (wcaps & AC_WCAP_OUT_AMP) { - smux->items[smux->num_items].label = "Off"; + strcpy(smux->items[smux->num_items].label, "Off"); smux->items[smux->num_items].index = 0; smux->num_items++; spec->spdif_mute = 1; @@ -3274,8 +3274,8 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) return -EINVAL; for (i = 0; i < num_cons; i++) { - mono_mux->items[mono_mux->num_items].label = - stac92xx_mono_labels[i]; + strcpy(mono_mux->items[mono_mux->num_items].label, + stac92xx_mono_labels[i]); mono_mux->items[mono_mux->num_items].index = i; mono_mux->num_items++; } @@ -3404,7 +3404,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) labels = stac92xx_spdif_labels; for (i = 0; i < num_cons; i++) { - spdif_mux->items[spdif_mux->num_items].label = labels[i]; + strcpy(spdif_mux->items[spdif_mux->num_items].label, labels[i]); spdif_mux->items[spdif_mux->num_items].index = i; spdif_mux->num_items++; } @@ -3538,7 +3538,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, int err, i; unsigned int def_conf; - dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; + strcpy(dimux->items[dimux->num_items].label, stac92xx_dmic_labels[0]); dimux->items[dimux->num_items].index = 0; dimux->num_items++; @@ -3572,11 +3572,11 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, return err; } - dimux->items[dimux->num_items].label = label; + strcpy(dimux->items[dimux->num_items].label, label); dimux->items[dimux->num_items].index = index; dimux->num_items++; if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) { - imux->items[imux->num_items].label = label; + strcpy(imux->items[imux->num_items].label, label); imux->items[imux->num_items].index = index; imux->num_items++; } @@ -3713,7 +3713,7 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const if (err < 0) return err; - imux->items[imux->num_items].label = label; + strcpy(imux->items[imux->num_items].label, label); imux->items[imux->num_items].index = index; imux->num_items++; } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 93b86adbce63..9c1909d398e3 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -2376,7 +2376,7 @@ static void create_hp_imux(struct via_spec *spec) /* for hp mode select */ i = 0; while (texts[i] != NULL) { - imux->items[imux->num_items].label = texts[i]; + strcpy(imux->items[imux->num_items].label, texts[i]); imux->items[imux->num_items].index = i; imux->num_items++; i++; @@ -2423,7 +2423,8 @@ static int vt_auto_create_analog_input_ctls(struct via_spec *spec, /* for internal loopback recording select */ for (idx = 0; idx < num_idxs; idx++) { if (pin_idxs[idx] == 0xff) { - imux->items[imux->num_items].label = "Stereo Mixer"; + strcpy(imux->items[imux->num_items].label, + "Stereo Mixer"); imux->items[imux->num_items].index = idx; imux->num_items++; break; @@ -2445,8 +2446,8 @@ static int vt_auto_create_analog_input_ctls(struct via_spec *spec, type_idx, idx, cap_nid); if (err < 0) return err; - imux->items[imux->num_items].label = - snd_hda_get_input_pin_label(cfg, i); + snd_hda_get_input_pin_label(cfg, i, + imux->items[imux->num_items].label); imux->items[imux->num_items].index = idx; imux->num_items++; } @@ -4336,7 +4337,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) /* for hp mode select */ i = 0; while (texts[i] != NULL) { - imux->items[imux->num_items].label = texts[i]; + strcpy(imux->items[imux->num_items].label, texts[i]); imux->items[imux->num_items].index = i; imux->num_items++; i++; @@ -5520,7 +5521,7 @@ static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec, return err; /* for digital mic select */ - imux->items[imux->num_items].label = "Digital Mic"; + strcpy(imux->items[imux->num_items].label, "Digital Mic"); imux->items[imux->num_items].index = 4; imux->num_items++; @@ -5843,7 +5844,7 @@ static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, return err; /* for digital mic select */ - imux->items[imux->num_items].label = "Digital Mic"; + strcpy(imux->items[imux->num_items].label, "Digital Mic"); imux->items[imux->num_items].index = 6; imux->num_items++; -- cgit v1.2.3-59-g8ed1b From 86e2959a10828dd2614e037fb2502bc833adca52 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 14:50:17 +0200 Subject: ALSA: hda - Remove AUTO_PIN_FRONT_{MIC|LINE} We can assign multiple pins to a single role now, let's reduce the redundant FRONT_MIC and FRONT_LINE. Also, autocfg->input_pins[] is no longer used, so this is removed as well. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 50 +++++------------------------------------- sound/pci/hda/hda_local.h | 5 +---- sound/pci/hda/patch_analog.c | 4 ++-- sound/pci/hda/patch_cirrus.c | 6 ++--- sound/pci/hda/patch_realtek.c | 8 +++---- sound/pci/hda/patch_sigmatel.c | 20 ++++++----------- sound/pci/hda/patch_via.c | 16 +++++++------- 7 files changed, 31 insertions(+), 78 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4348c33c6b85..0ee4439c68ca 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4396,7 +4396,7 @@ static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, * output, i.e. to line_out_pins[0]. So, line_outs is always positive * if any analog output exists. * - * The analog input pins are assigned to input_pins array. + * The analog input pins are assigned to inputs array. * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ @@ -4480,39 +4480,16 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; cfg->hp_outs++; break; - case AC_JACK_MIC_IN: { - int preferred, alt; - if (loc == AC_JACK_LOC_FRONT || - (loc & 0x30) == AC_JACK_LOC_INTERNAL) { - preferred = AUTO_PIN_FRONT_MIC; - alt = AUTO_PIN_MIC; - } else { - preferred = AUTO_PIN_MIC; - alt = AUTO_PIN_FRONT_MIC; - } - if (!cfg->input_pins[preferred]) - cfg->input_pins[preferred] = nid; - else if (!cfg->input_pins[alt]) - cfg->input_pins[alt] = nid; - add_auto_cfg_input_pin(cfg, nid, preferred); + case AC_JACK_MIC_IN: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); break; - } - case AC_JACK_LINE_IN: { - int type; - if (loc == AC_JACK_LOC_FRONT) - type = AUTO_PIN_FRONT_LINE; - else - type = AUTO_PIN_LINE; - cfg->input_pins[type] = nid; - add_auto_cfg_input_pin(cfg, nid, type); + case AC_JACK_LINE_IN: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); break; - } case AC_JACK_CD: - cfg->input_pins[AUTO_PIN_CD] = nid; add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); break; case AC_JACK_AUX: - cfg->input_pins[AUTO_PIN_AUX] = nid; add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); break; case AC_JACK_SPDIF_OUT: @@ -4570,21 +4547,6 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, sort_pins_by_sequence(cfg->hp_pins, sequences_hp, cfg->hp_outs); - /* if we have only one mic, make it AUTO_PIN_MIC */ - if (!cfg->input_pins[AUTO_PIN_MIC] && - cfg->input_pins[AUTO_PIN_FRONT_MIC]) { - cfg->input_pins[AUTO_PIN_MIC] = - cfg->input_pins[AUTO_PIN_FRONT_MIC]; - cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0; - } - /* ditto for line-in */ - if (!cfg->input_pins[AUTO_PIN_LINE] && - cfg->input_pins[AUTO_PIN_FRONT_LINE]) { - cfg->input_pins[AUTO_PIN_LINE] = - cfg->input_pins[AUTO_PIN_FRONT_LINE]; - cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0; - } - /* * FIX-UP: if no line-outs are detected, try to use speaker or HP pin * as a primary output @@ -4658,7 +4620,7 @@ EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); /* labels for input pins - for obsoleted config stuff */ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { - "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" + "Mic", "Line", "CD", "Aux" }; EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index b448b0a997b1..72e7b2f210ee 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -366,9 +366,7 @@ struct hda_bus_unsolicited { enum { AUTO_PIN_MIC, - AUTO_PIN_FRONT_MIC, - AUTO_PIN_LINE, - AUTO_PIN_FRONT_LINE, + AUTO_PIN_LINE_IN, AUTO_PIN_CD, AUTO_PIN_AUX, AUTO_PIN_LAST @@ -403,7 +401,6 @@ struct auto_pin_cfg { int hp_outs; int line_out_type; /* AUTO_PIN_XXX_OUT */ hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t input_pins[AUTO_PIN_LAST]; /* old config; to be deprecated */ int num_inputs; struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS]; int dig_outs; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 8de3a0dc45e4..85fc0b954603 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2923,7 +2923,7 @@ static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec, type_idx = 0; err = new_analog_input(spec, cfg->inputs[i].pin, auto_pin_cfg_labels[type], type_idx, - type <= AUTO_PIN_FRONT_MIC); + type == AUTO_PIN_MIC); if (err < 0) return err; snd_hda_get_input_pin_label(cfg, i, @@ -3015,7 +3015,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) break; } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN); + i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN); if (nid != AD1988_PIN_CD_NID) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 6adfc5625281..adb5ec50252a 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -436,8 +436,8 @@ static int parse_input(struct hda_codec *codec) /* check whether the automatic mic switch is available */ if (spec->num_inputs == 2 && - cfg->inputs[0].type <= AUTO_PIN_FRONT_MIC && - cfg->inputs[1].type == AUTO_PIN_FRONT_MIC) { + cfg->inputs[0].type == AUTO_PIN_MIC && + cfg->inputs[1].type == AUTO_PIN_MIC) { if (is_ext_mic(codec, cfg->inputs[0].pin)) { if (!is_ext_mic(codec, cfg->inputs[1].pin)) { spec->mic_detect = 1; @@ -921,7 +921,7 @@ static void init_input(struct hda_codec *codec) continue; /* set appropriate pin control and mute first */ ctl = PIN_IN; - if (cfg->inputs[i].type <= AUTO_PIN_FRONT_MIC) { + if (cfg->inputs[i].type == AUTO_PIN_MIC) { unsigned int caps = snd_hda_query_pin_caps(codec, pin); caps >>= AC_PINCAP_VREF_SHIFT; if (caps & AC_PINCAP_VREF_80) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0a7d9d5ea40e..8ae30ccf537a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -846,7 +846,7 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, { unsigned int val = PIN_IN; - if (auto_pin_type <= AUTO_PIN_FRONT_MIC) { + if (auto_pin_type == AUTO_PIN_MIC) { unsigned int pincap; unsigned int oldval; oldval = snd_hda_codec_read(codec, nid, 0, @@ -1298,7 +1298,7 @@ static void alc_init_auto_mic(struct hda_codec *codec) /* there must be only two mic inputs exclusively */ for (i = 0; i < cfg->num_inputs; i++) - if (cfg->inputs[i].type >= AUTO_PIN_LINE) + if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) return; fixed = ext = 0; @@ -10622,7 +10622,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) hda_nid_t nid; for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type > AUTO_PIN_FRONT_MIC) + if (cfg->inputs[i].type > AUTO_PIN_MIC) break; nid = cfg->inputs[i].pin; if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { @@ -19270,7 +19270,7 @@ static void alc680_base_setup(struct hda_codec *codec) spec->autocfg.inputs[0].pin = 0x18; spec->autocfg.inputs[0].type = AUTO_PIN_MIC; spec->autocfg.inputs[1].pin = 0x19; - spec->autocfg.inputs[1].type = AUTO_PIN_LINE; + spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN; } static void alc680_unsol_event(struct hda_codec *codec, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 852dae91edb1..d9c8b4d335d2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2834,7 +2834,7 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec) if (cfg->line_out_type != AUTO_PIN_LINE_OUT) return 0; for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type == AUTO_PIN_LINE) { + if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) { nid = cfg->inputs[i].pin; pincap = snd_hda_query_pin_caps(codec, nid); if (pincap & AC_PINCAP_OUT) @@ -2852,16 +2852,14 @@ static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac) struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int def_conf, pincap; - int i, mic_type; + int i; *dac = 0; if (cfg->line_out_type != AUTO_PIN_LINE_OUT) return 0; - mic_type = AUTO_PIN_MIC; - again: for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; - if (cfg->inputs[i].type != mic_type) + if (cfg->inputs[i].type != AUTO_PIN_MIC) continue; def_conf = snd_hda_codec_get_pincfg(codec, nid); /* some laptops have an internal analog microphone @@ -2875,10 +2873,6 @@ static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac) } } } - if (mic_type == AUTO_PIN_MIC) { - mic_type = AUTO_PIN_FRONT_MIC; - goto again; - } return 0; } @@ -3222,7 +3216,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } for (idx = 0; idx < cfg->num_inputs; idx++) { - if (cfg->inputs[idx].type > AUTO_PIN_FRONT_LINE) + if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN) break; nid = cfg->inputs[idx].pin; err = stac92xx_add_jack_mode_control(codec, nid, idx); @@ -3621,7 +3615,7 @@ static int set_mic_route(struct hda_codec *codec, if (pin == cfg->inputs[i].pin) break; } - if (i < cfg->num_inputs && cfg->inputs[i].type <= AUTO_PIN_FRONT_MIC) { + if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) { /* analog pin */ i = get_connection_index(codec, spec->mux_nids[0], pin); if (i < 0) @@ -3656,7 +3650,7 @@ static int stac_check_auto_mic(struct hda_codec *codec) int i; for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type >= AUTO_PIN_LINE) + if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) return 0; /* must be exclusively mics */ } fixed = ext = 0; @@ -4394,7 +4388,7 @@ static int stac92xx_init(struct hda_codec *codec) hda_nid_t nid = cfg->inputs[i].pin; int type = cfg->inputs[i].type; unsigned int pinctl, conf; - if (type == AUTO_PIN_MIC || type == AUTO_PIN_FRONT_MIC) { + if (type == AUTO_PIN_MIC) { /* for mic pins, force to initialize */ pinctl = stac92xx_get_default_vref(codec, nid); pinctl |= AC_PINCTL_IN_EN; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 9c1909d398e3..de5f61d1b725 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -568,7 +568,7 @@ static void via_auto_init_analog_input(struct hda_codec *codec) hda_nid_t nid = cfg->inputs[i].pin; if (spec->smart51_enabled && is_smart51_pins(spec, nid)) ctl = PIN_OUT; - else if (i <= AUTO_PIN_FRONT_MIC) + else if (i == AUTO_PIN_MIC) ctl = PIN_VREF50; else ctl = PIN_IN; @@ -1328,7 +1328,7 @@ static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin) for (i = 0; i < cfg->num_inputs; i++) { if (pin == cfg->inputs[i].pin) - return cfg->inputs[i].type < AUTO_PIN_FRONT_LINE; + return cfg->inputs[i].type <= AUTO_PIN_LINE_IN; } return 0; } @@ -1356,9 +1356,9 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol, hda_nid_t nid = cfg->inputs[i].pin; int ctl = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (cfg->inputs[i].type >= AUTO_PIN_FRONT_LINE) + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) continue; - if (cfg->inputs[i].type == AUTO_PIN_FRONT_MIC && + if (cfg->inputs[i].type == AUTO_PIN_MIC && spec->hp_independent_mode && spec->codec_type != VT1718S) continue; /* ignore FMic for independent HP */ if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN)) @@ -1382,9 +1382,9 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, hda_nid_t nid = cfg->inputs[i].pin; unsigned int parm; - if (cfg->inputs[i].type >= AUTO_PIN_FRONT_LINE) + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) continue; - if (cfg->inputs[i].type == AUTO_PIN_FRONT_MIC && + if (cfg->inputs[i].type == AUTO_PIN_MIC && spec->hp_independent_mode && spec->codec_type != VT1718S) continue; /* don't retask FMic for independent HP */ @@ -1404,7 +1404,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE); } - if (cfg->inputs[i].type == AUTO_PIN_FRONT_MIC) { + if (cfg->inputs[i].type == AUTO_PIN_MIC) { if (spec->codec_type == VT1708S || spec->codec_type == VT1716S) { /* input = index 1 (AOW3) */ @@ -1450,7 +1450,7 @@ static int via_smart51_build(struct via_spec *spec) for (i = 0; i < cfg->num_inputs; i++) { nid = cfg->inputs[i].pin; - if (cfg->inputs[i].type < AUTO_PIN_FRONT_LINE) { + if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) { knew = via_clone_control(spec, &via_smart51_mixer[1]); if (knew == NULL) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 10a20af7c944649dc6d1ffa06bc759f5f3a16cd9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 16:28:02 +0200 Subject: ALSA: hda - Improve the input source name labels This patch improves the input-source label strings to be generated from the pin information instead of fixed strings per AUTO_PIN_* type. This gives more suitable labels, especially for mic and line-in pins. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 91 +++++++++++++++++++++----- sound/pci/hda/hda_generic.c | 41 ++---------- sound/pci/hda/hda_local.h | 11 ++-- sound/pci/hda/patch_analog.c | 27 ++++---- sound/pci/hda/patch_ca0110.c | 3 +- sound/pci/hda/patch_cirrus.c | 4 +- sound/pci/hda/patch_realtek.c | 20 +++--- sound/pci/hda/patch_sigmatel.c | 144 ++++++----------------------------------- sound/pci/hda/patch_via.c | 100 ++++++++++++---------------- 9 files changed, 174 insertions(+), 267 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0ee4439c68ca..e3284341c484 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4607,7 +4607,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, snd_printd(" inputs:"); for (i = 0; i < cfg->num_inputs; i++) { snd_printdd(" %s=0x%x", - auto_pin_cfg_labels[cfg->inputs[i].type], + hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } snd_printd("\n"); @@ -4618,28 +4618,87 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); -/* labels for input pins - for obsoleted config stuff */ -const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { - "Mic", "Line", "CD", "Aux" -}; -EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); +const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, + int check_location) +{ + unsigned int def_conf, loc; + + def_conf = snd_hda_codec_get_pincfg(codec, pin); + loc = get_defcfg_location(def_conf); + + switch (get_defcfg_device(def_conf)) { + case AC_JACK_MIC_IN: + if (!check_location) + return "Mic"; + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || + (loc & 0x30) == AC_JACK_LOC_INTERNAL) + return "Internal Mic"; + if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) + return "Dock Mic"; + if (loc == AC_JACK_LOC_REAR) + return "Rear Mic"; + return "Mic"; + case AC_JACK_LINE_IN: + if (!check_location) + return "Line"; + if ((loc & 0xf0) == AC_JACK_LOC_SEPARATE) + return "Dock Line"; + return "Line"; + case AC_JACK_AUX: + return "Aux"; + case AC_JACK_CD: + return "CD"; + case AC_JACK_SPDIF_IN: + return "SPDIF In"; + case AC_JACK_DIG_OTHER_IN: + return "Digital In"; + default: + return "Misc"; + } +} +EXPORT_SYMBOL_HDA(hda_get_input_pin_label); -void snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, - int input, char *str) +const char *hda_get_autocfg_input_label(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input) { int type = cfg->inputs[input].type; - int idx; + int has_multiple_pins = 0; - for (idx = 0; idx < 3 && --input >= 0; idx++) { - if (type != cfg->inputs[input].type) - break; + if ((input > 0 && cfg->inputs[input - 1].type == type) || + (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type)) + has_multiple_pins = 1; + return hda_get_input_pin_label(codec, cfg->inputs[input].pin, + has_multiple_pins); +} +EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); + +int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, + int index, int *type_idx) +{ + int i, label_idx = 0; + if (imux->num_items >= HDA_MAX_NUM_INPUTS) { + snd_printd(KERN_ERR "hda_codec: Too many imux items!\n"); + return -EINVAL; + } + for (i = 0; i < imux->num_items; i++) { + if (!strncmp(label, imux->items[i].label, strlen(label))) + label_idx++; } - if (idx > 0) - sprintf(str, "%s %d", auto_pin_cfg_labels[type], idx); + if (type_idx) + *type_idx = label_idx; + if (label_idx > 0) + snprintf(imux->items[imux->num_items].label, + sizeof(imux->items[imux->num_items].label), + "%s %d", label, label_idx); else - strcpy(str, auto_pin_cfg_labels[type]); + strlcpy(imux->items[imux->num_items].label, label, + sizeof(imux->items[imux->num_items].label)); + imux->items[imux->num_items].index = index; + imux->num_items++; + return 0; } -EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_label); +EXPORT_SYMBOL_HDA(snd_hda_add_imux_item); #ifdef CONFIG_PM diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index cce18ba8b5a1..fb0582f8d725 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -61,7 +61,6 @@ struct hda_gspec { struct hda_gnode *cap_vol_node; /* Node for capture volume */ unsigned int cur_cap_src; /* current capture source */ struct hda_input_mux input_mux; - char cap_labels[HDA_MAX_NUM_INPUTS][16]; unsigned int def_amp_in_caps; unsigned int def_amp_out_caps; @@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) * returns 0 if not found, 1 if found, or a negative error code. */ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node) + struct hda_gnode *node, int idx) { int i, err; unsigned int pinctl; - char *label; const char *type; if (node->checked) @@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, child = hda_get_node(spec, node->conn_list[i]); if (! child) continue; - err = parse_adc_sub_nodes(codec, spec, child); + err = parse_adc_sub_nodes(codec, spec, child, idx); if (err < 0) return err; if (err > 0) { @@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, return 0; type = "Input"; } - label = spec->cap_labels[spec->input_mux.num_items]; - strcpy(label, type); - strcpy(spec->input_mux.items[spec->input_mux.num_items].label, label); + snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL); /* unmute the PIN external input */ unmute_input(codec, node, 0); /* index = 0? */ @@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, return 1; /* found */ } -/* add a capture source element */ -static void add_cap_src(struct hda_gspec *spec, int idx) -{ - struct hda_input_mux_item *csrc; - char *buf; - int num, ocap; - - num = spec->input_mux.num_items; - csrc = &spec->input_mux.items[num]; - buf = spec->cap_labels[num]; - for (ocap = 0; ocap < num; ocap++) { - if (! strcmp(buf, spec->cap_labels[ocap])) { - /* same label already exists, - * put the index number to be unique - */ - sprintf(buf, "%s %d", spec->cap_labels[ocap], num); - break; - } - } - csrc->index = idx; - spec->input_mux.num_items++; -} - /* * parse input */ @@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) for (i = 0; i < adc_node->nconns; i++) { node = hda_get_node(spec, adc_node->conn_list[i]); if (node && node->type == AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node); + err = parse_adc_sub_nodes(codec, spec, node, i); if (err < 0) return err; - else if (err > 0) - add_cap_src(spec, i); } } /* ... then check the rests, more complicated connections */ for (i = 0; i < adc_node->nconns; i++) { node = hda_get_node(spec, adc_node->conn_list[i]); if (node && node->type != AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node); + err = parse_adc_sub_nodes(codec, spec, node, i); if (err < 0) return err; - else if (err > 0) - add_cap_src(spec, i); } } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 72e7b2f210ee..6943efc78f66 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -378,8 +378,6 @@ enum { AUTO_PIN_HP_OUT }; -extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; - #define AUTO_CFG_MAX_OUTS 5 #define AUTO_CFG_MAX_INS 8 @@ -389,8 +387,13 @@ struct auto_pin_cfg_item { }; struct auto_pin_cfg; -void snd_hda_get_input_pin_label(const struct auto_pin_cfg *cfg, - int input, char *label); +const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, + int check_location); +const char *hda_get_autocfg_input_label(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input); +int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, + int index, int *type_index_ret); struct auto_pin_cfg { int line_outs; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 85fc0b954603..05db1cfcd8b8 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2909,32 +2909,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, } /* create playback/capture controls for input pins */ -static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec, +static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct ad198x_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux; - int i, err, type, type_idx = 0; + int i, err, type, type_idx; for (i = 0; i < cfg->num_inputs; i++) { + const char *label; type = cfg->inputs[i].type; - if (i > 0 && type != cfg->inputs[i - 1].type) - type_idx++; - else - type_idx = 0; + label = hda_get_autocfg_input_label(codec, cfg, i); + snd_hda_add_imux_item(imux, label, + ad1988_pin_to_adc_idx(cfg->inputs[i].pin), + &type_idx); err = new_analog_input(spec, cfg->inputs[i].pin, - auto_pin_cfg_labels[type], type_idx, + label, type_idx, type == AUTO_PIN_MIC); if (err < 0) return err; - snd_hda_get_input_pin_label(cfg, i, - imux->items[imux->num_items].label); - imux->items[imux->num_items].index = - ad1988_pin_to_adc_idx(cfg->inputs[i].pin); - imux->num_items++; } - strcpy(imux->items[imux->num_items].label, "Mix"); - imux->items[imux->num_items].index = 9; - imux->num_items++; + snd_hda_add_imux_item(imux, "Mix", 9, NULL); if ((err = add_control(spec, AD_CTL_WIDGET_VOL, "Analog Mix Playback Volume", @@ -3046,7 +3041,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) "Speaker")) < 0 || (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], "Headphone")) < 0 || - (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0) + (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) return err; spec->multiout.max_channels = spec->multiout.num_dacs * 2; diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 42b3fb4cafc4..cca11fdd3d79 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -474,8 +474,7 @@ static void parse_input(struct hda_codec *codec) if (j >= cfg->num_inputs) continue; spec->input_pins[n] = pin; - spec->input_labels[n] = - auto_pin_cfg_labels[cfg->inputs[j].type]; + spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1); spec->adcs[n] = nid; n++; } diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index adb5ec50252a..ae75283a5583 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -673,6 +673,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int idx; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -681,7 +682,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item >= spec->num_inputs) uinfo->value.enumerated.item = spec->num_inputs - 1; idx = spec->input_idx[uinfo->value.enumerated.item]; - strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]); + strcpy(uinfo->value.enumerated.name, + hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1)); return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8ae30ccf537a..9c2c19c8b059 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4947,6 +4947,7 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t pin; + const char *label; pin = cfg->inputs[i].pin; if (!alc_is_input_pin(codec, pin)) @@ -4957,12 +4958,13 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, type_idx++; else type_idx = 0; + label = hda_get_autocfg_input_label(codec, cfg, i); if (mixer) { idx = get_connection_index(codec, mixer, pin); if (idx >= 0) { err = new_analog_input(spec, pin, - auto_pin_cfg_labels[type], - type_idx, idx, mixer); + label, type_idx, + idx, mixer); if (err < 0) return err; } @@ -4973,12 +4975,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec, idx = get_connection_index(codec, cap1, pin); if (idx < 0 && cap2) idx = get_connection_index(codec, cap2, pin); - if (idx >= 0) { - snd_hda_get_input_pin_label(cfg, i, - imux->items[imux->num_items].label); - imux->items[imux->num_items].index = idx; - imux->num_items++; - } + if (idx >= 0) + snd_hda_add_imux_item(imux, label, idx, NULL); } return 0; } @@ -10626,9 +10624,9 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) break; nid = cfg->inputs[i].pin; if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - char pinname[32], label[32]; - snd_hda_get_input_pin_label(cfg, i, pinname); - snprintf(label, sizeof(label), "%s Boost", pinname); + char label[32]; + snprintf(label, sizeof(label), "%s Boost", + hda_get_autocfg_input_label(codec, cfg, i)); err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); if (err < 0) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d9c8b4d335d2..e4e7d43f911e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -191,11 +191,6 @@ struct sigmatel_mic_route { signed char dmux_idx; }; -struct unique_input_names { - int num; - char uname[HDA_MAX_NUM_INPUTS][32]; -}; - struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -312,7 +307,6 @@ struct sigmatel_spec { struct hda_input_mux private_imux; struct hda_input_mux private_smux; struct hda_input_mux private_mono_mux; - struct unique_input_names private_u_inp_names; }; static hda_nid_t stac9200_adc_nids[1] = { @@ -1116,9 +1110,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) struct hda_input_mux *smux = &spec->private_smux; /* check for mute support on SPDIF out */ if (wcaps & AC_WCAP_OUT_AMP) { - strcpy(smux->items[smux->num_items].label, "Off"); - smux->items[smux->num_items].index = 0; - smux->num_items++; + snd_hda_add_imux_item(smux, "Off", 0, NULL); spec->spdif_mute = 1; } stac_smux_mixer.count = spec->num_smuxes; @@ -2797,7 +2789,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, } if (control) { - strcpy(name, auto_pin_cfg_labels[idx]); + strcpy(name, hda_get_input_pin_label(codec, nid, 1)); return stac92xx_add_control(codec->spec, control, strcat(name, " Jack Mode"), nid); } @@ -3267,12 +3259,9 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) return -EINVAL; - for (i = 0; i < num_cons; i++) { - strcpy(mono_mux->items[mono_mux->num_items].label, - stac92xx_mono_labels[i]); - mono_mux->items[mono_mux->num_items].index = i; - mono_mux->num_items++; - } + for (i = 0; i < num_cons; i++) + snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i, + NULL); return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX, "Mono Mux", spec->mono_nid); @@ -3397,11 +3386,8 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) if (!labels) labels = stac92xx_spdif_labels; - for (i = 0; i < num_cons; i++) { - strcpy(spdif_mux->items[spdif_mux->num_items].label, labels[i]); - spdif_mux->items[spdif_mux->num_items].index = i; - spdif_mux->num_items++; - } + for (i = 0; i < num_cons; i++) + snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL); return 0; } @@ -3452,76 +3438,6 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, return 1; } -static const char *get_input_src_label(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int def_conf; - - def_conf = snd_hda_codec_get_pincfg(codec, nid); - - switch (get_defcfg_device(def_conf)) { - case AC_JACK_MIC_IN: - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || - ((get_defcfg_location(def_conf) & 0xf0) - == AC_JACK_LOC_INTERNAL)) - return "Internal Mic"; - if ((get_defcfg_location(def_conf) & 0xf0) - == AC_JACK_LOC_SEPARATE) - return "Dock Mic"; - if (get_defcfg_location(def_conf) == AC_JACK_LOC_REAR) - return "Rear Mic"; - return "Mic"; - case AC_JACK_LINE_IN: - if ((get_defcfg_location(def_conf) & 0xf0) - == AC_JACK_LOC_SEPARATE) - return "Dock Line"; - return "Line"; - case AC_JACK_AUX: - return "Aux"; - case AC_JACK_CD: - return "CD"; - case AC_JACK_SPDIF_IN: - return "SPDIF In"; - case AC_JACK_DIG_OTHER_IN: - return "Digital In"; - } - - snd_printd("invalid inp pin %02x device config %08x", nid, def_conf); - return NULL; -} - -static const char *get_unique_inp_src_label(struct hda_codec *codec, - hda_nid_t nid) -{ - int i, n; - const char *label; - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - struct hda_input_mux *dimux = &spec->private_dimux; - struct unique_input_names *unames = &spec->private_u_inp_names; - - label = get_input_src_label(codec, nid); - n = 0; - - for (i = 0; i < imux->num_items; i++) { - if (!strncmp(label, imux->items[i].label, strlen(label))) - n++; - } - if (snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { - for (i = 0; i < dimux->num_items; i++) { - if (!strncmp(label, dimux->items[i].label, - strlen(label))) - n++; - } - } - if (n > 0 && unames->num < HDA_MAX_NUM_INPUTS) { - sprintf(&unames->uname[unames->num][0], "%.28s %d", label, n); - label = &unames->uname[unames->num][0]; - unames->num++; - } - - return label; -} - /* create playback/capture controls for input pins on dmic capable codecs */ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) @@ -3532,13 +3448,11 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, int err, i; unsigned int def_conf; - strcpy(dimux->items[dimux->num_items].label, stac92xx_dmic_labels[0]); - dimux->items[dimux->num_items].index = 0; - dimux->num_items++; + snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL); for (i = 0; i < spec->num_dmics; i++) { hda_nid_t nid; - int index; + int index, type_idx; const char *label; nid = spec->dmic_nids[i]; @@ -3552,28 +3466,22 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, if (index < 0) continue; - label = get_unique_inp_src_label(codec, nid); - if (label == NULL) - return -EINVAL; + label = hda_get_input_pin_label(codec, nid, 1); + snd_hda_add_imux_item(dimux, label, index, &type_idx); - err = create_elem_capture_vol(codec, nid, label, 0, HDA_INPUT); + err = create_elem_capture_vol(codec, nid, label, type_idx, + HDA_INPUT); if (err < 0) return err; if (!err) { - err = create_elem_capture_vol(codec, nid, label, 0, - HDA_OUTPUT); + err = create_elem_capture_vol(codec, nid, label, + type_idx, HDA_OUTPUT); if (err < 0) return err; } - strcpy(dimux->items[dimux->num_items].label, label); - dimux->items[dimux->num_items].index = index; - dimux->num_items++; - if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) { - strcpy(imux->items[imux->num_items].label, label); - imux->items[imux->num_items].index = index; - imux->num_items++; - } + if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) + snd_hda_add_imux_item(imux, label, index, NULL); } return 0; @@ -3675,12 +3583,12 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const { struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux; - int i, j, type_idx = 0; + int i, j; const char *label; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; - int index, err; + int index, err, type_idx; index = -1; for (j = 0; j < spec->num_muxes; j++) { @@ -3692,24 +3600,14 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const if (index < 0) continue; - if (i > 0 && cfg->inputs[i].type == cfg->inputs[i - 1].type) - type_idx++; - else - type_idx = 0; - - label = get_unique_inp_src_label(codec, nid); - if (label == NULL) - return -EINVAL; + label = hda_get_autocfg_input_label(codec, cfg, i); + snd_hda_add_imux_item(imux, label, index, &type_idx); err = create_elem_capture_vol(codec, nid, label, type_idx, HDA_INPUT); if (err < 0) return err; - - strcpy(imux->items[imux->num_items].label, label); - imux->items[imux->num_items].index = index; - imux->num_items++; } spec->num_analog_muxes = imux->num_items; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index de5f61d1b725..d1c3f8defc48 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -2374,13 +2374,8 @@ static void create_hp_imux(struct via_spec *spec) static const char *texts[] = { "OFF", "ON", NULL}; /* for hp mode select */ - i = 0; - while (texts[i] != NULL) { - strcpy(imux->items[imux->num_items].label, texts[i]); - imux->items[imux->num_items].index = i; - imux->num_items++; - i++; - } + for (i = 0; texts[i]; i++) + snd_hda_add_imux_item(imux, texts[i], i, NULL); spec->hp_mux = &spec->private_imux[1]; } @@ -2412,26 +2407,25 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg, hda_nid_t cap_nid, hda_nid_t pin_idxs[], int num_idxs) { + struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; int i, err, idx, type, type_idx = 0; /* for internal loopback recording select */ for (idx = 0; idx < num_idxs; idx++) { if (pin_idxs[idx] == 0xff) { - strcpy(imux->items[imux->num_items].label, - "Stereo Mixer"); - imux->items[imux->num_items].index = idx; - imux->num_items++; + snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL); break; } } for (i = 0; i < cfg->num_inputs; i++) { + const char *label; type = cfg->inputs[i].type; for (idx = 0; idx < num_idxs; idx++) if (pin_idxs[idx] == cfg->inputs[i].pin) @@ -2442,24 +2436,21 @@ static int vt_auto_create_analog_input_ctls(struct via_spec *spec, type_idx++; else type_idx = 0; - err = via_new_analog_input(spec, auto_pin_cfg_labels[type], - type_idx, idx, cap_nid); + label = hda_get_autocfg_input_label(codec, cfg, i); + err = via_new_analog_input(spec, label, type_idx, idx, cap_nid); if (err < 0) return err; - snd_hda_get_input_pin_label(cfg, i, - imux->items[imux->num_items].label); - imux->items[imux->num_items].index = idx; - imux->num_items++; + snd_hda_add_imux_item(imux, label, idx, NULL); } return 0; } /* create playback/capture controls for input pins */ -static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 }; - return vt_auto_create_analog_input_ctls(spec, cfg, 0x17, pin_idxs, + return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -2559,7 +2550,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; /* add jack detect on/off control */ @@ -3026,11 +3017,11 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 }; - return vt_auto_create_analog_input_ctls(spec, cfg, 0x18, pin_idxs, + return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -3054,7 +3045,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -3556,11 +3547,11 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e }; - return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs, + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -3584,7 +3575,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -3992,11 +3983,11 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; - return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs, + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4045,7 +4036,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -4335,24 +4326,19 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) imux = &spec->private_imux[1]; /* for hp mode select */ - i = 0; - while (texts[i] != NULL) { - strcpy(imux->items[imux->num_items].label, texts[i]); - imux->items[imux->num_items].index = i; - imux->num_items++; - i++; - } + for (i = 0; texts[i]; i++) + snd_hda_add_imux_item(imux, texts[i], i, NULL); spec->hp_mux = &spec->private_imux[1]; return 0; } /* create playback/capture controls for input pins */ -static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff }; - return vt_auto_create_analog_input_ctls(spec, cfg, 0x1a, pin_idxs, + return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4382,7 +4368,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | (1 << AC_AMPCAP_MUTE_SHIFT)); - err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -4733,11 +4719,11 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff }; - return vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs, + return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -4762,7 +4748,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -5195,11 +5181,11 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff }; - return vt_auto_create_analog_input_ctls(spec, cfg, 0x16, pin_idxs, + return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs, ARRAY_SIZE(pin_idxs)); } @@ -5223,7 +5209,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -5504,14 +5490,15 @@ static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff }; int err; - err = vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs, + err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, ARRAY_SIZE(pin_idxs)); if (err < 0) return err; @@ -5521,9 +5508,7 @@ static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec, return err; /* for digital mic select */ - strcpy(imux->items[imux->num_items].label, "Digital Mic"); - imux->items[imux->num_items].index = 4; - imux->num_items++; + snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL); return 0; } @@ -5551,7 +5536,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; @@ -5826,14 +5811,15 @@ static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) } /* create playback/capture controls for input pins */ -static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, +static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { + struct via_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux[0]; static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff }; int err; - err = vt_auto_create_analog_input_ctls(spec, cfg, 0x21, pin_idxs, + err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs, ARRAY_SIZE(pin_idxs)); if (err < 0) return err; @@ -5844,9 +5830,7 @@ static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, return err; /* for digital mic select */ - strcpy(imux->items[imux->num_items].label, "Digital Mic"); - imux->items[imux->num_items].index = 6; - imux->num_items++; + snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL); return 0; } @@ -5874,7 +5858,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; - err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg); + err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From 3a5c19c23db65a554f2e4f5df5f307c668277056 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 16 Aug 2010 10:06:26 -0500 Subject: [SCSI] fix use-after-free in scsi_init_io() we're using a pointer through a freed command to reset the request, which has shown up as an oops with slab poisoning: Reported-by: Tejun Heo Reported-by: Alexey Dobriyan Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9ade720422c6..ee02d3838a0a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1011,8 +1011,8 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) err_exit: scsi_release_buffers(cmd); - scsi_put_command(cmd); cmd->request->special = NULL; + scsi_put_command(cmd); return error; } EXPORT_SYMBOL(scsi_init_io); -- cgit v1.2.3-59-g8ed1b From 39aa3cb3e8250db9188a6f1e3fb62ffa1a717678 Mon Sep 17 00:00:00 2001 From: Stefan Bader Date: Tue, 31 Aug 2010 15:52:27 +0200 Subject: mm: Move vma_stack_continue into mm.h So it can be used by all that need to check for that. Signed-off-by: Stefan Bader Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 3 ++- include/linux/mm.h | 6 ++++++ mm/mlock.c | 6 ------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 439fc1f1c1c4..271afc48b9a5 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -224,7 +224,8 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) /* We don't show the stack guard page in /proc/maps */ start = vma->vm_start; if (vma->vm_flags & VM_GROWSDOWN) - start += PAGE_SIZE; + if (!vma_stack_continue(vma->vm_prev, vma->vm_start)) + start += PAGE_SIZE; seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", start, diff --git a/include/linux/mm.h b/include/linux/mm.h index e6b1210772ce..74949fbef8c6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -864,6 +864,12 @@ int set_page_dirty(struct page *page); int set_page_dirty_lock(struct page *page); int clear_page_dirty_for_io(struct page *page); +/* Is the vma a continuation of the stack vma above it? */ +static inline int vma_stack_continue(struct vm_area_struct *vma, unsigned long addr) +{ + return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); +} + extern unsigned long move_page_tables(struct vm_area_struct *vma, unsigned long old_addr, struct vm_area_struct *new_vma, unsigned long new_addr, unsigned long len); diff --git a/mm/mlock.c b/mm/mlock.c index cbae7c5b9568..b70919ce4f72 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -135,12 +135,6 @@ void munlock_vma_page(struct page *page) } } -/* Is the vma a continuation of the stack vma above it? */ -static inline int vma_stack_continue(struct vm_area_struct *vma, unsigned long addr) -{ - return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); -} - static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) { return (vma->vm_flags & VM_GROWSDOWN) && -- cgit v1.2.3-59-g8ed1b From a73f8844e1fc54c3762555c1cf1f71774142ca91 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Wed, 8 Sep 2010 16:54:54 -0600 Subject: lglock: make lg_lock_global() actually lock globally lg_lock_global() currently only acquires spinlocks for online CPUs, but it's meant to lock all possible CPUs. Lglock-protected resources may be associated with removed CPUs - and, indeed, that could happen with the per-superblock open files lists. At Nick's suggestion, change for_each_online_cpu() to for_each_possible_cpu() to protect accesses to those resources. Cc: Al Viro Acked-by: Nick Piggin Signed-off-by: Jonathan Corbet Signed-off-by: Linus Torvalds --- include/linux/lglock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/lglock.h b/include/linux/lglock.h index b288cb713b90..f549056fb20b 100644 --- a/include/linux/lglock.h +++ b/include/linux/lglock.h @@ -150,7 +150,7 @@ int i; \ preempt_disable(); \ rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \ - for_each_online_cpu(i) { \ + for_each_possible_cpu(i) { \ arch_spinlock_t *lock; \ lock = &per_cpu(name##_lock, i); \ arch_spin_lock(lock); \ @@ -161,7 +161,7 @@ void name##_global_unlock(void) { \ int i; \ rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \ - for_each_online_cpu(i) { \ + for_each_possible_cpu(i) { \ arch_spinlock_t *lock; \ lock = &per_cpu(name##_lock, i); \ arch_spin_unlock(lock); \ -- cgit v1.2.3-59-g8ed1b From da908f2fb4e783c2a4de751fb90f11a0dd041161 Mon Sep 17 00:00:00 2001 From: Zachary Amsden Date: Thu, 19 Aug 2010 22:07:27 -1000 Subject: KVM: x86: Perform hardware_enable in CPU_STARTING callback The CPU_STARTING callback was added upstream with the intention of being used for KVM, specifically for the hardware enablement that must be done before we can run in hardware virt. It had bugs on the x86_64 architecture at the time, where it was called after CPU_ONLINE. The arches have since merged and the bug is gone. It might be noted other features should probably start making use of this callback; microcode updates in particular which might be fixing important erratums would be best applied before beginning to run user tasks. Signed-off-by: Zachary Amsden Signed-off-by: Marcelo Tosatti --- virt/kvm/kvm_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b78b794c1039..d4853a54771a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1958,10 +1958,10 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, cpu); hardware_disable(NULL); break; - case CPU_ONLINE: + case CPU_STARTING: printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", cpu); - smp_call_function_single(cpu, hardware_enable, NULL, 1); + hardware_enable(NULL); break; } return NOTIFY_OK; @@ -2096,7 +2096,6 @@ int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, static struct notifier_block kvm_cpu_notifier = { .notifier_call = kvm_cpu_hotplug, - .priority = 20, /* must be > scheduler priority */ }; static int vm_stat_get(void *_offset, u64 *val) -- cgit v1.2.3-59-g8ed1b From 5afddee415c829704d3a91031ae634008bc332e9 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 9 Sep 2010 19:58:23 +0200 Subject: AT91: clock: peripheral clocks can have other parent than mck While registering clock allow to set parent clock other than mck. It is useful for clocks than can be seen as child clock of a peripheral. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Andrew Victor --- arch/arm/mach-at91/clock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 7f7da439341f..7525cee3983f 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -501,7 +501,8 @@ postcore_initcall(at91_clk_debugfs_init); int __init clk_register(struct clk *clk) { if (clk_is_peripheral(clk)) { - clk->parent = &mck; + if (!clk->parent) + clk->parent = &mck; clk->mode = pmc_periph_mode; list_add_tail(&clk->node, &clocks); } -- cgit v1.2.3-59-g8ed1b From ab64511cbbd03196d84bcc32c6e7b9d46543df7b Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Fri, 3 Sep 2010 13:31:33 +0100 Subject: AT91: SAM9G45 - add a separate clock entry for every single TC block Without this patch you will not be able to register the first block because of the second association call on at91_add_device_tc(). Signed-off-by: Fabian Godehardt [nicolas.ferre@atmel.com: change tcb1_clk to fake child clock of tcb0_clk] Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Andrew Victor Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91sam9g45.c | 15 ++++++++++++--- arch/arm/mach-at91/at91sam9g45_devices.c | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 753c0d31a3d3..c67b47f1c0fd 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -121,8 +121,8 @@ static struct clk ssc1_clk = { .pmc_mask = 1 << AT91SAM9G45_ID_SSC1, .type = CLK_TYPE_PERIPHERAL, }; -static struct clk tcb_clk = { - .name = "tcb_clk", +static struct clk tcb0_clk = { + .name = "tcb0_clk", .pmc_mask = 1 << AT91SAM9G45_ID_TCB, .type = CLK_TYPE_PERIPHERAL, }; @@ -192,6 +192,14 @@ static struct clk ohci_clk = { .parent = &uhphs_clk, }; +/* One additional fake clock for second TC block */ +static struct clk tcb1_clk = { + .name = "tcb1_clk", + .pmc_mask = 0, + .type = CLK_TYPE_PERIPHERAL, + .parent = &tcb0_clk, +}; + static struct clk *periph_clocks[] __initdata = { &pioA_clk, &pioB_clk, @@ -208,7 +216,7 @@ static struct clk *periph_clocks[] __initdata = { &spi1_clk, &ssc0_clk, &ssc1_clk, - &tcb_clk, + &tcb0_clk, &pwm_clk, &tsc_clk, &dma_clk, @@ -221,6 +229,7 @@ static struct clk *periph_clocks[] __initdata = { &mmc1_clk, // irq0 &ohci_clk, + &tcb1_clk, }; /* diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 501ac6fae2e7..5e71ccd5e7d3 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -835,9 +835,9 @@ static struct platform_device at91sam9g45_tcb1_device = { static void __init at91_add_device_tc(void) { /* this chip has one clock and irq for all six TC channels */ - at91_clock_associate("tcb_clk", &at91sam9g45_tcb0_device.dev, "t0_clk"); + at91_clock_associate("tcb0_clk", &at91sam9g45_tcb0_device.dev, "t0_clk"); platform_device_register(&at91sam9g45_tcb0_device); - at91_clock_associate("tcb_clk", &at91sam9g45_tcb1_device.dev, "t0_clk"); + at91_clock_associate("tcb1_clk", &at91sam9g45_tcb1_device.dev, "t0_clk"); platform_device_register(&at91sam9g45_tcb1_device); } #else -- cgit v1.2.3-59-g8ed1b From 673424c0890a00e22398017c9adf999577526220 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 30 Aug 2010 17:37:05 +0200 Subject: pata_artop: Fix device ID parity check x % 1 always evaluates to 0, which clearly isn't the intent. The author probably had "% 2" or "& 1" in mind, and mispelled it. Signed-off-by: Jean Delvare Cc: Jeff Garzik Cc: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/pata_artop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index ba43f0f8c880..2215632e4b31 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -74,7 +74,8 @@ static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline) struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Odd numbered device ids are the units with enable bits (the -R cards) */ - if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) + if ((pdev->device & 1) && + !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) return -ENOENT; return ata_sff_prereset(link, deadline); -- cgit v1.2.3-59-g8ed1b From f1f5a807b051eddd3f302e503d39214e5bde0ef2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 27 Aug 2010 11:09:15 +0200 Subject: ahci: fix hang on failed softreset ahci_do_softreset() compared the current time and deadline in reverse when calculating timeout for SRST issue. The result is that if @deadline is in future, SRST is issued with 0 timeout, which hasn't caused any problem because it later waits for DRDY with the correct timeout. If deadline is already exceeded by the time SRST is about to be issued, the timeout calculation underflows and if the device doesn't respond, timeout doesn't trigger for a _very_ long time. Reverse the incorrect comparison order. Signed-off-by: Tejun Heo Reported-by: Anssi Hannula Tested-by: Gwendal Grignou Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/libahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 666850d31df2..68dc6785472f 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1326,7 +1326,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class, /* issue the first D2H Register FIS */ msecs = 0; now = jiffies; - if (time_after(now, deadline)) + if (time_after(deadline, now)) msecs = jiffies_to_msecs(deadline - now); tf.ctl |= ATA_SRST; -- cgit v1.2.3-59-g8ed1b From 9cb627d5f38830ca19aa0dca52d1d3a633018bf7 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 1 Sep 2010 12:58:43 +0200 Subject: perf, trace: Fix module leak Commit 1c024eca (perf, trace: Optimize tracepoints by using per-tracepoint-per-cpu hlist to track events) caused a module refcount leak. Reported-And-Tested-by: Avi Kivity Signed-off-by: Peter Zijlstra LKML-Reference: <4C7E1F12.8030304@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- kernel/trace/trace_event_perf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 000e6e85b445..31cc4cb0dbf2 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -91,6 +91,8 @@ int perf_trace_init(struct perf_event *p_event) tp_event->class && tp_event->class->reg && try_module_get(tp_event->mod)) { ret = perf_trace_event_init(tp_event, p_event); + if (ret) + module_put(tp_event->mod); break; } } @@ -146,6 +148,7 @@ void perf_trace_destroy(struct perf_event *p_event) } } out: + module_put(tp_event->mod); mutex_unlock(&event_mutex); } -- cgit v1.2.3-59-g8ed1b From 5e11637e2c929e34dcc0fbbfb48bdb638937701a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 11 Jun 2010 13:35:08 +0200 Subject: perf: Fix CPU hotplug Since we have UP_PREPARE, we should also have UP_CANCELED. Signed-off-by: Peter Zijlstra Cc: paulus LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/perf_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 657555a5f30f..db5b56064687 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -5761,15 +5761,15 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { unsigned int cpu = (long)hcpu; - switch (action) { + switch (action & ~CPU_TASKS_FROZEN) { case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: + case CPU_DOWN_FAILED: perf_event_init_cpu(cpu); break; + case CPU_UP_CANCELED: case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: perf_event_exit_cpu(cpu); break; -- cgit v1.2.3-59-g8ed1b From da2b71edd8a7db44fe1746261410a981f3e03632 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Mon, 23 Aug 2010 13:42:51 -0700 Subject: sched: Move sched_avg_update() to update_cpu_load() Currently sched_avg_update() (which updates rt_avg stats in the rq) is getting called from scale_rt_power() (in the load balance context) which doesn't take rq->lock. Fix it by moving the sched_avg_update() to more appropriate update_cpu_load() where the CFS load gets updated as well. Signed-off-by: Suresh Siddha Signed-off-by: Peter Zijlstra LKML-Reference: <1282596171.2694.3.camel@sbsiddha-MOBL3> Signed-off-by: Ingo Molnar --- kernel/sched.c | 6 ++++++ kernel/sched_fair.c | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 09b574e7f4df..ed09d4f2a69c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1294,6 +1294,10 @@ static void resched_task(struct task_struct *p) static void sched_rt_avg_update(struct rq *rq, u64 rt_delta) { } + +static void sched_avg_update(struct rq *rq) +{ +} #endif /* CONFIG_SMP */ #if BITS_PER_LONG == 32 @@ -3182,6 +3186,8 @@ static void update_cpu_load(struct rq *this_rq) this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i; } + + sched_avg_update(this_rq); } static void update_cpu_load_active(struct rq *this_rq) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index ab661ebc4895..f53ec7550056 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -2268,8 +2268,6 @@ unsigned long scale_rt_power(int cpu) struct rq *rq = cpu_rq(cpu); u64 total, available; - sched_avg_update(rq); - total = sched_avg_period() + (rq->clock - rq->age_stamp); available = total - rq->rt_avg; -- cgit v1.2.3-59-g8ed1b From a1c985158382cbce0b58b3264f771b3b153668a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 21:36:27 +0200 Subject: ALSA: hda - Reduce redundant mic location prefix in input source labels When the mic pins are assigned to the same location, we can omit the redundant location prefix like "Front" or "Rear". Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 90 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e3284341c484..affb4607c6da 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4618,32 +4618,64 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); +enum { + MIC_ATTR_INT, + MIC_ATTR_DOCK, + MIC_ATTR_NORMAL, + MIC_ATTR_FRONT, + MIC_ATTR_REAR, +}; + +static int get_mic_pin_attr(unsigned int def_conf) +{ + unsigned int loc = get_defcfg_location(def_conf); + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || + (loc & 0x30) == AC_JACK_LOC_INTERNAL) + return MIC_ATTR_INT; + if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) + return MIC_ATTR_DOCK; + if (loc == AC_JACK_LOC_REAR) + return MIC_ATTR_REAR; + if (loc == AC_JACK_LOC_FRONT) + return MIC_ATTR_FRONT; + return MIC_ATTR_NORMAL; +} + +enum { + LINE_ATTR_DOCK, + LINE_ATTR_NORMAL, +}; + +static int get_line_pin_attr(unsigned int def_conf) +{ + unsigned int loc = get_defcfg_location(def_conf); + if ((loc & 0xf0) == AC_JACK_LOC_SEPARATE) + return LINE_ATTR_DOCK; + return LINE_ATTR_NORMAL; +} + const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, int check_location) { - unsigned int def_conf, loc; + unsigned int def_conf; + static const char *mic_names[] = { + "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", + }; + static const char *line_names[] = { + "Dock Line", "Line", + }; def_conf = snd_hda_codec_get_pincfg(codec, pin); - loc = get_defcfg_location(def_conf); switch (get_defcfg_device(def_conf)) { case AC_JACK_MIC_IN: if (!check_location) return "Mic"; - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || - (loc & 0x30) == AC_JACK_LOC_INTERNAL) - return "Internal Mic"; - if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) - return "Dock Mic"; - if (loc == AC_JACK_LOC_REAR) - return "Rear Mic"; - return "Mic"; + return mic_names[get_mic_pin_attr(def_conf)]; case AC_JACK_LINE_IN: if (!check_location) return "Line"; - if ((loc & 0xf0) == AC_JACK_LOC_SEPARATE) - return "Dock Line"; - return "Line"; + return line_names[get_line_pin_attr(def_conf)]; case AC_JACK_AUX: return "Aux"; case AC_JACK_CD: @@ -4658,6 +4690,36 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, } EXPORT_SYMBOL_HDA(hda_get_input_pin_label); +/* Check whether the location prefix needs to be added to the label. + * If all mic-jacks are in the same location (e.g. rear panel), we don't + * have to put "Front" prefix to each label. In such a case, returns false. + */ +static int check_mic_location_need(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input) +{ + unsigned int defc; + int i, attr, attr2; + + defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin); + attr = get_mic_pin_attr(defc); + /* for internal or docking mics, we need locations */ + if (attr <= MIC_ATTR_NORMAL) + return 1; + + attr = 0; + for (i = 0; i < cfg->num_inputs; i++) { + defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin); + attr2 = get_mic_pin_attr(defc); + if (attr2 >= MIC_ATTR_NORMAL) { + if (attr && attr != attr2) + return 1; /* different locations found */ + attr = attr2; + } + } + return 0; +} + const char *hda_get_autocfg_input_label(struct hda_codec *codec, const struct auto_pin_cfg *cfg, int input) @@ -4668,6 +4730,8 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, if ((input > 0 && cfg->inputs[input - 1].type == type) || (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type)) has_multiple_pins = 1; + if (has_multiple_pins && type == AUTO_PIN_MIC) + has_multiple_pins &= check_mic_location_need(codec, cfg, input); return hda_get_input_pin_label(codec, cfg->inputs[input].pin, has_multiple_pins); } -- cgit v1.2.3-59-g8ed1b From 990061c28ab6c84e1120afb772b69d92d8965da8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 22:08:44 +0200 Subject: ALSA: hda - Add comments to new helper functions Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index affb4607c6da..ec38bdfad81e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4654,6 +4654,14 @@ static int get_line_pin_attr(unsigned int def_conf) return LINE_ATTR_NORMAL; } +/** + * hda_get_input_pin_label - Give a label for the given input pin + * + * When check_location is true, the function checks the pin location + * for mic and line-in pins, and set an appropriate prefix like "Front", + * "Rear", "Internal". + */ + const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, int check_location) { @@ -4720,6 +4728,14 @@ static int check_mic_location_need(struct hda_codec *codec, return 0; } +/** + * hda_get_autocfg_input_label - Get a label for the given input + * + * Get a label for the given input pin defined by the autocfg item. + * Unlike hda_get_input_pin_label(), this function checks all inputs + * defined in autocfg and avoids the redundant mic/line prefix as much as + * possible. + */ const char *hda_get_autocfg_input_label(struct hda_codec *codec, const struct auto_pin_cfg *cfg, int input) @@ -4737,6 +4753,13 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); +/** + * snd_hda_add_imux_item - Add an item to input_mux + * + * When the same label is used already in the existing items, the number + * suffix is appended to the label. This label index number is stored + * to type_idx when non-NULL pointer is given. + */ int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, int index, int *type_idx) { -- cgit v1.2.3-59-g8ed1b From 4a4d4a6985dd37a3c96534027f054be796bf95f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 22:22:02 +0200 Subject: ALSA: hda - Sort input pins in snd_hda_parse_pin_def_config() Sort inputs[] array in autocfg so that the codec parsers can filter out easily per input pin types. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ec38bdfad81e..08d81b873022 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4383,6 +4383,23 @@ static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, } } +/* sort inputs in the order of AUTO_PIN_* type */ +static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) +{ + int i, j; + + for (i = 0; i < cfg->num_inputs; i++) { + for (j = i + 1; j < cfg->num_inputs; j++) { + if (cfg->inputs[i].type > cfg->inputs[j].type) { + struct auto_pin_cfg_item tmp; + tmp = cfg->inputs[i]; + cfg->inputs[i] = cfg->inputs[j]; + cfg->inputs[j] = tmp; + } + } + } +} + /* * Parse all pin widgets and store the useful pin nids to cfg * @@ -4585,6 +4602,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, break; } + sort_autocfg_input_pins(cfg); + /* * debug prints of the parsed results */ -- cgit v1.2.3-59-g8ed1b From 0e52247a2ed1f211f0c4f682dc999610a368903f Mon Sep 17 00:00:00 2001 From: Cam Macdonell Date: Tue, 7 Sep 2010 17:25:20 -0700 Subject: PCI: fix pci_resource_alignment prototype This fixes the prototype for both pci_resource_alignment() and pci_sriov_resource_alignment(). Patch started as debugging effort from Cam Macdonell. Cc: Cam Macdonell Cc: Avi Kivity [chrisw: add iov bits] Signed-off-by: Chris Wright Signed-off-by: Jesse Barnes --- drivers/pci/iov.c | 2 +- drivers/pci/pci.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index ce6a3666b3d9..553d8ee55c1c 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -608,7 +608,7 @@ int pci_iov_resource_bar(struct pci_dev *dev, int resno, * the VF BAR size multiplied by the number of VFs. The alignment * is just the VF BAR size. */ -int pci_sriov_resource_alignment(struct pci_dev *dev, int resno) +resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno) { struct resource tmp; enum pci_bar_type type; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 7754a678ab15..6beb11b617a9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -264,7 +264,8 @@ extern int pci_iov_init(struct pci_dev *dev); extern void pci_iov_release(struct pci_dev *dev); extern int pci_iov_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); -extern int pci_sriov_resource_alignment(struct pci_dev *dev, int resno); +extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, + int resno); extern void pci_restore_iov_state(struct pci_dev *dev); extern int pci_iov_bus_range(struct pci_bus *bus); @@ -320,7 +321,7 @@ static inline int pci_ats_enabled(struct pci_dev *dev) } #endif /* CONFIG_PCI_IOV */ -static inline int pci_resource_alignment(struct pci_dev *dev, +static inline resource_size_t pci_resource_alignment(struct pci_dev *dev, struct resource *res) { #ifdef CONFIG_PCI_IOV -- cgit v1.2.3-59-g8ed1b From 85e00b55517a5696282b80836655e6b6f5702df0 Mon Sep 17 00:00:00 2001 From: Jovi Zhang Date: Thu, 9 Sep 2010 13:30:59 -0300 Subject: perf symbols: Fix multiple initialization of symbol system By returning immediately if it was already initialized, do it as well at symbol__exit, refusing multiple deinitializations. This fixes problems in the kmem, sched and timechart commands. Reported-by: Davidlohr Bueso Cc: Davidlohr Bueso Signed-off-by: Jovi Zhang LKML-Reference: AANLkTi=9Cn=R8SPMCRp5z+gEjXbaBHeb-AaOtRbuwwcn@mail.gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 7 +++++++ tools/perf/util/symbol.h | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 1a367734e016..b2f5ae97f33d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2268,6 +2268,9 @@ static int setup_list(struct strlist **list, const char *list_str, int symbol__init(void) { + if (symbol_conf.initialized) + return 0; + elf_version(EV_CURRENT); if (symbol_conf.sort_by_name) symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - @@ -2293,6 +2296,7 @@ int symbol__init(void) symbol_conf.sym_list_str, "symbol") < 0) goto out_free_comm_list; + symbol_conf.initialized = true; return 0; out_free_dso_list: @@ -2304,11 +2308,14 @@ out_free_comm_list: void symbol__exit(void) { + if (!symbol_conf.initialized) + return; strlist__delete(symbol_conf.sym_list); strlist__delete(symbol_conf.dso_list); strlist__delete(symbol_conf.comm_list); vmlinux_path__exit(); symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; + symbol_conf.initialized = false; } int machines__create_kernel_maps(struct rb_root *self, pid_t pid) diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index b7a8da4af5a0..ea95c2756f05 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -69,7 +69,8 @@ struct symbol_conf { show_nr_samples, use_callchain, exclude_other, - show_cpu_utilization; + show_cpu_utilization, + initialized; const char *vmlinux_name, *source_prefix, *field_sep; -- cgit v1.2.3-59-g8ed1b From 9e84ed63dc71e13b62cea5ec6b0049260cca0b7a Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 9 Sep 2010 22:39:41 +0100 Subject: ARM: Partially revert "Auto calculate ZRELADDR and provide option for exceptions" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partially revert e69edc7, which introduced automatic zreladdr support. The change in the way the manual definition is defined seems to be error and conflict prone. Go back to the original way we were handling this for the time being, while keeping the automatic zreladdr facility. Acked-by: Uwe Kleine-König --- arch/arm/Kconfig | 91 --------------------------------------- arch/arm/boot/Makefile | 8 ++-- arch/arm/boot/compressed/Makefile | 4 ++ arch/arm/boot/compressed/head.S | 2 +- 4 files changed, 10 insertions(+), 95 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 16bc8eb4901c..553b7cf17bfb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1576,97 +1576,6 @@ config AUTO_ZRELADDR 0xf8000000. This assumes the zImage being placed in the first 128MB from start of memory. -config ZRELADDR - hex "Physical address of the decompressed kernel image" - depends on !AUTO_ZRELADDR - default 0x00008000 if ARCH_BCMRING ||\ - ARCH_CNS3XXX ||\ - ARCH_DOVE ||\ - ARCH_EBSA110 ||\ - ARCH_FOOTBRIDGE ||\ - ARCH_INTEGRATOR ||\ - ARCH_IOP13XX ||\ - ARCH_IOP33X ||\ - ARCH_IXP2000 ||\ - ARCH_IXP23XX ||\ - ARCH_IXP4XX ||\ - ARCH_KIRKWOOD ||\ - ARCH_KS8695 ||\ - ARCH_LOKI ||\ - ARCH_MMP ||\ - ARCH_MV78XX0 ||\ - ARCH_NOMADIK ||\ - ARCH_NUC93X ||\ - ARCH_NS9XXX ||\ - ARCH_ORION5X ||\ - ARCH_SPEAR3XX ||\ - ARCH_SPEAR6XX ||\ - ARCH_TEGRA ||\ - ARCH_U8500 ||\ - ARCH_VERSATILE ||\ - ARCH_W90X900 - default 0x08008000 if ARCH_MX1 ||\ - ARCH_SHARK - default 0x10008000 if ARCH_MSM ||\ - ARCH_OMAP1 ||\ - ARCH_RPC - default 0x20008000 if ARCH_S5P6440 ||\ - ARCH_S5P6442 ||\ - ARCH_S5PC100 ||\ - ARCH_S5PV210 - default 0x30008000 if ARCH_S3C2410 ||\ - ARCH_S3C2400 ||\ - ARCH_S3C2412 ||\ - ARCH_S3C2416 ||\ - ARCH_S3C2440 ||\ - ARCH_S3C2443 - default 0x40008000 if ARCH_STMP378X ||\ - ARCH_STMP37XX ||\ - ARCH_SH7372 ||\ - ARCH_SH7377 ||\ - ARCH_S5PV310 - default 0x50008000 if ARCH_S3C64XX ||\ - ARCH_SH7367 - default 0x60008000 if ARCH_VEXPRESS - default 0x80008000 if ARCH_MX25 ||\ - ARCH_MX3 ||\ - ARCH_NETX ||\ - ARCH_OMAP2PLUS ||\ - ARCH_PNX4008 - default 0x90008000 if ARCH_MX5 ||\ - ARCH_MX91231 - default 0xa0008000 if ARCH_IOP32X ||\ - ARCH_PXA ||\ - MACH_MX27 - default 0xc0008000 if ARCH_LH7A40X ||\ - MACH_MX21 - default 0xf0008000 if ARCH_AAEC2000 ||\ - ARCH_L7200 - default 0xc0028000 if ARCH_CLPS711X - default 0x70008000 if ARCH_AT91 && (ARCH_AT91CAP9 || ARCH_AT91SAM9G45) - default 0x20008000 if ARCH_AT91 && !(ARCH_AT91CAP9 || ARCH_AT91SAM9G45) - default 0xc0008000 if ARCH_DAVINCI && ARCH_DAVINCI_DA8XX - default 0x80008000 if ARCH_DAVINCI && !ARCH_DAVINCI_DA8XX - default 0x00008000 if ARCH_EP93XX && EP93XX_SDCE3_SYNC_PHYS_OFFSET - default 0xc0008000 if ARCH_EP93XX && EP93XX_SDCE0_PHYS_OFFSET - default 0xd0008000 if ARCH_EP93XX && EP93XX_SDCE1_PHYS_OFFSET - default 0xe0008000 if ARCH_EP93XX && EP93XX_SDCE2_PHYS_OFFSET - default 0xf0008000 if ARCH_EP93XX && EP93XX_SDCE3_ASYNC_PHYS_OFFSET - default 0x00008000 if ARCH_GEMINI && GEMINI_MEM_SWAP - default 0x10008000 if ARCH_GEMINI && !GEMINI_MEM_SWAP - default 0x70008000 if ARCH_REALVIEW && REALVIEW_HIGH_PHYS_OFFSET - default 0x00008000 if ARCH_REALVIEW && !REALVIEW_HIGH_PHYS_OFFSET - default 0xc0208000 if ARCH_SA1100 && SA1111 - default 0xc0008000 if ARCH_SA1100 && !SA1111 - default 0x30108000 if ARCH_S3C2410 && PM_H1940 - default 0x28E08000 if ARCH_U300 && MACH_U300_SINGLE_RAM - default 0x48008000 if ARCH_U300 && !MACH_U300_SINGLE_RAM - help - ZRELADDR is the physical address where the decompressed kernel - image will be placed. ZRELADDR has to be specified when the - assumption of AUTO_ZRELADDR is not valid, or when ZBOOT_ROM is - selected. - endmenu menu "CPU Power Management" diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index f705213caa88..4a590f4113e2 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -14,16 +14,18 @@ MKIMAGE := $(srctree)/scripts/mkuboot.sh ifneq ($(MACHINE),) --include $(srctree)/$(MACHINE)/Makefile.boot +include $(srctree)/$(MACHINE)/Makefile.boot endif # Note: the following conditions must always be true: +# ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET) # PARAMS_PHYS must be within 4MB of ZRELADDR # INITRD_PHYS must be in RAM +ZRELADDR := $(zreladdr-y) PARAMS_PHYS := $(params_phys-y) INITRD_PHYS := $(initrd_phys-y) -export INITRD_PHYS PARAMS_PHYS +export ZRELADDR INITRD_PHYS PARAMS_PHYS targets := Image zImage xipImage bootpImage uImage @@ -65,7 +67,7 @@ quiet_cmd_uimage = UIMAGE $@ ifeq ($(CONFIG_ZBOOT_ROM),y) $(obj)/uImage: LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT) else -$(obj)/uImage: LOADADDR=$(CONFIG_ZRELADDR) +$(obj)/uImage: LOADADDR=$(ZRELADDR) endif ifeq ($(CONFIG_THUMB2_KERNEL),y) diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 68775e33476c..b23f6bc46cfa 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -79,6 +79,10 @@ endif EXTRA_CFLAGS := -fpic -fno-builtin EXTRA_AFLAGS := -Wa,-march=all +# Supply ZRELADDR to the decompressor via a linker symbol. +ifneq ($(CONFIG_AUTO_ZRELADDR),y) +LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR) +endif ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) LDFLAGS_vmlinux += --be8 endif diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 6af9907c3b5c..6825c34646d4 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -177,7 +177,7 @@ not_angel: and r4, pc, #0xf8000000 add r4, r4, #TEXT_OFFSET #else - ldr r4, =CONFIG_ZRELADDR + ldr r4, =zreladdr #endif subs r0, r0, r1 @ calculate the delta offset -- cgit v1.2.3-59-g8ed1b From a14d0404088a7b0d51bb5219baf33d77e5592007 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 9 Sep 2010 22:43:02 +0100 Subject: ARM: Update mach-types Signed-off-by: Russell King --- arch/arm/tools/mach-types | 98 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index 48cbdcb6bbd4..55590a4d87c9 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Mon Jul 12 21:10:14 2010 +# Last update: Thu Sep 9 22:43:01 2010 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -2622,7 +2622,7 @@ kraken MACH_KRAKEN KRAKEN 2634 gw2388 MACH_GW2388 GW2388 2635 jadecpu MACH_JADECPU JADECPU 2636 carlisle MACH_CARLISLE CARLISLE 2637 -lux_sf9 MACH_LUX_SFT9 LUX_SFT9 2638 +lux_sf9 MACH_LUX_SF9 LUX_SF9 2638 nemid_tb MACH_NEMID_TB NEMID_TB 2639 terrier MACH_TERRIER TERRIER 2640 turbot MACH_TURBOT TURBOT 2641 @@ -2950,3 +2950,97 @@ davinci_dm365_dvr MACH_DAVINCI_DM365_DVR DAVINCI_DM365_DVR 2963 netviz MACH_NETVIZ NETVIZ 2964 flexibity MACH_FLEXIBITY FLEXIBITY 2965 wlan_computer MACH_WLAN_COMPUTER WLAN_COMPUTER 2966 +lpc24xx MACH_LPC24XX LPC24XX 2967 +spica MACH_SPICA SPICA 2968 +gpsdisplay MACH_GPSDISPLAY GPSDISPLAY 2969 +bipnet MACH_BIPNET BIPNET 2970 +overo_ctu_inertial MACH_OVERO_CTU_INERTIAL OVERO_CTU_INERTIAL 2971 +davinci_dm355_mmm MACH_DAVINCI_DM355_MMM DAVINCI_DM355_MMM 2972 +pc9260_v2 MACH_PC9260_V2 PC9260_V2 2973 +ptx7545 MACH_PTX7545 PTX7545 2974 +tm_efdc MACH_TM_EFDC TM_EFDC 2975 +omap3_waldo1 MACH_OMAP3_WALDO1 OMAP3_WALDO1 2977 +flyer MACH_FLYER FLYER 2978 +tornado3240 MACH_TORNADO3240 TORNADO3240 2979 +soli_01 MACH_SOLI_01 SOLI_01 2980 +omapl138_europalc MACH_OMAPL138_EUROPALC OMAPL138_EUROPALC 2981 +helios_v1 MACH_HELIOS_V1 HELIOS_V1 2982 +netspace_lite_v2 MACH_NETSPACE_LITE_V2 NETSPACE_LITE_V2 2983 +ssc MACH_SSC SSC 2984 +premierwave_en MACH_PREMIERWAVE_EN PREMIERWAVE_EN 2985 +wasabi MACH_WASABI WASABI 2986 +vivow MACH_VIVOW VIVOW 2987 +mx50_rdp MACH_MX50_RDP MX50_RDP 2988 +universal MACH_UNIVERSAL UNIVERSAL 2989 +real6410 MACH_REAL6410 REAL6410 2990 +spx_sakura MACH_SPX_SAKURA SPX_SAKURA 2991 +ij3k_2440 MACH_IJ3K_2440 IJ3K_2440 2992 +omap3_bc10 MACH_OMAP3_BC10 OMAP3_BC10 2993 +thebe MACH_THEBE THEBE 2994 +rv082 MACH_RV082 RV082 2995 +armlguest MACH_ARMLGUEST ARMLGUEST 2996 +tjinc1000 MACH_TJINC1000 TJINC1000 2997 +dockstar MACH_DOCKSTAR DOCKSTAR 2998 +ax8008 MACH_AX8008 AX8008 2999 +gnet_sgce MACH_GNET_SGCE GNET_SGCE 3000 +pxwnas_500_1000 MACH_PXWNAS_500_1000 PXWNAS_500_1000 3001 +ea20 MACH_EA20 EA20 3002 +awm2 MACH_AWM2 AWM2 3003 +ti8148evm MACH_TI8148EVM TI8148EVM 3004 +tegra_seaboard MACH_TEGRA_SEABOARD TEGRA_SEABOARD 3005 +linkstation_chlv2 MACH_LINKSTATION_CHLV2 LINKSTATION_CHLV2 3006 +tera_pro2_rack MACH_TERA_PRO2_RACK TERA_PRO2_RACK 3007 +rubys MACH_RUBYS RUBYS 3008 +aquarius MACH_AQUARIUS AQUARIUS 3009 +mx53_ard MACH_MX53_ARD MX53_ARD 3010 +mx53_smd MACH_MX53_SMD MX53_SMD 3011 +lswxl MACH_LSWXL LSWXL 3012 +dove_avng_v3 MACH_DOVE_AVNG_V3 DOVE_AVNG_V3 3013 +sdi_ess_9263 MACH_SDI_ESS_9263 SDI_ESS_9263 3014 +jocpu550 MACH_JOCPU550 JOCPU550 3015 +msm8x60_rumi3 MACH_MSM8X60_RUMI3 MSM8X60_RUMI3 3016 +msm8x60_ffa MACH_MSM8X60_FFA MSM8X60_FFA 3017 +yanomami MACH_YANOMAMI YANOMAMI 3018 +gta04 MACH_GTA04 GTA04 3019 +cm_a510 MACH_CM_A510 CM_A510 3020 +omap3_rfs200 MACH_OMAP3_RFS200 OMAP3_RFS200 3021 +kx33xx MACH_KX33XX KX33XX 3022 +ptx7510 MACH_PTX7510 PTX7510 3023 +top9000 MACH_TOP9000 TOP9000 3024 +teenote MACH_TEENOTE TEENOTE 3025 +ts3 MACH_TS3 TS3 3026 +a0 MACH_A0 A0 3027 +fsm9xxx_surf MACH_FSM9XXX_SURF FSM9XXX_SURF 3028 +fsm9xxx_ffa MACH_FSM9XXX_FFA FSM9XXX_FFA 3029 +frrhwcdma60w MACH_FRRHWCDMA60W FRRHWCDMA60W 3030 +remus MACH_REMUS REMUS 3031 +at91cap7xdk MACH_AT91CAP7XDK AT91CAP7XDK 3032 +at91cap7stk MACH_AT91CAP7STK AT91CAP7STK 3033 +kt_sbc_sam9_1 MACH_KT_SBC_SAM9_1 KT_SBC_SAM9_1 3034 +oratisrouter MACH_ORATISROUTER ORATISROUTER 3035 +armada_xp_db MACH_ARMADA_XP_DB ARMADA_XP_DB 3036 +spdm MACH_SPDM SPDM 3037 +gtib MACH_GTIB GTIB 3038 +dgm3240 MACH_DGM3240 DGM3240 3039 +atlas_i_lpe MACH_ATLAS_I_LPE ATLAS_I_LPE 3040 +htcmega MACH_HTCMEGA HTCMEGA 3041 +tricorder MACH_TRICORDER TRICORDER 3042 +tx28 MACH_TX28 TX28 3043 +bstbrd MACH_BSTBRD BSTBRD 3044 +pwb3090 MACH_PWB3090 PWB3090 3045 +idea6410 MACH_IDEA6410 IDEA6410 3046 +qbc9263 MACH_QBC9263 QBC9263 3047 +borabora MACH_BORABORA BORABORA 3048 +valdez MACH_VALDEZ VALDEZ 3049 +ls9g20 MACH_LS9G20 LS9G20 3050 +mios_v1 MACH_MIOS_V1 MIOS_V1 3051 +s5pc110_crespo MACH_S5PC110_CRESPO S5PC110_CRESPO 3052 +controltek9g20 MACH_CONTROLTEK9G20 CONTROLTEK9G20 3053 +tin307 MACH_TIN307 TIN307 3054 +tin510 MACH_TIN510 TIN510 3055 +bluecheese MACH_BLUECHEESE BLUECHEESE 3057 +tem3x30 MACH_TEM3X30 TEM3X30 3058 +harvest_desoto MACH_HARVEST_DESOTO HARVEST_DESOTO 3059 +msm8x60_qrdc MACH_MSM8X60_QRDC MSM8X60_QRDC 3060 +spear900 MACH_SPEAR900 SPEAR900 3061 +pcontrol_g20 MACH_PCONTROL_G20 PCONTROL_G20 3062 -- cgit v1.2.3-59-g8ed1b From 123031c0eeda6144b4002dc3285375aa9ae9dc11 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 8 Sep 2010 11:04:21 +0000 Subject: sctp: fix test for end of loop Add a list_has_sctp_addr function to simplify loop Based on a patches by Dan Carpenter and David Miller Signed-off-by: Joe Perches Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 24b2cd555637..d344dc481ccc 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1232,6 +1232,18 @@ out: return 0; } +static bool list_has_sctp_addr(const struct list_head *list, + union sctp_addr *ipaddr) +{ + struct sctp_transport *addr; + + list_for_each_entry(addr, list, transports) { + if (sctp_cmp_addr_exact(ipaddr, &addr->ipaddr)) + return true; + } + + return false; +} /* A restart is occurring, check to make sure no new addresses * are being added as we may be under a takeover attack. */ @@ -1240,10 +1252,10 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc, struct sctp_chunk *init, sctp_cmd_seq_t *commands) { - struct sctp_transport *new_addr, *addr; - int found; + struct sctp_transport *new_addr; + int ret = 1; - /* Implementor's Guide - Sectin 5.2.2 + /* Implementor's Guide - Section 5.2.2 * ... * Before responding the endpoint MUST check to see if the * unexpected INIT adds new addresses to the association. If new @@ -1254,31 +1266,19 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc, /* Search through all current addresses and make sure * we aren't adding any new ones. */ - new_addr = NULL; - found = 0; - list_for_each_entry(new_addr, &new_asoc->peer.transport_addr_list, - transports) { - found = 0; - list_for_each_entry(addr, &asoc->peer.transport_addr_list, - transports) { - if (sctp_cmp_addr_exact(&new_addr->ipaddr, - &addr->ipaddr)) { - found = 1; - break; - } - } - if (!found) + transports) { + if (!list_has_sctp_addr(&asoc->peer.transport_addr_list, + &new_addr->ipaddr)) { + sctp_sf_send_restart_abort(&new_addr->ipaddr, init, + commands); + ret = 0; break; - } - - /* If a new address was added, ABORT the sender. */ - if (!found && new_addr) { - sctp_sf_send_restart_abort(&new_addr->ipaddr, init, commands); + } } /* Return success if all addresses were found. */ - return found; + return ret; } /* Populate the verification/tie tags based on overlapping INIT -- cgit v1.2.3-59-g8ed1b From f574c843191728d9407b766a027f779dcd27b272 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Thu, 9 Sep 2010 15:16:56 -0700 Subject: [IA64] fix siglock When ia64 converted to using ticket locks, an inline implementation of trylock/unlock in fsys.S was missed. This was not noticed because in most circumstances it simply resulted in using the slow path because the siglock was apparently not available (under old spinlock rules). Problems occur when the ticket spinlock has value 0x0 (when first initialised, or when it wraps around). At this point the fsys.S code acquires the lock (changing the 0x0 to 0x1. If another process attempts to get the lock at this point, it will change the value from 0x1 to 0x2 (using new ticket lock rules). Then the fsys.S code will free the lock using old spinlock rules by writing 0x0 to it. From here a variety of bad things can happen. Signed-off-by: Tony Luck --- arch/ia64/kernel/fsys.S | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 3567d54f8cee..471a1e783aca 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -424,14 +424,26 @@ EX(.fail_efault, ld8 r14=[r33]) // r14 <- *set andcm r14=r14,r17 // filter out SIGKILL & SIGSTOP #ifdef CONFIG_SMP - mov r17=1 - ;; - cmpxchg4.acq r18=[r31],r17,ar.ccv // try to acquire the lock + // __ticket_spin_trylock(r31) + ld4 r17=[r31] mov r8=EINVAL // default to EINVAL ;; + extr r9=r17,17,15 + ;; + xor r18=r17,r9 + adds r19=1,r17 + ;; + extr.u r18=r18,0,15 + ;; + cmp.eq p0,p7=0,r18 +(p7) br.cond.spnt.many .lock_contention + mov.m ar.ccv=r17 + ;; + cmpxchg4.acq r9=[r31],r19,ar.ccv + ;; + cmp4.eq p0,p7=r9,r17 +(p7) br.cond.spnt.many .lock_contention ld8 r3=[r2] // re-read current->blocked now that we hold the lock - cmp4.ne p6,p0=r18,r0 -(p6) br.cond.spnt.many .lock_contention ;; #else ld8 r3=[r2] // re-read current->blocked now that we hold the lock @@ -490,7 +502,17 @@ EX(.fail_efault, ld8 r14=[r33]) // r14 <- *set (p6) br.cond.spnt.few 1b // yes -> retry #ifdef CONFIG_SMP - st4.rel [r31]=r0 // release the lock + // __ticket_spin_unlock(r31) + adds r31=2,r31 + ;; + ld2.bias r2=[r31] + mov r3=65534 + ;; + adds r2=2,r2 + ;; + and r3=r3,r2 + ;; + st2.rel [r31]=r3 #endif SSM_PSR_I(p0, p9, r31) ;; @@ -512,7 +534,17 @@ EX(.fail_efault, (p15) st8 [r34]=r3) .sig_pending: #ifdef CONFIG_SMP - st4.rel [r31]=r0 // release the lock + // __ticket_spin_unlock(r31) + adds r31=2,r31 + ;; + ld2.bias r2=[r31] + mov r3=65534 + ;; + adds r2=2,r2 + ;; + and r3=r3,r2 + ;; + st2.rel [r31]=r3 #endif SSM_PSR_I(p0, p9, r17) ;; -- cgit v1.2.3-59-g8ed1b From f3c65b2870f2481f3646bc410a58a12989ecc704 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 9 Sep 2010 16:37:24 -0700 Subject: mmc: avoid getting CID on SDIO-only cards The introduction of support for SD combo cards breaks the initialization of all CSR SDIO chips. The GO_IDLE (CMD0) in mmc_sd_get_cid() causes CSR chips to be reset (this is non-standard behavior). When initializing an SDIO card check for a combo card by using the memory present bit in the R4 response to IO_SEND_OP_COND (CMD5). This avoids the call to mmc_sd_get_cid() on an SDIO-only card. Signed-off-by: David Vrabel Acked-by: Michal Mirolaw Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/core/sdio.c | 5 ++--- include/linux/mmc/sdio.h | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index bd2755e8d9a3..f332c52968b7 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -362,9 +362,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, goto err; } - err = mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid); - - if (!err) { + if (ocr & R4_MEMORY_PRESENT + && mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid) == 0) { card->type = MMC_TYPE_SD_COMBO; if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index 329a8faa6e37..245cdacee544 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -38,6 +38,8 @@ * [8:0] Byte/block count */ +#define R4_MEMORY_PRESENT (1 << 27) + /* SDIO status in R5 Type -- cgit v1.2.3-59-g8ed1b From e0bf1024b36be90da241af3c2767311e055b612c Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Thu, 9 Sep 2010 16:37:26 -0700 Subject: kfifo: add parenthesis for macro parameter reference Some macro parameter references inside typeof() operator are not enclosed with parenthesis. It should be safer to add them. Signed-off-by: Huang Ying Acked-by: Stefani Seibold Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kfifo.h | 58 +++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h index 4aa95f203f3e..62dbee554f60 100644 --- a/include/linux/kfifo.h +++ b/include/linux/kfifo.h @@ -214,7 +214,7 @@ __kfifo_must_check_helper(unsigned int val) */ #define kfifo_reset(fifo) \ (void)({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ __tmp->kfifo.in = __tmp->kfifo.out = 0; \ }) @@ -228,7 +228,7 @@ __kfifo_must_check_helper(unsigned int val) */ #define kfifo_reset_out(fifo) \ (void)({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ __tmp->kfifo.out = __tmp->kfifo.in; \ }) @@ -238,7 +238,7 @@ __kfifo_must_check_helper(unsigned int val) */ #define kfifo_len(fifo) \ ({ \ - typeof(fifo + 1) __tmpl = (fifo); \ + typeof((fifo) + 1) __tmpl = (fifo); \ __tmpl->kfifo.in - __tmpl->kfifo.out; \ }) @@ -248,7 +248,7 @@ __kfifo_must_check_helper(unsigned int val) */ #define kfifo_is_empty(fifo) \ ({ \ - typeof(fifo + 1) __tmpq = (fifo); \ + typeof((fifo) + 1) __tmpq = (fifo); \ __tmpq->kfifo.in == __tmpq->kfifo.out; \ }) @@ -258,7 +258,7 @@ __kfifo_must_check_helper(unsigned int val) */ #define kfifo_is_full(fifo) \ ({ \ - typeof(fifo + 1) __tmpq = (fifo); \ + typeof((fifo) + 1) __tmpq = (fifo); \ kfifo_len(__tmpq) > __tmpq->kfifo.mask; \ }) @@ -269,7 +269,7 @@ __kfifo_must_check_helper(unsigned int val) #define kfifo_avail(fifo) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmpq = (fifo); \ + typeof((fifo) + 1) __tmpq = (fifo); \ const size_t __recsize = sizeof(*__tmpq->rectype); \ unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \ (__recsize) ? ((__avail <= __recsize) ? 0 : \ @@ -284,7 +284,7 @@ __kfifo_must_check_helper( \ */ #define kfifo_skip(fifo) \ (void)({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ if (__recsize) \ @@ -302,7 +302,7 @@ __kfifo_must_check_helper( \ #define kfifo_peek_len(fifo) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ (!__recsize) ? kfifo_len(__tmp) * sizeof(*__tmp->type) : \ @@ -325,7 +325,7 @@ __kfifo_must_check_helper( \ #define kfifo_alloc(fifo, size, gfp_mask) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ __is_kfifo_ptr(__tmp) ? \ __kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \ @@ -339,7 +339,7 @@ __kfifo_must_check_helper( \ */ #define kfifo_free(fifo) \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ if (__is_kfifo_ptr(__tmp)) \ __kfifo_free(__kfifo); \ @@ -358,7 +358,7 @@ __kfifo_must_check_helper( \ */ #define kfifo_init(fifo, buffer, size) \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ __is_kfifo_ptr(__tmp) ? \ __kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \ @@ -379,8 +379,8 @@ __kfifo_must_check_helper( \ */ #define kfifo_put(fifo, val) \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ - typeof(val + 1) __val = (val); \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ unsigned int __ret; \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -421,8 +421,8 @@ __kfifo_must_check_helper( \ #define kfifo_get(fifo, val) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ - typeof(val + 1) __val = (val); \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ unsigned int __ret; \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -462,8 +462,8 @@ __kfifo_must_check_helper( \ #define kfifo_peek(fifo, val) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ - typeof(val + 1) __val = (val); \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((val) + 1) __val = (val); \ unsigned int __ret; \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -501,8 +501,8 @@ __kfifo_must_check_helper( \ */ #define kfifo_in(fifo, buf, n) \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ - typeof(buf + 1) __buf = (buf); \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ unsigned long __n = (n); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -554,8 +554,8 @@ __kfifo_must_check_helper( \ #define kfifo_out(fifo, buf, n) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ - typeof(buf + 1) __buf = (buf); \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ unsigned long __n = (n); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -611,7 +611,7 @@ __kfifo_must_check_helper( \ #define kfifo_from_user(fifo, from, len, copied) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ const void __user *__from = (from); \ unsigned int __len = (len); \ unsigned int *__copied = (copied); \ @@ -639,7 +639,7 @@ __kfifo_must_check_helper( \ #define kfifo_to_user(fifo, to, len, copied) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ void __user *__to = (to); \ unsigned int __len = (len); \ unsigned int *__copied = (copied); \ @@ -666,7 +666,7 @@ __kfifo_must_check_helper( \ */ #define kfifo_dma_in_prepare(fifo, sgl, nents, len) \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ struct scatterlist *__sgl = (sgl); \ int __nents = (nents); \ unsigned int __len = (len); \ @@ -690,7 +690,7 @@ __kfifo_must_check_helper( \ */ #define kfifo_dma_in_finish(fifo, len) \ (void)({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ unsigned int __len = (len); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -717,7 +717,7 @@ __kfifo_must_check_helper( \ */ #define kfifo_dma_out_prepare(fifo, sgl, nents, len) \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ struct scatterlist *__sgl = (sgl); \ int __nents = (nents); \ unsigned int __len = (len); \ @@ -741,7 +741,7 @@ __kfifo_must_check_helper( \ */ #define kfifo_dma_out_finish(fifo, len) \ (void)({ \ - typeof(fifo + 1) __tmp = (fifo); \ + typeof((fifo) + 1) __tmp = (fifo); \ unsigned int __len = (len); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ @@ -766,8 +766,8 @@ __kfifo_must_check_helper( \ #define kfifo_out_peek(fifo, buf, n) \ __kfifo_must_check_helper( \ ({ \ - typeof(fifo + 1) __tmp = (fifo); \ - typeof(buf + 1) __buf = (buf); \ + typeof((fifo) + 1) __tmp = (fifo); \ + typeof((buf) + 1) __buf = (buf); \ unsigned long __n = (n); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ -- cgit v1.2.3-59-g8ed1b From 110b7e9698601b28f313c2c560d51a8b1c742002 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 9 Sep 2010 16:37:27 -0700 Subject: rtc-bfin: fix inverted logic in suspend path The int_clear helper takes a bitmask of interrupts to keep, not to disable. When suspending without wakeup enabled, we want to disable all interrupts, so use 0 (keep none) instead of -1 (keep all). Signed-off-by: Mike Frysinger Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 72b2bcc2c224..65facfbe70fb 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -426,7 +426,7 @@ static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state) enable_irq_wake(IRQ_RTC); bfin_rtc_sync_pending(&pdev->dev); } else - bfin_rtc_int_clear(-1); + bfin_rtc_int_clear(0); return 0; } -- cgit v1.2.3-59-g8ed1b From b6de860651d5a9e56ba4f4e3edc1aa52ac2ac849 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 9 Sep 2010 16:37:29 -0700 Subject: rtc-bfin: fix state restoration when resuming Much (but not all) of the RTC state is kept in the RTC peripheral which has its own power domain. Periodically (1 HZ), that state is synced from one power domain to the other (peripheral->core). When we are resuming, we need to wait for the sync to occur so that we don't get a mismatch of reading undefined state in the rest of the driver. Further, once the externally maintained bits have been synced back into the core, we then need to restore the bits maintained in the core. In our particular case, that is just the write completion interrupt bit. If we don't do any of this, working with the RTC causes ~5 second delays from time to time after waking up due to the write completion interrupt never firing. Reported-by: Michael Dean Reported-by: Michael Hennerich Signed-off-by: Mike Frysinger Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-bfin.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 65facfbe70fb..d4fb82d85e9b 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -435,8 +435,17 @@ static int bfin_rtc_resume(struct platform_device *pdev) { if (device_may_wakeup(&pdev->dev)) disable_irq_wake(IRQ_RTC); - else - bfin_write_RTC_ISTAT(-1); + + /* + * Since only some of the RTC bits are maintained externally in the + * Vbat domain, we need to wait for the RTC MMRs to be synced into + * the core after waking up. This happens every RTC 1HZ. Once that + * has happened, we can go ahead and re-enable the important write + * complete interrupt event. + */ + while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_SEC)) + continue; + bfin_rtc_int_set(RTC_ISTAT_WRITE_COMPLETE); return 0; } -- cgit v1.2.3-59-g8ed1b From 841a23ae1e7a8f8758ac915ceaf2e11a1cc235c5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 9 Sep 2010 16:37:30 -0700 Subject: MAINTAINERS: remove drivers/char/hpet.c bob.picco@hp.com doesn't work any more and Bob says that he's unlikely to work on hpet.c in the future. Signed-off-by: Jiri Slaby Acked-by: Bob Picco Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7e189b57c8b5..05e5537b7690 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2787,11 +2787,6 @@ S: Maintained F: arch/x86/kernel/hpet.c F: arch/x86/include/asm/hpet.h -HPET: ACPI -M: Bob Picco -S: Maintained -F: drivers/char/hpet.c - HPFS FILESYSTEM M: Mikulas Patocka W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi -- cgit v1.2.3-59-g8ed1b From 4e70598c3b56e6fec551454c495d4d4025834749 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 16:37:31 -0700 Subject: hp_accel: add quirks for HP ProBook 532x and HP Mini 5102 Added missing axis-mapping for HP ProBook 532x and HP Mini 5102. Signed-off-by: Takashi Iwai Cc: Eric Piel Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/hwmon/hp_accel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index 7580f55e67e3..36e957532230 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c @@ -221,6 +221,8 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), + AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted), + AXIS_DMI_MATCH("Mini5102", "HP Mini 5102", xy_rotated_left_usd), { NULL, } /* Laptop models without axis info (yet): * "NC6910" "HP Compaq 6910" -- cgit v1.2.3-59-g8ed1b From 7a801ac6f5067539ceb5fad0fe90ec49fc156e47 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Thu, 9 Sep 2010 16:37:33 -0700 Subject: O_DIRECT: fix the splitting up of contiguous I/O commit c2c6ca4 (direct-io: do not merge logically non-contiguous requests) introduced a bug whereby all O_DIRECT I/Os were submitted a page at a time to the block layer. The problem is that the code expected dio->block_in_file to correspond to the current page in the dio. In fact, it corresponds to the previous page submitted via submit_page_section. This was purely an oversight, as the dio->cur_page_fs_offset field was introduced for just this purpose. This patch simply uses the correct variable when calculating whether there is a mismatch between contiguous logical blocks and contiguous physical blocks (as described in the comments). I also switched the if conditional following this check to an else if, to ensure that we never call dio_bio_submit twice for the same dio (in theory, this should not happen, anyway). I've tested this by running blktrace and verifying that a 64KB I/O was submitted as a single I/O. I also ran the patched kernel through xfstests' aio tests using xfs, ext4 (with 1k and 4k block sizes) and btrfs and verified that there were no regressions as compared to an unpatched kernel. Signed-off-by: Jeff Moyer Acked-by: Josef Bacik Cc: Christoph Hellwig Cc: Chris Mason Cc: [2.6.35.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/direct-io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/direct-io.c b/fs/direct-io.c index 51f270b479b6..48d74c7391d1 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -634,7 +634,7 @@ static int dio_send_cur_page(struct dio *dio) int ret = 0; if (dio->bio) { - loff_t cur_offset = dio->block_in_file << dio->blkbits; + loff_t cur_offset = dio->cur_page_fs_offset; loff_t bio_next_offset = dio->logical_offset_in_bio + dio->bio->bi_size; @@ -659,7 +659,7 @@ static int dio_send_cur_page(struct dio *dio) * Submit now if the underlying fs is about to perform a * metadata read */ - if (dio->boundary) + else if (dio->boundary) dio_bio_submit(dio); } -- cgit v1.2.3-59-g8ed1b From 2f327dad14aa8bc939a4f0a2d3fdcf64a2d8c09e Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 9 Sep 2010 16:37:33 -0700 Subject: MAINTAINERS: kexec-tools has moved Kexec tools has been moved to http://kernel.org/pub/linux/utils/kernel/kexec/ as user-space code shouldn't be in /pub/linux/kernel Signed-off-by: Simon Horman Acked-by: "Eric W. Biederman" Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 05e5537b7690..a3da87f82a75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3399,7 +3399,7 @@ F: drivers/s390/kvm/ KEXEC M: Eric Biederman -W: http://ftp.kernel.org/pub/linux/kernel/people/horms/kexec-tools/ +W: http://kernel.org/pub/linux/utils/kernel/kexec/ L: kexec@lists.infradead.org S: Maintained F: include/linux/kexec.h -- cgit v1.2.3-59-g8ed1b From 85a0fdfd0f967507f3903e8419bc7e408f5a59de Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 9 Sep 2010 16:37:35 -0700 Subject: gcov: fix null-pointer dereference for certain module types The gcov-kernel infrastructure expects that each object file is loaded only once. This may not be true, e.g. when loading multiple kernel modules which are linked to the same object file. As a result, loading such kernel modules will result in incorrect gcov results while unloading will cause a null-pointer dereference. This patch fixes these problems by changing the gcov-kernel infrastructure so that multiple profiling data sets can be associated with one debugfs entry. It applies to 2.6.36-rc1. Signed-off-by: Peter Oberparleiter Reported-by: Werner Spies Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/gcov/fs.c | 244 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 180 insertions(+), 64 deletions(-) diff --git a/kernel/gcov/fs.c b/kernel/gcov/fs.c index ef3c3f88a7a3..f83972b16564 100644 --- a/kernel/gcov/fs.c +++ b/kernel/gcov/fs.c @@ -33,10 +33,11 @@ * @children: child nodes * @all: list head for list of all nodes * @parent: parent node - * @info: associated profiling data structure if not a directory - * @ghost: when an object file containing profiling data is unloaded we keep a - * copy of the profiling data here to allow collecting coverage data - * for cleanup code. Such a node is called a "ghost". + * @loaded_info: array of pointers to profiling data sets for loaded object + * files. + * @num_loaded: number of profiling data sets for loaded object files. + * @unloaded_info: accumulated copy of profiling data sets for unloaded + * object files. Used only when gcov_persist=1. * @dentry: main debugfs entry, either a directory or data file * @links: associated symbolic links * @name: data file basename @@ -51,10 +52,11 @@ struct gcov_node { struct list_head children; struct list_head all; struct gcov_node *parent; - struct gcov_info *info; - struct gcov_info *ghost; + struct gcov_info **loaded_info; + struct gcov_info *unloaded_info; struct dentry *dentry; struct dentry **links; + int num_loaded; char name[0]; }; @@ -136,16 +138,37 @@ static const struct seq_operations gcov_seq_ops = { }; /* - * Return the profiling data set for a given node. This can either be the - * original profiling data structure or a duplicate (also called "ghost") - * in case the associated object file has been unloaded. + * Return a profiling data set associated with the given node. This is + * either a data set for a loaded object file or a data set copy in case + * all associated object files have been unloaded. */ static struct gcov_info *get_node_info(struct gcov_node *node) { - if (node->info) - return node->info; + if (node->num_loaded > 0) + return node->loaded_info[0]; - return node->ghost; + return node->unloaded_info; +} + +/* + * Return a newly allocated profiling data set which contains the sum of + * all profiling data associated with the given node. + */ +static struct gcov_info *get_accumulated_info(struct gcov_node *node) +{ + struct gcov_info *info; + int i = 0; + + if (node->unloaded_info) + info = gcov_info_dup(node->unloaded_info); + else + info = gcov_info_dup(node->loaded_info[i++]); + if (!info) + return NULL; + for (; i < node->num_loaded; i++) + gcov_info_add(info, node->loaded_info[i]); + + return info; } /* @@ -163,9 +186,10 @@ static int gcov_seq_open(struct inode *inode, struct file *file) mutex_lock(&node_lock); /* * Read from a profiling data copy to minimize reference tracking - * complexity and concurrent access. + * complexity and concurrent access and to keep accumulating multiple + * profiling data sets associated with one node simple. */ - info = gcov_info_dup(get_node_info(node)); + info = get_accumulated_info(node); if (!info) goto out_unlock; iter = gcov_iter_new(info); @@ -225,12 +249,25 @@ static struct gcov_node *get_node_by_name(const char *name) return NULL; } +/* + * Reset all profiling data associated with the specified node. + */ +static void reset_node(struct gcov_node *node) +{ + int i; + + if (node->unloaded_info) + gcov_info_reset(node->unloaded_info); + for (i = 0; i < node->num_loaded; i++) + gcov_info_reset(node->loaded_info[i]); +} + static void remove_node(struct gcov_node *node); /* * write() implementation for gcov data files. Reset profiling data for the - * associated file. If the object file has been unloaded (i.e. this is - * a "ghost" node), remove the debug fs node as well. + * corresponding file. If all associated object files have been unloaded, + * remove the debug fs node as well. */ static ssize_t gcov_seq_write(struct file *file, const char __user *addr, size_t len, loff_t *pos) @@ -245,10 +282,10 @@ static ssize_t gcov_seq_write(struct file *file, const char __user *addr, node = get_node_by_name(info->filename); if (node) { /* Reset counts or remove node for unloaded modules. */ - if (node->ghost) + if (node->num_loaded == 0) remove_node(node); else - gcov_info_reset(node->info); + reset_node(node); } /* Reset counts for open file. */ gcov_info_reset(info); @@ -378,7 +415,10 @@ static void init_node(struct gcov_node *node, struct gcov_info *info, INIT_LIST_HEAD(&node->list); INIT_LIST_HEAD(&node->children); INIT_LIST_HEAD(&node->all); - node->info = info; + if (node->loaded_info) { + node->loaded_info[0] = info; + node->num_loaded = 1; + } node->parent = parent; if (name) strcpy(node->name, name); @@ -394,9 +434,13 @@ static struct gcov_node *new_node(struct gcov_node *parent, struct gcov_node *node; node = kzalloc(sizeof(struct gcov_node) + strlen(name) + 1, GFP_KERNEL); - if (!node) { - pr_warning("out of memory\n"); - return NULL; + if (!node) + goto err_nomem; + if (info) { + node->loaded_info = kcalloc(1, sizeof(struct gcov_info *), + GFP_KERNEL); + if (!node->loaded_info) + goto err_nomem; } init_node(node, info, name, parent); /* Differentiate between gcov data file nodes and directory nodes. */ @@ -416,6 +460,11 @@ static struct gcov_node *new_node(struct gcov_node *parent, list_add(&node->all, &all_head); return node; + +err_nomem: + kfree(node); + pr_warning("out of memory\n"); + return NULL; } /* Remove symbolic links associated with node. */ @@ -441,8 +490,9 @@ static void release_node(struct gcov_node *node) list_del(&node->all); debugfs_remove(node->dentry); remove_links(node); - if (node->ghost) - gcov_info_free(node->ghost); + kfree(node->loaded_info); + if (node->unloaded_info) + gcov_info_free(node->unloaded_info); kfree(node); } @@ -477,7 +527,7 @@ static struct gcov_node *get_child_by_name(struct gcov_node *parent, /* * write() implementation for reset file. Reset all profiling data to zero - * and remove ghost nodes. + * and remove nodes for which all associated object files are unloaded. */ static ssize_t reset_write(struct file *file, const char __user *addr, size_t len, loff_t *pos) @@ -487,8 +537,8 @@ static ssize_t reset_write(struct file *file, const char __user *addr, mutex_lock(&node_lock); restart: list_for_each_entry(node, &all_head, all) { - if (node->info) - gcov_info_reset(node->info); + if (node->num_loaded > 0) + reset_node(node); else if (list_empty(&node->children)) { remove_node(node); /* Several nodes may have gone - restart loop. */ @@ -564,37 +614,115 @@ err_remove: } /* - * The profiling data set associated with this node is being unloaded. Store a - * copy of the profiling data and turn this node into a "ghost". + * Associate a profiling data set with an existing node. Needs to be called + * with node_lock held. */ -static int ghost_node(struct gcov_node *node) +static void add_info(struct gcov_node *node, struct gcov_info *info) { - node->ghost = gcov_info_dup(node->info); - if (!node->ghost) { - pr_warning("could not save data for '%s' (out of memory)\n", - node->info->filename); - return -ENOMEM; + struct gcov_info **loaded_info; + int num = node->num_loaded; + + /* + * Prepare new array. This is done first to simplify cleanup in + * case the new data set is incompatible, the node only contains + * unloaded data sets and there's not enough memory for the array. + */ + loaded_info = kcalloc(num + 1, sizeof(struct gcov_info *), GFP_KERNEL); + if (!loaded_info) { + pr_warning("could not add '%s' (out of memory)\n", + info->filename); + return; + } + memcpy(loaded_info, node->loaded_info, + num * sizeof(struct gcov_info *)); + loaded_info[num] = info; + /* Check if the new data set is compatible. */ + if (num == 0) { + /* + * A module was unloaded, modified and reloaded. The new + * data set replaces the copy of the last one. + */ + if (!gcov_info_is_compatible(node->unloaded_info, info)) { + pr_warning("discarding saved data for %s " + "(incompatible version)\n", info->filename); + gcov_info_free(node->unloaded_info); + node->unloaded_info = NULL; + } + } else { + /* + * Two different versions of the same object file are loaded. + * The initial one takes precedence. + */ + if (!gcov_info_is_compatible(node->loaded_info[0], info)) { + pr_warning("could not add '%s' (incompatible " + "version)\n", info->filename); + kfree(loaded_info); + return; + } } - node->info = NULL; + /* Overwrite previous array. */ + kfree(node->loaded_info); + node->loaded_info = loaded_info; + node->num_loaded = num + 1; +} - return 0; +/* + * Return the index of a profiling data set associated with a node. + */ +static int get_info_index(struct gcov_node *node, struct gcov_info *info) +{ + int i; + + for (i = 0; i < node->num_loaded; i++) { + if (node->loaded_info[i] == info) + return i; + } + return -ENOENT; } /* - * Profiling data for this node has been loaded again. Add profiling data - * from previous instantiation and turn this node into a regular node. + * Save the data of a profiling data set which is being unloaded. */ -static void revive_node(struct gcov_node *node, struct gcov_info *info) +static void save_info(struct gcov_node *node, struct gcov_info *info) { - if (gcov_info_is_compatible(node->ghost, info)) - gcov_info_add(info, node->ghost); + if (node->unloaded_info) + gcov_info_add(node->unloaded_info, info); else { - pr_warning("discarding saved data for '%s' (version changed)\n", + node->unloaded_info = gcov_info_dup(info); + if (!node->unloaded_info) { + pr_warning("could not save data for '%s' " + "(out of memory)\n", info->filename); + } + } +} + +/* + * Disassociate a profiling data set from a node. Needs to be called with + * node_lock held. + */ +static void remove_info(struct gcov_node *node, struct gcov_info *info) +{ + int i; + + i = get_info_index(node, info); + if (i < 0) { + pr_warning("could not remove '%s' (not found)\n", info->filename); + return; } - gcov_info_free(node->ghost); - node->ghost = NULL; - node->info = info; + if (gcov_persist) + save_info(node, info); + /* Shrink array. */ + node->loaded_info[i] = node->loaded_info[node->num_loaded - 1]; + node->num_loaded--; + if (node->num_loaded > 0) + return; + /* Last loaded data set was removed. */ + kfree(node->loaded_info); + node->loaded_info = NULL; + node->num_loaded = 0; + if (!node->unloaded_info) + remove_node(node); } /* @@ -609,30 +737,18 @@ void gcov_event(enum gcov_action action, struct gcov_info *info) node = get_node_by_name(info->filename); switch (action) { case GCOV_ADD: - /* Add new node or revive ghost. */ - if (!node) { + if (node) + add_info(node, info); + else add_node(info); - break; - } - if (gcov_persist) - revive_node(node, info); - else { - pr_warning("could not add '%s' (already exists)\n", - info->filename); - } break; case GCOV_REMOVE: - /* Remove node or turn into ghost. */ - if (!node) { + if (node) + remove_info(node, info); + else { pr_warning("could not remove '%s' (not found)\n", info->filename); - break; } - if (gcov_persist) { - if (!ghost_node(node)) - break; - } - remove_node(node); break; } mutex_unlock(&node_lock); -- cgit v1.2.3-59-g8ed1b From ed430fec756ad65f7cfba24f8ad17c3d5a403290 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Sep 2010 16:37:36 -0700 Subject: proc: export uncached bit properly in /proc/kpageflags Fix the left-over old ifdef for PG_uncached in /proc/kpageflags. Now it's used by x86, too. Signed-off-by: Takashi Iwai Cc: Wu Fengguang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/page.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/page.c b/fs/proc/page.c index 180cf5a0bd67..3b8b45660331 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -146,7 +146,7 @@ u64 stable_page_flags(struct page *page) u |= kpf_copy_bit(k, KPF_HWPOISON, PG_hwpoison); #endif -#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR +#ifdef CONFIG_ARCH_USES_PG_UNCACHED u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached); #endif -- cgit v1.2.3-59-g8ed1b From 31583bb0cf6cc40f2a468a4d2f3b9cbefd24f891 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 9 Sep 2010 16:37:37 -0700 Subject: cgroups: fix API thinko Add cgroup_attach_task_all() The existing cgroup_attach_task_current_cg() API is called by a thread to attach another thread to all of its cgroups; this is unsuitable for cases where a privileged task wants to attach itself to the cgroups of a less privileged one, since the call must be made from the context of the target task. This patch adds a more generic cgroup_attach_task_all() API that allows both the source task and to-be-moved task to be specified. cgroup_attach_task_current_cg() becomes a specialization of the more generic new function. [menage@google.com: rewrote changelog] [akpm@linux-foundation.org: address reviewer comments] Signed-off-by: Michael S. Tsirkin Tested-by: Alex Williamson Acked-by: Paul Menage Cc: Li Zefan Cc: Ben Blum Cc: Sridhar Samudrala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/cgroup.h | 12 +++++++++++- kernel/cgroup.c | 13 +++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index ed3e92e41c6e..0c991023ee47 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -578,7 +578,12 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp, void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it); int cgroup_scan_tasks(struct cgroup_scanner *scan); int cgroup_attach_task(struct cgroup *, struct task_struct *); -int cgroup_attach_task_current_cg(struct task_struct *); +int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); + +static inline int cgroup_attach_task_current_cg(struct task_struct *tsk) +{ + return cgroup_attach_task_all(current, tsk); +} /* * CSS ID is ID for cgroup_subsys_state structs under subsys. This only works @@ -636,6 +641,11 @@ static inline int cgroupstats_build(struct cgroupstats *stats, } /* No cgroups - nothing to do */ +static inline int cgroup_attach_task_all(struct task_struct *from, + struct task_struct *t) +{ + return 0; +} static inline int cgroup_attach_task_current_cg(struct task_struct *t) { return 0; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 192f88c5b0f9..c9483d8f6140 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1791,19 +1791,20 @@ out: } /** - * cgroup_attach_task_current_cg - attach task 'tsk' to current task's cgroup + * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from' + * @from: attach to all cgroups of a given task * @tsk: the task to be attached */ -int cgroup_attach_task_current_cg(struct task_struct *tsk) +int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk) { struct cgroupfs_root *root; - struct cgroup *cur_cg; int retval = 0; cgroup_lock(); for_each_active_root(root) { - cur_cg = task_cgroup_from_root(current, root); - retval = cgroup_attach_task(cur_cg, tsk); + struct cgroup *from_cg = task_cgroup_from_root(from, root); + + retval = cgroup_attach_task(from_cg, tsk); if (retval) break; } @@ -1811,7 +1812,7 @@ int cgroup_attach_task_current_cg(struct task_struct *tsk) return retval; } -EXPORT_SYMBOL_GPL(cgroup_attach_task_current_cg); +EXPORT_SYMBOL_GPL(cgroup_attach_task_all); /* * Attach task with pid 'pid' to cgroup 'cgrp'. Call with cgroup_mutex -- cgit v1.2.3-59-g8ed1b From b78d6c5f51935ba89df8db33a57bacb547aa7325 Mon Sep 17 00:00:00 2001 From: Yusuke Goda Date: Thu, 9 Sep 2010 16:37:39 -0700 Subject: tmio_mmc: don't clear unhandled pending interrupts Previously, it was possible for ack_mmc_irqs() to clear pending interrupt bits in the CTL_STATUS register, even though the interrupt handler had not been called. This was because of a race that existed when doing a read-modify-write sequence on CTL_STATUS. After the read step in this sequence, if an interrupt occurred (causing one of the bits in CTL_STATUS to be set) the write step would inadvertently clear it. Observed with the TMIO_STAT_RXRDY bit together with CMD53 on AR6002 and BCM4318 SDIO cards in polled mode. This patch eliminates this race by only writing to CTL_STATUS and clearing the interrupts that were passed as an argument to ack_mmc_irqs()." [matt@console-pimps.org: rewrote changelog] Signed-off-by: Yusuke Goda Acked-by: Magnus Damm " Tested-by: Arnd Hannemann " Acked-by: Ian Molton Cc: Matt Fleming Cc: Samuel Ortiz Cc: Paul Mundt Cc: Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/tmio_mmc.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 64f7d5dfc106..79446047ee78 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -82,10 +82,7 @@ #define ack_mmc_irqs(host, i) \ do { \ - u32 mask;\ - mask = sd_ctrl_read32((host), CTL_STATUS); \ - mask &= ~((i) & TMIO_MASK_IRQ); \ - sd_ctrl_write32((host), CTL_STATUS, mask); \ + sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ } while (0) -- cgit v1.2.3-59-g8ed1b From 5600efb1bc2745d93ae0bc08130117a84f2b9d69 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Sep 2010 16:37:43 -0700 Subject: mmc: fix the use of kunmap_atomic() in tmio_mmc.h kunmap_atomic() takes the cookie, returned by the kmap_atomic() as its argument and not the page address, used as an argument to kmap_atomic(). This patch fixes the compile error: In file included from drivers/mmc/host/tmio_mmc.c:37: drivers/mmc/host/tmio_mmc.h: In function 'tmio_mmc_kunmap_atomic': drivers/mmc/host/tmio_mmc.h:192: error: negative width in bit-field '' Signed-off-by: Guennadi Liakhovetski Acked-by: Eric Miao Tested-by: Magnus Damm Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/tmio_mmc.c | 7 ++++--- drivers/mmc/host/tmio_mmc.h | 8 +++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index ee7d0a5a51c4..69d98e3bf6ab 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -164,6 +164,7 @@ tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) { struct mmc_data *data = host->data; + void *sg_virt; unsigned short *buf; unsigned int count; unsigned long flags; @@ -173,8 +174,8 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) return; } - buf = (unsigned short *)(tmio_mmc_kmap_atomic(host, &flags) + - host->sg_off); + sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); + buf = (unsigned short *)(sg_virt + host->sg_off); count = host->sg_ptr->length - host->sg_off; if (count > data->blksz) @@ -191,7 +192,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) host->sg_off += count; - tmio_mmc_kunmap_atomic(host, &flags); + tmio_mmc_kunmap_atomic(sg_virt, &flags); if (host->sg_off == host->sg_ptr->length) tmio_mmc_next_sg(host); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 79446047ee78..0fedc78e3ea5 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -174,19 +174,17 @@ static inline int tmio_mmc_next_sg(struct tmio_mmc_host *host) return --host->sg_len; } -static inline char *tmio_mmc_kmap_atomic(struct tmio_mmc_host *host, +static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { - struct scatterlist *sg = host->sg_ptr; - local_irq_save(*flags); return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; } -static inline void tmio_mmc_kunmap_atomic(struct tmio_mmc_host *host, +static inline void tmio_mmc_kunmap_atomic(void *virt, unsigned long *flags) { - kunmap_atomic(sg_page(host->sg_ptr), KM_BIO_SRC_IRQ); + kunmap_atomic(virt, KM_BIO_SRC_IRQ); local_irq_restore(*flags); } -- cgit v1.2.3-59-g8ed1b From 60c2c0d5658082468b569d039f4d0dc24f92c66b Mon Sep 17 00:00:00 2001 From: Jiri Pinkava Date: Tue, 25 May 2010 09:48:58 +0200 Subject: ARM: SAMSUNG: MMC: fix build error when both DMA and PIO mode selected [cjb: fix line-wrapped patch] Signed-off-by: Jiri Pinkava Signed-off-by: Chris Ball Cc: Matt Fleming Cc: Russell King Cc: Ben Dooks Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/s3cmci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 2e16e0a90a5e..976330de379e 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1600,7 +1600,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev) host->pio_active = XFER_NONE; #ifdef CONFIG_MMC_S3C_PIODMA - host->dodma = host->pdata->dma; + host->dodma = host->pdata->use_dma; #endif host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3-59-g8ed1b From 16d9b130783c54c30cab80e24810ab1ab9596e11 Mon Sep 17 00:00:00 2001 From: Sergio Aguirre Date: Thu, 9 Sep 2010 16:37:46 -0700 Subject: omap_hsmmc: remove unused local `state' This fixes the following warning: drivers/mmc/host/omap_hsmmc.c: In function 'omap_hsmmc_suspend': drivers/mmc/host/omap_hsmmc.c:2275: warning: unused variable 'state' Introduced by commit ID: commit 1a13f8fa76c880be41d6b1e6a2b44404bcbfdf9e Author: Matt Fleming Date: Wed May 26 14:42:08 2010 -0700 mmc: remove the "state" argument to mmc_suspend_host() The unique usage of this var was removed there, and missed removing the respective declaration aswell. Signed-off-by: Sergio Aguirre Signed-off-by: Chris Ball Acked-by: Matt Fleming Cc: Madhusudhan Chikkature Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/omap_hsmmc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4a8776f8afdd..fb6446a6fb4d 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2305,7 +2305,6 @@ static int omap_hsmmc_suspend(struct device *dev) int ret = 0; struct platform_device *pdev = to_platform_device(dev); struct omap_hsmmc_host *host = platform_get_drvdata(pdev); - pm_message_t state = PMSG_SUSPEND; /* unused by MMC core */ if (host && host->suspended) return 0; -- cgit v1.2.3-59-g8ed1b From 23ef309a6e070490da0a37b9b6383819f8170ea3 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 9 Sep 2010 16:37:48 -0700 Subject: mmc: at91_mci: add missing linux/highmem.h include Fix the following error: at91_mci.c: In function 'at91_mci_sg_to_dma': at91_mci.c:236: error: implicit declaration of function 'kmap_atomic' at91_mci.c:236: error: 'KM_BIO_SRC_IRQ' undeclared (first use in this function) at91_mci.c:236: error: (Each undeclared identifier is reported only once at91_mci.c:236: error: for each function it appears in.) at91_mci.c:236: warning: assignment makes pointer from integer without a cast at91_mci.c:252: error: implicit declaration of function 'kunmap_atomic' at91_mci.c: In function 'at91_mci_post_dma_read': at91_mci.c:302: error: 'KM_BIO_SRC_IRQ' undeclared (first use in this function) at91_mci.c:302: warning: assignment makes pointer from integer without a cast at91_mci.c:317: error: implicit declaration of function 'flush_kernel_dcache_page' Signed-off-by: Marc Kleine-Budde Signed-off-by: Chris Ball Cc: Nicolas Ferre Cc: Andrew Victor Cc: Wolfgang Muees Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/at91_mci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 5f3a599ead07..87226cd202a5 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -66,6 +66,7 @@ #include #include #include +#include #include -- cgit v1.2.3-59-g8ed1b From e7cb756fc3c7c32040283963572258381b342dff Mon Sep 17 00:00:00 2001 From: Ethan Du Date: Thu, 9 Sep 2010 16:37:49 -0700 Subject: omap hsmmc: fix a racing case between kmmcd and omap_hsmmc_suspend If suspend called when kmmcd is doing host->ops->disable, as kmmcd already increased host->en_dis_recurs to 1, the mmc_host_enable in suspend function will return directly without increase the nesting_cnt, which will cause the followed register access carried out to the disabled host. mmc_suspend_host will enable host itself. No need to enable host before it. Also works on kmmcd will get flushed in mmc_suspend_host, enable host after it will be safe. So make the mmc_host_enable after it. [cjb: rebase against current Linus] Signed-off-by: Ethan Signed-off-by: Chris Ball Acked-by: Adrian Hunter Acked-by: Madhusudhan Chikkature Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/omap_hsmmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index fb6446a6fb4d..4526d2791f29 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2323,8 +2323,8 @@ static int omap_hsmmc_suspend(struct device *dev) } } cancel_work_sync(&host->mmc_carddetect_work); - mmc_host_enable(host->mmc); ret = mmc_suspend_host(host->mmc); + mmc_host_enable(host->mmc); if (ret == 0) { omap_hsmmc_disable_irq(host); OMAP_HSMMC_WRITE(host->base, HCTL, -- cgit v1.2.3-59-g8ed1b From 7c5367f205f7d53659fb19b9fdf65b7bc1a592c6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 9 Sep 2010 16:37:50 -0700 Subject: drivers/mmc/host/imxmmc.c: adjust confusing if indentation Move the second if (reg & ...) test into the branch indicated by its indentation. The test was previously always executed after the if containing that branch, but it was always false unless the if branch was taken. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r disable braces4@ position p1,p2; statement S1,S2; @@ ( if (...) { ... } | if (...) S1@p1 S2@p2 ) @script:python@ p1 << r.p1; p2 << r.p2; @@ if (p1[0].column == p2[0].column): cocci.print_main("branch",p1) cocci.print_secs("after",p2) // Signed-off-by: Julia Lawall Signed-off-by: Chris Ball Cc: Pavel Pisa Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/imxmmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c index 9a68ff4353a2..5a950b16d9e6 100644 --- a/drivers/mmc/host/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -148,11 +148,12 @@ static int imxmci_start_clock(struct imxmci_host *host) while (delay--) { reg = readw(host->base + MMC_REG_STATUS); - if (reg & STATUS_CARD_BUS_CLK_RUN) + if (reg & STATUS_CARD_BUS_CLK_RUN) { /* Check twice before cut */ reg = readw(host->base + MMC_REG_STATUS); if (reg & STATUS_CARD_BUS_CLK_RUN) return 0; + } if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) return 0; -- cgit v1.2.3-59-g8ed1b From 4969c1192d15afa3389e7ae3302096ff684ba655 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Thu, 9 Sep 2010 16:37:52 -0700 Subject: mm: fix swapin race condition The pte_same check is reliable only if the swap entry remains pinned (by the page lock on swapcache). We've also to ensure the swapcache isn't removed before we take the lock as try_to_free_swap won't care about the page pin. One of the possible impacts of this patch is that a KSM-shared page can point to the anon_vma of another process, which could exit before the page is freed. This can leave a page with a pointer to a recycled anon_vma object, or worse, a pointer to something that is no longer an anon_vma. [riel@redhat.com: changelog help] Signed-off-by: Andrea Arcangeli Acked-by: Hugh Dickins Reviewed-by: Rik van Riel Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ksm.h | 20 +++++++++----------- mm/ksm.c | 3 --- mm/memory.c | 39 ++++++++++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/include/linux/ksm.h b/include/linux/ksm.h index 74d691ee9121..3319a6967626 100644 --- a/include/linux/ksm.h +++ b/include/linux/ksm.h @@ -16,6 +16,9 @@ struct stable_node; struct mem_cgroup; +struct page *ksm_does_need_to_copy(struct page *page, + struct vm_area_struct *vma, unsigned long address); + #ifdef CONFIG_KSM int ksm_madvise(struct vm_area_struct *vma, unsigned long start, unsigned long end, int advice, unsigned long *vm_flags); @@ -70,19 +73,14 @@ static inline void set_page_stable_node(struct page *page, * We'd like to make this conditional on vma->vm_flags & VM_MERGEABLE, * but what if the vma was unmerged while the page was swapped out? */ -struct page *ksm_does_need_to_copy(struct page *page, - struct vm_area_struct *vma, unsigned long address); -static inline struct page *ksm_might_need_to_copy(struct page *page, +static inline int ksm_might_need_to_copy(struct page *page, struct vm_area_struct *vma, unsigned long address) { struct anon_vma *anon_vma = page_anon_vma(page); - if (!anon_vma || - (anon_vma->root == vma->anon_vma->root && - page->index == linear_page_index(vma, address))) - return page; - - return ksm_does_need_to_copy(page, vma, address); + return anon_vma && + (anon_vma->root != vma->anon_vma->root || + page->index != linear_page_index(vma, address)); } int page_referenced_ksm(struct page *page, @@ -115,10 +113,10 @@ static inline int ksm_madvise(struct vm_area_struct *vma, unsigned long start, return 0; } -static inline struct page *ksm_might_need_to_copy(struct page *page, +static inline int ksm_might_need_to_copy(struct page *page, struct vm_area_struct *vma, unsigned long address) { - return page; + return 0; } static inline int page_referenced_ksm(struct page *page, diff --git a/mm/ksm.c b/mm/ksm.c index e2ae00458320..b1873cf03ed9 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -1504,8 +1504,6 @@ struct page *ksm_does_need_to_copy(struct page *page, { struct page *new_page; - unlock_page(page); /* any racers will COW it, not modify it */ - new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address); if (new_page) { copy_user_highpage(new_page, page, address, vma); @@ -1521,7 +1519,6 @@ struct page *ksm_does_need_to_copy(struct page *page, add_page_to_unevictable_list(new_page); } - page_cache_release(page); return new_page; } diff --git a/mm/memory.c b/mm/memory.c index 6b2ab1051851..71b161b73bb5 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2623,7 +2623,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned int flags, pte_t orig_pte) { spinlock_t *ptl; - struct page *page; + struct page *page, *swapcache = NULL; swp_entry_t entry; pte_t pte; struct mem_cgroup *ptr = NULL; @@ -2679,10 +2679,23 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, lock_page(page); delayacct_clear_flag(DELAYACCT_PF_SWAPIN); - page = ksm_might_need_to_copy(page, vma, address); - if (!page) { - ret = VM_FAULT_OOM; - goto out; + /* + * Make sure try_to_free_swap didn't release the swapcache + * from under us. The page pin isn't enough to prevent that. + */ + if (unlikely(!PageSwapCache(page))) + goto out_page; + + if (ksm_might_need_to_copy(page, vma, address)) { + swapcache = page; + page = ksm_does_need_to_copy(page, vma, address); + + if (unlikely(!page)) { + ret = VM_FAULT_OOM; + page = swapcache; + swapcache = NULL; + goto out_page; + } } if (mem_cgroup_try_charge_swapin(mm, page, GFP_KERNEL, &ptr)) { @@ -2735,6 +2748,18 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, if (vm_swap_full() || (vma->vm_flags & VM_LOCKED) || PageMlocked(page)) try_to_free_swap(page); unlock_page(page); + if (swapcache) { + /* + * Hold the lock to avoid the swap entry to be reused + * until we take the PT lock for the pte_same() check + * (to avoid false positives from pte_same). For + * further safety release the lock after the swap_free + * so that the swap count won't change under a + * parallel locked swapcache. + */ + unlock_page(swapcache); + page_cache_release(swapcache); + } if (flags & FAULT_FLAG_WRITE) { ret |= do_wp_page(mm, vma, address, page_table, pmd, ptl, pte); @@ -2756,6 +2781,10 @@ out_page: unlock_page(page); out_release: page_cache_release(page); + if (swapcache) { + unlock_page(swapcache); + page_cache_release(swapcache); + } return ret; } -- cgit v1.2.3-59-g8ed1b From 152e0659fc001029c70fa4373af1792b1ae0d01c Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Thu, 9 Sep 2010 16:37:53 -0700 Subject: mm: avoid warning when COMPACTION is selected COMPACTION enables MIGRATION, but MIGRATION spawns a warning if numa or memhotplug aren't selected. However MIGRATION doesn't depend on them. I guess it's just trying to be strict doing a double check on who's enabling it, but it doesn't know that compaction also enables MIGRATION. Signed-off-by: Andrea Arcangeli Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/Kconfig b/mm/Kconfig index f4e516e9c37c..f0fb9124e410 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -189,7 +189,7 @@ config COMPACTION config MIGRATION bool "Page migration" def_bool y - depends on NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE + depends on NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION help Allows the migration of the physical location of pages of processes while the virtual addresses are not changed. This is useful in -- cgit v1.2.3-59-g8ed1b From ee3aebdd8f5f8eac41c25c80ceee3d728f920f3b Mon Sep 17 00:00:00 2001 From: Jan Sembera Date: Thu, 9 Sep 2010 16:37:54 -0700 Subject: binfmt_misc: fix binfmt_misc priority Commit 74641f584da ("alpha: binfmt_aout fix") (May 2009) introduced a regression - binfmt_misc is now consulted after binfmt_elf, which will unfortunately break ia32el. ia32 ELF binaries on ia64 used to be matched using binfmt_misc and executed using wrapper. As 32bit binaries are now matched by binfmt_elf before bindmt_misc kicks in, the wrapper is ignored. The fix increases precedence of binfmt_misc to the original state. Signed-off-by: Jan Sembera Cc: Ivan Kokshaysky Cc: Al Viro Cc: Richard Henderson [2.6.everything.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/binfmt_misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index a7528b913936..fd0cc0bf9a40 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -724,7 +724,7 @@ static int __init init_misc_binfmt(void) { int err = register_filesystem(&bm_fs_type); if (!err) { - err = register_binfmt(&misc_format); + err = insert_binfmt(&misc_format); if (err) unregister_filesystem(&bm_fs_type); } -- cgit v1.2.3-59-g8ed1b From 408929bed7841686ce5fdd06366fb652cb653d6c Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Thu, 9 Sep 2010 16:37:56 -0700 Subject: rtc: m41t80: do not use rtc_valid_tm in m41t80_rtc_read_alarm Commit b485fe5ea ("rtc/m41t80: use rtc_valid_tm() to check returned tm") added rtc_valid_tm to m41t80_rtc_read_alarm() but it was wrong while the t->time does not contain complete date/time. This patch also fixes a warning: warning: passing argument 1 of 'rtc_valid_tm' from incompatible pointer type Signed-off-by: Atsushi Nemoto Cc: Wan ZongShun Cc: Alessandro Zummo Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-m41t80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 66377f3e28b8..d60557cae8ef 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -364,7 +364,7 @@ static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) t->time.tm_isdst = -1; t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE); t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF); - return rtc_valid_tm(t); + return 0; } static struct rtc_class_ops m41t80_rtc_ops = { -- cgit v1.2.3-59-g8ed1b From 94131e174fedd9f3f9bb148cee4be12f2d46d68e Mon Sep 17 00:00:00 2001 From: "Ira W. Snyder" Date: Thu, 9 Sep 2010 16:37:58 -0700 Subject: arch/powerpc/include/asm/fsldma.h needs slab.h The slab.h header is required to use the kmalloc() family of functions. Due to recent kernel changes, this header must be directly included by code that calls into the memory allocator. Without this patch, any code which includes this header fails to build. Signed-off-by: Ira W. Snyder Cc: Dan Williams Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/include/asm/fsldma.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/include/asm/fsldma.h b/arch/powerpc/include/asm/fsldma.h index a67aeed17d40..debc5ed96d6e 100644 --- a/arch/powerpc/include/asm/fsldma.h +++ b/arch/powerpc/include/asm/fsldma.h @@ -11,6 +11,7 @@ #ifndef __ARCH_POWERPC_ASM_FSLDMA_H__ #define __ARCH_POWERPC_ASM_FSLDMA_H__ +#include #include /* -- cgit v1.2.3-59-g8ed1b From 1c24de60e50fb19b94d94225458da17c720f0729 Mon Sep 17 00:00:00 2001 From: Jerome Marchand Date: Thu, 9 Sep 2010 16:37:59 -0700 Subject: kernel/groups.c: fix integer overflow in groups_search gid_t is a unsigned int. If group_info contains a gid greater than MAX_INT, groups_search() function may look on the wrong side of the search tree. This solves some unfair "permission denied" problems. Signed-off-by: Jerome Marchand Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/groups.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/groups.c b/kernel/groups.c index 53b1916c9492..253dc0f35cf4 100644 --- a/kernel/groups.c +++ b/kernel/groups.c @@ -143,10 +143,9 @@ int groups_search(const struct group_info *group_info, gid_t grp) right = group_info->ngroups; while (left < right) { unsigned int mid = (left+right)/2; - int cmp = grp - GROUP_AT(group_info, mid); - if (cmp > 0) + if (grp > GROUP_AT(group_info, mid)) left = mid + 1; - else if (cmp < 0) + else if (grp < GROUP_AT(group_info, mid)) right = mid; else return 1; -- cgit v1.2.3-59-g8ed1b From bc6930457460788e14b2c0808ed4632a1592bd61 Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Thu, 9 Sep 2010 16:38:00 -0700 Subject: mm: compaction: handle active and inactive fairly in too_many_isolated Iram reported that compaction's too_many_isolated() loops forever. (http://www.spinics.net/lists/linux-mm/msg08123.html) The meminfo when the situation happened was inactive anon is zero. That's because the system has no memory pressure until then. While all anon pages were in the active lru, compaction could select active lru as well as inactive lru. That's a different thing from vmscan's isolated. So we has been two too_many_isolated. While compaction can isolate pages in both active and inactive, current implementation of too_many_isolated only considers inactive. It made Iram's problem. This patch handles active and inactive fairly. That's because we can't expect where from and how many compaction would isolated pages. This patch changes (nr_isolated > nr_inactive) with nr_isolated > (nr_active + nr_inactive) / 2. Signed-off-by: Minchan Kim Reported-by: Iram Shahzad Acked-by: Mel Gorman Acked-by: Wu Fengguang Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/compaction.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 94cce51b0b35..4d709ee59013 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -214,15 +214,16 @@ static void acct_isolated(struct zone *zone, struct compact_control *cc) /* Similar to reclaim, but different enough that they don't share logic */ static bool too_many_isolated(struct zone *zone) { - - unsigned long inactive, isolated; + unsigned long active, inactive, isolated; inactive = zone_page_state(zone, NR_INACTIVE_FILE) + zone_page_state(zone, NR_INACTIVE_ANON); + active = zone_page_state(zone, NR_ACTIVE_FILE) + + zone_page_state(zone, NR_ACTIVE_ANON); isolated = zone_page_state(zone, NR_ISOLATED_FILE) + zone_page_state(zone, NR_ISOLATED_ANON); - return isolated > inactive; + return isolated > (inactive + active) / 2; } /* -- cgit v1.2.3-59-g8ed1b From 0dcc48c15f63ee86c2fcd33968b08d651f0360a5 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Thu, 9 Sep 2010 16:38:01 -0700 Subject: memory hotplug: fix next block calculation in is_removable next_active_pageblock() is for finding next _used_ freeblock. It skips several blocks when it finds there are a chunk of free pages lager than pageblock. But it has 2 bugs. 1. We have no lock. page_order(page) - pageblock_order can be minus. 2. pageblocks_stride += is wrong. it should skip page_order(p) of pages. Signed-off-by: KAMEZAWA Hiroyuki Cc: Michal Hocko Cc: Wu Fengguang Cc: Mel Gorman Cc: KAMEZAWA Hiroyuki Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory_hotplug.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index a4cfcdc00455..dd186c1a5d53 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -584,19 +584,19 @@ static inline int pageblock_free(struct page *page) /* Return the start of the next active pageblock after a given page */ static struct page *next_active_pageblock(struct page *page) { - int pageblocks_stride; - /* Ensure the starting page is pageblock-aligned */ BUG_ON(page_to_pfn(page) & (pageblock_nr_pages - 1)); - /* Move forward by at least 1 * pageblock_nr_pages */ - pageblocks_stride = 1; - /* If the entire pageblock is free, move to the end of free page */ - if (pageblock_free(page)) - pageblocks_stride += page_order(page) - pageblock_order; + if (pageblock_free(page)) { + int order; + /* be careful. we don't have locks, page_order can be changed.*/ + order = page_order(page); + if ((order < MAX_ORDER) && (order >= pageblock_order)) + return page + (1 << order); + } - return page + (pageblocks_stride * pageblock_nr_pages); + return page + pageblock_nr_pages; } /* Checks if this range of memory is likely to be hot-removable. */ -- cgit v1.2.3-59-g8ed1b From 5affb607720d734ca572b8a77c5c7d62d3042b6f Mon Sep 17 00:00:00 2001 From: Gregory Bean Date: Thu, 9 Sep 2010 16:38:02 -0700 Subject: gpio: sx150x: correct and refine reset-on-probe behavior Replace the arbitrary software-reset call from the device-probe method, because: - It is defective. To work correctly, it should be two byte writes, not a single word write. As it stands, it does nothing. - Some devices with sx150x expanders installed have their NRESET pins ganged on the same line, so resetting one causes the others to reset - not a nice thing to do arbitrarily! - The probe, usually taking place at boot, implies a recent hard-reset, so a software reset at this point is just a waste of energy anyway. Therefore, make it optional, defaulting to off, as this will match the common case of probing at powerup and also matches the current broken no-op behavior. Signed-off-by: Gregory Bean Reviewed-by: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/sx150x.c | 26 +++++++++++++++++++++----- include/linux/i2c/sx150x.h | 4 ++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c index b42f42ca70c3..823559ab0e24 100644 --- a/drivers/gpio/sx150x.c +++ b/drivers/gpio/sx150x.c @@ -459,17 +459,33 @@ static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg) return err; } -static int sx150x_init_hw(struct sx150x_chip *chip, - struct sx150x_platform_data *pdata) +static int sx150x_reset(struct sx150x_chip *chip) { - int err = 0; + int err; - err = i2c_smbus_write_word_data(chip->client, + err = i2c_smbus_write_byte_data(chip->client, chip->dev_cfg->reg_reset, - 0x3412); + 0x12); if (err < 0) return err; + err = i2c_smbus_write_byte_data(chip->client, + chip->dev_cfg->reg_reset, + 0x34); + return err; +} + +static int sx150x_init_hw(struct sx150x_chip *chip, + struct sx150x_platform_data *pdata) +{ + int err = 0; + + if (pdata->reset_during_probe) { + err = sx150x_reset(chip); + if (err < 0) + return err; + } + err = sx150x_i2c_write(chip->client, chip->dev_cfg->reg_misc, 0x01); diff --git a/include/linux/i2c/sx150x.h b/include/linux/i2c/sx150x.h index ee3049cb9ba5..52baa79d69a7 100644 --- a/include/linux/i2c/sx150x.h +++ b/include/linux/i2c/sx150x.h @@ -63,6 +63,9 @@ * IRQ lines will appear. Similarly to gpio_base, the expander * will create a block of irqs beginning at this number. * This value is ignored if irq_summary is < 0. + * @reset_during_probe: If set to true, the driver will trigger a full + * reset of the chip at the beginning of the probe + * in order to place it in a known state. */ struct sx150x_platform_data { unsigned gpio_base; @@ -73,6 +76,7 @@ struct sx150x_platform_data { u16 io_polarity; int irq_summary; unsigned irq_base; + bool reset_during_probe; }; #endif /* __LINUX_I2C_SX150X_H */ -- cgit v1.2.3-59-g8ed1b From c956126c137d97acb6f4d56fa9572d0bcc84e4ed Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 9 Sep 2010 16:38:03 -0700 Subject: gpio: doc updates There's been some recent confusion about error checking GPIO numbers. briefly, it should be handled mostly during setup, when gpio_request() is called, and NEVER by expectig gpio_is_valid to report more than never-usable GPIO numbers. [akpm@linux-foundation.org: terminate unterminated comment] Signed-off-by: David Brownell Cc: Eric Miao" Cc: "Ryan Mallon" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/gpio.txt | 22 ++++++++++++++-------- include/asm-generic/gpio.h | 14 +++++++++++++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index d96a6dba5748..9633da01ff46 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -109,17 +109,19 @@ use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders. If you want to initialize a structure with an invalid GPIO number, use some negative number (perhaps "-EINVAL"); that will never be valid. To -test if a number could reference a GPIO, you may use this predicate: +test if such number from such a structure could reference a GPIO, you +may use this predicate: int gpio_is_valid(int number); A number that's not valid will be rejected by calls which may request or free GPIOs (see below). Other numbers may also be rejected; for -example, a number might be valid but unused on a given board. - -Whether a platform supports multiple GPIO controllers is currently a -platform-specific implementation issue. +example, a number might be valid but temporarily unused on a given board. +Whether a platform supports multiple GPIO controllers is a platform-specific +implementation issue, as are whether that support can leave "holes" in the space +of GPIO numbers, and whether new controllers can be added at runtime. Such issues +can affect things including whether adjacent GPIO numbers are both valid. Using GPIOs ----------- @@ -480,12 +482,16 @@ To support this framework, a platform's Kconfig will "select" either ARCH_REQUIRE_GPIOLIB or ARCH_WANT_OPTIONAL_GPIOLIB and arrange that its includes and defines three functions: gpio_get_value(), gpio_set_value(), and gpio_cansleep(). -They may also want to provide a custom value for ARCH_NR_GPIOS. -ARCH_REQUIRE_GPIOLIB means that the gpio-lib code will always get compiled +It may also provide a custom value for ARCH_NR_GPIOS, so that it better +reflects the number of GPIOs in actual use on that platform, without +wasting static table space. (It should count both built-in/SoC GPIOs and +also ones on GPIO expanders. + +ARCH_REQUIRE_GPIOLIB means that the gpiolib code will always get compiled into the kernel on that architecture. -ARCH_WANT_OPTIONAL_GPIOLIB means the gpio-lib code defaults to off and the user +ARCH_WANT_OPTIONAL_GPIOLIB means the gpiolib code defaults to off and the user can enable it and build it into the kernel optionally. If neither of these options are selected, the platform does not support diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index c7376bf80b06..8ca18e26d7e3 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -16,15 +16,27 @@ * While the GPIO programming interface defines valid GPIO numbers * to be in the range 0..MAX_INT, this library restricts them to the * smaller range 0..ARCH_NR_GPIOS-1. + * + * ARCH_NR_GPIOS is somewhat arbitrary; it usually reflects the sum of + * builtin/SoC GPIOs plus a number of GPIOs on expanders; the latter is + * actually an estimate of a board-specific value. */ #ifndef ARCH_NR_GPIOS #define ARCH_NR_GPIOS 256 #endif +/* + * "valid" GPIO numbers are nonnegative and may be passed to + * setup routines like gpio_request(). only some valid numbers + * can successfully be requested and used. + * + * Invalid GPIO numbers are useful for indicating no-such-GPIO in + * platform data and other tables. + */ + static inline int gpio_is_valid(int number) { - /* only some non-negative numbers are valid */ return ((unsigned)number) < ARCH_NR_GPIOS; } -- cgit v1.2.3-59-g8ed1b From b7bbbf354ed0edbbffdc70c9c17f1a5d4d78204c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 9 Sep 2010 16:38:04 -0700 Subject: MAINTAINERS: correct entry for legacy RTC-driver Because no one dared to remove it so far, let's keep the entry correct, at least. Signed-off-by: Wolfram Sang Acked-by: Mike Frysinger Cc: Paul Gortmaker Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a3da87f82a75..9800de5ec222 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4838,12 +4838,10 @@ F: kernel/rcu* F: kernel/srcu* X: kernel/rcutorture.c -REAL TIME CLOCK DRIVER +REAL TIME CLOCK DRIVER (LEGACY) M: Paul Gortmaker S: Maintained -F: Documentation/rtc.txt -F: drivers/rtc/ -F: include/linux/rtc.h +F: drivers/char/rtc.c REAL TIME CLOCK (RTC) SUBSYSTEM M: Alessandro Zummo -- cgit v1.2.3-59-g8ed1b From 47016434257b90445113eed1c5b8b57eb2d35330 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 9 Sep 2010 16:38:04 -0700 Subject: drivers/rtc/rtc-pl031.c: do not mark PL031 IRQ as shared It was a mistake to mark the PL031 IRQ as shared (for the U8500), we misread the datasheet. Get rid of this. Signed-off-by: Linus Walleij Cc: Jonas Aberg Cc: Mian Yousaf Kaukab Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-pl031.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 6c418fe7f288..b7a6690e5b35 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -403,7 +403,7 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id) } if (request_irq(adev->irq[0], pl031_interrupt, - IRQF_DISABLED | IRQF_SHARED, "rtc-pl031", ldata)) { + IRQF_DISABLED, "rtc-pl031", ldata)) { ret = -EIO; goto out_no_irq; } -- cgit v1.2.3-59-g8ed1b From ac8456d6f9a3011c824176bd6084d39e5f70a382 Mon Sep 17 00:00:00 2001 From: Gary King Date: Thu, 9 Sep 2010 16:38:05 -0700 Subject: bounce: call flush_dcache_page() after bounce_copy_vec() I have been seeing problems on Tegra 2 (ARMv7 SMP) systems with HIGHMEM enabled on 2.6.35 (plus some patches targetted at 2.6.36 to perform cache maintenance lazily), and the root cause appears to be that the mm bouncing code is calling flush_dcache_page before it copies the bounce buffer into the bio. The bounced page needs to be flushed after data is copied into it, to ensure that architecture implementations can synchronize instruction and data caches if necessary. Signed-off-by: Gary King Cc: Tejun Heo Cc: Russell King Acked-by: Jens Axboe Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/bounce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/bounce.c b/mm/bounce.c index 13b6dad1eed2..1481de68184b 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -116,8 +116,8 @@ static void copy_to_high_bio_irq(struct bio *to, struct bio *from) */ vfrom = page_address(fromvec->bv_page) + tovec->bv_offset; - flush_dcache_page(tovec->bv_page); bounce_copy_vec(tovec, vfrom); + flush_dcache_page(tovec->bv_page); } } -- cgit v1.2.3-59-g8ed1b From 910321ea817a202ff70fac666e37e2c8e2f88823 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Thu, 9 Sep 2010 16:38:07 -0700 Subject: swap: revert special hibernation allocation Please revert 2.6.36-rc commit d2997b1042ec150616c1963b5e5e919ffd0b0ebf "hibernation: freeze swap at hibernation". It complicated matters by adding a second swap allocation path, just for hibernation; without in any way fixing the issue that it was intended to address - page reclaim after fixing the hibernation image might free swap from a page already imaged as swapcache, letting its swap be reallocated to store a different page of the image: resulting in data corruption if the imaged page were freed as clean then swapped back in. Pages freed to si->swap_map were still in danger of being reallocated by the alternative allocation path. I guess it inadvertently fixed slow SSD swap allocation for hibernation, as reported by Nigel Cunningham: by missing out the discards that occur on the usual swap allocation path; but that was unintentional, and needs a separate fix. Signed-off-by: Hugh Dickins Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Cc: "Rafael J. Wysocki" Cc: Ondrej Zary Cc: Andrea Gelmini Cc: Balbir Singh Cc: Andrea Arcangeli Cc: Nigel Cunningham Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 8 +---- kernel/power/hibernate.c | 1 - kernel/power/snapshot.c | 1 - kernel/power/swap.c | 6 ++-- mm/swapfile.c | 94 ++++++++++++------------------------------------ 5 files changed, 26 insertions(+), 84 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 2fee51a11b73..bf4eb62506db 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -315,6 +315,7 @@ extern long nr_swap_pages; extern long total_swap_pages; extern void si_swapinfo(struct sysinfo *); extern swp_entry_t get_swap_page(void); +extern swp_entry_t get_swap_page_of_type(int); extern int valid_swaphandles(swp_entry_t, unsigned long *); extern int add_swap_count_continuation(swp_entry_t, gfp_t); extern void swap_shmem_alloc(swp_entry_t); @@ -331,13 +332,6 @@ extern int reuse_swap_page(struct page *); extern int try_to_free_swap(struct page *); struct backing_dev_info; -#ifdef CONFIG_HIBERNATION -void hibernation_freeze_swap(void); -void hibernation_thaw_swap(void); -swp_entry_t get_swap_for_hibernation(int type); -void swap_free_for_hibernation(swp_entry_t val); -#endif - /* linux/mm/thrash.c */ extern struct mm_struct *swap_token_mm; extern void grab_swap_token(struct mm_struct *); diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index c77963938bca..8dc31e02ae12 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -338,7 +338,6 @@ int hibernation_snapshot(int platform_mode) goto Close; suspend_console(); - hibernation_freeze_swap(); saved_mask = clear_gfp_allowed_mask(GFP_IOFS); error = dpm_suspend_start(PMSG_FREEZE); if (error) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 5e7edfb05e66..f6cd6faf84fd 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1086,7 +1086,6 @@ void swsusp_free(void) buffer = NULL; alloc_normal = 0; alloc_highmem = 0; - hibernation_thaw_swap(); } /* Helper functions used for the shrinking of memory. */ diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 5d0059eed3e4..e6a5bdf61a37 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -136,10 +136,10 @@ sector_t alloc_swapdev_block(int swap) { unsigned long offset; - offset = swp_offset(get_swap_for_hibernation(swap)); + offset = swp_offset(get_swap_page_of_type(swap)); if (offset) { if (swsusp_extents_insert(offset)) - swap_free_for_hibernation(swp_entry(swap, offset)); + swap_free(swp_entry(swap, offset)); else return swapdev_block(swap, offset); } @@ -163,7 +163,7 @@ void free_all_swap_pages(int swap) ext = container_of(node, struct swsusp_extent, node); rb_erase(node, &swsusp_extents); for (offset = ext->start; offset <= ext->end; offset++) - swap_free_for_hibernation(swp_entry(swap, offset)); + swap_free(swp_entry(swap, offset)); kfree(ext); } diff --git a/mm/swapfile.c b/mm/swapfile.c index 1f3f9c59a73a..f08d165871b3 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -47,8 +47,6 @@ long nr_swap_pages; long total_swap_pages; static int least_priority; -static bool swap_for_hibernation; - static const char Bad_file[] = "Bad swap file entry "; static const char Unused_file[] = "Unused swap file entry "; static const char Bad_offset[] = "Bad swap offset entry "; @@ -453,8 +451,6 @@ swp_entry_t get_swap_page(void) spin_lock(&swap_lock); if (nr_swap_pages <= 0) goto noswap; - if (swap_for_hibernation) - goto noswap; nr_swap_pages--; for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) { @@ -487,6 +483,28 @@ noswap: return (swp_entry_t) {0}; } +/* The only caller of this function is now susupend routine */ +swp_entry_t get_swap_page_of_type(int type) +{ + struct swap_info_struct *si; + pgoff_t offset; + + spin_lock(&swap_lock); + si = swap_info[type]; + if (si && (si->flags & SWP_WRITEOK)) { + nr_swap_pages--; + /* This is called for allocating swap entry, not cache */ + offset = scan_swap_map(si, 1); + if (offset) { + spin_unlock(&swap_lock); + return swp_entry(type, offset); + } + nr_swap_pages++; + } + spin_unlock(&swap_lock); + return (swp_entry_t) {0}; +} + static struct swap_info_struct *swap_info_get(swp_entry_t entry) { struct swap_info_struct *p; @@ -746,74 +764,6 @@ int mem_cgroup_count_swap_user(swp_entry_t ent, struct page **pagep) #endif #ifdef CONFIG_HIBERNATION - -static pgoff_t hibernation_offset[MAX_SWAPFILES]; -/* - * Once hibernation starts to use swap, we freeze swap_map[]. Otherwise, - * saved swap_map[] image to the disk will be an incomplete because it's - * changing without synchronization with hibernation snap shot. - * At resume, we just make swap_for_hibernation=false. We can forget - * used maps easily. - */ -void hibernation_freeze_swap(void) -{ - int i; - - spin_lock(&swap_lock); - - printk(KERN_INFO "PM: Freeze Swap\n"); - swap_for_hibernation = true; - for (i = 0; i < MAX_SWAPFILES; i++) - hibernation_offset[i] = 1; - spin_unlock(&swap_lock); -} - -void hibernation_thaw_swap(void) -{ - spin_lock(&swap_lock); - if (swap_for_hibernation) { - printk(KERN_INFO "PM: Thaw Swap\n"); - swap_for_hibernation = false; - } - spin_unlock(&swap_lock); -} - -/* - * Because updateing swap_map[] can make not-saved-status-change, - * we use our own easy allocator. - * Please see kernel/power/swap.c, Used swaps are recorded into - * RB-tree. - */ -swp_entry_t get_swap_for_hibernation(int type) -{ - pgoff_t off; - swp_entry_t val = {0}; - struct swap_info_struct *si; - - spin_lock(&swap_lock); - - si = swap_info[type]; - if (!si || !(si->flags & SWP_WRITEOK)) - goto done; - - for (off = hibernation_offset[type]; off < si->max; ++off) { - if (!si->swap_map[off]) - break; - } - if (off < si->max) { - val = swp_entry(type, off); - hibernation_offset[type] = off + 1; - } -done: - spin_unlock(&swap_lock); - return val; -} - -void swap_free_for_hibernation(swp_entry_t ent) -{ - /* Nothing to do */ -} - /* * Find the swap type that corresponds to given device (if any). * -- cgit v1.2.3-59-g8ed1b From b73d7fcecd93dc15eaa3c45c8c587b613f6673c4 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Thu, 9 Sep 2010 16:38:09 -0700 Subject: swap: prevent reuse during hibernation Move the hibernation check from scan_swap_map() into try_to_free_swap(): to catch not only the common case when hibernation's allocation itself triggers swap reuse, but also the less likely case when concurrent page reclaim (shrink_page_list) might happen to try_to_free_swap from a page. Hibernation already clears __GFP_IO from the gfp_allowed_mask, to stop reclaim from going to swap: check that to prevent swap reuse too. Signed-off-by: Hugh Dickins Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Cc: "Rafael J. Wysocki" Cc: Ondrej Zary Cc: Andrea Gelmini Cc: Balbir Singh Cc: Andrea Arcangeli Cc: Nigel Cunningham Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index f08d165871b3..ed5151079f59 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -318,10 +318,8 @@ checks: if (offset > si->highest_bit) scan_base = offset = si->lowest_bit; - /* reuse swap entry of cache-only swap if not hibernation. */ - if (vm_swap_full() - && usage == SWAP_HAS_CACHE - && si->swap_map[offset] == SWAP_HAS_CACHE) { + /* reuse swap entry of cache-only swap if not busy. */ + if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) { int swap_was_freed; spin_unlock(&swap_lock); swap_was_freed = __try_to_reclaim_swap(si, offset); @@ -688,6 +686,24 @@ int try_to_free_swap(struct page *page) if (page_swapcount(page)) return 0; + /* + * Once hibernation has begun to create its image of memory, + * there's a danger that one of the calls to try_to_free_swap() + * - most probably a call from __try_to_reclaim_swap() while + * hibernation is allocating its own swap pages for the image, + * but conceivably even a call from memory reclaim - will free + * the swap from a page which has already been recorded in the + * image as a clean swapcache page, and then reuse its swap for + * another page of the image. On waking from hibernation, the + * original page might be freed under memory pressure, then + * later read back in from swap, now with the wrong data. + * + * Hibernation clears bits from gfp_allowed_mask to prevent + * memory reclaim from writing to disk, so check that here. + */ + if (!(gfp_allowed_mask & __GFP_IO)) + return 0; + delete_from_swap_cache(page); SetPageDirty(page); return 1; -- cgit v1.2.3-59-g8ed1b From 8f2ae0faa3a119158c4dcfe89926d6fad5f5332c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 9 Sep 2010 16:38:10 -0700 Subject: swap: do not send discards as barriers The swap code already uses synchronous discards, no need to add I/O barriers. This fixes the worst of the terrible slowdown in swap allocation for hibernation, reported on 2.6.35 by Nigel Cunningham; but does not entirely eliminate that regression. [tj@kernel.org: superflous newlines removed] Signed-off-by: Christoph Hellwig Tested-by: Nigel Cunningham Signed-off-by: Tejun Heo Signed-off-by: Hugh Dickins Cc: Jens Axboe Cc: James Bottomley Cc: "Martin K. Petersen" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/swapfile.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index ed5151079f59..1894dead0b58 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -139,8 +139,7 @@ static int discard_swap(struct swap_info_struct *si) nr_blocks = ((sector_t)se->nr_pages - 1) << (PAGE_SHIFT - 9); if (nr_blocks) { err = blkdev_issue_discard(si->bdev, start_block, - nr_blocks, GFP_KERNEL, - BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER); + nr_blocks, GFP_KERNEL, BLKDEV_IFL_WAIT); if (err) return err; cond_resched(); @@ -151,8 +150,7 @@ static int discard_swap(struct swap_info_struct *si) nr_blocks = (sector_t)se->nr_pages << (PAGE_SHIFT - 9); err = blkdev_issue_discard(si->bdev, start_block, - nr_blocks, GFP_KERNEL, - BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER); + nr_blocks, GFP_KERNEL, BLKDEV_IFL_WAIT); if (err) break; @@ -191,8 +189,7 @@ static void discard_swap_cluster(struct swap_info_struct *si, start_block <<= PAGE_SHIFT - 9; nr_blocks <<= PAGE_SHIFT - 9; if (blkdev_issue_discard(si->bdev, start_block, - nr_blocks, GFP_NOIO, BLKDEV_IFL_WAIT | - BLKDEV_IFL_BARRIER)) + nr_blocks, GFP_NOIO, BLKDEV_IFL_WAIT)) break; } -- cgit v1.2.3-59-g8ed1b From 3399446632739fcd05fd8b272b476a69c6e6d14a Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Thu, 9 Sep 2010 16:38:11 -0700 Subject: swap: discard while swapping only if SWAP_FLAG_DISCARD Tests with recent firmware on Intel X25-M 80GB and OCZ Vertex 60GB SSDs show a shift since I last tested in December: in part because of firmware updates, in part because of the necessary move from barriers to awaiting completion at the block layer. While discard at swapon still shows as slightly beneficial on both, discarding 1MB swap cluster when allocating is now disadvanteous: adds 25% overhead on Intel, adds 230% on OCZ (YMMV). Surrender: discard as presently implemented is more hindrance than help for swap; but might prove useful on other devices, or with improvements. So continue to do the discard at swapon, but make discard while swapping conditional on a SWAP_FLAG_DISCARD to sys_swapon() (which has been using only the lower 16 bits of int flags). We can add a --discard or -d to swapon(8), and a "discard" to swap in /etc/fstab: matching the mount option for btrfs, ext4, fat, gfs2, nilfs2. Signed-off-by: Hugh Dickins Cc: Christoph Hellwig Cc: Nigel Cunningham Cc: Tejun Heo Cc: Jens Axboe Cc: James Bottomley Cc: "Martin K. Petersen" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 3 ++- mm/swapfile.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index bf4eb62506db..7cdd63366f88 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -19,6 +19,7 @@ struct bio; #define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ #define SWAP_FLAG_PRIO_MASK 0x7fff #define SWAP_FLAG_PRIO_SHIFT 0 +#define SWAP_FLAG_DISCARD 0x10000 /* discard swap cluster after use */ static inline int current_is_kswapd(void) { @@ -142,7 +143,7 @@ struct swap_extent { enum { SWP_USED = (1 << 0), /* is slot in swap_info[] used? */ SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */ - SWP_DISCARDABLE = (1 << 2), /* blkdev supports discard */ + SWP_DISCARDABLE = (1 << 2), /* swapon+blkdev support discard */ SWP_DISCARDING = (1 << 3), /* now discarding a free cluster */ SWP_SOLIDSTATE = (1 << 4), /* blkdev seeks are cheap */ SWP_CONTINUED = (1 << 5), /* swap_map has count continuation */ diff --git a/mm/swapfile.c b/mm/swapfile.c index 1894dead0b58..7c703ff2f36f 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2047,7 +2047,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) p->flags |= SWP_SOLIDSTATE; p->cluster_next = 1 + (random32() % p->highest_bit); } - if (discard_swap(p) == 0) + if (discard_swap(p) == 0 && (swap_flags & SWAP_FLAG_DISCARD)) p->flags |= SWP_DISCARDABLE; } -- cgit v1.2.3-59-g8ed1b From 3ab04d5cf9736b7a4e9dfcf28285d8663b01aa0e Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 9 Sep 2010 16:38:12 -0700 Subject: vfs: take O_NONBLOCK out of the O_* uniqueness test O_NONBLOCK on parisc has a dual value: #define O_NONBLOCK 000200004 /* HPUX has separate NDELAY & NONBLOCK */ It is caught by the O_* bits uniqueness check and leads to a parisc compile error. The fix would be to take O_NONBLOCK out. Signed-off-by: Wu Fengguang Signed-off-by: James Bottomley Cc: Jamie Lokier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fcntl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/fcntl.c b/fs/fcntl.c index 6769fd0f35b8..f8cc34f542c3 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -769,11 +769,15 @@ EXPORT_SYMBOL(kill_fasync); static int __init fcntl_init(void) { - /* please add new bits here to ensure allocation uniqueness */ - BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( + /* + * Please add new bits here to ensure allocation uniqueness. + * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY + * is defined as O_NONBLOCK on some platforms and not on others. + */ + BUILD_BUG_ON(18 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | - O_TRUNC | O_APPEND | O_NONBLOCK | + O_TRUNC | O_APPEND | /* O_NONBLOCK | */ __O_SYNC | O_DSYNC | FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | -- cgit v1.2.3-59-g8ed1b From 5ee28a447625b9fe64fbf7cff026561084fc5f16 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Thu, 9 Sep 2010 16:38:14 -0700 Subject: vmstat: update zone stat threshold when onlining a cpu refresh_zone_stat_thresholds() calculates parameter based on the number of online cpus. It's called at cpu offlining but needs to be called at onlining, too. Signed-off-by: KAMEZAWA Hiroyuki Cc: Christoph Lameter Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmstat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/vmstat.c b/mm/vmstat.c index f389168f9a83..a8d6b59e609a 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -998,6 +998,7 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb, switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: + refresh_zone_stat_thresholds(); start_cpu_timer(cpu); node_set_state(cpu_to_node(cpu), N_CPU); break; -- cgit v1.2.3-59-g8ed1b From 72853e2991a2702ae93aaf889ac7db743a415dd3 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 9 Sep 2010 16:38:16 -0700 Subject: mm: page allocator: update free page counters after pages are placed on the free list When allocating a page, the system uses NR_FREE_PAGES counters to determine if watermarks would remain intact after the allocation was made. This check is made without interrupts disabled or the zone lock held and so is race-prone by nature. Unfortunately, when pages are being freed in batch, the counters are updated before the pages are added on the list. During this window, the counters are misleading as the pages do not exist yet. When under significant pressure on systems with large numbers of CPUs, it's possible for processes to make progress even though they should have been stalled. This is particularly problematic if a number of the processes are using GFP_ATOMIC as the min watermark can be accidentally breached and in extreme cases, the system can livelock. This patch updates the counters after the pages have been added to the list. This makes the allocator more cautious with respect to preserving the watermarks and mitigates livelock possibilities. [akpm@linux-foundation.org: avoid modifying incoming args] Signed-off-by: Mel Gorman Reviewed-by: Rik van Riel Reviewed-by: Minchan Kim Reviewed-by: KAMEZAWA Hiroyuki Reviewed-by: Christoph Lameter Reviewed-by: KOSAKI Motohiro Acked-by: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a9649f4b261e..452e2ba06c7c 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -588,13 +588,13 @@ static void free_pcppages_bulk(struct zone *zone, int count, { int migratetype = 0; int batch_free = 0; + int to_free = count; spin_lock(&zone->lock); zone->all_unreclaimable = 0; zone->pages_scanned = 0; - __mod_zone_page_state(zone, NR_FREE_PAGES, count); - while (count) { + while (to_free) { struct page *page; struct list_head *list; @@ -619,8 +619,9 @@ static void free_pcppages_bulk(struct zone *zone, int count, /* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */ __free_one_page(page, zone, 0, page_private(page)); trace_mm_page_pcpu_drain(page, 0, page_private(page)); - } while (--count && --batch_free && !list_empty(list)); + } while (--to_free && --batch_free && !list_empty(list)); } + __mod_zone_page_state(zone, NR_FREE_PAGES, count); spin_unlock(&zone->lock); } @@ -631,8 +632,8 @@ static void free_one_page(struct zone *zone, struct page *page, int order, zone->all_unreclaimable = 0; zone->pages_scanned = 0; - __mod_zone_page_state(zone, NR_FREE_PAGES, 1 << order); __free_one_page(page, zone, order, migratetype); + __mod_zone_page_state(zone, NR_FREE_PAGES, 1 << order); spin_unlock(&zone->lock); } -- cgit v1.2.3-59-g8ed1b From aa45484031ddee09b06350ab8528bfe5b2c76d1c Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Thu, 9 Sep 2010 16:38:17 -0700 Subject: mm: page allocator: calculate a better estimate of NR_FREE_PAGES when memory is low and kswapd is awake Ordinarily watermark checks are based on the vmstat NR_FREE_PAGES as it is cheaper than scanning a number of lists. To avoid synchronization overhead, counter deltas are maintained on a per-cpu basis and drained both periodically and when the delta is above a threshold. On large CPU systems, the difference between the estimated and real value of NR_FREE_PAGES can be very high. If NR_FREE_PAGES is much higher than number of real free page in buddy, the VM can allocate pages below min watermark, at worst reducing the real number of pages to zero. Even if the OOM killer kills some victim for freeing memory, it may not free memory if the exit path requires a new page resulting in livelock. This patch introduces a zone_page_state_snapshot() function (courtesy of Christoph) that takes a slightly more accurate view of an arbitrary vmstat counter. It is used to read NR_FREE_PAGES while kswapd is awake to avoid the watermark being accidentally broken. The estimate is not perfect and may result in cache line bounces but is expected to be lighter than the IPI calls necessary to continually drain the per-cpu counters while kswapd is awake. Signed-off-by: Christoph Lameter Signed-off-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 13 +++++++++++++ include/linux/vmstat.h | 22 ++++++++++++++++++++++ mm/mmzone.c | 21 +++++++++++++++++++++ mm/page_alloc.c | 4 ++-- mm/vmstat.c | 15 ++++++++++++++- 5 files changed, 72 insertions(+), 3 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 6e6e62648a4d..3984c4eb41fd 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -283,6 +283,13 @@ struct zone { /* zone watermarks, access with *_wmark_pages(zone) macros */ unsigned long watermark[NR_WMARK]; + /* + * When free pages are below this point, additional steps are taken + * when reading the number of free pages to avoid per-cpu counter + * drift allowing watermarks to be breached + */ + unsigned long percpu_drift_mark; + /* * We don't know if the memory that we're going to allocate will be freeable * or/and it will be released eventually, so to avoid totally wasting several @@ -441,6 +448,12 @@ static inline int zone_is_oom_locked(const struct zone *zone) return test_bit(ZONE_OOM_LOCKED, &zone->flags); } +#ifdef CONFIG_SMP +unsigned long zone_nr_free_pages(struct zone *zone); +#else +#define zone_nr_free_pages(zone) zone_page_state(zone, NR_FREE_PAGES) +#endif /* CONFIG_SMP */ + /* * The "priority" of VM scanning is how much of the queues we will scan in one * go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index 7f43ccdc1d38..eaaea37b3b75 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -170,6 +170,28 @@ static inline unsigned long zone_page_state(struct zone *zone, return x; } +/* + * More accurate version that also considers the currently pending + * deltas. For that we need to loop over all cpus to find the current + * deltas. There is no synchronization so the result cannot be + * exactly accurate either. + */ +static inline unsigned long zone_page_state_snapshot(struct zone *zone, + enum zone_stat_item item) +{ + long x = atomic_long_read(&zone->vm_stat[item]); + +#ifdef CONFIG_SMP + int cpu; + for_each_online_cpu(cpu) + x += per_cpu_ptr(zone->pageset, cpu)->vm_stat_diff[item]; + + if (x < 0) + x = 0; +#endif + return x; +} + extern unsigned long global_reclaimable_pages(void); extern unsigned long zone_reclaimable_pages(struct zone *zone); diff --git a/mm/mmzone.c b/mm/mmzone.c index f5b7d1760213..e35bfb82c855 100644 --- a/mm/mmzone.c +++ b/mm/mmzone.c @@ -87,3 +87,24 @@ int memmap_valid_within(unsigned long pfn, return 1; } #endif /* CONFIG_ARCH_HAS_HOLES_MEMORYMODEL */ + +#ifdef CONFIG_SMP +/* Called when a more accurate view of NR_FREE_PAGES is needed */ +unsigned long zone_nr_free_pages(struct zone *zone) +{ + unsigned long nr_free_pages = zone_page_state(zone, NR_FREE_PAGES); + + /* + * While kswapd is awake, it is considered the zone is under some + * memory pressure. Under pressure, there is a risk that + * per-cpu-counter-drift will allow the min watermark to be breached + * potentially causing a live-lock. While kswapd is awake and + * free pages are low, get a better estimate for free pages + */ + if (nr_free_pages < zone->percpu_drift_mark && + !waitqueue_active(&zone->zone_pgdat->kswapd_wait)) + return zone_page_state_snapshot(zone, NR_FREE_PAGES); + + return nr_free_pages; +} +#endif /* CONFIG_SMP */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 452e2ba06c7c..b2d21e06d45d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1462,7 +1462,7 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark, { /* free_pages my go negative - that's OK */ long min = mark; - long free_pages = zone_page_state(z, NR_FREE_PAGES) - (1 << order) + 1; + long free_pages = zone_nr_free_pages(z) - (1 << order) + 1; int o; if (alloc_flags & ALLOC_HIGH) @@ -2424,7 +2424,7 @@ void show_free_areas(void) " all_unreclaimable? %s" "\n", zone->name, - K(zone_page_state(zone, NR_FREE_PAGES)), + K(zone_nr_free_pages(zone)), K(min_wmark_pages(zone)), K(low_wmark_pages(zone)), K(high_wmark_pages(zone)), diff --git a/mm/vmstat.c b/mm/vmstat.c index a8d6b59e609a..355a9e669aaa 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -138,11 +138,24 @@ static void refresh_zone_stat_thresholds(void) int threshold; for_each_populated_zone(zone) { + unsigned long max_drift, tolerate_drift; + threshold = calculate_threshold(zone); for_each_online_cpu(cpu) per_cpu_ptr(zone->pageset, cpu)->stat_threshold = threshold; + + /* + * Only set percpu_drift_mark if there is a danger that + * NR_FREE_PAGES reports the low watermark is ok when in fact + * the min watermark could be breached by an allocation + */ + tolerate_drift = low_wmark_pages(zone) - min_wmark_pages(zone); + max_drift = num_online_cpus() * threshold; + if (max_drift > tolerate_drift) + zone->percpu_drift_mark = high_wmark_pages(zone) + + max_drift; } } @@ -813,7 +826,7 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, "\n scanned %lu" "\n spanned %lu" "\n present %lu", - zone_page_state(zone, NR_FREE_PAGES), + zone_nr_free_pages(zone), min_wmark_pages(zone), low_wmark_pages(zone), high_wmark_pages(zone), -- cgit v1.2.3-59-g8ed1b From 9ee493ce0a60bf42c0f8fd0b0fe91df5704a1cbf Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 9 Sep 2010 16:38:18 -0700 Subject: mm: page allocator: drain per-cpu lists after direct reclaim allocation fails When under significant memory pressure, a process enters direct reclaim and immediately afterwards tries to allocate a page. If it fails and no further progress is made, it's possible the system will go OOM. However, on systems with large amounts of memory, it's possible that a significant number of pages are on per-cpu lists and inaccessible to the calling process. This leads to a process entering direct reclaim more often than it should increasing the pressure on the system and compounding the problem. This patch notes that if direct reclaim is making progress but allocations are still failing that the system is already under heavy pressure. In this case, it drains the per-cpu lists and tries the allocation a second time before continuing. Signed-off-by: Mel Gorman Reviewed-by: Minchan Kim Reviewed-by: KAMEZAWA Hiroyuki Reviewed-by: KOSAKI Motohiro Reviewed-by: Christoph Lameter Cc: Dave Chinner Cc: Wu Fengguang Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b2d21e06d45d..a8cfa9cc6e86 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1847,6 +1847,7 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, struct page *page = NULL; struct reclaim_state reclaim_state; struct task_struct *p = current; + bool drained = false; cond_resched(); @@ -1865,14 +1866,25 @@ __alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, cond_resched(); - if (order != 0) - drain_all_pages(); + if (unlikely(!(*did_some_progress))) + return NULL; - if (likely(*did_some_progress)) - page = get_page_from_freelist(gfp_mask, nodemask, order, +retry: + page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist, high_zoneidx, alloc_flags, preferred_zone, migratetype); + + /* + * If an allocation failed after direct reclaim, it could be because + * pages are pinned on the per-cpu lists. Drain them and try again + */ + if (!page && !drained) { + drain_all_pages(); + drained = true; + goto retry; + } + return page; } -- cgit v1.2.3-59-g8ed1b From eee743fd7eac9f2ea69ad06d093dfb5a12538fe5 Mon Sep 17 00:00:00 2001 From: "Jorge Boncompte [DTI2]" Date: Thu, 9 Sep 2010 16:38:19 -0700 Subject: minix: fix regression in minix_mkdir() Commit 9eed1fb721c ("minix: replace inode uid,gid,mode init with helper") broke directory creation on minix filesystems. Fix it by passing the needed mode flag to inode init helper. Signed-off-by: Jorge Boncompte [DTI2] Cc: Dmitry Monakhov Cc: Al Viro Cc: [2.6.35.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/minix/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/minix/namei.c b/fs/minix/namei.c index e20ee85955d1..f3f3578393a4 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -115,7 +115,7 @@ static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) inode_inc_link_count(dir); - inode = minix_new_inode(dir, mode, &err); + inode = minix_new_inode(dir, S_IFDIR | mode, &err); if (!inode) goto out_dir; -- cgit v1.2.3-59-g8ed1b From 40c6023031369ae5573e622ca54fa3ffe89fb865 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 9 Sep 2010 17:13:31 +0200 Subject: libata,pata_via: revert ata_wait_idle() removal from ata_sff/via_tf_load() Commit 978c0666 (libata: Remove excess delay in the tf_load path) removed ata_wait_idle() from ata_sff_tf_load() and via_tf_load(). This caused obscure detection problems in sata_sil. https://bugzilla.kernel.org/show_bug.cgi?id=16606 The commit was pure performance optimization. Revert it for now. Reported-by: Dieter Plaetinck Reported-by: Jan Beulich Bisected-by: gianluca Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 3 +++ drivers/ata/pata_via.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 3b82d8ef76f0..dee3c2c52562 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -418,6 +418,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) if (ioaddr->ctl_addr) iowrite8(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; + ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { @@ -453,6 +454,8 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) iowrite8(tf->device, ioaddr->device_addr); VPRINTK("device 0x%X\n", tf->device); } + + ata_wait_idle(ap); } EXPORT_SYMBOL_GPL(ata_sff_tf_load); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 5e659885de16..ac8d7d97e408 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -417,6 +417,8 @@ static void via_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) tf->lbam, tf->lbah); } + + ata_wait_idle(ap); } static int via_port_start(struct ata_port *ap) -- cgit v1.2.3-59-g8ed1b From 238e149c7a92eb79ab9f48c171e907a5bde18333 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Thu, 9 Sep 2010 09:42:40 -0700 Subject: ata_piix: IDE Mode SATA patch for Intel Patsburg DeviceIDs This patch adds the Intel Patsburg (PCH) IDE mode SATA Controller DeviceIDs. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 3971bc0a4838..d712675d0a96 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -302,6 +302,10 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x1c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (CPT) */ { 0x8086, 0x1c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (PBG) */ + { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (PBG) */ + { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; -- cgit v1.2.3-59-g8ed1b From 992b3fb9b5391bc4de5b42bb810dc6dd583a6c4a Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Thu, 9 Sep 2010 09:44:56 -0700 Subject: ahci: AHCI and RAID mode SATA patch for Intel Patsburg DeviceIDs This patch adds the Intel Patsburg (PCH) SATA AHCI and RAID Controller DeviceIDs. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 013727b20417..ff1c945fba98 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -253,6 +253,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1c05), board_ahci }, /* CPT RAID */ { PCI_VDEVICE(INTEL, 0x1c06), board_ahci }, /* CPT RAID */ { PCI_VDEVICE(INTEL, 0x1c07), board_ahci }, /* CPT RAID */ + { PCI_VDEVICE(INTEL, 0x1d02), board_ahci }, /* PBG AHCI */ + { PCI_VDEVICE(INTEL, 0x1d04), board_ahci }, /* PBG RAID */ + { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v1.2.3-59-g8ed1b From e2f3d75fc0e4a0d03c61872bad39ffa2e74a04ff Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 7 Sep 2010 14:05:31 +0200 Subject: libata: skip EH autopsy and recovery during suspend For some mysterious reason, certain hardware reacts badly to usual EH actions while the system is going for suspend. As the devices won't be needed until the system is resumed, ask EH to skip usual autopsy and recovery and proceed directly to suspend. Signed-off-by: Tejun Heo Tested-by: Stephan Diestelhorst Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 14 +++++++++++++- drivers/ata/libata-eh.c | 4 ++++ include/linux/libata.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index c035b3d041ee..932eaee50245 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5418,6 +5418,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, */ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) { + unsigned int ehi_flags = ATA_EHI_QUIET; int rc; /* @@ -5426,7 +5427,18 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) */ ata_lpm_enable(host); - rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1); + /* + * On some hardware, device fails to respond after spun down + * for suspend. As the device won't be used before being + * resumed, we don't need to touch the device. Ask EH to skip + * the usual stuff and proceed directly to suspend. + * + * http://thread.gmane.org/gmane.linux.ide/46764 + */ + if (mesg.event == PM_EVENT_SUSPEND) + ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY; + + rc = ata_host_request_pm(host, mesg, 0, ehi_flags, 1); if (rc == 0) host->dev->power.power_state = mesg; return rc; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index c9ae299b8342..e48302eae55f 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3235,6 +3235,10 @@ static int ata_eh_skip_recovery(struct ata_link *link) if (link->flags & ATA_LFLAG_DISABLED) return 1; + /* skip if explicitly requested */ + if (ehc->i.flags & ATA_EHI_NO_RECOVERY) + return 1; + /* thaw frozen port and recover failed devices */ if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link)) return 0; diff --git a/include/linux/libata.h b/include/linux/libata.h index f010f18a0f86..7de282d8bedf 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -335,6 +335,7 @@ enum { ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ ATA_EHI_QUIET = (1 << 3), /* be quiet */ + ATA_EHI_NO_RECOVERY = (1 << 4), /* no recovery */ ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ -- cgit v1.2.3-59-g8ed1b From ea3c64506ea7965f86f030155e6fdef381de10e2 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Tue, 31 Aug 2010 16:20:36 -0700 Subject: libata-sff: Reenable Port Multiplier after libata-sff remodeling. Keep track of the link on the which the current request is in progress. It allows support of links behind port multiplier. Not all libata-sff is PMP compliant. Code for native BMDMA controller does not take in accound PMP. Tested on Marvell 7042 and Sil7526. Signed-off-by: Gwendal Grignou Signed-off-by: Jeff Garzik --- drivers/ata/libata-sff.c | 38 ++++++++++++++++++++++++++++---------- drivers/ata/sata_mv.c | 2 +- include/linux/libata.h | 3 ++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index dee3c2c52562..e30c537cce32 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1045,7 +1045,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, u8 status, int in_wq) { - struct ata_eh_info *ehi = &ap->link.eh_info; + struct ata_link *link = qc->dev->link; + struct ata_eh_info *ehi = &link->eh_info; unsigned long flags = 0; int poll_next; @@ -1301,8 +1302,14 @@ fsm_start: } EXPORT_SYMBOL_GPL(ata_sff_hsm_move); -void ata_sff_queue_pio_task(struct ata_port *ap, unsigned long delay) +void ata_sff_queue_pio_task(struct ata_link *link, unsigned long delay) { + struct ata_port *ap = link->ap; + + WARN_ON((ap->sff_pio_task_link != NULL) && + (ap->sff_pio_task_link != link)); + ap->sff_pio_task_link = link; + /* may fail if ata_sff_flush_pio_task() in progress */ queue_delayed_work(ata_sff_wq, &ap->sff_pio_task, msecs_to_jiffies(delay)); @@ -1324,14 +1331,18 @@ static void ata_sff_pio_task(struct work_struct *work) { struct ata_port *ap = container_of(work, struct ata_port, sff_pio_task.work); + struct ata_link *link = ap->sff_pio_task_link; struct ata_queued_cmd *qc; u8 status; int poll_next; + BUG_ON(ap->sff_pio_task_link == NULL); /* qc can be NULL if timeout occurred */ - qc = ata_qc_from_tag(ap, ap->link.active_tag); - if (!qc) + qc = ata_qc_from_tag(ap, link->active_tag); + if (!qc) { + ap->sff_pio_task_link = NULL; return; + } fsm_start: WARN_ON_ONCE(ap->hsm_task_state == HSM_ST_IDLE); @@ -1348,11 +1359,16 @@ fsm_start: msleep(2); status = ata_sff_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { - ata_sff_queue_pio_task(ap, ATA_SHORT_PAUSE); + ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); return; } } + /* + * hsm_move() may trigger another command to be processed. + * clean the link beforehand. + */ + ap->sff_pio_task_link = NULL; /* move the HSM */ poll_next = ata_sff_hsm_move(ap, qc, status, 1); @@ -1379,6 +1395,7 @@ fsm_start: unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; /* Use polling pio if the LLD doesn't handle * interrupt driven pio and atapi CDB interrupt. @@ -1399,7 +1416,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_LAST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_sff_queue_pio_task(ap, 0); + ata_sff_queue_pio_task(link, 0); break; @@ -1412,7 +1429,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - ata_sff_queue_pio_task(ap, 0); + ata_sff_queue_pio_task(link, 0); /* always send first data block using the * ata_sff_pio_task() codepath. @@ -1422,7 +1439,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_sff_queue_pio_task(ap, 0); + ata_sff_queue_pio_task(link, 0); /* if polling, ata_sff_pio_task() handles the * rest. otherwise, interrupt handler takes @@ -1444,7 +1461,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - ata_sff_queue_pio_task(ap, 0); + ata_sff_queue_pio_task(link, 0); break; default: @@ -2737,6 +2754,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_dumb_qc_prep); unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; /* defer PIO handling to sff_qc_issue */ if (!ata_is_dma(qc->tf.protocol)) @@ -2765,7 +2783,7 @@ unsigned int ata_bmdma_qc_issue(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - ata_sff_queue_pio_task(ap, 0); + ata_sff_queue_pio_task(link, 0); break; default: diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 81982594a014..a9fd9709c262 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2284,7 +2284,7 @@ static unsigned int mv_qc_issue_fis(struct ata_queued_cmd *qc) } if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_sff_queue_pio_task(ap, 0); + ata_sff_queue_pio_task(link, 0); return 0; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 7de282d8bedf..45fb2967b66d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -724,6 +724,7 @@ struct ata_port { struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ u8 ctl; /* cache of ATA control register */ u8 last_ctl; /* Cache last written value */ + struct ata_link* sff_pio_task_link; /* link currently used */ struct delayed_work sff_pio_task; #ifdef CONFIG_ATA_BMDMA struct ata_bmdma_prd *bmdma_prd; /* BMDMA SG list */ @@ -1595,7 +1596,7 @@ extern void ata_sff_irq_on(struct ata_port *ap); extern void ata_sff_irq_clear(struct ata_port *ap); extern int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, u8 status, int in_wq); -extern void ata_sff_queue_pio_task(struct ata_port *ap, unsigned long delay); +extern void ata_sff_queue_pio_task(struct ata_link *link, unsigned long delay); extern unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc); extern bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc); extern unsigned int ata_sff_port_intr(struct ata_port *ap, -- cgit v1.2.3-59-g8ed1b From df09162550fbb53354f0c88e85b5d0e6129ee9cc Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Thu, 9 Sep 2010 16:34:59 -0700 Subject: tracing: t_start: reset FTRACE_ITER_HASH in case of seek/pread Be sure to avoid entering t_show() with FTRACE_ITER_HASH set without having properly started the iterator to iterate the hash. This case is degenerate and, as discovered by Robert Swiecki, can cause t_hash_show() to misuse a pointer. This causes a NULL ptr deref with possible security implications. Tracked as CVE-2010-3079. Cc: Robert Swiecki Cc: Eugene Teo Cc: Signed-off-by: Chris Wright Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 83a16e9ee518..fa7ece649fe1 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1510,6 +1510,8 @@ static void *t_start(struct seq_file *m, loff_t *pos) if (*pos > 0) return t_hash_start(m, pos); iter->flags |= FTRACE_ITER_PRINTALL; + /* reset in case of seek/pread */ + iter->flags &= ~FTRACE_ITER_HASH; return iter; } -- cgit v1.2.3-59-g8ed1b From 201b6bab6798fcd8ec1cb30165b91fdb89a91775 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 7 Sep 2010 20:33:24 +0000 Subject: MAINTAINERS: Add CAIF Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 087912aa09bd..b5fb9bdcabb1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1445,6 +1445,16 @@ S: Maintained F: Documentation/video4linux/cafe_ccic F: drivers/media/video/cafe_ccic* +CAIF NETWORK LAYER +M: Sjur Braendeland +L: netdev@vger.kernel.org +S: Supported +F: Documentation/networking/caif/ +F: drivers/net/caif/ +F: include/linux/caif/ +F: include/net/caif/ +F: net/caif/ + CALGARY x86-64 IOMMU M: Muli Ben-Yehuda M: "Jon D. Mason" -- cgit v1.2.3-59-g8ed1b From c9cedbba0fc591e1c0587f838932ca3f3c6fec57 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 8 Sep 2010 07:50:47 +0000 Subject: ipheth: remove incorrect devtype to WWAN The 'wwan' devtype is meant for devices that require preconfiguration and *every* time setup before the ethernet interface can be used, like cellular modems which require a series of setup commands on serial ports or other mechanisms before the ethernet interface will handle packets. As ipheth only requires one-per-hotplug pairing setup with no preconfiguration (like APN, phone #, etc) and the network interface is usable at any time after that initial setup, remove the incorrect devtype wwan. Signed-off-by: Dan Williams Signed-off-by: David S. Miller --- drivers/net/usb/ipheth.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 8ed30fa35d0a..b2bcf99e6f08 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -429,10 +429,6 @@ static const struct net_device_ops ipheth_netdev_ops = { .ndo_get_stats = &ipheth_stats, }; -static struct device_type ipheth_type = { - .name = "wwan", -}; - static int ipheth_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -450,7 +446,7 @@ static int ipheth_probe(struct usb_interface *intf, netdev->netdev_ops = &ipheth_netdev_ops; netdev->watchdog_timeo = IPHETH_TX_TIMEOUT; - strcpy(netdev->name, "wwan%d"); + strcpy(netdev->name, "eth%d"); dev = netdev_priv(netdev); dev->udev = udev; @@ -500,7 +496,6 @@ static int ipheth_probe(struct usb_interface *intf, SET_NETDEV_DEV(netdev, &intf->dev); SET_ETHTOOL_OPS(netdev, &ops); - SET_NETDEV_DEVTYPE(netdev, &ipheth_type); retval = register_netdev(netdev); if (retval) { -- cgit v1.2.3-59-g8ed1b From be14eb619108fa8b7120eb2c42d66d5f623ae10e Mon Sep 17 00:00:00 2001 From: Brian King Date: Fri, 10 Sep 2010 09:03:21 +0200 Subject: block: Range check cpu in blk_cpu_to_group While testing CPU DLPAR, the following problem was discovered. We were DLPAR removing the first CPU, which in this case was logical CPUs 0-3. CPUs 0-2 were already marked offline and we were in the process of offlining CPU 3. After marking the CPU inactive and offline in cpu_disable, but before the cpu was completely idle (cpu_die), we ended up in __make_request on CPU 3. There we looked at the topology map to see which CPU to complete the I/O on and found no CPUs in the cpu_sibling_map. This resulted in the block layer setting the completion cpu to be NR_CPUS, which then caused an oops when we tried to complete the I/O. Fix this by sanity checking the value we return from blk_cpu_to_group to be a valid cpu value. Signed-off-by: Brian King Signed-off-by: Jens Axboe --- block/blk.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/block/blk.h b/block/blk.h index 6e7dc87141e4..d6b911ac002c 100644 --- a/block/blk.h +++ b/block/blk.h @@ -142,14 +142,18 @@ static inline int queue_congestion_off_threshold(struct request_queue *q) static inline int blk_cpu_to_group(int cpu) { + int group = NR_CPUS; #ifdef CONFIG_SCHED_MC const struct cpumask *mask = cpu_coregroup_mask(cpu); - return cpumask_first(mask); + group = cpumask_first(mask); #elif defined(CONFIG_SCHED_SMT) - return cpumask_first(topology_thread_cpumask(cpu)); + group = cpumask_first(topology_thread_cpumask(cpu)); #else return cpu; #endif + if (likely(group < NR_CPUS)) + return group; + return cpu; } /* -- cgit v1.2.3-59-g8ed1b From 6008fd5aa4c15f2ea80a9f997983a9cbfa14ba73 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 10 Sep 2010 16:12:34 +0800 Subject: ALSA: snd-usb-caiaq: drop version number Let git do the job. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/caiaq/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index cdfb856bddd2..da9cb6dcee2a 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -36,7 +36,7 @@ #include "input.h" MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21"); +MODULE_DESCRIPTION("caiaq USB audio"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," -- cgit v1.2.3-59-g8ed1b From 15c5ab607045e278ebf4d2ca4aea2250617d50ca Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 10 Sep 2010 17:04:57 +0800 Subject: ALSA: snd-usb-caiaq: Add support for Traktor Kontrol S4 This patch adds support for the new Traktor Kontrol S4 by Native Instruments. It features a new audio data streaming model, MIDI in and out ports, a huge number of 174 dimmable LEDs, 96 buttons and 46 absolute encoder axis, including some rotary encoders. All features are supported by the driver now. Did some code refactoring along the way. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/Kconfig | 2 + sound/usb/caiaq/audio.c | 175 +++++++++++++++++++++++++++++--- sound/usb/caiaq/control.c | 208 +++++++++++++++++++++++++++++++++++++- sound/usb/caiaq/device.c | 8 +- sound/usb/caiaq/device.h | 6 +- sound/usb/caiaq/input.c | 248 +++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 598 insertions(+), 49 deletions(-) diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 44d6d2ec964f..112984f4080f 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -65,6 +65,7 @@ config SND_USB_CAIAQ * Native Instruments Guitar Rig Session I/O * Native Instruments Guitar Rig mobile * Native Instruments Traktor Kontrol X1 + * Native Instruments Traktor Kontrol S4 To compile this driver as a module, choose M here: the module will be called snd-usb-caiaq. @@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT * Native Instruments Kore Controller * Native Instruments Kore Controller 2 * Native Instruments Audio Kontrol 1 + * Native Instruments Traktor Kontrol S4 config SND_USB_US122L tristate "Tascam US-122L USB driver" diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 4328cad6c3a2..68b97477577b 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev) memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); dev->input_panic = 0; dev->output_panic = 0; - dev->first_packet = 1; + dev->first_packet = 4; dev->streaming = 1; dev->warned = 0; @@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) } static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, - struct snd_pcm_hw_params *hw_params) + struct snd_pcm_hw_params *hw_params) { debug("%s(%p)\n", __func__, sub); return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); @@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) #endif static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 }; + 48000, 64000, 88200, 96000, 176400, 192000 }; static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) { @@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) debug("%s(%p)\n", __func__, substream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dev->period_out_count[index] = BYTES_PER_SAMPLE + 1; - dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; + int out_pos; + + switch (dev->spec.data_alignment) { + case 0: + case 2: + out_pos = BYTES_PER_SAMPLE + 1; + break; + case 3: + default: + out_pos = 0; + break; + } + + dev->period_out_count[index] = out_pos; + dev->audio_out_buf_pos[index] = out_pos; } else { - int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2; - dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos; - dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos; + int in_pos; + + switch (dev->spec.data_alignment) { + case 0: + in_pos = BYTES_PER_SAMPLE + 2; + break; + case 2: + in_pos = BYTES_PER_SAMPLE; + break; + case 3: + default: + in_pos = 0; + break; + } + + dev->period_in_count[index] = in_pos; + dev->audio_in_buf_pos[index] = in_pos; } if (dev->streaming) @@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) snd_pcm_limit_hw_rates(runtime); bytes_per_sample = BYTES_PER_SAMPLE; - if (dev->spec.data_alignment == 2) + if (dev->spec.data_alignment >= 2) bytes_per_sample++; bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) @@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) { struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); + debug("%s(%p) cmd %d\n", __func__, sub, cmd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, } } +static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev, + const struct urb *urb, + const struct usb_iso_packet_descriptor *iso) +{ + unsigned char *usb_buf = urb->transfer_buffer + iso->offset; + int stream, i; + + /* paranoia check */ + if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM)) + return; + + for (i = 0; i < iso->actual_length;) { + for (stream = 0; stream < dev->n_streams; stream++) { + struct snd_pcm_substream *sub = dev->sub_capture[stream]; + char *audio_buf = NULL; + int c, n, sz = 0; + + if (sub && !dev->input_panic) { + struct snd_pcm_runtime *rt = sub->runtime; + audio_buf = rt->dma_area; + sz = frames_to_bytes(rt, rt->buffer_size); + } + + for (c = 0; c < CHANNELS_PER_STREAM; c++) { + /* 3 audio data bytes, followed by 1 check byte */ + if (audio_buf) { + for (n = 0; n < BYTES_PER_SAMPLE; n++) { + audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n]; + + if (dev->audio_in_buf_pos[stream] == sz) + dev->audio_in_buf_pos[stream] = 0; + } + + dev->period_in_count[stream] += BYTES_PER_SAMPLE; + } + + i += BYTES_PER_SAMPLE; + + if (usb_buf[i] != ((stream << 1) | c) && + !dev->first_packet) { + if (!dev->input_panic) + printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n", + ((stream << 1) | c), usb_buf[i], c, stream, i); + dev->input_panic = 1; + } + + i++; + } + } + } + + if (dev->first_packet > 0) + dev->first_packet--; +} + static void read_in_urb(struct snd_usb_caiaqdev *dev, const struct urb *urb, const struct usb_iso_packet_descriptor *iso) @@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, case 2: read_in_urb_mode2(dev, urb, iso); break; + case 3: + read_in_urb_mode3(dev, urb, iso); + break; } if ((dev->input_panic || dev->output_panic) && !dev->warned) { @@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev, } } -static void fill_out_urb(struct snd_usb_caiaqdev *dev, - struct urb *urb, - const struct usb_iso_packet_descriptor *iso) +static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev, + struct urb *urb, + const struct usb_iso_packet_descriptor *iso) { unsigned char *usb_buf = urb->transfer_buffer + iso->offset; struct snd_pcm_substream *sub; @@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev, /* fill in the check bytes */ if (dev->spec.data_alignment == 2 && i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == - (dev->n_streams * CHANNELS_PER_STREAM)) - for (stream = 0; stream < dev->n_streams; stream++, i++) - usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); + (dev->n_streams * CHANNELS_PER_STREAM)) + for (stream = 0; stream < dev->n_streams; stream++, i++) + usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); + } +} + +static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev, + struct urb *urb, + const struct usb_iso_packet_descriptor *iso) +{ + unsigned char *usb_buf = urb->transfer_buffer + iso->offset; + int stream, i; + + for (i = 0; i < iso->length;) { + for (stream = 0; stream < dev->n_streams; stream++) { + struct snd_pcm_substream *sub = dev->sub_playback[stream]; + char *audio_buf = NULL; + int c, n, sz = 0; + + if (sub) { + struct snd_pcm_runtime *rt = sub->runtime; + audio_buf = rt->dma_area; + sz = frames_to_bytes(rt, rt->buffer_size); + } + + for (c = 0; c < CHANNELS_PER_STREAM; c++) { + for (n = 0; n < BYTES_PER_SAMPLE; n++) { + if (audio_buf) { + usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++]; + + if (dev->audio_out_buf_pos[stream] == sz) + dev->audio_out_buf_pos[stream] = 0; + } else { + usb_buf[i+n] = 0; + } + } + + if (audio_buf) + dev->period_out_count[stream] += BYTES_PER_SAMPLE; + + i += BYTES_PER_SAMPLE; + + /* fill in the check byte pattern */ + usb_buf[i++] = (stream << 1) | c; + } + } + } +} + +static inline void fill_out_urb(struct snd_usb_caiaqdev *dev, + struct urb *urb, + const struct usb_iso_packet_descriptor *iso) +{ + switch (dev->spec.data_alignment) { + case 0: + case 2: + fill_out_urb_mode_0(dev, urb, iso); + break; + case 3: + fill_out_urb_mode_3(dev, urb, iso); + break; } } diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 91c804cd2782..00e5d0a469e1 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c @@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol, case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): maxval = 127; break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + maxval = 31; + break; } if (is_intval) { @@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol, struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); int pos = kcontrol->private_value; + int v = ucontrol->value.integer.value[0]; unsigned char cmd = EP1_CMD_WRITE_IO; if (dev->chip.usb_id == @@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol, cmd = EP1_CMD_DIMM_LEDS; if (pos & CNT_INTVAL) { - dev->control_state[pos & ~CNT_INTVAL] - = ucontrol->value.integer.value[0]; - snd_usb_caiaq_send_command(dev, cmd, - dev->control_state, sizeof(dev->control_state)); + int i = pos & ~CNT_INTVAL; + + dev->control_state[i] = v; + + if (dev->chip.usb_id == + USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) { + int actual_len; + + dev->ep8_out_buf[0] = i; + dev->ep8_out_buf[1] = v; + + usb_bulk_msg(dev->chip.dev, + usb_sndbulkpipe(dev->chip.dev, 8), + dev->ep8_out_buf, sizeof(dev->ep8_out_buf), + &actual_len, 200); + } else { + snd_usb_caiaq_send_command(dev, cmd, + dev->control_state, sizeof(dev->control_state)); + } } else { - if (ucontrol->value.integer.value[0]) + if (v) dev->control_state[pos / 8] |= 1 << (pos % 8); else dev->control_state[pos / 8] &= ~(1 << (pos % 8)); @@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = { { "LED Deck B: SYNC", 8 | CNT_INTVAL }, }; +static struct caiaq_controller kontrols4_controller[] = { + { "LED: Master: Quant", 10 | CNT_INTVAL }, + { "LED: Master: Headphone", 11 | CNT_INTVAL }, + { "LED: Master: Master", 12 | CNT_INTVAL }, + { "LED: Master: Snap", 14 | CNT_INTVAL }, + { "LED: Master: Warning", 15 | CNT_INTVAL }, + { "LED: Master: Master button", 112 | CNT_INTVAL }, + { "LED: Master: Snap button", 113 | CNT_INTVAL }, + { "LED: Master: Rec", 118 | CNT_INTVAL }, + { "LED: Master: Size", 119 | CNT_INTVAL }, + { "LED: Master: Quant button", 120 | CNT_INTVAL }, + { "LED: Master: Browser button", 121 | CNT_INTVAL }, + { "LED: Master: Play button", 126 | CNT_INTVAL }, + { "LED: Master: Undo button", 127 | CNT_INTVAL }, + + { "LED: Channel A: >", 4 | CNT_INTVAL }, + { "LED: Channel A: <", 5 | CNT_INTVAL }, + { "LED: Channel A: Meter 1", 97 | CNT_INTVAL }, + { "LED: Channel A: Meter 2", 98 | CNT_INTVAL }, + { "LED: Channel A: Meter 3", 99 | CNT_INTVAL }, + { "LED: Channel A: Meter 4", 100 | CNT_INTVAL }, + { "LED: Channel A: Meter 5", 101 | CNT_INTVAL }, + { "LED: Channel A: Meter 6", 102 | CNT_INTVAL }, + { "LED: Channel A: Meter clip", 103 | CNT_INTVAL }, + { "LED: Channel A: Active", 114 | CNT_INTVAL }, + { "LED: Channel A: Cue", 116 | CNT_INTVAL }, + { "LED: Channel A: FX1", 149 | CNT_INTVAL }, + { "LED: Channel A: FX2", 148 | CNT_INTVAL }, + + { "LED: Channel B: >", 2 | CNT_INTVAL }, + { "LED: Channel B: <", 3 | CNT_INTVAL }, + { "LED: Channel B: Meter 1", 89 | CNT_INTVAL }, + { "LED: Channel B: Meter 2", 90 | CNT_INTVAL }, + { "LED: Channel B: Meter 3", 91 | CNT_INTVAL }, + { "LED: Channel B: Meter 4", 92 | CNT_INTVAL }, + { "LED: Channel B: Meter 5", 93 | CNT_INTVAL }, + { "LED: Channel B: Meter 6", 94 | CNT_INTVAL }, + { "LED: Channel B: Meter clip", 95 | CNT_INTVAL }, + { "LED: Channel B: Active", 122 | CNT_INTVAL }, + { "LED: Channel B: Cue", 125 | CNT_INTVAL }, + { "LED: Channel B: FX1", 147 | CNT_INTVAL }, + { "LED: Channel B: FX2", 146 | CNT_INTVAL }, + + { "LED: Channel C: >", 6 | CNT_INTVAL }, + { "LED: Channel C: <", 7 | CNT_INTVAL }, + { "LED: Channel C: Meter 1", 105 | CNT_INTVAL }, + { "LED: Channel C: Meter 2", 106 | CNT_INTVAL }, + { "LED: Channel C: Meter 3", 107 | CNT_INTVAL }, + { "LED: Channel C: Meter 4", 108 | CNT_INTVAL }, + { "LED: Channel C: Meter 5", 109 | CNT_INTVAL }, + { "LED: Channel C: Meter 6", 110 | CNT_INTVAL }, + { "LED: Channel C: Meter clip", 111 | CNT_INTVAL }, + { "LED: Channel C: Active", 115 | CNT_INTVAL }, + { "LED: Channel C: Cue", 117 | CNT_INTVAL }, + { "LED: Channel C: FX1", 151 | CNT_INTVAL }, + { "LED: Channel C: FX2", 150 | CNT_INTVAL }, + + { "LED: Channel D: >", 0 | CNT_INTVAL }, + { "LED: Channel D: <", 1 | CNT_INTVAL }, + { "LED: Channel D: Meter 1", 81 | CNT_INTVAL }, + { "LED: Channel D: Meter 2", 82 | CNT_INTVAL }, + { "LED: Channel D: Meter 3", 83 | CNT_INTVAL }, + { "LED: Channel D: Meter 4", 84 | CNT_INTVAL }, + { "LED: Channel D: Meter 5", 85 | CNT_INTVAL }, + { "LED: Channel D: Meter 6", 86 | CNT_INTVAL }, + { "LED: Channel D: Meter clip", 87 | CNT_INTVAL }, + { "LED: Channel D: Active", 123 | CNT_INTVAL }, + { "LED: Channel D: Cue", 124 | CNT_INTVAL }, + { "LED: Channel D: FX1", 145 | CNT_INTVAL }, + { "LED: Channel D: FX2", 144 | CNT_INTVAL }, + + { "LED: Deck A: 1 (blue)", 22 | CNT_INTVAL }, + { "LED: Deck A: 1 (green)", 23 | CNT_INTVAL }, + { "LED: Deck A: 2 (blue)", 20 | CNT_INTVAL }, + { "LED: Deck A: 2 (green)", 21 | CNT_INTVAL }, + { "LED: Deck A: 3 (blue)", 18 | CNT_INTVAL }, + { "LED: Deck A: 3 (green)", 19 | CNT_INTVAL }, + { "LED: Deck A: 4 (blue)", 16 | CNT_INTVAL }, + { "LED: Deck A: 4 (green)", 17 | CNT_INTVAL }, + { "LED: Deck A: Load", 44 | CNT_INTVAL }, + { "LED: Deck A: Deck C button", 45 | CNT_INTVAL }, + { "LED: Deck A: In", 47 | CNT_INTVAL }, + { "LED: Deck A: Out", 46 | CNT_INTVAL }, + { "LED: Deck A: Shift", 24 | CNT_INTVAL }, + { "LED: Deck A: Sync", 27 | CNT_INTVAL }, + { "LED: Deck A: Cue", 26 | CNT_INTVAL }, + { "LED: Deck A: Play", 25 | CNT_INTVAL }, + { "LED: Deck A: Tempo up", 33 | CNT_INTVAL }, + { "LED: Deck A: Tempo down", 32 | CNT_INTVAL }, + { "LED: Deck A: Master", 34 | CNT_INTVAL }, + { "LED: Deck A: Keylock", 35 | CNT_INTVAL }, + { "LED: Deck A: Deck A", 37 | CNT_INTVAL }, + { "LED: Deck A: Deck C", 36 | CNT_INTVAL }, + { "LED: Deck A: Samples", 38 | CNT_INTVAL }, + { "LED: Deck A: On Air", 39 | CNT_INTVAL }, + { "LED: Deck A: Sample 1", 31 | CNT_INTVAL }, + { "LED: Deck A: Sample 2", 30 | CNT_INTVAL }, + { "LED: Deck A: Sample 3", 29 | CNT_INTVAL }, + { "LED: Deck A: Sample 4", 28 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - A", 55 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - B", 54 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - C", 53 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - D", 52 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - E", 51 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - F", 50 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - G", 49 | CNT_INTVAL }, + { "LED: Deck A: Digit 1 - dot", 48 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - A", 63 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - B", 62 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - C", 61 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - D", 60 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - E", 59 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - F", 58 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - G", 57 | CNT_INTVAL }, + { "LED: Deck A: Digit 2 - dot", 56 | CNT_INTVAL }, + + { "LED: Deck B: 1 (blue)", 78 | CNT_INTVAL }, + { "LED: Deck B: 1 (green)", 79 | CNT_INTVAL }, + { "LED: Deck B: 2 (blue)", 76 | CNT_INTVAL }, + { "LED: Deck B: 2 (green)", 77 | CNT_INTVAL }, + { "LED: Deck B: 3 (blue)", 74 | CNT_INTVAL }, + { "LED: Deck B: 3 (green)", 75 | CNT_INTVAL }, + { "LED: Deck B: 4 (blue)", 72 | CNT_INTVAL }, + { "LED: Deck B: 4 (green)", 73 | CNT_INTVAL }, + { "LED: Deck B: Load", 180 | CNT_INTVAL }, + { "LED: Deck B: Deck D button", 181 | CNT_INTVAL }, + { "LED: Deck B: In", 183 | CNT_INTVAL }, + { "LED: Deck B: Out", 182 | CNT_INTVAL }, + { "LED: Deck B: Shift", 64 | CNT_INTVAL }, + { "LED: Deck B: Sync", 67 | CNT_INTVAL }, + { "LED: Deck B: Cue", 66 | CNT_INTVAL }, + { "LED: Deck B: Play", 65 | CNT_INTVAL }, + { "LED: Deck B: Tempo up", 185 | CNT_INTVAL }, + { "LED: Deck B: Tempo down", 184 | CNT_INTVAL }, + { "LED: Deck B: Master", 186 | CNT_INTVAL }, + { "LED: Deck B: Keylock", 187 | CNT_INTVAL }, + { "LED: Deck B: Deck B", 189 | CNT_INTVAL }, + { "LED: Deck B: Deck D", 188 | CNT_INTVAL }, + { "LED: Deck B: Samples", 190 | CNT_INTVAL }, + { "LED: Deck B: On Air", 191 | CNT_INTVAL }, + { "LED: Deck B: Sample 1", 71 | CNT_INTVAL }, + { "LED: Deck B: Sample 2", 70 | CNT_INTVAL }, + { "LED: Deck B: Sample 3", 69 | CNT_INTVAL }, + { "LED: Deck B: Sample 4", 68 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - A", 175 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - B", 174 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - C", 173 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - D", 172 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - E", 171 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - F", 170 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - G", 169 | CNT_INTVAL }, + { "LED: Deck B: Digit 1 - dot", 168 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - A", 167 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - B", 166 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - C", 165 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - D", 164 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - E", 163 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - F", 162 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - G", 161 | CNT_INTVAL }, + { "LED: Deck B: Digit 2 - dot", 160 | CNT_INTVAL }, + + { "LED: FX1: dry/wet", 153 | CNT_INTVAL }, + { "LED: FX1: 1", 154 | CNT_INTVAL }, + { "LED: FX1: 2", 155 | CNT_INTVAL }, + { "LED: FX1: 3", 156 | CNT_INTVAL }, + { "LED: FX1: Mode", 157 | CNT_INTVAL }, + { "LED: FX2: dry/wet", 129 | CNT_INTVAL }, + { "LED: FX2: 1", 130 | CNT_INTVAL }, + { "LED: FX2: 2", 131 | CNT_INTVAL }, + { "LED: FX2: 3", 132 | CNT_INTVAL }, + { "LED: FX2: Mode", 133 | CNT_INTVAL }, +}; + static int __devinit add_controls(struct caiaq_controller *c, int num, struct snd_usb_caiaqdev *dev) { @@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) ret = add_controls(kontrolx1_controller, ARRAY_SIZE(kontrolx1_controller), dev); break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + ret = add_controls(kontrols4_controller, + ARRAY_SIZE(kontrols4_controller), dev); + break; } return ret; diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index da9cb6dcee2a..6480c3283c05 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, Audio 8 DJ}," "{Native Instruments, Session I/O}," "{Native Instruments, GuitarRig mobile}" - "{Native Instruments, Traktor Kontrol X1}"); + "{Native Instruments, Traktor Kontrol X1}" + "{Native Instruments, Traktor Kontrol S4}"); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ @@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = { .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_TRAKTORKONTROLX1 }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_TRAKTORKONTROLS4 + }, { /* terminator */ } }; diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index f1117ecc84fd..e3d8a3efb35b 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h @@ -16,6 +16,7 @@ #define USB_PID_SESSIONIO 0x1915 #define USB_PID_GUITARRIGMOBILE 0x0d8d #define USB_PID_TRAKTORKONTROLX1 0x2305 +#define USB_PID_TRAKTORKONTROLS4 0xbaff #define EP1_BUFSIZE 64 #define EP4_BUFSIZE 512 @@ -99,13 +100,14 @@ struct snd_usb_caiaqdev { struct snd_pcm_substream *sub_capture[MAX_STREAMS]; /* Controls */ - unsigned char control_state[64]; + unsigned char control_state[256]; + unsigned char ep8_out_buf[2]; /* Linux input */ #ifdef CONFIG_SND_USB_CAIAQ_INPUT struct input_dev *input_dev; char phys[64]; /* physical device path */ - unsigned short keycode[64]; + unsigned short keycode[128]; struct urb *ep4_in_urb; unsigned char ep4_in_buf[EP4_BUFSIZE]; #endif diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index dcb620796d9e..4432ef7a70a9 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = { KEY_BRL_DOT5 }; -#define KONTROLX1_INPUTS 40 +#define KONTROLX1_INPUTS (40) +#define KONTROLS4_BUTTONS (12 * 8) +#define KONTROLS4_AXIS (46) + +#define KONTROLS4_BUTTON(X) ((X) + BTN_MISC) +#define KONTROLS4_ABS(X) ((X) + ABS_HAT0X) #define DEG90 (range / 2) #define DEG180 (range) @@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) #undef HIGH_PEAK #undef LOW_PEAK +static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev, + int axis, const unsigned char *buf, + int offset) +{ + input_report_abs(dev->input_dev, axis, + (buf[offset * 2] << 8) | buf[offset * 2 + 1]); +} static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, const unsigned char *buf, @@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): - input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]); - input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]); - input_sync(input_dev); + snd_caiaq_input_report_abs(dev, ABS_X, buf, 2); + snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0); + snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1); break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): - input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); - input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); - input_sync(input_dev); - break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): - input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]); - input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); - input_sync(input_dev); + snd_caiaq_input_report_abs(dev, ABS_X, buf, 0); + snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1); + snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2); break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): - input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]); - input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]); - input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]); - input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]); - input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]); - input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]); - input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]); - input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]); - input_sync(input_dev); + snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4); + snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2); + snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6); + snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1); + snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7); + snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0); + snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5); + snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3); break; } + + input_sync(input_dev); } static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, @@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, input_sync(input_dev); } +#define TKS4_MSGBLOCK_SIZE 16 + +static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev, + const unsigned char *buf, + unsigned int len) +{ + while (len) { + unsigned int i, block_id = (buf[0] << 8) | buf[1]; + + switch (block_id) { + case 0: + /* buttons */ + for (i = 0; i < KONTROLS4_BUTTONS; i++) + input_report_key(dev->input_dev, KONTROLS4_BUTTON(i), + (buf[4 + (i / 8)] >> (i % 8)) & 1); + break; + + case 1: + /* left wheel */ + input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8)); + /* right wheel */ + input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8)); + + /* rotary encoders */ + input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf); + input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4); + input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf); + + break; + case 2: + /* Volume Fader Channel D */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1); + /* Volume Fader Channel B */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2); + /* Volume Fader Channel A */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3); + /* Volume Fader Channel C */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4); + /* Loop Volume */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6); + /* Crossfader */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7); + + break; + + case 3: + /* Tempo Fader R */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3); + /* Tempo Fader L */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4); + /* Mic Volume */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6); + /* Cue Mix */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7); + + break; + + case 4: + /* Wheel distance sensor L */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1); + /* Wheel distance sensor R */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2); + /* Channel D EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3); + /* Channel D EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4); + /* Channel D EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5); + /* Channel D EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6); + /* FX2 - dry/wet */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7); + + break; + + case 5: + /* FX2 - 1 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1); + /* FX2 - 2 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2); + /* FX2 - 3 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3); + /* Channel B EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4); + /* Channel B EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5); + /* Channel B EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6); + /* Channel B EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7); + + break; + + case 6: + /* Channel A EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1); + /* Channel A EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2); + /* Channel A EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3); + /* Channel A EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4); + /* Channel C EQ - Filter */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5); + /* Channel C EQ - Low */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6); + /* Channel C EQ - Mid */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7); + + break; + + case 7: + /* Channel C EQ - Hi */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1); + /* FX1 - wet/dry */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2); + /* FX1 - 1 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3); + /* FX1 - 2 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4); + /* FX1 - 3 */ + snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5); + + break; + + default: + debug("%s(): bogus block (id %d)\n", + __func__, block_id); + return; + } + + len -= TKS4_MSGBLOCK_SIZE; + buf += TKS4_MSGBLOCK_SIZE; + } + + input_sync(dev->input_dev); +} + static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) { struct snd_usb_caiaqdev *dev = urb->context; @@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) if (urb->status || !dev || urb != dev->ep4_in_urb) return; - if (urb->actual_length < 24) - goto requeue; - switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): + if (urb->actual_length < 24) + goto requeue; + if (buf[0] & 0x3) snd_caiaq_input_read_io(dev, buf + 1, 7); @@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) snd_caiaq_input_read_analog(dev, buf + 8, 16); break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length); + break; } requeue: @@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) return -EIO; break; @@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): usb_kill_urb(dev->ep4_in_urb); break; } @@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4): + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS); + for (i = 0; i < KONTROLS4_BUTTONS; i++) + dev->keycode[i] = KONTROLS4_BUTTON(i); + input->keycodemax = KONTROLS4_BUTTONS; + + for (i = 0; i < KONTROLS4_AXIS; i++) { + int axis = KONTROLS4_ABS(i); + input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); + } + + /* 36 analog potentiometers and faders */ + for (i = 0; i < 36; i++) + input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10); + + /* 2 encoder wheels */ + input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1); + input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1); + + /* 9 rotary encoders */ + for (i = 0; i < 9; i++) + input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1); + + dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->ep4_in_urb) { + ret = -ENOMEM; + goto exit_free_idev; + } + + usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, + usb_rcvbulkpipe(usb_dev, 0x4), + dev->ep4_in_buf, EP4_BUFSIZE, + snd_usb_caiaq_ep4_reply_dispatch, dev); + + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); + + break; + default: /* no input methods supported on this device */ goto exit_free_idev; -- cgit v1.2.3-59-g8ed1b From 1879c45cce6411fe97b0b65ccad38f5206700dda Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Sep 2010 11:38:43 +0200 Subject: AT91: dm9000 initialization update Add information in dm9000 mac/phy chip initialization: - irq resource details - platform data details Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/board-sam9261ek.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index c4c8865d52d7..b4307aba523d 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -93,11 +93,12 @@ static struct resource dm9000_resource[] = { .start = AT91_PIN_PC11, .end = AT91_PIN_PC11, .flags = IORESOURCE_IRQ + | IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE, } }; static struct dm9000_plat_data dm9000_platdata = { - .flags = DM9000_PLATF_16BITONLY, + .flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM, }; static struct platform_device dm9000_device = { -- cgit v1.2.3-59-g8ed1b From 64d72bbeeb68b536a27319471f212d413f58bf6f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Sep 2010 11:26:42 +0200 Subject: AT91: at91sam9261ek board: remove warnings related to use of SPI or SD/MMC The sd/mmc data structure is not used if SPI is selected. The configuration of PIO on the board prevent from using both interfaces at the same time (board dependent). Remove the warnings at compilation time adding a preprocessor condition. Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/board-sam9261ek.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index b4307aba523d..19d4d2cbc9c4 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -168,17 +168,6 @@ static struct at91_udc_data __initdata ek_udc_data = { }; -/* - * MCI (SD/MMC) - */ -static struct at91_mmc_data __initdata ek_mmc_data = { - .wire4 = 1, -// .det_pin = ... not connected -// .wp_pin = ... not connected -// .vcc_pin = ... not connected -}; - - /* * NAND flash */ @@ -247,6 +236,10 @@ static void __init ek_add_device_nand(void) at91_add_device_nand(&ek_nand_data); } +/* + * SPI related devices + */ +#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) /* * ADS7846 Touchscreen @@ -357,6 +350,21 @@ static struct spi_board_info ek_spi_devices[] = { #endif }; +#else /* CONFIG_SPI_ATMEL_* */ + +/* + * MCI (SD/MMC) + * spi0 and mmc/sd share the same PIO pins: cannot be used at the same time + */ +static struct at91_mmc_data __initdata ek_mmc_data = { + .wire4 = 1, +// .det_pin = ... not connected +// .wp_pin = ... not connected +// .vcc_pin = ... not connected +}; + +#endif /* CONFIG_SPI_ATMEL_* */ + /* * LCD Controller -- cgit v1.2.3-59-g8ed1b From 4deb22a6001eb0d4058295c3645c36190a0ec603 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Sep 2010 14:36:06 +0200 Subject: AT91: at91sam9261ek: remove C99 comments but keep information Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/board-sam9261ek.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 19d4d2cbc9c4..65eb0943194f 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -351,16 +351,14 @@ static struct spi_board_info ek_spi_devices[] = { }; #else /* CONFIG_SPI_ATMEL_* */ +/* spi0 and mmc/sd share the same PIO pins: cannot be used at the same time */ /* * MCI (SD/MMC) - * spi0 and mmc/sd share the same PIO pins: cannot be used at the same time + * det_pin, wp_pin and vcc_pin are not connected */ static struct at91_mmc_data __initdata ek_mmc_data = { .wire4 = 1, -// .det_pin = ... not connected -// .wp_pin = ... not connected -// .vcc_pin = ... not connected }; #endif /* CONFIG_SPI_ATMEL_* */ -- cgit v1.2.3-59-g8ed1b From a122eb2fdfd78b58c6dd992d6f4b1aaef667eef9 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Mon, 6 Sep 2010 18:24:57 -0400 Subject: xfs: prevent reading uninitialized stack memory The XFS_IOC_FSGETXATTR ioctl allows unprivileged users to read 12 bytes of uninitialized stack memory, because the fsxattr struct declared on the stack in xfs_ioc_fsgetxattr() does not alter (or zero) the 12-byte fsx_pad member before copying it back to the user. This patch takes care of it. Signed-off-by: Dan Rosenberg Reviewed-by: Eric Sandeen Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_ioctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 4fec427b83ef..3b9e626f7cd1 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -785,6 +785,8 @@ xfs_ioc_fsgetxattr( { struct fsxattr fa; + memset(&fa, 0, sizeof(struct fsxattr)); + xfs_ilock(ip, XFS_ILOCK_SHARED); fa.fsx_xflags = xfs_ip2xflags(ip); fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; -- cgit v1.2.3-59-g8ed1b From dd8849c8f59ec1cee4809a0c5e603e045abe860e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 9 Sep 2010 11:58:02 -0700 Subject: drm/i915: don't enable self-refresh on Ironlake We don't know how to enable it safely, especially as outputs turn on and off. When disabling LP1 we also need to make sure LP2 and 3 are already disabled. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29173 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29082 Reported-by: Chris Lord Signed-off-by: Jesse Barnes Tested-by: Daniel Vetter Cc: stable@kernel.org Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++++ drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d094e9129223..4f5e15577e89 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2206,9 +2206,17 @@ #define WM1_LP_SR_EN (1<<31) #define WM1_LP_LATENCY_SHIFT 24 #define WM1_LP_LATENCY_MASK (0x7f<<24) +#define WM1_LP_FBC_LP1_MASK (0xf<<20) +#define WM1_LP_FBC_LP1_SHIFT 20 #define WM1_LP_SR_MASK (0x1ff<<8) #define WM1_LP_SR_SHIFT 8 #define WM1_LP_CURSOR_MASK (0x3f) +#define WM2_LP_ILK 0x4510c +#define WM2_LP_EN (1<<31) +#define WM3_LP_ILK 0x45110 +#define WM3_LP_EN (1<<31) +#define WM1S_LP_ILK 0x45120 +#define WM1S_LP_EN (1<<31) /* Memory latency timer register */ #define MLTR_ILK 0x11222 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7c9103030036..19daead5b525 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3382,8 +3382,7 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, reg_value = I915_READ(WM1_LP_ILK); reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK | WM1_LP_CURSOR_MASK); - reg_value |= WM1_LP_SR_EN | - (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) | + reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) | (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm; I915_WRITE(WM1_LP_ILK, reg_value); @@ -5669,6 +5668,9 @@ void intel_init_clock_gating(struct drm_device *dev) I915_WRITE(DISP_ARB_CTL, (I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS)); + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); } /* * Based on the document from hardware guys the following bits -- cgit v1.2.3-59-g8ed1b From 9d1ac65a9698513d00e5608d93fca0c53f536c14 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 10 Sep 2010 09:59:46 +0100 Subject: KEYS: Fix RCU no-lock warning in keyctl_session_to_parent() There's an protected access to the parent process's credentials in the middle of keyctl_session_to_parent(). This results in the following RCU warning: =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- security/keys/keyctl.c:1291 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 1 lock held by keyctl-session-/2137: #0: (tasklist_lock){.+.+..}, at: [] keyctl_session_to_parent+0x60/0x236 stack backtrace: Pid: 2137, comm: keyctl-session- Not tainted 2.6.36-rc2-cachefs+ #1 Call Trace: [] lockdep_rcu_dereference+0xaa/0xb3 [] keyctl_session_to_parent+0xed/0x236 [] sys_keyctl+0xb4/0xb6 [] system_call_fastpath+0x16/0x1b The code should take the RCU read lock to make sure the parents credentials don't go away, even though it's holding a spinlock and has IRQ disabled. Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- security/keys/keyctl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index b2b0998d6abd..3868c6700b58 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1272,6 +1272,7 @@ long keyctl_session_to_parent(void) keyring_r = NULL; me = current; + rcu_read_lock(); write_lock_irq(&tasklist_lock); parent = me->real_parent; @@ -1319,6 +1320,7 @@ long keyctl_session_to_parent(void) set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); write_unlock_irq(&tasklist_lock); + rcu_read_unlock(); if (oldcred) put_cred(oldcred); return 0; @@ -1327,6 +1329,7 @@ already_same: ret = 0; not_permitted: write_unlock_irq(&tasklist_lock); + rcu_read_unlock(); put_cred(cred); return ret; -- cgit v1.2.3-59-g8ed1b From 3d96406c7da1ed5811ea52a3b0905f4f0e295376 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 10 Sep 2010 09:59:51 +0100 Subject: KEYS: Fix bug in keyctl_session_to_parent() if parent has no session keyring Fix a bug in keyctl_session_to_parent() whereby it tries to check the ownership of the parent process's session keyring whether or not the parent has a session keyring [CVE-2010-2960]. This results in the following oops: BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 IP: [] keyctl_session_to_parent+0x251/0x443 ... Call Trace: [] ? keyctl_session_to_parent+0x67/0x443 [] ? __do_fault+0x24b/0x3d0 [] sys_keyctl+0xb4/0xb8 [] system_call_fastpath+0x16/0x1b if the parent process has no session keyring. If the system is using pam_keyinit then it mostly protected against this as all processes derived from a login will have inherited the session keyring created by pam_keyinit during the log in procedure. To test this, pam_keyinit calls need to be commented out in /etc/pam.d/. Reported-by: Tavis Ormandy Signed-off-by: David Howells Acked-by: Tavis Ormandy Signed-off-by: Linus Torvalds --- security/keys/keyctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 3868c6700b58..60924f6a52db 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1305,7 +1305,8 @@ long keyctl_session_to_parent(void) goto not_permitted; /* the keyrings must have the same UID */ - if (pcred->tgcred->session_keyring->uid != mycred->euid || + if ((pcred->tgcred->session_keyring && + pcred->tgcred->session_keyring->uid != mycred->euid) || mycred->tgcred->session_keyring->uid != mycred->euid) goto not_permitted; -- cgit v1.2.3-59-g8ed1b From 27c379f7f89a4d558c685b5d89b5ba2fe79ae701 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 10 Sep 2010 13:47:29 +0200 Subject: generic-ipi: Fix deadlock in __smp_call_function_single Just got my 6 way machine to a state where cpu 0 is in an endless loop within __smp_call_function_single. All other cpus are idle. The call trace on cpu 0 looks like this: __smp_call_function_single scheduler_tick update_process_times tick_sched_timer __run_hrtimer hrtimer_interrupt clock_comparator_work do_extint ext_int_handler ----> timer irq cpu_idle __smp_call_function_single() got called from nohz_balancer_kick() (inlined) with the remote cpu being 1, wait being 0 and the per cpu variable remote_sched_softirq_cb (call_single_data) of the current cpu (0). Then it loops forever when it tries to grab the lock of the call_single_data, since it is already locked and enqueued on cpu 0. My theory how this could have happened: for some reason the scheduler decided to call __smp_call_function_single() on it's own cpu, and sends an IPI to itself. The interrupt stays pending since IRQs are disabled. If then the hypervisor schedules the cpu away it might happen that upon rescheduling both the IPI and the timer IRQ are pending. If then interrupts are enabled again it depends which one gets scheduled first. If the timer interrupt gets delivered first we end up with the local deadlock as seen in the calltrace above. Let's make __smp_call_function_single() check if the target cpu is the current cpu and execute the function immediately just like smp_call_function_single does. That should prevent at least the scenario described here. It might also be that the scheduler is not supposed to call __smp_call_function_single with the remote cpu being the current cpu, but that is a different issue. Signed-off-by: Heiko Carstens Acked-by: Peter Zijlstra Acked-by: Jens Axboe Cc: Venkatesh Pallipadi Cc: Suresh Siddha LKML-Reference: <20100910114729.GB2827@osiris.boeblingen.de.ibm.com> Signed-off-by: Ingo Molnar --- kernel/smp.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/kernel/smp.c b/kernel/smp.c index 75c970c715d3..ed6aacfcb7ef 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -365,9 +365,10 @@ call: EXPORT_SYMBOL_GPL(smp_call_function_any); /** - * __smp_call_function_single(): Run a function on another CPU + * __smp_call_function_single(): Run a function on a specific CPU * @cpu: The CPU to run on. * @data: Pre-allocated and setup data structure + * @wait: If true, wait until function has completed on specified CPU. * * Like smp_call_function_single(), but allow caller to pass in a * pre-allocated data structure. Useful for embedding @data inside @@ -376,8 +377,10 @@ EXPORT_SYMBOL_GPL(smp_call_function_any); void __smp_call_function_single(int cpu, struct call_single_data *data, int wait) { - csd_lock(data); + unsigned int this_cpu; + unsigned long flags; + this_cpu = get_cpu(); /* * Can deadlock when called with interrupts disabled. * We allow cpu's that are not yet online though, as no one else can @@ -387,7 +390,15 @@ void __smp_call_function_single(int cpu, struct call_single_data *data, WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled() && !oops_in_progress); - generic_exec_single(cpu, data, wait); + if (cpu == this_cpu) { + local_irq_save(flags); + data->func(data->info); + local_irq_restore(flags); + } else { + csd_lock(data); + generic_exec_single(cpu, data, wait); + } + put_cpu(); } /** -- cgit v1.2.3-59-g8ed1b From 1b528181b2ffa14721fb28ad1bd539fe1732c583 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 7 Sep 2010 19:35:49 -0700 Subject: setup_arg_pages: diagnose excessive argument size The CONFIG_STACK_GROWSDOWN variant of setup_arg_pages() does not check the size of the argument/environment area on the stack. When it is unworkably large, shift_arg_pages() hits its BUG_ON. This is exploitable with a very large RLIMIT_STACK limit, to create a crash pretty easily. Check that the initial stack is not too large to make it possible to map in any executable. We're not checking that the actual executable (or intepreter, for binfmt_elf) will fit. So those mappings might clobber part of the initial stack mapping. But that is just userland lossage that userland made happen, not a kernel problem. Signed-off-by: Roland McGrath Reviewed-by: KOSAKI Motohiro Signed-off-by: Linus Torvalds --- fs/exec.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/exec.c b/fs/exec.c index 2d9455282744..1b63237fc6dc 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -594,6 +594,11 @@ int setup_arg_pages(struct linux_binprm *bprm, #else stack_top = arch_align_stack(stack_top); stack_top = PAGE_ALIGN(stack_top); + + if (unlikely(stack_top < mmap_min_addr) || + unlikely(vma->vm_end - vma->vm_start >= stack_top - mmap_min_addr)) + return -ENOMEM; + stack_shift = vma->vm_end - stack_top; bprm->p -= stack_shift; -- cgit v1.2.3-59-g8ed1b From 7993bc1f4663c0db67bb8f0d98e6678145b387cd Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 7 Sep 2010 19:36:28 -0700 Subject: execve: improve interactivity with large arguments This adds a preemption point during the copying of the argument and environment strings for execve, in copy_strings(). There is already a preemption point in the count() loop, so this doesn't add any new points in the abstract sense. When the total argument+environment strings are very large, the time spent copying them can be much more than a normal user time slice. So this change improves the interactivity of the rest of the system when one process is doing an execve with very large arguments. Signed-off-by: Roland McGrath Reviewed-by: KOSAKI Motohiro Signed-off-by: Linus Torvalds --- fs/exec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/exec.c b/fs/exec.c index 1b63237fc6dc..6f2d777431a8 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -419,6 +419,8 @@ static int copy_strings(int argc, const char __user *const __user *argv, while (len > 0) { int offset, bytes_to_copy; + cond_resched(); + offset = pos % PAGE_SIZE; if (offset == 0) offset = PAGE_SIZE; -- cgit v1.2.3-59-g8ed1b From 9aea5a65aa7a1af9a4236dfaeb0088f1624f9919 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 7 Sep 2010 19:37:06 -0700 Subject: execve: make responsive to SIGKILL with large arguments An execve with a very large total of argument/environment strings can take a really long time in the execve system call. It runs uninterruptibly to count and copy all the strings. This change makes it abort the exec quickly if sent a SIGKILL. Note that this is the conservative change, to interrupt only for SIGKILL, by using fatal_signal_pending(). It would be perfectly correct semantics to let any signal interrupt the string-copying in execve, i.e. use signal_pending() instead of fatal_signal_pending(). We'll save that change for later, since it could have user-visible consequences, such as having a timer set too quickly make it so that an execve can never complete, though it always happened to work before. Signed-off-by: Roland McGrath Reviewed-by: KOSAKI Motohiro Signed-off-by: Linus Torvalds --- fs/exec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/exec.c b/fs/exec.c index 6f2d777431a8..828dd2461d6b 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -376,6 +376,9 @@ static int count(const char __user * const __user * argv, int max) argv++; if (i++ >= max) return -E2BIG; + + if (fatal_signal_pending(current)) + return -ERESTARTNOHAND; cond_resched(); } } @@ -419,6 +422,10 @@ static int copy_strings(int argc, const char __user *const __user *argv, while (len > 0) { int offset, bytes_to_copy; + if (fatal_signal_pending(current)) { + ret = -ERESTARTNOHAND; + goto out; + } cond_resched(); offset = pos % PAGE_SIZE; -- cgit v1.2.3-59-g8ed1b From 36ac4b987bea9a95217e1af552252f275ca7fc44 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Fri, 10 Sep 2010 10:08:08 -0500 Subject: x86, UV: Fix initialization of max_pnode Fix calculation of "max_pnode" for systems where the the highest blade has neither cpus or memory. (And, yes, although rare this does occur). Signed-off-by: Jack Steiner LKML-Reference: <20100910150808.GA19802@sgi.com> Signed-off-by: Ingo Molnar --- arch/x86/kernel/apic/x2apic_uv_x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 7b598b84c902..f744f54cb248 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -698,9 +698,11 @@ void __init uv_system_init(void) for (j = 0; j < 64; j++) { if (!test_bit(j, &present)) continue; - uv_blade_info[blade].pnode = (i * 64 + j); + pnode = (i * 64 + j); + uv_blade_info[blade].pnode = pnode; uv_blade_info[blade].nr_possible_cpus = 0; uv_blade_info[blade].nr_online_cpus = 0; + max_pnode = max(pnode, max_pnode); blade++; } } @@ -738,7 +740,6 @@ void __init uv_system_init(void) uv_cpu_hub_info(cpu)->scir.offset = uv_scir_offset(apicid); uv_node_to_blade[nid] = blade; uv_cpu_to_blade[cpu] = blade; - max_pnode = max(pnode, max_pnode); } /* Add blade/pnode info for nodes without cpus */ @@ -750,7 +751,6 @@ void __init uv_system_init(void) pnode = (paddr >> m_val) & pnode_mask; blade = boot_pnode_to_blade(pnode); uv_node_to_blade[nid] = blade; - max_pnode = max(pnode, max_pnode); } map_gru_high(max_pnode); -- cgit v1.2.3-59-g8ed1b From 51749e47e191db8e588ad5cebea731caf7b705d7 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Wed, 8 Sep 2010 09:00:22 +0000 Subject: xfs: log IO completion workqueue is a high priority queue The workqueue implementation in 2.6.36-rcX has changed, resulting in the workqueues no longer having dedicated threads for work processing. This has caused severe livelocks under heavy parallel create workloads because the log IO completions have been getting held up behind metadata IO completions. Hence log commits would stall, memory allocation would stall because pages could not be cleaned, and lock contention on the AIL during inode IO completion processing was being seen to slow everything down even further. By making the log Io completion workqueue a high priority workqueue, they are queued ahead of all data/metadata IO completions and processed before the data/metadata completions. Hence the log never gets stalled, and operations needed to clean memory can continue as quickly as possible. This avoids the livelock conditions and allos the system to keep running under heavy load as per normal. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder --- fs/xfs/linux-2.6/xfs_buf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index d72cf2bb054a..286e36e21dae 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1932,7 +1932,8 @@ xfs_buf_init(void) if (!xfs_buf_zone) goto out; - xfslogd_workqueue = create_workqueue("xfslogd"); + xfslogd_workqueue = alloc_workqueue("xfslogd", + WQ_RESCUER | WQ_HIGHPRI, 1); if (!xfslogd_workqueue) goto out_free_buf_zone; -- cgit v1.2.3-59-g8ed1b From 5e64b0d9e86ffff8b299556341d85319117539e9 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Tue, 7 Sep 2010 13:30:05 +0800 Subject: ocfs2/lockdep: Move ip_xattr_sem out of ocfs2_xattr_get_nolock. As the name shows, we shouldn't have any lock in ocfs2_xattr_get_nolock. so lift ip_xattr_sem to the caller. This should be safe for us since the only 2 callers are: 1. ocfs2_xattr_get which will lock the resources. 2. ocfs2_mknod which don't need this locking. And this also resolves the following lockdep warning. ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.35+ #5 ------------------------------------------------------- reflink/30027 is trying to acquire lock: (&oi->ip_alloc_sem){+.+.+.}, at: [] ocfs2_reflink_ioctl+0x69a/0x1226 [ocfs2] but task is already holding lock: (&oi->ip_xattr_sem){++++..}, at: [] ocfs2_reflink_ioctl+0x68b/0x1226 [ocfs2] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (&oi->ip_xattr_sem){++++..}: [] __lock_acquire+0x79a/0x7f1 [] lock_acquire+0xc6/0xed [] down_read+0x34/0x47 [] ocfs2_xattr_get_nolock+0xa0/0x4e6 [ocfs2] [] ocfs2_get_acl_nolock+0x5c/0x132 [ocfs2] [] ocfs2_init_acl+0x60/0x243 [ocfs2] [] ocfs2_mknod+0xae8/0xfea [ocfs2] [] ocfs2_create+0x9d/0x105 [ocfs2] [] vfs_create+0x9b/0xf4 [] do_last+0x2fd/0x5be [] do_filp_open+0x1fb/0x572 [] do_sys_open+0x5a/0xe7 [] sys_open+0x1b/0x1d [] system_call_fastpath+0x16/0x1b -> #2 (jbd2_handle){+.+...}: [] __lock_acquire+0x79a/0x7f1 [] lock_acquire+0xc6/0xed [] start_this_handle+0x4a3/0x4bc [jbd2] [] jbd2__journal_start+0xba/0xee [jbd2] [] jbd2_journal_start+0xe/0x10 [jbd2] [] ocfs2_start_trans+0xb7/0x19b [ocfs2] [] ocfs2_mknod+0x73e/0xfea [ocfs2] [] ocfs2_create+0x9d/0x105 [ocfs2] [] vfs_create+0x9b/0xf4 [] do_last+0x2fd/0x5be [] do_filp_open+0x1fb/0x572 [] do_sys_open+0x5a/0xe7 [] sys_open+0x1b/0x1d [] system_call_fastpath+0x16/0x1b -> #1 (&journal->j_trans_barrier){.+.+..}: [] __lock_acquire+0x79a/0x7f1 [] lock_release_non_nested+0x1e5/0x24b [] lock_release+0x158/0x17a [] __mutex_unlock_slowpath+0xbf/0x11b [] mutex_unlock+0x9/0xb [] ocfs2_free_ac_resource+0x31/0x67 [ocfs2] [] ocfs2_free_alloc_context+0x11/0x1d [ocfs2] [] ocfs2_write_begin_nolock+0x141e/0x159b [ocfs2] [] ocfs2_write_begin+0x11e/0x1e7 [ocfs2] [] generic_file_buffered_write+0x10c/0x210 [] ocfs2_file_aio_write+0x4cc/0x6d3 [ocfs2] [] do_sync_write+0xc2/0x106 [] vfs_write+0xae/0x131 [] sys_write+0x47/0x6f [] system_call_fastpath+0x16/0x1b -> #0 (&oi->ip_alloc_sem){+.+.+.}: [] validate_chain+0x727/0xd68 [] __lock_acquire+0x79a/0x7f1 [] lock_acquire+0xc6/0xed [] down_write+0x31/0x52 [] ocfs2_reflink_ioctl+0x69a/0x1226 [ocfs2] [] ocfs2_ioctl+0x61a/0x656 [ocfs2] [] vfs_ioctl+0x2a/0x9d [] do_vfs_ioctl+0x45d/0x4ae [] sys_ioctl+0x57/0x7a [] system_call_fastpath+0x16/0x1b Signed-off-by: Tao Ma Signed-off-by: Joel Becker --- fs/ocfs2/xattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index d03469f61801..06fa5e77c40e 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -1286,13 +1286,11 @@ int ocfs2_xattr_get_nolock(struct inode *inode, xis.inode_bh = xbs.inode_bh = di_bh; di = (struct ocfs2_dinode *)di_bh->b_data; - down_read(&oi->ip_xattr_sem); ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer, buffer_size, &xis); if (ret == -ENODATA && di->i_xattr_loc) ret = ocfs2_xattr_block_get(inode, name_index, name, buffer, buffer_size, &xbs); - up_read(&oi->ip_xattr_sem); return ret; } @@ -1316,8 +1314,10 @@ static int ocfs2_xattr_get(struct inode *inode, mlog_errno(ret); return ret; } + down_read(&OCFS2_I(inode)->ip_xattr_sem); ret = ocfs2_xattr_get_nolock(inode, di_bh, name_index, name, buffer, buffer_size); + up_read(&OCFS2_I(inode)->ip_xattr_sem); ocfs2_inode_unlock(inode, 0); -- cgit v1.2.3-59-g8ed1b From 07eaac9438b13ec0b863111698b91ccec8f3b8d4 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Tue, 7 Sep 2010 13:30:06 +0800 Subject: ocfs2: Fix lockdep warning in reflink. This patch change mutex_lock to a new subclass and add a new inode lock subclass for the target inode which caused this lockdep warning. ============================================= [ INFO: possible recursive locking detected ] 2.6.35+ #5 --------------------------------------------- reflink/11086 is trying to acquire lock: (Meta){+++++.}, at: [] ocfs2_reflink_ioctl+0x898/0x1229 [ocfs2] but task is already holding lock: (Meta){+++++.}, at: [] ocfs2_reflink_ioctl+0x5d3/0x1229 [ocfs2] other info that might help us debug this: 6 locks held by reflink/11086: #0: (&sb->s_type->i_mutex_key#15/1){+.+.+.}, at: [] lookup_create+0x26/0x97 #1: (&sb->s_type->i_mutex_key#15){+.+.+.}, at: [] ocfs2_reflink_ioctl+0x4d3/0x1229 [ocfs2] #2: (Meta){+++++.}, at: [] ocfs2_reflink_ioctl+0x5d3/0x1229 [ocfs2] #3: (&oi->ip_xattr_sem){+.+.+.}, at: [] ocfs2_reflink_ioctl+0x68b/0x1229 [ocfs2] #4: (&oi->ip_alloc_sem){+.+.+.}, at: [] ocfs2_reflink_ioctl+0x69a/0x1229 [ocfs2] #5: (&sb->s_type->i_mutex_key#15/2){+.+...}, at: [] ocfs2_reflink_ioctl+0x882/0x1229 [ocfs2] stack backtrace: Pid: 11086, comm: reflink Not tainted 2.6.35+ #5 Call Trace: [] validate_chain+0x56e/0xd68 [] ? mark_held_locks+0x49/0x69 [] __lock_acquire+0x79a/0x7f1 [] lock_acquire+0xc6/0xed [] ? ocfs2_reflink_ioctl+0x898/0x1229 [ocfs2] [] __ocfs2_cluster_lock+0x975/0xa0d [ocfs2] [] ? ocfs2_reflink_ioctl+0x898/0x1229 [ocfs2] [] ? ocfs2_wait_for_recovery+0x15/0x8a [ocfs2] [] ocfs2_inode_lock_full_nested+0x1ac/0xdc5 [ocfs2] [] ? ocfs2_reflink_ioctl+0x898/0x1229 [ocfs2] [] ? trace_hardirqs_on_caller+0x10b/0x12f [] ? debug_mutex_free_waiter+0x4f/0x53 [] ocfs2_reflink_ioctl+0x898/0x1229 [ocfs2] [] ? ocfs2_file_lock_res_init+0x66/0x78 [ocfs2] [] ? might_fault+0x40/0x8d [] ocfs2_ioctl+0x61a/0x656 [ocfs2] [] ? mntput_no_expire+0x1d/0xb0 [] ? path_put+0x2c/0x31 [] vfs_ioctl+0x2a/0x9d [] do_vfs_ioctl+0x45d/0x4ae [] ? _raw_spin_unlock+0x26/0x2a [] ? sysret_check+0x27/0x62 [] sys_ioctl+0x57/0x7a [] system_call_fastpath+0x16/0x1b Signed-off-by: Tao Ma Signed-off-by: Joel Becker --- fs/ocfs2/dlmglue.h | 1 + fs/ocfs2/refcounttree.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index d1ce48e1b3d6..1d596d8c4a4a 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h @@ -84,6 +84,7 @@ enum { OI_LS_PARENT, OI_LS_RENAME1, OI_LS_RENAME2, + OI_LS_REFLINK_TARGET, }; int ocfs2_dlm_init(struct ocfs2_super *osb); diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 0afeda83120f..efdd75607406 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4201,8 +4201,9 @@ static int __ocfs2_reflink(struct dentry *old_dentry, goto out; } - mutex_lock(&new_inode->i_mutex); - ret = ocfs2_inode_lock(new_inode, &new_bh, 1); + mutex_lock_nested(&new_inode->i_mutex, I_MUTEX_CHILD); + ret = ocfs2_inode_lock_nested(new_inode, &new_bh, 1, + OI_LS_REFLINK_TARGET); if (ret) { mlog_errno(ret); goto out_unlock; -- cgit v1.2.3-59-g8ed1b From 0f4da216b8c3c35c90ecd18e1899c6f125957c2b Mon Sep 17 00:00:00 2001 From: Tristan Ye Date: Wed, 8 Sep 2010 17:12:38 +0800 Subject: Ocfs2: Re-access the journal after ocfs2_insert_extent() in dxdir codes. In ocfs2_dx_dir_rebalance(), we need to rejournal_acess the blocks after calling ocfs2_insert_extent() since growing an extent tree may trigger ocfs2_extend_trans(), which makes previous journal_access meaningless. Signed-off-by: Tristan Ye Signed-off-by: Joel Becker --- fs/ocfs2/dir.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index f04ebcfffc4a..c49f6de0e7ab 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -3931,6 +3931,15 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir, goto out_commit; } + cpos = split_hash; + ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle, + data_ac, meta_ac, new_dx_leaves, + num_dx_leaves); + if (ret) { + mlog_errno(ret); + goto out_commit; + } + for (i = 0; i < num_dx_leaves; i++) { ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), orig_dx_leaves[i], @@ -3939,15 +3948,14 @@ static int ocfs2_dx_dir_rebalance(struct ocfs2_super *osb, struct inode *dir, mlog_errno(ret); goto out_commit; } - } - cpos = split_hash; - ret = ocfs2_dx_dir_new_cluster(dir, &et, cpos, handle, - data_ac, meta_ac, new_dx_leaves, - num_dx_leaves); - if (ret) { - mlog_errno(ret); - goto out_commit; + ret = ocfs2_journal_access_dl(handle, INODE_CACHE(dir), + new_dx_leaves[i], + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + mlog_errno(ret); + goto out_commit; + } } ocfs2_dx_dir_transfer_leaf(dir, split_hash, handle, tmp_dx_leaf, -- cgit v1.2.3-59-g8ed1b From 228ac6357718df2d5c8d70210fa51b2225aab5ee Mon Sep 17 00:00:00 2001 From: Tristan Ye Date: Fri, 10 Sep 2010 10:16:33 +0800 Subject: Ocfs2: Handle empty list in lockres_seq_start() for dlmdebug.c This patch tries to handle the case in which list 'dlm->tracking_list' is empty, to avoid accessing an invalid pointer. It fixes the following oops: http://oss.oracle.com/bugzilla/show_bug.cgi?id=1287 Signed-off-by: Tristan Ye Signed-off-by: Joel Becker --- fs/ocfs2/dlm/dlmdebug.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c index 5efdd37dfe48..901ca52bf86b 100644 --- a/fs/ocfs2/dlm/dlmdebug.c +++ b/fs/ocfs2/dlm/dlmdebug.c @@ -636,8 +636,14 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos) spin_lock(&dlm->track_lock); if (oldres) track_list = &oldres->tracking; - else + else { track_list = &dlm->tracking_list; + if (list_empty(track_list)) { + dl = NULL; + spin_unlock(&dlm->track_lock); + goto bail; + } + } list_for_each_entry(res, track_list, tracking) { if (&res->tracking == &dlm->tracking_list) @@ -660,6 +666,7 @@ static void *lockres_seq_start(struct seq_file *m, loff_t *pos) } else dl = NULL; +bail: /* passed to seq_show */ return dl; } -- cgit v1.2.3-59-g8ed1b From 0109c2c48d062a04685638926a35ed20153fedc8 Mon Sep 17 00:00:00 2001 From: mark gross Date: Thu, 9 Sep 2010 23:20:09 +0200 Subject: PM QoS: Correct pr_debug() misuse and improve parameter checks Correct some pr_debug() misuse and add a stronger parameter check to pm_qos_write() for the ASCII hex value case. Thanks to Dan Carpenter for pointing out the problem! Signed-off-by: mark gross Signed-off-by: Rafael J. Wysocki --- kernel/pm_qos_params.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c index b7e4c362361b..645e541a45f6 100644 --- a/kernel/pm_qos_params.c +++ b/kernel/pm_qos_params.c @@ -389,10 +389,12 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, } else if (count == 11) { /* len('0x12345678/0') */ if (copy_from_user(ascii_value, buf, 11)) return -EFAULT; + if (strlen(ascii_value) != 10) + return -EINVAL; x = sscanf(ascii_value, "%x", &value); if (x != 1) return -EINVAL; - pr_debug(KERN_ERR "%s, %d, 0x%x\n", ascii_value, x, value); + pr_debug("%s, %d, 0x%x\n", ascii_value, x, value); } else return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 5ee5e97ee9bca919af11c562beeaf61741ad33f1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 10 Sep 2010 22:32:53 +0200 Subject: x86, tsc: Fix a preemption leak in restore_sched_clock_state() A real life genuine preemption leak.. Reported-and-tested-by: Jeff Chua Signed-off-by: Peter Zijlstra Acked-by: Suresh Siddha Signed-off-by: Linus Torvalds --- arch/x86/kernel/tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index d632934cb638..26a863a9c2a8 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -655,7 +655,7 @@ void restore_sched_clock_state(void) local_irq_save(flags); - get_cpu_var(cyc2ns_offset) = 0; + __get_cpu_var(cyc2ns_offset) = 0; offset = cyc2ns_suspend - sched_clock(); for_each_possible_cpu(cpu) -- cgit v1.2.3-59-g8ed1b From 55496c896b8a695140045099d4e0175cf09d4eae Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 10 Sep 2010 22:32:53 +0200 Subject: x86, tsc: Fix a preemption leak in restore_sched_clock_state() Doh, a real life genuine preemption leak.. This caused a suspend failure. Reported-bisected-and-tested-by-the-invaluable: Jeff Chua Acked-by: Suresh Siddha Signed-off-by: Peter Zijlstra Cc: Rafael J. Wysocki Cc: Nico Schottelius Cc: Jesse Barnes Cc: Linus Torvalds Cc: Florian Pritz Cc: Suresh Siddha Cc: Len Brown Cc: # Greg, please apply after: cd7240c ("x86, tsc, sched: Recompute cyc2ns_offset's during resume from") sleep states LKML-Reference: <1284150773.402.122.camel@laptop> Signed-off-by: Ingo Molnar --- arch/x86/kernel/tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index d632934cb638..26a863a9c2a8 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -655,7 +655,7 @@ void restore_sched_clock_state(void) local_irq_save(flags); - get_cpu_var(cyc2ns_offset) = 0; + __get_cpu_var(cyc2ns_offset) = 0; offset = cyc2ns_suspend - sched_clock(); for_each_possible_cpu(cpu) -- cgit v1.2.3-59-g8ed1b From ca04d9c3ec721e474f00992efc1b1afb625507f5 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 26 Aug 2010 16:12:01 -0700 Subject: ceph: fix null pointer deref on anon root dentry release When we release a root dentry, particularly after a splice, the parent (actually our) inode was evaluating to NULL and was getting dereferenced by ceph_snap(). This is reproduced by something as simple as mount -t ceph monhost:/a/b mnt mount -t ceph monhost:/a mnt2 ls mnt2 A splice_dentry() would kill the old 'b' inode's root dentry, and we'd crash while releasing it. Fix by checking for both the ROOT and NULL cases explicitly. We only need to invalidate the parent dir when we have a correct parent to invalidate. Signed-off-by: Sage Weil --- fs/ceph/dir.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 6e4f43ff23ec..a1986eb52045 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1021,11 +1021,15 @@ out_touch: static void ceph_dentry_release(struct dentry *dentry) { struct ceph_dentry_info *di = ceph_dentry(dentry); - struct inode *parent_inode = dentry->d_parent->d_inode; - u64 snapid = ceph_snap(parent_inode); + struct inode *parent_inode = NULL; + u64 snapid = CEPH_NOSNAP; + if (!IS_ROOT(dentry)) { + parent_inode = dentry->d_parent->d_inode; + if (parent_inode) + snapid = ceph_snap(parent_inode); + } dout("dentry_release %p parent %p\n", dentry, parent_inode); - if (parent_inode && snapid != CEPH_SNAPDIR) { struct ceph_inode_info *ci = ceph_inode(parent_inode); -- cgit v1.2.3-59-g8ed1b From 3d4401d9d0aef5c40706350685ddea3df6708496 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 3 Sep 2010 12:57:11 -0700 Subject: ceph: fix pagelist kunmap tail A wrong parameter was passed to the kunmap. Signed-off-by: Yehuda Sadeh Signed-off-by: Sage Weil --- fs/ceph/pagelist.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/ceph/pagelist.c b/fs/ceph/pagelist.c index b6859f47d364..46a368b6dce5 100644 --- a/fs/ceph/pagelist.c +++ b/fs/ceph/pagelist.c @@ -5,10 +5,18 @@ #include "pagelist.h" +static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl) +{ + struct page *page = list_entry(pl->head.prev, struct page, + lru); + kunmap(page); +} + int ceph_pagelist_release(struct ceph_pagelist *pl) { if (pl->mapped_tail) - kunmap(pl->mapped_tail); + ceph_pagelist_unmap_tail(pl); + while (!list_empty(&pl->head)) { struct page *page = list_first_entry(&pl->head, struct page, lru); @@ -26,7 +34,7 @@ static int ceph_pagelist_addpage(struct ceph_pagelist *pl) pl->room += PAGE_SIZE; list_add_tail(&page->lru, &pl->head); if (pl->mapped_tail) - kunmap(pl->mapped_tail); + ceph_pagelist_unmap_tail(pl); pl->mapped_tail = kmap(page); return 0; } -- cgit v1.2.3-59-g8ed1b From 3612abbd5df6baa9ca3e0777c6c8646e202d3f66 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 7 Sep 2010 15:59:27 -0700 Subject: ceph: fix reconnect encoding for old servers Fix the reconnect encoding to encode the cap record when the MDS does not have the FLOCK capability (i.e., pre v0.22). Signed-off-by: Sage Weil --- fs/ceph/mds_client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f091b1351786..fad95f8f2608 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2374,6 +2374,8 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, num_fcntl_locks, num_flock_locks); unlock_kernel(); + } else { + err = ceph_pagelist_append(pagelist, &rec, reclen); } out_free: -- cgit v1.2.3-59-g8ed1b From a77d9f7dce7600058d56f0670ed29d77abffcde2 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Sat, 11 Sep 2010 10:55:25 -0700 Subject: ceph: fix file offset wrapping at 4GB on 32-bit archs Cast the value before shifting so that we don't run out of bits with a 32-bit unsigned long. This fixes wrapping of high file offsets into the low 4GB of a file on disk, and the subsequent data corruption for large files. Signed-off-by: Sage Weil --- fs/ceph/addr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 4cfce1ee31fa..50461b8c23a4 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -766,7 +766,8 @@ get_more_pages: /* ok */ if (locked_pages == 0) { /* prepare async write request */ - offset = page->index << PAGE_CACHE_SHIFT; + offset = (unsigned long long)page->index + << PAGE_CACHE_SHIFT; len = wsize; req = ceph_osdc_new_request(&client->osdc, &ci->i_layout, -- cgit v1.2.3-59-g8ed1b From 6715045ddc7472a22be5e49d4047d2d89b391f45 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 11 Sep 2010 20:58:27 +0200 Subject: PM / Hibernate: Avoid hitting OOM during preallocation of memory There is a problem in hibernate_preallocate_memory() that it calls preallocate_image_memory() with an argument that may be greater than the total number of available non-highmem memory pages. If that's the case, the OOM condition is guaranteed to trigger, which in turn can cause significant slowdown to occur during hibernation. To avoid that, make preallocate_image_memory() adjust its argument before calling preallocate_image_pages(), so that the total number of saveable non-highem pages left is not less than the minimum size of a hibernation image. Change hibernate_preallocate_memory() to try to allocate from highmem if the number of pages allocated by preallocate_image_memory() is too low. Modify free_unnecessary_pages() to take all possible memory allocation patterns into account. Reported-by: KOSAKI Motohiro Signed-off-by: Rafael J. Wysocki Tested-by: M. Vefa Bicakci --- kernel/power/snapshot.c | 85 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 20 deletions(-) diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 5e7edfb05e66..5209b39e6982 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1122,9 +1122,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask) return nr_alloc; } -static unsigned long preallocate_image_memory(unsigned long nr_pages) +static unsigned long preallocate_image_memory(unsigned long nr_pages, + unsigned long avail_normal) { - return preallocate_image_pages(nr_pages, GFP_IMAGE); + unsigned long alloc; + + if (avail_normal <= alloc_normal) + return 0; + + alloc = avail_normal - alloc_normal; + if (nr_pages < alloc) + alloc = nr_pages; + + return preallocate_image_pages(alloc, GFP_IMAGE); } #ifdef CONFIG_HIGHMEM @@ -1170,15 +1180,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages, */ static void free_unnecessary_pages(void) { - unsigned long save_highmem, to_free_normal, to_free_highmem; + unsigned long save, to_free_normal, to_free_highmem; - to_free_normal = alloc_normal - count_data_pages(); - save_highmem = count_highmem_pages(); - if (alloc_highmem > save_highmem) { - to_free_highmem = alloc_highmem - save_highmem; + save = count_data_pages(); + if (alloc_normal >= save) { + to_free_normal = alloc_normal - save; + save = 0; + } else { + to_free_normal = 0; + save -= alloc_normal; + } + save += count_highmem_pages(); + if (alloc_highmem >= save) { + to_free_highmem = alloc_highmem - save; } else { to_free_highmem = 0; - to_free_normal -= save_highmem - alloc_highmem; + to_free_normal -= save - alloc_highmem; } memory_bm_position_reset(©_bm); @@ -1259,7 +1276,7 @@ int hibernate_preallocate_memory(void) { struct zone *zone; unsigned long saveable, size, max_size, count, highmem, pages = 0; - unsigned long alloc, save_highmem, pages_highmem; + unsigned long alloc, save_highmem, pages_highmem, avail_normal; struct timeval start, stop; int error; @@ -1296,6 +1313,7 @@ int hibernate_preallocate_memory(void) else count += zone_page_state(zone, NR_FREE_PAGES); } + avail_normal = count; count += highmem; count -= totalreserve_pages; @@ -1310,12 +1328,21 @@ int hibernate_preallocate_memory(void) */ if (size >= saveable) { pages = preallocate_image_highmem(save_highmem); - pages += preallocate_image_memory(saveable - pages); + pages += preallocate_image_memory(saveable - pages, avail_normal); goto out; } /* Estimate the minimum size of the image. */ pages = minimum_image_size(saveable); + /* + * To avoid excessive pressure on the normal zone, leave room in it to + * accommodate an image of the minimum size (unless it's already too + * small, in which case don't preallocate pages from it at all). + */ + if (avail_normal > pages) + avail_normal -= pages; + else + avail_normal = 0; if (size < pages) size = min_t(unsigned long, pages, max_size); @@ -1336,16 +1363,34 @@ int hibernate_preallocate_memory(void) */ pages_highmem = preallocate_image_highmem(highmem / 2); alloc = (count - max_size) - pages_highmem; - pages = preallocate_image_memory(alloc); - if (pages < alloc) - goto err_out; - size = max_size - size; - alloc = size; - size = preallocate_highmem_fraction(size, highmem, count); - pages_highmem += size; - alloc -= size; - pages += preallocate_image_memory(alloc); - pages += pages_highmem; + pages = preallocate_image_memory(alloc, avail_normal); + if (pages < alloc) { + /* We have exhausted non-highmem pages, try highmem. */ + alloc -= pages; + pages += pages_highmem; + pages_highmem = preallocate_image_highmem(alloc); + if (pages_highmem < alloc) + goto err_out; + pages += pages_highmem; + /* + * size is the desired number of saveable pages to leave in + * memory, so try to preallocate (all memory - size) pages. + */ + alloc = (count - pages) - size; + pages += preallocate_image_highmem(alloc); + } else { + /* + * There are approximately max_size saveable pages at this point + * and we want to reduce this number down to size. + */ + alloc = max_size - size; + size = preallocate_highmem_fraction(alloc, highmem, count); + pages_highmem += size; + alloc -= size; + size = preallocate_image_memory(alloc, avail_normal); + pages_highmem += preallocate_image_highmem(alloc - size); + pages += pages_highmem + size; + } /* * We only need as many page frames for the image as there are saveable -- cgit v1.2.3-59-g8ed1b From 1f3a66889c4c80c821f3eadf899c140e91452f8e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 11 Sep 2010 15:55:12 -0700 Subject: kernel-doc: ignore case when stripping attributes There are valid attributes that could have upper case letters, but we still want to remove, like for example __attribute__((aligned(NETDEV_ALIGN))) as encountered in the wireless code. Signed-off-by: Johannes Berg Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 102e1235fd5c..a68240c188f3 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1679,7 +1679,7 @@ sub check_sections($$$$$$) { foreach $px (0 .. $#prms) { $prm_clean = $prms[$px]; $prm_clean =~ s/\[.*\]//; - $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//; + $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i; # ignore array size in a parameter string; # however, the original param string may contain # spaces, e.g.: addr[6 + 2] -- cgit v1.2.3-59-g8ed1b From eda603f6cdba4b14dbf80531fab2fe545232e7a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 11 Sep 2010 15:55:22 -0700 Subject: docbook: warn on unused doc entries When you don't use !E or !I but only !F, then it's very easy to miss including some functions, structs etc. in documentation. To help finding which ones were missed, allow printing out the unused ones as warnings. For example, using this on mac80211 yields a lot of warnings like this: Warning: didn't use docs for DOC: mac80211 workqueue Warning: didn't use docs for ieee80211_max_queues Warning: didn't use docs for ieee80211_bss_change Warning: didn't use docs for ieee80211_bss_conf when generating the documentation for it. Signed-off-by: Johannes Berg Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/kernel-doc-nano-HOWTO.txt | 5 ++ scripts/basic/docproc.c | 129 +++++++++++++++++++++++++++++++- scripts/kernel-doc | 52 ++++++++++++- 3 files changed, 183 insertions(+), 3 deletions(-) diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt index 27a52b35d55b..3d8a97747f77 100644 --- a/Documentation/kernel-doc-nano-HOWTO.txt +++ b/Documentation/kernel-doc-nano-HOWTO.txt @@ -345,5 +345,10 @@ documentation, in , for the functions listed. section titled
from . Spaces are allowed in
; do not quote the
. +!C is replaced by nothing, but makes the tools check that +all DOC: sections and documented functions, symbols, etc. are used. +This makes sense to use when you use !F/!P only and want to verify +that all documentation is included. + Tim. */ diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index 79ab973fb43a..fc3b18d844af 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -34,12 +34,14 @@ * */ +#define _GNU_SOURCE #include #include #include #include #include #include +#include #include #include @@ -54,6 +56,7 @@ typedef void FILEONLY(char * file); FILEONLY *internalfunctions; FILEONLY *externalfunctions; FILEONLY *symbolsonly; +FILEONLY *findall; typedef void FILELINE(char * file, char * line); FILELINE * singlefunctions; @@ -65,12 +68,30 @@ FILELINE * docsection; #define KERNELDOCPATH "scripts/" #define KERNELDOC "kernel-doc" #define DOCBOOK "-docbook" +#define LIST "-list" #define FUNCTION "-function" #define NOFUNCTION "-nofunction" #define NODOCSECTIONS "-no-doc-sections" static char *srctree, *kernsrctree; +static char **all_list = NULL; +static int all_list_len = 0; + +static void consume_symbol(const char *sym) +{ + int i; + + for (i = 0; i < all_list_len; i++) { + if (!all_list[i]) + continue; + if (strcmp(sym, all_list[i])) + continue; + all_list[i] = NULL; + break; + } +} + static void usage (void) { fprintf(stderr, "Usage: docproc {doc|depend} file\n"); @@ -248,6 +269,7 @@ static void docfunctions(char * filename, char * type) struct symfile * sym = &symfilelist[i]; for (j=0; j < sym->symbolcnt; j++) { vec[idx++] = type; + consume_symbol(sym->symbollist[j].name); vec[idx++] = sym->symbollist[j].name; } } @@ -287,6 +309,11 @@ static void singfunc(char * filename, char * line) vec[idx++] = &line[i]; } } + for (i = 0; i < idx; i++) { + if (strcmp(vec[i], FUNCTION)) + continue; + consume_symbol(vec[i + 1]); + } vec[idx++] = filename; vec[idx] = NULL; exec_kernel_doc(vec); @@ -306,6 +333,10 @@ static void docsect(char *filename, char *line) if (*s == '\n') *s = '\0'; + asprintf(&s, "DOC: %s", line); + consume_symbol(s); + free(s); + vec[0] = KERNELDOC; vec[1] = DOCBOOK; vec[2] = FUNCTION; @@ -315,6 +346,84 @@ static void docsect(char *filename, char *line) exec_kernel_doc(vec); } +static void find_all_symbols(char *filename) +{ + char *vec[4]; /* kerneldoc -list file NULL */ + pid_t pid; + int ret, i, count, start; + char real_filename[PATH_MAX + 1]; + int pipefd[2]; + char *data, *str; + size_t data_len = 0; + + vec[0] = KERNELDOC; + vec[1] = LIST; + vec[2] = filename; + vec[3] = NULL; + + if (pipe(pipefd)) { + perror("pipe"); + exit(1); + } + + switch (pid=fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + close(pipefd[0]); + dup2(pipefd[1], 1); + memset(real_filename, 0, sizeof(real_filename)); + strncat(real_filename, kernsrctree, PATH_MAX); + strncat(real_filename, "/" KERNELDOCPATH KERNELDOC, + PATH_MAX - strlen(real_filename)); + execvp(real_filename, vec); + fprintf(stderr, "exec "); + perror(real_filename); + exit(1); + default: + close(pipefd[1]); + data = malloc(4096); + do { + while ((ret = read(pipefd[0], + data + data_len, + 4096)) > 0) { + data_len += ret; + data = realloc(data, data_len + 4096); + } + } while (ret == -EAGAIN); + if (ret != 0) { + perror("read"); + exit(1); + } + waitpid(pid, &ret ,0); + } + if (WIFEXITED(ret)) + exitstatus |= WEXITSTATUS(ret); + else + exitstatus = 0xff; + + count = 0; + /* poor man's strtok, but with counting */ + for (i = 0; i < data_len; i++) { + if (data[i] == '\n') { + count++; + data[i] = '\0'; + } + } + start = all_list_len; + all_list_len += count; + all_list = realloc(all_list, sizeof(char *) * all_list_len); + str = data; + for (i = 0; i < data_len && start != all_list_len; i++) { + if (data[i] == '\0') { + all_list[start] = str; + str = data + i + 1; + start++; + } + } +} + /* * Parse file, calling action specific functions for: * 1) Lines containing !E @@ -322,7 +431,8 @@ static void docsect(char *filename, char *line) * 3) Lines containing !D * 4) Lines containing !F * 5) Lines containing !P - * 6) Default lines - lines not matching the above + * 6) Lines containing !C + * 7) Default lines - lines not matching the above */ static void parse_file(FILE *infile) { @@ -365,6 +475,12 @@ static void parse_file(FILE *infile) s++; docsection(line + 2, s); break; + case 'C': + while (*s && !isspace(*s)) s++; + *s = '\0'; + if (findall) + findall(line+2); + break; default: defaultline(line); } @@ -380,6 +496,7 @@ static void parse_file(FILE *infile) int main(int argc, char *argv[]) { FILE * infile; + int i; srctree = getenv("SRCTREE"); if (!srctree) @@ -415,6 +532,7 @@ int main(int argc, char *argv[]) symbolsonly = find_export_symbols; singlefunctions = noaction2; docsection = noaction2; + findall = find_all_symbols; parse_file(infile); /* Rewind to start from beginning of file again */ @@ -425,8 +543,16 @@ int main(int argc, char *argv[]) symbolsonly = printline; singlefunctions = singfunc; docsection = docsect; + findall = NULL; parse_file(infile); + + for (i = 0; i < all_list_len; i++) { + if (!all_list[i]) + continue; + fprintf(stderr, "Warning: didn't use docs for %s\n", + all_list[i]); + } } else if (strcmp("depend", argv[1]) == 0) { @@ -439,6 +565,7 @@ int main(int argc, char *argv[]) symbolsonly = adddep; singlefunctions = adddep2; docsection = adddep2; + findall = adddep; parse_file(infile); printf("\n"); } diff --git a/scripts/kernel-doc b/scripts/kernel-doc index a68240c188f3..cdb6dc1f6458 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -44,12 +44,13 @@ use strict; # Note: This only supports 'c'. # usage: -# kernel-doc [ -docbook | -html | -text | -man ] [ -no-doc-sections ] +# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ] # [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile # or # [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile # # Set output format using one of -docbook -html -text or -man. Default is man. +# The -list format is for internal use by docproc. # # -no-doc-sections # Do not output DOC: sections @@ -210,9 +211,16 @@ my %highlights_text = ( $type_constant, "\$1", $type_param, "\$1" ); my $blankline_text = ""; +# list mode +my %highlights_list = ( $type_constant, "\$1", + $type_func, "\$1", + $type_struct, "\$1", + $type_param, "\$1" ); +my $blankline_list = ""; sub usage { - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ] [ -no-doc-sections ]\n"; + print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; + print " [ -no-doc-sections ]\n"; print " [ -function funcname [ -function funcname ...] ]\n"; print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; print " c source file(s) > outputfile\n"; @@ -318,6 +326,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { $output_mode = "xml"; %highlights = %highlights_xml; $blankline = $blankline_xml; + } elsif ($cmd eq "-list") { + $output_mode = "list"; + %highlights = %highlights_list; + $blankline = $blankline_list; } elsif ($cmd eq "-gnome") { $output_mode = "gnome"; %highlights = %highlights_gnome; @@ -1361,6 +1373,42 @@ sub output_blockhead_text(%) { } } +## list mode output functions + +sub output_function_list(%) { + my %args = %{$_[0]}; + + print $args{'function'} . "\n"; +} + +# output enum in list +sub output_enum_list(%) { + my %args = %{$_[0]}; + print $args{'enum'} . "\n"; +} + +# output typedef in list +sub output_typedef_list(%) { + my %args = %{$_[0]}; + print $args{'typedef'} . "\n"; +} + +# output struct as list +sub output_struct_list(%) { + my %args = %{$_[0]}; + + print $args{'struct'} . "\n"; +} + +sub output_blockhead_list(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + + foreach $section (@{$args{'sectionlist'}}) { + print "DOC: $section\n"; + } +} + ## # generic output function for all types (function, struct/union, typedef, enum); # calls the generated, variable output_ function name based on -- cgit v1.2.3-59-g8ed1b From 39d709392ffc1d05f825191b07b7d865d434f282 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 11 Sep 2010 15:55:26 -0700 Subject: docbook: skip files with no docs since they generate scary warnings Fix docbook templates that reference files that do not contain the expected kernel-doc notation. Fixes these warnings: Warning(arch/x86/include/asm/unaligned.h): no structured comments found Warning(lib/vsprintf.c): no structured comments found These cause errors in the generated html output, like below, so drop these lines. Name arch/x86/include/asm/unaligned.h - Document generation inconsistency Oops Warning The template for this document tried to insert the structured comment from the file arch/x86/include/asm/unaligned.h at this point, but none was found. This dummy section is inserted to allow generation to continue. Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/DocBook/device-drivers.tmpl | 1 - Documentation/DocBook/kernel-api.tmpl | 1 - 2 files changed, 2 deletions(-) diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index ecd35e9d4410..feca0758391e 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -46,7 +46,6 @@ Atomic and pointer manipulation !Iarch/x86/include/asm/atomic.h -!Iarch/x86/include/asm/unaligned.h Delaying, scheduling, and timer routines diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index a20c6f6fffc3..6899f471fb15 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -57,7 +57,6 @@ String Conversions -!Ilib/vsprintf.c !Elib/vsprintf.c String Manipulation -- cgit v1.2.3-59-g8ed1b From a505b3b30fc69904f858822a2aa95990a4bf7958 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 12 Sep 2010 11:56:44 -0700 Subject: sch_atm: Fix potential NULL deref. The list_head conversion unearther an unnecessary flow check. Since flow is always NULL here we don't need to see if a matching flow exists already. Reported-by: Jiri Slaby Signed-off-by: David S. Miller --- net/sched/sch_atm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 340662789529..6318e1136b83 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -255,10 +255,6 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, error = -EINVAL; goto err_out; } - if (!list_empty(&flow->list)) { - error = -EEXIST; - goto err_out; - } } else { int i; unsigned long cl; -- cgit v1.2.3-59-g8ed1b From 897493504addc5609f04a2c4f73c37ab972c29b2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 18:25:19 +0100 Subject: drm/i915: Ensure that the crtcinfo is populated during mode_fixup() This should fix the mysterious mode setting failures reported during boot up and after resume, generally for i8xx class machines. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16478 Reported-and-tested-by: Xavier Chantry Buzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29413 Tested-by: Daniel Vetter Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 19daead5b525..b5bf51a4502d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2463,11 +2463,19 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = crtc->dev; + if (HAS_PCH_SPLIT(dev)) { /* FDI link clock is fixed at 2.7G */ if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4) return false; } + + /* XXX some encoders set the crtcinfo, others don't. + * Obviously we need some form of conflict resolution here... + */ + if (adjusted_mode->crtc_htotal == 0) + drm_mode_set_crtcinfo(adjusted_mode, 0); + return true; } -- cgit v1.2.3-59-g8ed1b From 49553c2ef88749dd502687f4eb9c258bb10a4f44 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 12 Sep 2010 16:07:37 -0700 Subject: Linux 2.6.36-rc4 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4df9873f83b2..92ab33f16cf0 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 36 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = Sheep on Meth # *DOCUMENTATION* -- cgit v1.2.3-59-g8ed1b From f2d47d02fd84343a3c5452daca6ed12c75618aff Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 12 Sep 2010 19:55:25 -0400 Subject: Fix null dereference in call_allocate In call_allocate we need to reach the auth in order to factor au_cslack into the allocation. As of a17c2153d2e271b0cbacae9bed83b0eaa41db7e1 "SUNRPC: Move the bound cred to struct rpc_rqst", call_allocate attempts to do this by dereferencing tk_client->cl_auth, however this is not guaranteed to be defined--cl_auth can be zero in the case of gss context destruction (see rpc_free_auth). Reorder the client state machine to bind credentials before allocating, so that we can instead reach the auth through the cred. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- net/sunrpc/clnt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 2388d83b68ff..657aac630fc9 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -931,7 +931,7 @@ call_reserveresult(struct rpc_task *task) task->tk_status = 0; if (status >= 0) { if (task->tk_rqstp) { - task->tk_action = call_allocate; + task->tk_action = call_refresh; return; } @@ -972,7 +972,7 @@ call_reserveresult(struct rpc_task *task) static void call_allocate(struct rpc_task *task) { - unsigned int slack = task->tk_client->cl_auth->au_cslack; + unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack; struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = task->tk_xprt; struct rpc_procinfo *proc = task->tk_msg.rpc_proc; @@ -980,7 +980,7 @@ call_allocate(struct rpc_task *task) dprint_status(task); task->tk_status = 0; - task->tk_action = call_refresh; + task->tk_action = call_bind; if (req->rq_buffer) return; @@ -1042,7 +1042,7 @@ call_refreshresult(struct rpc_task *task) dprint_status(task); task->tk_status = 0; - task->tk_action = call_bind; + task->tk_action = call_allocate; if (status >= 0 && rpcauth_uptodatecred(task)) return; switch (status) { -- cgit v1.2.3-59-g8ed1b From 5a67657a2e90c9e4a48518f95d4ba7777aa20fbb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 12 Sep 2010 19:55:25 -0400 Subject: SUNRPC: Fix race corrupting rpc upcall If rpc_queue_upcall() adds a new upcall to the rpci->pipe list just after rpc_pipe_release calls rpc_purge_list(), but before it calls gss_pipe_release (as rpci->ops->release_pipe(inode)), then the latter will free a message without deleting it from the rpci->pipe list. We will be left with a freed object on the rpc->pipe list. Most frequent symptoms are kernel crashes in rpc.gssd system calls on the pipe in question. Reported-by: J. Bruce Fields Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- net/sunrpc/auth_gss/auth_gss.c | 9 +++++---- net/sunrpc/rpc_pipe.c | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index dcfc66bab2bb..12c485982814 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -745,17 +745,18 @@ gss_pipe_release(struct inode *inode) struct rpc_inode *rpci = RPC_I(inode); struct gss_upcall_msg *gss_msg; +restart: spin_lock(&inode->i_lock); - while (!list_empty(&rpci->in_downcall)) { + list_for_each_entry(gss_msg, &rpci->in_downcall, list) { - gss_msg = list_entry(rpci->in_downcall.next, - struct gss_upcall_msg, list); + if (!list_empty(&gss_msg->msg.list)) + continue; gss_msg->msg.errno = -EPIPE; atomic_inc(&gss_msg->count); __gss_unhash_msg(gss_msg); spin_unlock(&inode->i_lock); gss_release_msg(gss_msg); - spin_lock(&inode->i_lock); + goto restart; } spin_unlock(&inode->i_lock); diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 95ccbcf45d3e..41a762f82630 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -48,7 +48,7 @@ static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, return; do { msg = list_entry(head->next, struct rpc_pipe_msg, list); - list_del(&msg->list); + list_del_init(&msg->list); msg->errno = err; destroy_msg(msg); } while (!list_empty(head)); @@ -208,7 +208,7 @@ rpc_pipe_release(struct inode *inode, struct file *filp) if (msg != NULL) { spin_lock(&inode->i_lock); msg->errno = -EAGAIN; - list_del(&msg->list); + list_del_init(&msg->list); spin_unlock(&inode->i_lock); rpci->ops->destroy_msg(msg); } @@ -268,7 +268,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset) if (res < 0 || msg->len == msg->copied) { filp->private_data = NULL; spin_lock(&inode->i_lock); - list_del(&msg->list); + list_del_init(&msg->list); spin_unlock(&inode->i_lock); rpci->ops->destroy_msg(msg); } -- cgit v1.2.3-59-g8ed1b From 006abe887c5e637d059c44310de6c92f36aded3b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 12 Sep 2010 19:55:25 -0400 Subject: SUNRPC: Fix a race in rpc_info_open There is a race between rpc_info_open and rpc_release_client() in that nothing stops a process from opening the file after the clnt->cl_kref goes to zero. Fix this by using atomic_inc_unless_zero()... Reported-by: J. Bruce Fields Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- include/linux/sunrpc/clnt.h | 2 +- net/sunrpc/clnt.c | 26 ++++++++++++-------------- net/sunrpc/rpc_pipe.c | 14 ++++++++------ 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 569dc722a600..85f38a63f098 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -30,7 +30,7 @@ struct rpc_inode; * The high-level client handle */ struct rpc_clnt { - struct kref cl_kref; /* Number of references */ + atomic_t cl_count; /* Number of references */ struct list_head cl_clients; /* Global list of clients */ struct list_head cl_tasks; /* List of tasks */ spinlock_t cl_lock; /* spinlock */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 657aac630fc9..3a8f53e7ba07 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -226,7 +226,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru goto out_no_principal; } - kref_init(&clnt->cl_kref); + atomic_set(&clnt->cl_count, 1); err = rpc_setup_pipedir(clnt, program->pipe_dir_name); if (err < 0) @@ -390,14 +390,14 @@ rpc_clone_client(struct rpc_clnt *clnt) if (new->cl_principal == NULL) goto out_no_principal; } - kref_init(&new->cl_kref); + atomic_set(&new->cl_count, 1); err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); if (err != 0) goto out_no_path; if (new->cl_auth) atomic_inc(&new->cl_auth->au_count); xprt_get(clnt->cl_xprt); - kref_get(&clnt->cl_kref); + atomic_inc(&clnt->cl_count); rpc_register_client(new); rpciod_up(); return new; @@ -465,10 +465,8 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client); * Free an RPC client */ static void -rpc_free_client(struct kref *kref) +rpc_free_client(struct rpc_clnt *clnt) { - struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); - dprintk("RPC: destroying %s client for %s\n", clnt->cl_protname, clnt->cl_server); if (!IS_ERR(clnt->cl_path.dentry)) { @@ -495,12 +493,10 @@ out_free: * Free an RPC client */ static void -rpc_free_auth(struct kref *kref) +rpc_free_auth(struct rpc_clnt *clnt) { - struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); - if (clnt->cl_auth == NULL) { - rpc_free_client(kref); + rpc_free_client(clnt); return; } @@ -509,10 +505,11 @@ rpc_free_auth(struct kref *kref) * release remaining GSS contexts. This mechanism ensures * that it can do so safely. */ - kref_init(kref); + atomic_inc(&clnt->cl_count); rpcauth_release(clnt->cl_auth); clnt->cl_auth = NULL; - kref_put(kref, rpc_free_client); + if (atomic_dec_and_test(&clnt->cl_count)) + rpc_free_client(clnt); } /* @@ -525,7 +522,8 @@ rpc_release_client(struct rpc_clnt *clnt) if (list_empty(&clnt->cl_tasks)) wake_up(&destroy_wait); - kref_put(&clnt->cl_kref, rpc_free_auth); + if (atomic_dec_and_test(&clnt->cl_count)) + rpc_free_auth(clnt); } /** @@ -588,7 +586,7 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) if (clnt != NULL) { rpc_task_release_client(task); task->tk_client = clnt; - kref_get(&clnt->cl_kref); + atomic_inc(&clnt->cl_count); if (clnt->cl_softrtry) task->tk_flags |= RPC_TASK_SOFT; /* Add to the client's list of all tasks */ diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 41a762f82630..8c8eef2b8f26 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -371,21 +371,23 @@ rpc_show_info(struct seq_file *m, void *v) static int rpc_info_open(struct inode *inode, struct file *file) { - struct rpc_clnt *clnt; + struct rpc_clnt *clnt = NULL; int ret = single_open(file, rpc_show_info, NULL); if (!ret) { struct seq_file *m = file->private_data; - mutex_lock(&inode->i_mutex); - clnt = RPC_I(inode)->private; - if (clnt) { - kref_get(&clnt->cl_kref); + + spin_lock(&file->f_path.dentry->d_lock); + if (!d_unhashed(file->f_path.dentry)) + clnt = RPC_I(inode)->private; + if (clnt != NULL && atomic_inc_not_zero(&clnt->cl_count)) { + spin_unlock(&file->f_path.dentry->d_lock); m->private = clnt; } else { + spin_unlock(&file->f_path.dentry->d_lock); single_release(inode, file); ret = -EINVAL; } - mutex_unlock(&inode->i_mutex); } return ret; } -- cgit v1.2.3-59-g8ed1b From 55576244eba805307a2b2b6a145b8f85f8c7c124 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sun, 12 Sep 2010 19:55:25 -0400 Subject: SUNRPC: cleanup state-machine ordering This is just a minor cleanup: net/sunrpc/clnt.c clarifies the rpc client state machine by commenting each state and by laying out the functions implementing each state in the order that each state is normally executed (in the absence of errors). The previous patch "Fix null dereference in call_allocate" changed the order of the states. Move the functions and update the comments to reflect the change. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 84 +++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 3a8f53e7ba07..fa5549079d79 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -964,7 +964,48 @@ call_reserveresult(struct rpc_task *task) } /* - * 2. Allocate the buffer. For details, see sched.c:rpc_malloc. + * 2. Bind and/or refresh the credentials + */ +static void +call_refresh(struct rpc_task *task) +{ + dprint_status(task); + + task->tk_action = call_refreshresult; + task->tk_status = 0; + task->tk_client->cl_stats->rpcauthrefresh++; + rpcauth_refreshcred(task); +} + +/* + * 2a. Process the results of a credential refresh + */ +static void +call_refreshresult(struct rpc_task *task) +{ + int status = task->tk_status; + + dprint_status(task); + + task->tk_status = 0; + task->tk_action = call_allocate; + if (status >= 0 && rpcauth_uptodatecred(task)) + return; + switch (status) { + case -EACCES: + rpc_exit(task, -EACCES); + return; + case -ENOMEM: + rpc_exit(task, -ENOMEM); + return; + case -ETIMEDOUT: + rpc_delay(task, 3*HZ); + } + task->tk_action = call_refresh; +} + +/* + * 2b. Allocate the buffer. For details, see sched.c:rpc_malloc. * (Note: buffer memory is freed in xprt_release). */ static void @@ -1015,47 +1056,6 @@ call_allocate(struct rpc_task *task) rpc_exit(task, -ERESTARTSYS); } -/* - * 2a. Bind and/or refresh the credentials - */ -static void -call_refresh(struct rpc_task *task) -{ - dprint_status(task); - - task->tk_action = call_refreshresult; - task->tk_status = 0; - task->tk_client->cl_stats->rpcauthrefresh++; - rpcauth_refreshcred(task); -} - -/* - * 2b. Process the results of a credential refresh - */ -static void -call_refreshresult(struct rpc_task *task) -{ - int status = task->tk_status; - - dprint_status(task); - - task->tk_status = 0; - task->tk_action = call_allocate; - if (status >= 0 && rpcauth_uptodatecred(task)) - return; - switch (status) { - case -EACCES: - rpc_exit(task, -EACCES); - return; - case -ENOMEM: - rpc_exit(task, -ENOMEM); - return; - case -ETIMEDOUT: - rpc_delay(task, 3*HZ); - } - task->tk_action = call_refresh; -} - static inline int rpc_task_need_encode(struct rpc_task *task) { -- cgit v1.2.3-59-g8ed1b From b1bde04c6d9a120dec602cc8a70b8a7f21600883 Mon Sep 17 00:00:00 2001 From: Fabio Olive Leite Date: Sun, 12 Sep 2010 19:55:25 -0400 Subject: Remove incorrect do_vfs_lock message The do_vfs_lock function on fs/nfs/file.c is only called if NLM is not being used, via the -onolock mount option. Therefore it cannot really be "out of sync with lock manager" when the local locking function called returns an error, as there will be no corresponding call to the NLM. For details, simply check the if/else on do_setlk and do_unlk on fs/nfs/file.c. Signed-Off-By: Fabio Olive Leite Reviewed-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index eb51bd6201da..05bf3c0dc751 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -723,10 +723,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) default: BUG(); } - if (res < 0) - dprintk(KERN_WARNING "%s: VFS is out of sync with lock manager" - " - error %d!\n", - __func__, res); return res; } -- cgit v1.2.3-59-g8ed1b From ce8477e1176389ed920550f4c925ad4a815b22d5 Mon Sep 17 00:00:00 2001 From: Bian Naimeng Date: Sun, 12 Sep 2010 19:55:25 -0400 Subject: gss:krb5 miss returning error to caller when import security context krb5 miss returning error to up layer when import security context, it may be return ok though it has failed to import security context. Signed-off-by: Bian Naimeng Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_krb5_mech.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 032644610524..778e5dfc5144 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -237,6 +237,7 @@ get_key(const void *p, const void *end, if (!supported_gss_krb5_enctype(alg)) { printk(KERN_WARNING "gss_kerberos_mech: unsupported " "encryption key algorithm %d\n", alg); + p = ERR_PTR(-EINVAL); goto out_err; } p = simple_get_netobj(p, end, &key); @@ -282,15 +283,19 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) ctx->enctype = ENCTYPE_DES_CBC_RAW; ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); - if (ctx->gk5e == NULL) + if (ctx->gk5e == NULL) { + p = ERR_PTR(-EINVAL); goto out_err; + } /* The downcall format was designed before we completely understood * the uses of the context fields; so it includes some stuff we * just give some minimal sanity-checking, and some we ignore * completely (like the next twenty bytes): */ - if (unlikely(p + 20 > end || p + 20 < p)) + if (unlikely(p + 20 > end || p + 20 < p)) { + p = ERR_PTR(-EFAULT); goto out_err; + } p += 20; p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); if (IS_ERR(p)) @@ -619,6 +624,7 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, if (ctx->seq_send64 != ctx->seq_send) { dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__, (long unsigned)ctx->seq_send64, ctx->seq_send); + p = ERR_PTR(-EINVAL); goto out_err; } p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); -- cgit v1.2.3-59-g8ed1b From 651b2933b22a0c060e6bb940c4104eb447a61f9a Mon Sep 17 00:00:00 2001 From: Bian Naimeng Date: Sun, 12 Sep 2010 19:55:26 -0400 Subject: gss:spkm3 miss returning error to caller when import security context spkm3 miss returning error to up layer when import security context, it may be return ok though it has failed to import security context. Signed-off-by: Bian Naimeng Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_spkm3_mech.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index dc3f1f5ed865..adade3d313f2 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -100,6 +100,7 @@ gss_import_sec_context_spkm3(const void *p, size_t len, if (version != 1) { dprintk("RPC: unknown spkm3 token format: " "obsolete nfs-utils?\n"); + p = ERR_PTR(-EINVAL); goto out_err_free_ctx; } @@ -135,8 +136,10 @@ gss_import_sec_context_spkm3(const void *p, size_t len, if (IS_ERR(p)) goto out_err_free_intg_alg; - if (p != end) + if (p != end) { + p = ERR_PTR(-EFAULT); goto out_err_free_intg_key; + } ctx_id->internal_ctx_id = ctx; -- cgit v1.2.3-59-g8ed1b From db5fe26541b6b48460104a0d949a27cdc7786957 Mon Sep 17 00:00:00 2001 From: Miquel van Smoorenburg Date: Sun, 12 Sep 2010 19:55:26 -0400 Subject: sunrpc: increase MAX_HASHTABLE_BITS to 14 The maximum size of the authcache is now set to 1024 (10 bits), but on our server we need at least 4096 (12 bits). Increase MAX_HASHTABLE_BITS to 14. This is a maximum of 16384 entries, each containing a pointer (8 bytes on x86_64). This is exactly the limit of kmalloc() (128K). Signed-off-by: Miquel van Smoorenburg Signed-off-by: Trond Myklebust --- net/sunrpc/auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 36cb66022a27..e9eaaf7d43c1 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -38,7 +38,7 @@ static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { static LIST_HEAD(cred_unused); static unsigned long number_cred_unused; -#define MAX_HASHTABLE_BITS (10) +#define MAX_HASHTABLE_BITS (14) static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) { unsigned long num; -- cgit v1.2.3-59-g8ed1b From b20d37ca9561711c6a3c4b859c2855f49565e061 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 12 Sep 2010 19:55:26 -0400 Subject: NFS: Fix a typo in nfs_sockaddr_match_ipaddr6 Reported-by: Ben Greear Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- fs/nfs/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 4e7df2adb212..e7340729af89 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -275,7 +275,7 @@ static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, sin1->sin6_scope_id != sin2->sin6_scope_id) return 0; - return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr); + return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr); } #else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */ static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, -- cgit v1.2.3-59-g8ed1b From fbf3fdd2443965d9ba6fb4b5fecd1f6e0847218f Mon Sep 17 00:00:00 2001 From: Menyhart Zoltan Date: Sun, 12 Sep 2010 19:55:26 -0400 Subject: statfs() gives ESTALE error Hi, An NFS client executes a statfs("file", &buff) call. "file" exists / existed, the client has read / written it, but it has already closed it. user_path(pathname, &path) looks up "file" successfully in the directory-cache and restarts the aging timer of the directory-entry. Even if "file" has already been removed from the server, because the lookupcache=positive option I use, keeps the entries valid for a while. nfs_statfs() returns ESTALE if "file" has already been removed from the server. If the user application repeats the statfs("file", &buff) call, we are stuck: "file" remains young forever in the directory-cache. Signed-off-by: Zoltan Menyhart Signed-off-by: Trond Myklebust Cc: stable@kernel.org --- fs/nfs/super.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ec3966e4706b..f4cbf0c306c6 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -431,7 +431,15 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) goto out_err; error = server->nfs_client->rpc_ops->statfs(server, fh, &res); + if (unlikely(error == -ESTALE)) { + struct dentry *pd_dentry; + pd_dentry = dget_parent(dentry); + if (pd_dentry != NULL) { + nfs_zap_caches(pd_dentry->d_inode); + dput(pd_dentry); + } + } nfs_free_fattr(res.fattr); if (error < 0) goto out_err; -- cgit v1.2.3-59-g8ed1b From 827e3457022d0bb0b1bb8a0eb88501876fe7dcf0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 12 Sep 2010 19:57:50 -0400 Subject: SUNRPC: Fix the NFSv4 and RPCSEC_GSS Kconfig dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NFSv4 client's callback server calls svc_gss_principal(), which is defined in the auth_rpcgss.ko The NFSv4 server has the same dependency, and in addition calls svcauth_gss_flavor(), gss_mech_get_by_pseudoflavor(), gss_pseudoflavor_to_service() and gss_mech_put() from the same module. The module auth_rpcgss itself has no dependencies aside from sunrpc, so we only need to select RPCSEC_GSS. Reported-by: Uwe Kleine-König Signed-off-by: Trond Myklebust --- fs/nfs/Kconfig | 1 + fs/nfsd/Kconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 6c2aad49d731..f7e13db613cb 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig @@ -63,6 +63,7 @@ config NFS_V3_ACL config NFS_V4 bool "NFS client support for NFS version 4" depends on NFS_FS + select SUNRPC_GSS help This option enables support for version 4 of the NFS protocol (RFC 3530) in the kernel's NFS client. diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 95932f523aef..4264377552e2 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -69,6 +69,7 @@ config NFSD_V4 depends on NFSD && PROC_FS && EXPERIMENTAL select NFSD_V3 select FS_POSIX_ACL + select SUNRPC_GSS help This option enables support in your system's NFS server for version 4 of the NFS protocol (RFC 3530). -- cgit v1.2.3-59-g8ed1b From b343ae51c116dffaef07a8596661774c12212b66 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 12 Sep 2010 17:20:24 -0700 Subject: sparc64: Support RAW perf events. Encoding is "(encoding << 16) | pic_mask" Signed-off-by: David S. Miller --- arch/sparc/kernel/perf_event.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 357ced3c33ff..6318e622cfb0 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1038,6 +1038,7 @@ static int __hw_perf_event_init(struct perf_event *event) if (atomic_read(&nmi_active) < 0) return -ENODEV; + pmap = NULL; if (attr->type == PERF_TYPE_HARDWARE) { if (attr->config >= sparc_pmu->max_events) return -EINVAL; @@ -1046,9 +1047,18 @@ static int __hw_perf_event_init(struct perf_event *event) pmap = sparc_map_cache_event(attr->config); if (IS_ERR(pmap)) return PTR_ERR(pmap); - } else + } else if (attr->type != PERF_TYPE_RAW) return -EOPNOTSUPP; + if (pmap) { + hwc->event_base = perf_event_encode(pmap); + } else { + /* User gives us "(encoding << 16) | pic_mask" for + * PERF_TYPE_RAW events. + */ + hwc->event_base = attr->config; + } + /* We save the enable bits in the config_base. */ hwc->config_base = sparc_pmu->irq_bit; if (!attr->exclude_user) @@ -1058,8 +1068,6 @@ static int __hw_perf_event_init(struct perf_event *event) if (!attr->exclude_hv) hwc->config_base |= sparc_pmu->hv_bit; - hwc->event_base = perf_event_encode(pmap); - n = 0; if (event->group_leader != event) { n = collect_events(event->group_leader, -- cgit v1.2.3-59-g8ed1b From cea310e8f8702226f982f09386cfd3c5793c5e2f Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Fri, 10 Sep 2010 16:29:56 -0700 Subject: ALSA: hda_intel: ALSA HD Audio patch for Intel Patsburg DeviceIDs This patch adds the Intel Patsburg (PCH) HD Audio Controller DeviceIDs. Signed-off-by: Seth Heasley Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1053fff4bd0a..34940a079051 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -126,6 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH10}," "{Intel, PCH}," "{Intel, CPT}," + "{Intel, PBG}," "{Intel, SCH}," "{ATI, SB450}," "{ATI, SB600}," @@ -2749,6 +2750,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH }, /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, + /* PBG */ + { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, /* ATI SB 450/600 */ -- cgit v1.2.3-59-g8ed1b From eac15a429a27cb74115daaf4c1127c5e854d50e4 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 28 Aug 2010 01:45:00 -0400 Subject: mtd: Blackfin NFC: fix build error after nand_scan_ident() change Seems some patches got out sync when being merged. The Blackfin NFC driver was updated to use nand_scan_ident(), but it missed the change where nand_scan_ident() now takes 3 arguments. So update this driver to fix build failures. Signed-off-by: Mike Frysinger Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/bf5xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index a382e3dd0a5d..162c5ea2b773 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -710,7 +710,7 @@ static int bf5xx_nand_scan(struct mtd_info *mtd) struct nand_chip *chip = mtd->priv; int ret; - ret = nand_scan_ident(mtd, 1); + ret = nand_scan_ident(mtd, 1, NULL); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 8b865d5efd9205b131dd9a43a6f450c05d38aaa1 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 28 Aug 2010 16:42:04 -0400 Subject: mtd: Blackfin NFC: fix invalid free in remove() Since info->mtd isn't dynamically allocated, we shouldn't attempt to kfree() it. Otherwise we get random fun corruption when unloading the driver built as a module. Signed-off-by: Mike Frysinger Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/bf5xx_nand.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 162c5ea2b773..6fbeefa3a766 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -682,7 +682,6 @@ static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info) static int __devexit bf5xx_nand_remove(struct platform_device *pdev) { struct bf5xx_nand_info *info = to_nand_info(pdev); - struct mtd_info *mtd = NULL; platform_set_drvdata(pdev, NULL); @@ -690,11 +689,7 @@ static int __devexit bf5xx_nand_remove(struct platform_device *pdev) * and their partitions, then go through freeing the * resources used */ - mtd = &info->mtd; - if (mtd) { - nand_release(mtd); - kfree(mtd); - } + nand_release(&info->mtd); peripheral_free_list(bfin_nfc_pin_req); bf5xx_nand_dma_remove(info); -- cgit v1.2.3-59-g8ed1b From 9aba97ad004ed0cde9747a9daf5b1484edb746cd Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 27 Aug 2010 11:55:44 +0900 Subject: mtd: OneNAND: Fix 2KiB pagesize handling at Samsung SoCs Wrong assumption bufferram can be switched between BufferRAM0 and BufferRAM1 Signed-off-by: Kyungmin Park Signed-off-by: David Woodhouse --- drivers/mtd/onenand/samsung.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index cb443af3d45f..094dfcbe2347 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -571,13 +571,12 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, unsigned char *buffer, int offset, size_t count) { struct onenand_chip *this = mtd->priv; - void __iomem *bufferram; void __iomem *p; void *buf = (void *) buffer; dma_addr_t dma_src, dma_dst; int err; - p = bufferram = this->base + area; + p = this->base + area; if (ONENAND_CURRENT_BUFFERRAM(this)) { if (area == ONENAND_DATARAM) p += this->writesize; @@ -621,7 +620,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, normal: if (count != mtd->writesize) { /* Copy the bufferram to memory to prevent unaligned access */ - memcpy(this->page_buf, bufferram, mtd->writesize); + memcpy(this->page_buf, p, mtd->writesize); p = this->page_buf + offset; } -- cgit v1.2.3-59-g8ed1b From 53d1e137d5ddd8a1c5ec54c5375cb2832e1cbcd1 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Fri, 27 Aug 2010 11:55:37 +0900 Subject: mtd: OneNAND: Fix loop hang when DMA error at Samsung SoCs When DMA error occurs. it's loop hang since it can't exit the loop. and it's the right DMA handling code as Spec. Signed-off-by: Kyungmin Park Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/samsung.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 094dfcbe2347..a460f1b748c2 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -554,14 +554,13 @@ static int s5pc110_dma_ops(void *dst, void *src, size_t count, int direction) do { status = readl(base + S5PC110_DMA_TRANS_STATUS); + if (status & S5PC110_DMA_TRANS_STATUS_TE) { + writel(S5PC110_DMA_TRANS_CMD_TEC, + base + S5PC110_DMA_TRANS_CMD); + return -EIO; + } } while (!(status & S5PC110_DMA_TRANS_STATUS_TD)); - if (status & S5PC110_DMA_TRANS_STATUS_TE) { - writel(S5PC110_DMA_TRANS_CMD_TEC, base + S5PC110_DMA_TRANS_CMD); - writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD); - return -EIO; - } - writel(S5PC110_DMA_TRANS_CMD_TDC, base + S5PC110_DMA_TRANS_CMD); return 0; -- cgit v1.2.3-59-g8ed1b From b8db2f51dcccbaf4d23ed44cd0c64856c58a16c0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 9 Aug 2010 15:04:19 +0200 Subject: mtd: mxc_nand: configure pages per block for v2 controller This patch initializes the pages per block field in CONFIG1 for v2 controllers. It also sets the FP_INT field. This is the last field not correctly initialized, so we can switch from read/modify/write the CONFIG1 reg to just write the correct value. Signed-off-by: Sascha Hauer Acked-by: John Ogness Tested-by: John Ogness Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 26caa01e34a6..b2828e84d243 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -67,7 +67,9 @@ #define NFC_V1_V2_CONFIG1_BIG (1 << 5) #define NFC_V1_V2_CONFIG1_RST (1 << 6) #define NFC_V1_V2_CONFIG1_CE (1 << 7) -#define NFC_V1_V2_CONFIG1_ONE_CYCLE (1 << 8) +#define NFC_V2_CONFIG1_ONE_CYCLE (1 << 8) +#define NFC_V2_CONFIG1_PPB(x) (((x) & 0x3) << 9) +#define NFC_V2_CONFIG1_FP_INT (1 << 11) #define NFC_V1_V2_CONFIG2_INT (1 << 15) @@ -729,27 +731,30 @@ static void preset_v1_v2(struct mtd_info *mtd) { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - uint16_t tmp; - - /* enable interrupt, disable spare enable */ - tmp = readw(NFC_V1_V2_CONFIG1); - tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK; - tmp &= ~NFC_V1_V2_CONFIG1_SP_EN; - if (nand_chip->ecc.mode == NAND_ECC_HW) { - tmp |= NFC_V1_V2_CONFIG1_ECC_EN; - } else { - tmp &= ~NFC_V1_V2_CONFIG1_ECC_EN; - } + uint16_t config1 = 0; + + if (nand_chip->ecc.mode == NAND_ECC_HW) + config1 |= NFC_V1_V2_CONFIG1_ECC_EN; + + if (nfc_is_v21()) + config1 |= NFC_V2_CONFIG1_FP_INT; + + if (!cpu_is_mx21()) + config1 |= NFC_V1_V2_CONFIG1_INT_MSK; if (nfc_is_v21() && mtd->writesize) { + uint16_t pages_per_block = mtd->erasesize / mtd->writesize; + host->eccsize = get_eccsize(mtd); if (host->eccsize == 4) - tmp |= NFC_V2_CONFIG1_ECC_MODE_4; + config1 |= NFC_V2_CONFIG1_ECC_MODE_4; + + config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6); } else { host->eccsize = 1; } - writew(tmp, NFC_V1_V2_CONFIG1); + writew(config1, NFC_V1_V2_CONFIG1); /* preset operation */ /* Unlock the internal RAM Buffer */ -- cgit v1.2.3-59-g8ed1b From 99d389640b58052884fb231bce9dbffb4f595aa4 Mon Sep 17 00:00:00 2001 From: "Mark F. Brown" Date: Thu, 26 Aug 2010 04:56:51 -0400 Subject: mtd: pxa3xx: fix build error when CONFIG_MTD_PARTITIONS is not defined Signed-off-by: Mark F. Brown Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4d89f3780207..4d01cda68844 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1320,6 +1320,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) goto fail_free_irq; } +#ifdef CONFIG_MTD_PARTITIONS if (mtd_has_cmdlinepart()) { static const char *probes[] = { "cmdlinepart", NULL }; struct mtd_partition *parts; @@ -1332,6 +1333,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); +#else + return 0; +#endif fail_free_irq: free_irq(irq, info); @@ -1364,7 +1368,9 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); del_mtd_device(mtd); +#ifdef CONFIG_MTD_PARTITIONS del_mtd_partitions(mtd); +#endif irq = platform_get_irq(pdev, 0); if (irq >= 0) free_irq(irq, info); -- cgit v1.2.3-59-g8ed1b From c54fce6eff197d9c57c97afbf6c9722ce434fc8f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Sep 2010 16:51:36 +0200 Subject: workqueue: add documentation Update copyright notice and add Documentation/workqueue.txt. Randy Dunlap, Dave Chinner: misc fixes. Signed-off-by: Tejun Heo Reviewed-By: Florian Mickler Cc: Ingo Molnar Cc: Christoph Lameter Cc: Randy Dunlap Cc: Dave Chinner --- Documentation/workqueue.txt | 380 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/workqueue.h | 4 + kernel/workqueue.c | 27 ++-- 3 files changed, 401 insertions(+), 10 deletions(-) create mode 100644 Documentation/workqueue.txt diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt new file mode 100644 index 000000000000..e4498a2872c3 --- /dev/null +++ b/Documentation/workqueue.txt @@ -0,0 +1,380 @@ + +Concurrency Managed Workqueue (cmwq) + +September, 2010 Tejun Heo + Florian Mickler + +CONTENTS + +1. Introduction +2. Why cmwq? +3. The Design +4. Application Programming Interface (API) +5. Example Execution Scenarios +6. Guidelines + + +1. Introduction + +There are many cases where an asynchronous process execution context +is needed and the workqueue (wq) API is the most commonly used +mechanism for such cases. + +When such an asynchronous execution context is needed, a work item +describing which function to execute is put on a queue. An +independent thread serves as the asynchronous execution context. The +queue is called workqueue and the thread is called worker. + +While there are work items on the workqueue the worker executes the +functions associated with the work items one after the other. When +there is no work item left on the workqueue the worker becomes idle. +When a new work item gets queued, the worker begins executing again. + + +2. Why cmwq? + +In the original wq implementation, a multi threaded (MT) wq had one +worker thread per CPU and a single threaded (ST) wq had one worker +thread system-wide. A single MT wq needed to keep around the same +number of workers as the number of CPUs. The kernel grew a lot of MT +wq users over the years and with the number of CPU cores continuously +rising, some systems saturated the default 32k PID space just booting +up. + +Although MT wq wasted a lot of resource, the level of concurrency +provided was unsatisfactory. The limitation was common to both ST and +MT wq albeit less severe on MT. Each wq maintained its own separate +worker pool. A MT wq could provide only one execution context per CPU +while a ST wq one for the whole system. Work items had to compete for +those very limited execution contexts leading to various problems +including proneness to deadlocks around the single execution context. + +The tension between the provided level of concurrency and resource +usage also forced its users to make unnecessary tradeoffs like libata +choosing to use ST wq for polling PIOs and accepting an unnecessary +limitation that no two polling PIOs can progress at the same time. As +MT wq don't provide much better concurrency, users which require +higher level of concurrency, like async or fscache, had to implement +their own thread pool. + +Concurrency Managed Workqueue (cmwq) is a reimplementation of wq with +focus on the following goals. + +* Maintain compatibility with the original workqueue API. + +* Use per-CPU unified worker pools shared by all wq to provide + flexible level of concurrency on demand without wasting a lot of + resource. + +* Automatically regulate worker pool and level of concurrency so that + the API users don't need to worry about such details. + + +3. The Design + +In order to ease the asynchronous execution of functions a new +abstraction, the work item, is introduced. + +A work item is a simple struct that holds a pointer to the function +that is to be executed asynchronously. Whenever a driver or subsystem +wants a function to be executed asynchronously it has to set up a work +item pointing to that function and queue that work item on a +workqueue. + +Special purpose threads, called worker threads, execute the functions +off of the queue, one after the other. If no work is queued, the +worker threads become idle. These worker threads are managed in so +called thread-pools. + +The cmwq design differentiates between the user-facing workqueues that +subsystems and drivers queue work items on and the backend mechanism +which manages thread-pool and processes the queued work items. + +The backend is called gcwq. There is one gcwq for each possible CPU +and one gcwq to serve work items queued on unbound workqueues. + +Subsystems and drivers can create and queue work items through special +workqueue API functions as they see fit. They can influence some +aspects of the way the work items are executed by setting flags on the +workqueue they are putting the work item on. These flags include +things like CPU locality, reentrancy, concurrency limits and more. To +get a detailed overview refer to the API description of +alloc_workqueue() below. + +When a work item is queued to a workqueue, the target gcwq is +determined according to the queue parameters and workqueue attributes +and appended on the shared worklist of the gcwq. For example, unless +specifically overridden, a work item of a bound workqueue will be +queued on the worklist of exactly that gcwq that is associated to the +CPU the issuer is running on. + +For any worker pool implementation, managing the concurrency level +(how many execution contexts are active) is an important issue. cmwq +tries to keep the concurrency at a minimal but sufficient level. +Minimal to save resources and sufficient in that the system is used at +its full capacity. + +Each gcwq bound to an actual CPU implements concurrency management by +hooking into the scheduler. The gcwq is notified whenever an active +worker wakes up or sleeps and keeps track of the number of the +currently runnable workers. Generally, work items are not expected to +hog a CPU and consume many cycles. That means maintaining just enough +concurrency to prevent work processing from stalling should be +optimal. As long as there are one or more runnable workers on the +CPU, the gcwq doesn't start execution of a new work, but, when the +last running worker goes to sleep, it immediately schedules a new +worker so that the CPU doesn't sit idle while there are pending work +items. This allows using a minimal number of workers without losing +execution bandwidth. + +Keeping idle workers around doesn't cost other than the memory space +for kthreads, so cmwq holds onto idle ones for a while before killing +them. + +For an unbound wq, the above concurrency management doesn't apply and +the gcwq for the pseudo unbound CPU tries to start executing all work +items as soon as possible. The responsibility of regulating +concurrency level is on the users. There is also a flag to mark a +bound wq to ignore the concurrency management. Please refer to the +API section for details. + +Forward progress guarantee relies on that workers can be created when +more execution contexts are necessary, which in turn is guaranteed +through the use of rescue workers. All work items which might be used +on code paths that handle memory reclaim are required to be queued on +wq's that have a rescue-worker reserved for execution under memory +pressure. Else it is possible that the thread-pool deadlocks waiting +for execution contexts to free up. + + +4. Application Programming Interface (API) + +alloc_workqueue() allocates a wq. The original create_*workqueue() +functions are deprecated and scheduled for removal. alloc_workqueue() +takes three arguments - @name, @flags and @max_active. @name is the +name of the wq and also used as the name of the rescuer thread if +there is one. + +A wq no longer manages execution resources but serves as a domain for +forward progress guarantee, flush and work item attributes. @flags +and @max_active control how work items are assigned execution +resources, scheduled and executed. + +@flags: + + WQ_NON_REENTRANT + + By default, a wq guarantees non-reentrance only on the same + CPU. A work item may not be executed concurrently on the same + CPU by multiple workers but is allowed to be executed + concurrently on multiple CPUs. This flag makes sure + non-reentrance is enforced across all CPUs. Work items queued + to a non-reentrant wq are guaranteed to be executed by at most + one worker system-wide at any given time. + + WQ_UNBOUND + + Work items queued to an unbound wq are served by a special + gcwq which hosts workers which are not bound to any specific + CPU. This makes the wq behave as a simple execution context + provider without concurrency management. The unbound gcwq + tries to start execution of work items as soon as possible. + Unbound wq sacrifices locality but is useful for the following + cases. + + * Wide fluctuation in the concurrency level requirement is + expected and using bound wq may end up creating large number + of mostly unused workers across different CPUs as the issuer + hops through different CPUs. + + * Long running CPU intensive workloads which can be better + managed by the system scheduler. + + WQ_FREEZEABLE + + A freezeable wq participates in the freeze phase of the system + suspend operations. Work items on the wq are drained and no + new work item starts execution until thawed. + + WQ_RESCUER + + All wq which might be used in the memory reclaim paths _MUST_ + have this flag set. This reserves one worker exclusively for + the execution of this wq under memory pressure. + + WQ_HIGHPRI + + Work items of a highpri wq are queued at the head of the + worklist of the target gcwq and start execution regardless of + the current concurrency level. In other words, highpri work + items will always start execution as soon as execution + resource is available. + + Ordering among highpri work items is preserved - a highpri + work item queued after another highpri work item will start + execution after the earlier highpri work item starts. + + Although highpri work items are not held back by other + runnable work items, they still contribute to the concurrency + level. Highpri work items in runnable state will prevent + non-highpri work items from starting execution. + + This flag is meaningless for unbound wq. + + WQ_CPU_INTENSIVE + + Work items of a CPU intensive wq do not contribute to the + concurrency level. In other words, runnable CPU intensive + work items will not prevent other work items from starting + execution. This is useful for bound work items which are + expected to hog CPU cycles so that their execution is + regulated by the system scheduler. + + Although CPU intensive work items don't contribute to the + concurrency level, start of their executions is still + regulated by the concurrency management and runnable + non-CPU-intensive work items can delay execution of CPU + intensive work items. + + This flag is meaningless for unbound wq. + + WQ_HIGHPRI | WQ_CPU_INTENSIVE + + This combination makes the wq avoid interaction with + concurrency management completely and behave as a simple + per-CPU execution context provider. Work items queued on a + highpri CPU-intensive wq start execution as soon as resources + are available and don't affect execution of other work items. + +@max_active: + +@max_active determines the maximum number of execution contexts per +CPU which can be assigned to the work items of a wq. For example, +with @max_active of 16, at most 16 work items of the wq can be +executing at the same time per CPU. + +Currently, for a bound wq, the maximum limit for @max_active is 512 +and the default value used when 0 is specified is 256. For an unbound +wq, the limit is higher of 512 and 4 * num_possible_cpus(). These +values are chosen sufficiently high such that they are not the +limiting factor while providing protection in runaway cases. + +The number of active work items of a wq is usually regulated by the +users of the wq, more specifically, by how many work items the users +may queue at the same time. Unless there is a specific need for +throttling the number of active work items, specifying '0' is +recommended. + +Some users depend on the strict execution ordering of ST wq. The +combination of @max_active of 1 and WQ_UNBOUND is used to achieve this +behavior. Work items on such wq are always queued to the unbound gcwq +and only one work item can be active at any given time thus achieving +the same ordering property as ST wq. + + +5. Example Execution Scenarios + +The following example execution scenarios try to illustrate how cmwq +behave under different configurations. + + Work items w0, w1, w2 are queued to a bound wq q0 on the same CPU. + w0 burns CPU for 5ms then sleeps for 10ms then burns CPU for 5ms + again before finishing. w1 and w2 burn CPU for 5ms then sleep for + 10ms. + +Ignoring all other tasks, works and processing overhead, and assuming +simple FIFO scheduling, the following is one highly simplified version +of possible sequences of events with the original wq. + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 starts and burns CPU + 25 w1 sleeps + 35 w1 wakes up and finishes + 35 w2 starts and burns CPU + 40 w2 sleeps + 50 w2 wakes up and finishes + +And with cmwq with @max_active >= 3, + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 5 w1 starts and burns CPU + 10 w1 sleeps + 10 w2 starts and burns CPU + 15 w2 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 wakes up and finishes + 25 w2 wakes up and finishes + +If @max_active == 2, + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 5 w1 starts and burns CPU + 10 w1 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 wakes up and finishes + 20 w2 starts and burns CPU + 25 w2 sleeps + 35 w2 wakes up and finishes + +Now, let's assume w1 and w2 are queued to a different wq q1 which has +WQ_HIGHPRI set, + + TIME IN MSECS EVENT + 0 w1 and w2 start and burn CPU + 5 w1 sleeps + 10 w2 sleeps + 10 w0 starts and burns CPU + 15 w0 sleeps + 15 w1 wakes up and finishes + 20 w2 wakes up and finishes + 25 w0 wakes up and burns CPU + 30 w0 finishes + +If q1 has WQ_CPU_INTENSIVE set, + + TIME IN MSECS EVENT + 0 w0 starts and burns CPU + 5 w0 sleeps + 5 w1 and w2 start and burn CPU + 10 w1 sleeps + 15 w2 sleeps + 15 w0 wakes up and burns CPU + 20 w0 finishes + 20 w1 wakes up and finishes + 25 w2 wakes up and finishes + + +6. Guidelines + +* Do not forget to use WQ_RESCUER if a wq may process work items which + are used during memory reclaim. Each wq with WQ_RESCUER set has one + rescuer thread reserved for it. If there is dependency among + multiple work items used during memory reclaim, they should be + queued to separate wq each with WQ_RESCUER. + +* Unless strict ordering is required, there is no need to use ST wq. + +* Unless there is a specific need, using 0 for @max_active is + recommended. In most use cases, concurrency level usually stays + well under the default limit. + +* A wq serves as a domain for forward progress guarantee (WQ_RESCUER), + flush and work item attributes. Work items which are not involved + in memory reclaim and don't need to be flushed as a part of a group + of work items, and don't require any special attribute, can use one + of the system wq. There is no difference in execution + characteristics between using a dedicated wq and a system wq. + +* Unless work items are expected to consume a huge amount of CPU + cycles, using a bound wq is usually beneficial due to the increased + level of locality in wq operations and work item execution. diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index f11100f96482..25e02c941bac 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -235,6 +235,10 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; } #define work_clear_pending(work) \ clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)) +/* + * Workqueue flags and constants. For details, please refer to + * Documentation/workqueue.txt. + */ enum { WQ_NON_REENTRANT = 1 << 0, /* guarantee non-reentrance */ WQ_UNBOUND = 1 << 1, /* not bound to any cpu */ diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 727f24e563ae..f77afd939229 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1,19 +1,26 @@ /* - * linux/kernel/workqueue.c + * kernel/workqueue.c - generic async execution with shared worker pool * - * Generic mechanism for defining kernel helper threads for running - * arbitrary tasks in process context. + * Copyright (C) 2002 Ingo Molnar * - * Started by Ingo Molnar, Copyright (C) 2002 + * Derived from the taskqueue/keventd code by: + * David Woodhouse + * Andrew Morton + * Kai Petzke + * Theodore Ts'o * - * Derived from the taskqueue/keventd code by: + * Made to use alloc_percpu by Christoph Lameter. * - * David Woodhouse - * Andrew Morton - * Kai Petzke - * Theodore Ts'o + * Copyright (C) 2010 SUSE Linux Products GmbH + * Copyright (C) 2010 Tejun Heo * - * Made to use alloc_percpu by Christoph Lameter. + * This is the generic async execution mechanism. Work items as are + * executed in process context. The worker pool is shared and + * automatically managed. There is one worker pool for each CPU and + * one extra for works which are better served by workers which are + * not bound to any specific CPU. + * + * Please read Documentation/workqueue.txt for details. */ #include -- cgit v1.2.3-59-g8ed1b From 551402a30efa45560e23c22a7aa04453861602c3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 6 Sep 2010 23:53:47 +0100 Subject: drm: Fix regression in disable polling e58f637 I broke out my trusty i845 and found a new boot failure, which upon inspection turned out to be a recursion within: drm_helper_probe_single_connector_modes() -> drm_helper_hpd_irq_event() -> intel_crt_detect() -> drm_helper_probe_single_connector_modes() Calling drm_kms_helper_poll_enable() instead performs the desired re-initialisation of the polling should the user have toggled the parameter, without the recursive side-effect. Signed-off-by: Chris Wilson Cc: Dave Airlie Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index d2ab01e90a96..4238a19c36db 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -104,7 +104,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, connector->funcs->force(connector); } else { connector->status = connector->funcs->detect(connector); - drm_helper_hpd_irq_event(dev); + drm_kms_helper_poll_enable(dev); } if (connector->status == connector_status_disconnected) { -- cgit v1.2.3-59-g8ed1b From ff32a59daea4f3eae980ae8d0932b135c633ec5d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 7 Sep 2010 13:26:39 -0400 Subject: drm/radeon/kms: fix regression in RMX code (v2) caused by d65d65b175a29bd7ea2bb69c046419329c4a5db7 need to update the radeon crtc priv native mode before using it. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=30049 v2: integrate v/h copy paste typo Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 6dd434ad2429..8c987c9923ed 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1140,14 +1140,14 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, radeon_crtc->rmx_type = radeon_encoder->rmx_type; else radeon_crtc->rmx_type = RMX_OFF; - src_v = crtc->mode.vdisplay; - dst_v = radeon_crtc->native_mode.vdisplay; - src_h = crtc->mode.hdisplay; - dst_h = radeon_crtc->native_mode.vdisplay; /* copy native mode */ memcpy(&radeon_crtc->native_mode, &radeon_encoder->native_mode, sizeof(struct drm_display_mode)); + src_v = crtc->mode.vdisplay; + dst_v = radeon_crtc->native_mode.vdisplay; + src_h = crtc->mode.hdisplay; + dst_h = radeon_crtc->native_mode.hdisplay; /* fix up for overscan on hdmi */ if (ASIC_IS_AVIVO(rdev) && -- cgit v1.2.3-59-g8ed1b From aa74fbb4c905c6c746b79d4d7d8c95d8bbd4360c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 7 Sep 2010 14:41:30 -0400 Subject: drm/radeon/kms: add connector table for Mac x800 Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=28671 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 47 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_mode.h | 3 ++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index bd74e428bd14..a04b7a6ad95f 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -1485,6 +1485,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) /* PowerMac8,1 ? */ /* imac g5 isight */ rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT; + } else if ((rdev->pdev->device == 0x4a48) && + (rdev->pdev->subsystem_vendor == 0x1002) && + (rdev->pdev->subsystem_device == 0x4a48)) { + /* Mac X800 */ + rdev->mode_info.connector_table = CT_MAC_X800; } else #endif /* CONFIG_PPC_PMAC */ #ifdef CONFIG_PPC64 @@ -1961,6 +1966,48 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) CONNECTOR_OBJECT_ID_VGA, &hpd); break; + case CT_MAC_X800: + DRM_INFO("Connector Table: %d (mac x800)\n", + rdev->mode_info.connector_table); + /* DVI - primary dac, internal tmds */ + ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0); + hpd.hpd = RADEON_HPD_1; /* ??? */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_DFP1_SUPPORT, + 0), + ATOM_DEVICE_DFP1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_CRT1_SUPPORT, + 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_connector(dev, 0, + ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_CRT1_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c, + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I, + &hpd); + /* DVI - tv dac, dvo */ + ddc_i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0); + hpd.hpd = RADEON_HPD_2; /* ??? */ + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_DFP2_SUPPORT, + 0), + ATOM_DEVICE_DFP2_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_CRT2_SUPPORT, + 2), + ATOM_DEVICE_CRT2_SUPPORT); + radeon_add_legacy_connector(dev, 1, + ATOM_DEVICE_DFP2_SUPPORT | + ATOM_DEVICE_CRT2_SUPPORT, + DRM_MODE_CONNECTOR_DVII, &ddc_i2c, + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I, + &hpd); + break; default: DRM_INFO("Connector table: %d (invalid)\n", rdev->mode_info.connector_table); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index efbe975312dc..17a6602b5885 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -204,7 +204,7 @@ struct radeon_i2c_chan { /* mostly for macs, but really any system without connector tables */ enum radeon_connector_table { - CT_NONE, + CT_NONE = 0, CT_GENERIC, CT_IBOOK, CT_POWERBOOK_EXTERNAL, @@ -215,6 +215,7 @@ enum radeon_connector_table { CT_IMAC_G5_ISIGHT, CT_EMAC, CT_RN50_POWER, + CT_MAC_X800, }; enum radeon_dvo_chip { -- cgit v1.2.3-59-g8ed1b From e6db0da02ea753968d15ae3e835059c207647e78 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 10 Sep 2010 03:19:05 -0400 Subject: drm/radeon/kms: don't enable underscan with interlaced modes They aren't compatible. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 8c987c9923ed..127a395f70fb 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1151,6 +1151,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, /* fix up for overscan on hdmi */ if (ASIC_IS_AVIVO(rdev) && + (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) && ((radeon_encoder->underscan_type == UNDERSCAN_ON) || ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && drm_detect_hdmi_monitor(radeon_connector->edid) && -- cgit v1.2.3-59-g8ed1b From 356ad3cd616185631235ffb48b3efbf39f9923b3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 09:41:32 +0100 Subject: drm: Only decouple the old_fb from the crtc is we call mode_set* Otherwise when disabling the output we switch to the new fb (which is likely NULL) and skip the call to mode_set -- leaking driver private state on the old_fb. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29857 Reported-by: Sitsofe Wheeler Signed-off-by: Chris Wilson Cc: Dave Airlie Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 4238a19c36db..de152a58967d 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -637,13 +637,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) mode_changed = true; if (mode_changed) { - old_fb = set->crtc->fb; - set->crtc->fb = set->fb; set->crtc->enabled = (set->mode != NULL); if (set->mode != NULL) { DRM_DEBUG_KMS("attempting to set mode from" " userspace\n"); drm_mode_debug_printmodeline(set->mode); + old_fb = set->crtc->fb; + set->crtc->fb = set->fb; if (!drm_crtc_helper_set_mode(set->crtc, set->mode, set->x, set->y, old_fb)) { -- cgit v1.2.3-59-g8ed1b From 27849044ca6ff9c52f63271b511282acf6d1c251 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 9 Sep 2010 11:31:13 -0400 Subject: drm/radeon: add some missing copyright headers Noticed while adding evergreen blit support. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_blit_kms.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/radeon/r600_blit_shaders.h | 24 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index d13622ae74e9..9ceb2a1ce799 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -1,3 +1,28 @@ +/* + * Copyright 2009 Advanced Micro Devices, Inc. + * Copyright 2009 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + #include "drmP.h" #include "drm.h" #include "radeon_drm.h" diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.h b/drivers/gpu/drm/radeon/r600_blit_shaders.h index fdc3b378cbb0..f437d36dd98c 100644 --- a/drivers/gpu/drm/radeon/r600_blit_shaders.h +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.h @@ -1,3 +1,27 @@ +/* + * Copyright 2009 Advanced Micro Devices, Inc. + * Copyright 2009 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ #ifndef R600_BLIT_SHADERS_H #define R600_BLIT_SHADERS_H -- cgit v1.2.3-59-g8ed1b From 7b334fcb45b757ffb093696ca3de1b0c8b4a33f1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 9 Sep 2010 23:51:02 +0100 Subject: drm: Use a nondestructive mode for output detect when polling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Destructive load-detection is very expensive and due to failings elsewhere can trigger system wide stalls of up to 600ms. A simple first step to correcting this is not to invoke such an expensive and destructive load-detection operation automatically. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=29536 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=16265 Reported-by: Bruno Prémont Tested-by: Sitsofe Wheeler Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 4 ++-- drivers/gpu/drm/drm_sysfs.c | 2 +- drivers/gpu/drm/i915/intel_crt.c | 7 ++++++- drivers/gpu/drm/i915/intel_dp.c | 3 ++- drivers/gpu/drm/i915/intel_dvo.c | 4 +++- drivers/gpu/drm/i915/intel_hdmi.c | 3 ++- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++-- drivers/gpu/drm/i915/intel_sdvo.c | 6 ++++-- drivers/gpu/drm/i915/intel_tv.c | 12 ++++++------ drivers/gpu/drm/nouveau/nouveau_connector.c | 8 +++++--- drivers/gpu/drm/radeon/radeon_connectors.c | 20 +++++++++++++++----- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 3 ++- include/drm/drm_crtc.h | 3 ++- 13 files changed, 56 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index de152a58967d..fb6b70fc6572 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -103,7 +103,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (connector->funcs->force) connector->funcs->force(connector); } else { - connector->status = connector->funcs->detect(connector); + connector->status = connector->funcs->detect(connector, false); drm_kms_helper_poll_enable(dev); } @@ -866,7 +866,7 @@ static void output_poll_execute(struct work_struct *work) !(connector->polled & DRM_CONNECTOR_POLL_HPD)) continue; - status = connector->funcs->detect(connector); + status = connector->funcs->detect(connector, true); if (old_status != status) changed = true; } diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 86118a742231..85da4c40694c 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -159,7 +159,7 @@ static ssize_t status_show(struct device *device, struct drm_connector *connector = to_drm_connector(device); enum drm_connector_status status; - status = connector->funcs->detect(connector); + status = connector->funcs->detect(connector, true); return snprintf(buf, PAGE_SIZE, "%s\n", drm_get_connector_status_name(status)); } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 4b7735196cd5..0350e5d711f8 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -400,7 +400,9 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder return status; } -static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) +static enum drm_connector_status +intel_crt_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_device *dev = connector->dev; struct drm_encoder *encoder = intel_attached_encoder(connector); @@ -419,6 +421,9 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto if (intel_crt_detect_ddc(encoder)) return connector_status_connected; + if (nondestructive) + return connector->status; + /* for pre-945g platforms use load detect */ if (encoder->crtc && encoder->crtc->enabled) { status = intel_crt_load_detect(encoder->crtc, intel_encoder); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 51d142939a26..e1a2a05fb838 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1386,7 +1386,8 @@ ironlake_dp_detect(struct drm_connector *connector) * \return false if DP port is disconnected. */ static enum drm_connector_status -intel_dp_detect(struct drm_connector *connector) +intel_dp_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index a399f4b2c1c5..f0de1addf8a4 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -221,7 +221,9 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, * * Unimplemented. */ -static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) +static enum drm_connector_status +intel_dvo_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ccd4c97e6524..2ea123d8d22b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -139,7 +139,8 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, } static enum drm_connector_status -intel_hdmi_detect(struct drm_connector *connector) +intel_hdmi_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 4fbb0165b26f..fb1bed8f4071 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -445,7 +445,9 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * connected and closed means disconnected. We also send hotplug events as * needed, using lid status notification from the input layer. */ -static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector) +static enum drm_connector_status +intel_lvds_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_device *dev = connector->dev; enum drm_connector_status status = connector_status_connected; @@ -540,7 +542,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, * the LID nofication event. */ if (connector) - connector->status = connector->funcs->detect(connector); + connector->status = connector->funcs->detect(connector, + true); + /* Don't force modeset on machines where it causes a GPU lockup */ if (dmi_check_system(intel_no_modeset_on_lid)) return NOTIFY_OK; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index e3b7a7ee39cb..db6b6d4b8fae 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1417,7 +1417,7 @@ intel_analog_is_connected(struct drm_device *dev) if (!analog_connector) return false; - if (analog_connector->funcs->detect(analog_connector) == + if (analog_connector->funcs->detect(analog_connector, true) == connector_status_disconnected) return false; @@ -1486,7 +1486,9 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) return status; } -static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) +static enum drm_connector_status +intel_sdvo_detect(struct drm_connector *connector, + bool nondestructive) { uint16_t response; struct drm_encoder *encoder = intel_attached_encoder(connector); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index c671f60ce80b..d20b550c0f55 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1341,7 +1341,8 @@ static void intel_tv_find_better_format(struct drm_connector *connector) * we have a pipe programmed in order to probe the TV. */ static enum drm_connector_status -intel_tv_detect(struct drm_connector *connector) +intel_tv_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_display_mode mode; struct drm_encoder *encoder = intel_attached_encoder(connector); @@ -1353,7 +1354,7 @@ intel_tv_detect(struct drm_connector *connector) if (encoder->crtc && encoder->crtc->enabled) { type = intel_tv_detect_type(intel_tv); - } else { + } else if (nondestructive) { struct drm_crtc *crtc; int dpms_mode; @@ -1364,10 +1365,9 @@ intel_tv_detect(struct drm_connector *connector) intel_release_load_detect_pipe(&intel_tv->base, connector, dpms_mode); } else - type = -1; - } - - intel_tv->type = type; + return connector_status_unknown; + } else + return connector->status; if (type < 0) return connector_status_disconnected; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index a1473fff06ac..67d515cb67e0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -168,7 +168,8 @@ nouveau_connector_set_encoder(struct drm_connector *connector, } static enum drm_connector_status -nouveau_connector_detect(struct drm_connector *connector) +nouveau_connector_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_device *dev = connector->dev; struct nouveau_connector *nv_connector = nouveau_connector(connector); @@ -246,7 +247,8 @@ detect_analog: } static enum drm_connector_status -nouveau_connector_detect_lvds(struct drm_connector *connector) +nouveau_connector_detect_lvds(struct drm_connector *connector, + bool nondestructive) { struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -267,7 +269,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector) /* Try retrieving EDID via DDC */ if (!dev_priv->vbios.fp_no_ddc) { - status = nouveau_connector_detect(connector); + status = nouveau_connector_detect(connector, nondestructive); if (status == connector_status_connected) goto out; } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index a9dd7847d96e..31d309a8e75b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -481,7 +481,9 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, return MODE_OK; } -static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) +static enum drm_connector_status +radeon_lvds_detect(struct drm_connector *connector, + bool nondestructive) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector); @@ -594,7 +596,9 @@ static int radeon_vga_mode_valid(struct drm_connector *connector, return MODE_OK; } -static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector) +static enum drm_connector_status +radeon_vga_detect(struct drm_connector *connector, + bool nondestructive) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; @@ -691,7 +695,9 @@ static int radeon_tv_mode_valid(struct drm_connector *connector, return MODE_OK; } -static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector) +static enum drm_connector_status +radeon_tv_detect(struct drm_connector *connector, + bool nondestructive) { struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; @@ -748,7 +754,9 @@ static int radeon_dvi_get_modes(struct drm_connector *connector) * we have to check if this analog encoder is shared with anyone else (TV) * if its shared we have to set the other connector to disconnected. */ -static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) +static enum drm_connector_status +radeon_dvi_detect(struct drm_connector *connector, + bool nondestructive) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = NULL; @@ -972,7 +980,9 @@ static int radeon_dp_get_modes(struct drm_connector *connector) return ret; } -static enum drm_connector_status radeon_dp_detect(struct drm_connector *connector) +static enum drm_connector_status +radeon_dp_detect(struct drm_connector *connector, + bool nondestructive) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); enum drm_connector_status ret = connector_status_disconnected; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 2ff5cf78235f..a527c91c0ba6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -335,7 +335,8 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector) } static enum drm_connector_status - vmw_ldu_connector_detect(struct drm_connector *connector) + vmw_ldu_connector_detect(struct drm_connector *connector, + bool nondestructive) { if (vmw_connector_to_ldu(connector)->pref_active) return connector_status_connected; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c9f3cc5949a8..5536223fbac8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -386,7 +386,8 @@ struct drm_connector_funcs { void (*dpms)(struct drm_connector *connector, int mode); void (*save)(struct drm_connector *connector); void (*restore)(struct drm_connector *connector); - enum drm_connector_status (*detect)(struct drm_connector *connector); + enum drm_connector_status (*detect)(struct drm_connector *connector, + bool nondestructive); int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); int (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t val); -- cgit v1.2.3-59-g8ed1b From b741be82cf2079f71553af595610f17a3a3a752a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 9 Sep 2010 19:15:23 -0400 Subject: drm/radeon/kms/evergreen: fix backend setup This patch fixes rendering errors on some evergreen boards. Hardcoding the backend map is not an optimal solution, but a better fix is being worked on. Similar to the fix for rv740 (6271901d828b34b27607314026deaf417f9f9b75). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=29986 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index b8b7f010b25f..79082d4398ae 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1160,14 +1160,25 @@ static void evergreen_gpu_init(struct radeon_device *rdev) EVERGREEN_MAX_BACKENDS_MASK)); break; } - } else - gb_backend_map = - evergreen_get_tile_pipe_to_backend_map(rdev, - rdev->config.evergreen.max_tile_pipes, - rdev->config.evergreen.max_backends, - ((EVERGREEN_MAX_BACKENDS_MASK << - rdev->config.evergreen.max_backends) & - EVERGREEN_MAX_BACKENDS_MASK)); + } else { + switch (rdev->family) { + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + gb_backend_map = 0x66442200; + break; + case CHIP_JUNIPER: + gb_backend_map = 0x00006420; + break; + default: + gb_backend_map = + evergreen_get_tile_pipe_to_backend_map(rdev, + rdev->config.evergreen.max_tile_pipes, + rdev->config.evergreen.max_backends, + ((EVERGREEN_MAX_BACKENDS_MASK << + rdev->config.evergreen.max_backends) & + EVERGREEN_MAX_BACKENDS_MASK)); + } + } rdev->config.evergreen.tile_config = gb_addr_config; WREG32(GB_BACKEND_MAP, gb_backend_map); -- cgit v1.2.3-59-g8ed1b From ec00efb72f4b88078427d01f38f664c67c7ca0c0 Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Sun, 12 Sep 2010 05:09:12 +0200 Subject: drm/radeon/kms: increase lockup detection interval to 10 sec for r100-r500 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One subtest of mesa/demos/gltestperf takes 9 seconds to complete, so to prevent an unnecessary gpu reset followed by a hardlock, I am increasing the interval to 10 seconds after which a GPU is considered in a locked-up state. This is on RV530. However, with a little slower GPU, we would surpass the interval easily, so this is not a good fix for gltestperf. Nevertheless, this commit also fixes hardlocks in the applications which render at speed of less than 1 frame per second, where the whole frame consists of only one command stream. The game Tiny & Big is an example. This bar is now lowered to 0.1 fps. Now the question comes down to whether we should (often unsuccessfully) reset the GPU at all? Once we have stable enough drivers, we won't have to. Has the time come already? If possible, this commit should go to stable as well. Signed-off-by: Marek Olšák Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index e817a0bb5eb4..ec64b365ee1f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2020,18 +2020,7 @@ bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *l return false; } elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies); - if (elapsed >= 3000) { - /* very likely the improbable case where current - * rptr is equal to last recorded, a while ago, rptr - * this is more likely a false positive update tracking - * information which should force us to be recall at - * latter point - */ - lockup->last_cp_rptr = cp->rptr; - lockup->last_jiffies = jiffies; - return false; - } - if (elapsed >= 1000) { + if (elapsed >= 10000) { dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); return true; } -- cgit v1.2.3-59-g8ed1b From a41ceb1c17af06a17c0d88e987215ef20b93c471 Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Sun, 12 Sep 2010 05:09:13 +0200 Subject: drm/radeon/kms: fix the colorbuffer CS checker for r300-r500 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes bogus CS rejection if it contains a sequence of the following operations: - Set the color buffer 0. track->cb[i].robj becomes non-NULL. - Render. - Set a larger zbuffer than the previously-set color buffer. - Set a larger scissor area as well. - Set the color channel mask to 0 to do depth-only rendering. - Render. --> rejected, because track->cb[i].robj remained non-NULL, therefore the conditional checking for the color channel mask and friends is not performed, and the larger scissor area causes the rejection. This fixes bugs: - https://bugs.freedesktop.org/show_bug.cgi?id=29762 - https://bugs.freedesktop.org/show_bug.cgi?id=28869 And maybe some others which seem to look the same. If possible, this commit should go to stable as well. Signed-off-by: Marek Olšák Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index ec64b365ee1f..e151f16a8f86 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3297,13 +3297,14 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track) unsigned long size; unsigned prim_walk; unsigned nverts; + unsigned num_cb = track->num_cb; - for (i = 0; i < track->num_cb; i++) { + if (!track->zb_cb_clear && !track->color_channel_mask && + !track->blend_read_enable) + num_cb = 0; + + for (i = 0; i < num_cb; i++) { if (track->cb[i].robj == NULL) { - if (!(track->zb_cb_clear || track->color_channel_mask || - track->blend_read_enable)) { - continue; - } DRM_ERROR("[drm] No buffer for color buffer %d !\n", i); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 2ca9cac965e81da4b74f2dcec4b87ebfd106b357 Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Fri, 10 Sep 2010 15:47:55 +0200 Subject: ALSA: hda - Add quirk for Toshiba C650D using a Conexant CX20585 Add a quirk for laptop Toshiba Satellite C650D to have proper external HP and external Mic support. Signed-off-by: Anisse Astier Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 71f9d6475b09..972e7c453b3d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3092,6 +3092,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), + SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), -- cgit v1.2.3-59-g8ed1b From 62b2be591a9b12c550308ef7718a31abfc815b50 Mon Sep 17 00:00:00 2001 From: Latchesar Ionkov Date: Tue, 24 Aug 2010 18:13:59 +0000 Subject: fs/9p, net/9p: memory leak fixes Four memory leak fixes in the 9P code. Signed-off-by: Latchesar Ionkov Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 2 ++ net/9p/client.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index c7c23eab9440..84159cf9c521 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1128,6 +1128,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); generic_fillattr(dentry->d_inode, stat); + p9stat_free(st); kfree(st); return 0; } @@ -1489,6 +1490,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) retval = strnlen(buffer, buflen); done: + p9stat_free(st); kfree(st); return retval; } diff --git a/net/9p/client.c b/net/9p/client.c index dc6f2f26d023..9eb72505308f 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -331,8 +331,10 @@ static void p9_tag_cleanup(struct p9_client *c) } } - if (c->tagpool) + if (c->tagpool) { + p9_idpool_put(0, c->tagpool); /* free reserved tag 0 */ p9_idpool_destroy(c->tagpool); + } /* free requests associated with tags */ for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) { @@ -944,6 +946,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, int16_t nwqids, count; err = 0; + wqids = NULL; clnt = oldfid->clnt; if (clone) { fid = p9_fid_create(clnt); @@ -994,9 +997,11 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, else fid->qid = oldfid->qid; + kfree(wqids); return fid; clunk_fid: + kfree(wqids); p9_client_clunk(fid); fid = NULL; -- cgit v1.2.3-59-g8ed1b From 5c25f347a7b00b2ebe0a55c4a3cfe4c3e1e8725e Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 24 Aug 2010 10:30:49 +0000 Subject: fs/9p: Fix error handling in v9fs_get_sb This was introduced by 7cadb63d58a932041afa3f957d5cbb6ce69dcee5 Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_super.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index f9311077de68..1d12ba0ed3db 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -122,6 +122,10 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, fid = v9fs_session_init(v9ses, dev_name, data); if (IS_ERR(fid)) { retval = PTR_ERR(fid); + /* + * we need to call session_close to tear down some + * of the data structure setup by session_init + */ goto close_session; } @@ -144,7 +148,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, retval = -ENOMEM; goto release_sb; } - sb->s_root = root; if (v9fs_proto_dotl(v9ses)) { @@ -152,7 +155,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); if (IS_ERR(st)) { retval = PTR_ERR(st); - goto clunk_fid; + goto release_sb; } v9fs_stat2inode_dotl(st, root->d_inode); @@ -162,7 +165,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, st = p9_client_stat(fid); if (IS_ERR(st)) { retval = PTR_ERR(st); - goto clunk_fid; + goto release_sb; } root->d_inode->i_ino = v9fs_qid2ino(&st->qid); @@ -174,19 +177,24 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, v9fs_fid_add(root, fid); -P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); + P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); simple_set_mnt(mnt, sb); return 0; clunk_fid: p9_client_clunk(fid); - close_session: v9fs_session_close(v9ses); kfree(v9ses); return retval; - release_sb: + /* + * we will do the session_close and root dentry release + * in the below call. But we need to clunk fid, because we haven't + * attached the fid to dentry so it won't get clunked + * automatically. + */ + p9_client_clunk(fid); deactivate_locked_super(sb); return retval; } -- cgit v1.2.3-59-g8ed1b From 62726a7ab3a6a3624256172af055ff0a38c6ffa2 Mon Sep 17 00:00:00 2001 From: jvrao Date: Wed, 25 Aug 2010 16:26:21 +0000 Subject: 9p: Check for NULL fid in v9fs_dir_release() NULL fid should be handled in cases where we endup calling v9fs_dir_release() before even we instantiate the fid in filp. Signed-off-by: Venkateswararao Jujjuri Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_dir.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 16c8a2a98c1b..899f168fd19c 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -292,9 +292,11 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) fid = filp->private_data; P9_DPRINTK(P9_DEBUG_VFS, - "inode: %p filp: %p fid: %d\n", inode, filp, fid->fid); + "v9fs_dir_release: inode: %p filp: %p fid: %d\n", + inode, filp, fid ? fid->fid : -1); filemap_write_and_wait(inode->i_mapping); - p9_client_clunk(fid); + if (fid) + p9_client_clunk(fid); return 0; } -- cgit v1.2.3-59-g8ed1b From 3c30750ffafbc32af040b09f777b67aa2486b063 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 30 Aug 2010 16:04:35 +0000 Subject: fs/9p: Use the correct dentry operations We should use the cached dentry operation only if caching mode is enabled Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 84159cf9c521..a6990bbf6056 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -730,7 +730,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); goto error; } - dentry->d_op = &v9fs_cached_dentry_operations; + if (v9ses->cache) + dentry->d_op = &v9fs_cached_dentry_operations; + else + dentry->d_op = &v9fs_dentry_operations; d_instantiate(dentry, inode); err = v9fs_fid_add(dentry, fid); if (err < 0) -- cgit v1.2.3-59-g8ed1b From 1d76e3135733a06aa12bb35891c05f306b27b2d6 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Mon, 30 Aug 2010 17:43:07 +0000 Subject: fs/9p: Don't use dotl version of mknod for dotu inode operations We should not use dotlversion for the dotu inode operations Signed-off-by: Aneesh Kumar K.V Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index a6990bbf6056..9e670d527646 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1947,7 +1947,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { .unlink = v9fs_vfs_unlink, .mkdir = v9fs_vfs_mkdir, .rmdir = v9fs_vfs_rmdir, - .mknod = v9fs_vfs_mknod_dotl, + .mknod = v9fs_vfs_mknod, .rename = v9fs_vfs_rename, .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr, -- cgit v1.2.3-59-g8ed1b From 0bf377bbb0bea6130f35613491887cc622e42a8b Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 12 Sep 2010 08:14:52 +0200 Subject: sched: Improve latencies under load by decreasing minimum scheduling granularity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mathieu reported bad latencies with make -j10 kind of kbuild workloads - which is mostly caused by us scheduling with a too coarse granularity. Reduce the minimum granularity some more, to make sure we can meet the latency target. I got the following results (make -j10 kbuild load, average of 3 runs): vanilla: maximum latency: 38278.9 µs average latency: 7730.1 µs patched: maximum latency: 22702.1 µs average latency: 6684.8 µs Mathieu also measured it: | | * wakeup-latency.c (SIGEV_THREAD) with make -j10 | | - Mainline 2.6.35.2 kernel | | maximum latency: 45762.1 µs | average latency: 7348.6 µs | | - With only Peter's smaller min_gran (shown below): | | maximum latency: 29100.6 µs | average latency: 6684.1 µs | Reported-by: Mathieu Desnoyers Reported-by: Linus Torvalds Acked-by: Mathieu Desnoyers Suggested-by: Peter Zijlstra Acked-by: Peter Zijlstra LKML-Reference: Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 9b5b4f86b742..a171138a9402 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -54,13 +54,13 @@ enum sched_tunable_scaling sysctl_sched_tunable_scaling * Minimal preemption granularity for CPU-bound tasks: * (default: 2 msec * (1 + ilog(ncpus)), units: nanoseconds) */ -unsigned int sysctl_sched_min_granularity = 2000000ULL; -unsigned int normalized_sysctl_sched_min_granularity = 2000000ULL; +unsigned int sysctl_sched_min_granularity = 750000ULL; +unsigned int normalized_sysctl_sched_min_granularity = 750000ULL; /* * is kept at sysctl_sched_latency / sysctl_sched_min_granularity */ -static unsigned int sched_nr_latency = 3; +static unsigned int sched_nr_latency = 8; /* * After fork, child runs first. If set to 0 (default) then -- cgit v1.2.3-59-g8ed1b From edc805b7c5e45c3d7202cea5239985d204178e24 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 16 Aug 2010 14:05:20 +0200 Subject: m68k,m68knommu: Wire up fanotify_init, fanotify_mark, and prlimit64 Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer --- arch/m68k/include/asm/unistd.h | 5 ++++- arch/m68k/kernel/entry.S | 3 +++ arch/m68knommu/kernel/syscalltable.S | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 60b15d0aa072..b43b36beafe3 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -340,10 +340,13 @@ #define __NR_set_thread_area 334 #define __NR_atomic_cmpxchg_32 335 #define __NR_atomic_barrier 336 +#define __NR_fanotify_init 337 +#define __NR_fanotify_mark 338 +#define __NR_prlimit64 339 #ifdef __KERNEL__ -#define NR_syscalls 337 +#define NR_syscalls 340 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 2391bdff0996..6360c437dcf5 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -765,4 +765,7 @@ sys_call_table: .long sys_set_thread_area .long sys_atomic_cmpxchg_32 /* 335 */ .long sys_atomic_barrier + .long sys_fanotify_init + .long sys_fanotify_mark + .long sys_prlimit64 diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S index b30b3eb197a5..79b1ed198c07 100644 --- a/arch/m68knommu/kernel/syscalltable.S +++ b/arch/m68knommu/kernel/syscalltable.S @@ -355,6 +355,9 @@ ENTRY(sys_call_table) .long sys_set_thread_area .long sys_atomic_cmpxchg_32 /* 335 */ .long sys_atomic_barrier + .long sys_fanotify_init + .long sys_fanotify_mark + .long sys_prlimit64 .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall -- cgit v1.2.3-59-g8ed1b From 467c525109d5d542d7d416b0c11bdd54610fe2f4 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Mon, 13 Sep 2010 11:39:20 -0700 Subject: ceph: fix dn offset during readdir_prepopulate When adding the readdir results to the cache, ceph_set_dentry_offset was clobbered our just-set offset. This can cause the readdir result offsets to get out of sync with the server. Add an argument to the helper so that it does not. This bug was introduced by 1cd3935bedccf592d44343890251452a6dd74fc4. Signed-off-by: Sage Weil --- fs/ceph/inode.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index e7cca414da03..62377ec37edf 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -845,7 +845,7 @@ static void ceph_set_dentry_offset(struct dentry *dn) * the caller) if we fail. */ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, - bool *prehash) + bool *prehash, bool set_offset) { struct dentry *realdn; @@ -877,7 +877,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, } if ((!prehash || *prehash) && d_unhashed(dn)) d_rehash(dn); - ceph_set_dentry_offset(dn); + if (set_offset) + ceph_set_dentry_offset(dn); out: return dn; } @@ -1062,7 +1063,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, d_delete(dn); goto done; } - dn = splice_dentry(dn, in, &have_lease); + dn = splice_dentry(dn, in, &have_lease, true); if (IS_ERR(dn)) { err = PTR_ERR(dn); goto done; @@ -1105,7 +1106,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, goto done; } dout(" linking snapped dir %p to dn %p\n", in, dn); - dn = splice_dentry(dn, in, NULL); + dn = splice_dentry(dn, in, NULL, true); if (IS_ERR(dn)) { err = PTR_ERR(dn); goto done; @@ -1237,7 +1238,7 @@ retry_lookup: err = PTR_ERR(in); goto out; } - dn = splice_dentry(dn, in, NULL); + dn = splice_dentry(dn, in, NULL, false); if (IS_ERR(dn)) dn = NULL; } -- cgit v1.2.3-59-g8ed1b From 05ed160e89baf7f5fb3432d527fec467d2493626 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Mon, 13 Sep 2010 19:25:41 +0900 Subject: kprobes: Fix Kconfig dependency Fix Kconfig dependency among Kprobes, optprobe and kallsyms. Kprobes uses kallsyms_lookup for finding target function and checking instruction boundary, thus CONFIG_KPROBES should select CONFIG_KALLSYMS. Optprobe is an optional feature which is supported on x86 arch, and it also uses kallsyms_lookup for checking instructions in the target function. Since KALLSYMS_ALL just adds symbols of kernel variables, it doesn't need to select KALLSYMS_ALL. Signed-off-by: Masami Hiramatsu Acked-by: Randy Dunlap , Cc: Ananth N Mavinakayanahalli Cc: Felipe Contreras Cc: Randy Dunlap Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Cc: David S. Miller Cc: akpm LKML-Reference: <20100913102541.20260.85700.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Ingo Molnar --- arch/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 4877a8c8ee16..fe48fc7a3eba 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -32,8 +32,9 @@ config HAVE_OPROFILE config KPROBES bool "Kprobes" - depends on KALLSYMS && MODULES + depends on MODULES depends on HAVE_KPROBES + select KALLSYMS help Kprobes allows you to trap at almost any kernel address and execute a callback function. register_kprobe() establishes @@ -45,7 +46,6 @@ config OPTPROBES def_bool y depends on KPROBES && HAVE_OPTPROBES depends on !PREEMPT - select KALLSYMS_ALL config HAVE_EFFICIENT_UNALIGNED_ACCESS bool -- cgit v1.2.3-59-g8ed1b From 339db11b219f36cf7da61b390992d95bb6b7ba2e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 10 Sep 2010 01:56:16 +0000 Subject: net/llc: make opt unsigned in llc_ui_setsockopt() The members of struct llc_sock are unsigned so if we pass a negative value for "opt" it can cause a sign bug. Also it can cause an integer overflow when we multiply "opt * HZ". CC: stable@kernel.org Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/llc/af_llc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 023ba820236f..582612998211 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -1024,7 +1024,8 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, { struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); - int rc = -EINVAL, opt; + unsigned int opt; + int rc = -EINVAL; lock_sock(sk); if (unlikely(level != SOL_LLC || optlen != sizeof(int))) -- cgit v1.2.3-59-g8ed1b From 3429769bc67c7a48b3c01b2452b32171b3450202 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 10 Sep 2010 01:58:10 +0000 Subject: ppp: potential NULL dereference in ppp_mp_explode() Smatch complains because we check whether "pch->chan" is NULL and then dereference it unconditionally on the next line. Partly the reason this bug was introduced is because code was too complicated. I've simplified it a little. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ppp_generic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 6695a51e09e9..736b91703b3e 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1314,8 +1314,13 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; i = 0; list_for_each_entry(pch, &ppp->channels, clist) { - navail += pch->avail = (pch->chan != NULL); - pch->speed = pch->chan->speed; + if (pch->chan) { + pch->avail = 1; + navail++; + pch->speed = pch->chan->speed; + } else { + pch->avail = 0; + } if (pch->avail) { if (skb_queue_empty(&pch->file.xq) || !pch->had_frag) { -- cgit v1.2.3-59-g8ed1b From 7998156344b0d93de61ff8e5d75e96500e43a571 Mon Sep 17 00:00:00 2001 From: Bob Arendt Date: Mon, 13 Sep 2010 12:56:03 -0700 Subject: ipv4: force_igmp_version ignored when a IGMPv3 query received After all these years, it turns out that the /proc/sys/net/ipv4/conf/*/force_igmp_version parameter isn't fully implemented. *Symptom*: When set force_igmp_version to a value of 2, the kernel should only perform multicast IGMPv2 operations (IETF rfc2236). An host-initiated Join message will be sent as a IGMPv2 Join message. But if a IGMPv3 query message is received, the host responds with a IGMPv3 join message. Per rfc3376 and rfc2236, a IGMPv2 host should treat a IGMPv3 query as a IGMPv2 query and respond with an IGMPv2 Join message. *Consequences*: This is an issue when a IGMPv3 capable switch is the querier and will only issue IGMPv3 queries (which double as IGMPv2 querys) and there's an intermediate switch that is only IGMPv2 capable. The intermediate switch processes the initial v2 Join, but fails to recognize the IGMPv3 Join responses to the Query, resulting in a dropped connection when the intermediate v2-only switch times it out. *Identifying issue in the kernel source*: The issue is in this section of code (in net/ipv4/igmp.c), which is called when an IGMP query is received (from mainline 2.6.36-rc3 gitweb): ... A IGMPv3 query has a length >= 12 and no sources. This routine will exit after line 880, setting the general query timer (random timeout between 0 and query response time). This calls igmp_gq_timer_expire(): ... .. which only sends a v3 response. So if a v3 query is received, the kernel always sends a v3 response. IGMP queries happen once every 60 sec (per vlan), so the traffic is low. A IGMPv3 query *is* a strict superset of a IGMPv2 query, so this patch properly short circuit's the v3 behaviour. One issue is that this does not address force_igmp_version=1. Then again, I've never seen any IGMPv1 multicast equipment in the wild. However there is a lot of v2-only equipment. If it's necessary to support the IGMPv1 case as well: 837 if (len == 8 || IGMP_V2_SEEN(in_dev) || IGMP_V1_SEEN(in_dev)) { Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a1ad0e7180d2..1fdcacd36ce7 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -834,7 +834,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, int mark = 0; - if (len == 8) { + if (len == 8 || IGMP_V2_SEEN(in_dev)) { if (ih->code == 0) { /* Alas, old v1 router presents here. */ -- cgit v1.2.3-59-g8ed1b From 147fcf1c211f1a87bf4d0711b7e9637f3d6ce080 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 11 Sep 2010 22:10:59 -0700 Subject: sound: Remove pr_ uses of KERN_ Signed-off-by: Joe Perches Acked-by: Mark Brown Acked-by: Geoff Levand Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3.c | 2 +- sound/soc/s3c24xx/s3c-dma.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 2f12da4da561..581a670e8261 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -579,7 +579,7 @@ static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream, rate * delay_ms / 1000) * substream->runtime->channels; - pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n", + pr_debug("%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n", __func__, delay_ms, rate, diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c index 1b61c23ff300..f1b1bc4bacfb 100644 --- a/sound/soc/s3c24xx/s3c-dma.c +++ b/sound/soc/s3c24xx/s3c-dma.c @@ -94,8 +94,7 @@ static void s3c_dma_enqueue(struct snd_pcm_substream *substream) if ((pos + len) > prtd->dma_end) { len = prtd->dma_end - pos; - pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n", - __func__, len); + pr_debug("%s: corrected dma len %ld\n", __func__, len); } ret = s3c2410_dma_enqueue(prtd->params->channel, -- cgit v1.2.3-59-g8ed1b From 2fd818642a3c3a257f3b1262145a52bc1bfebd26 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 30 Aug 2010 09:45:40 +0900 Subject: x86, cpufeature: Suppress compiler warning with gcc 3.x Gcc 3.x generates a warning arch/x86/include/asm/cpufeature.h: In function `__static_cpu_has': arch/x86/include/asm/cpufeature.h:326: warning: asm operand 1 probably doesn't match constraints on each file. But static_cpu_has() for gcc 3.x does not need __static_cpu_has(). Signed-off-by: Tetsuo Handa LKML-Reference: <201008300127.o7U1RC6Z044051@www262.sakura.ne.jp> Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/cpufeature.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 781a50b29a49..c6fbb7b430d1 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -296,6 +296,7 @@ extern const char * const x86_power_flags[32]; #endif /* CONFIG_X86_64 */ +#if __GNUC__ >= 4 /* * Static testing of CPU features. Used the same as boot_cpu_has(). * These are only valid after alternatives have run, but will statically @@ -304,7 +305,7 @@ extern const char * const x86_power_flags[32]; */ static __always_inline __pure bool __static_cpu_has(u16 bit) { -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) +#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5 asm goto("1: jmp %l[t_no]\n" "2:\n" ".section .altinstructions,\"a\"\n" @@ -345,7 +346,6 @@ static __always_inline __pure bool __static_cpu_has(u16 bit) #endif } -#if __GNUC__ >= 4 #define static_cpu_has(bit) \ ( \ __builtin_constant_p(boot_cpu_has(bit)) ? \ -- cgit v1.2.3-59-g8ed1b From 08c2b394b98786ebb067e2a54d08f1f6f0d247da Mon Sep 17 00:00:00 2001 From: "basile@opensource.dyc.edu" Date: Mon, 13 Sep 2010 06:13:19 -0400 Subject: x86, build: Disable -fPIE when compiling with CONFIG_CC_STACKPROTECTOR=y The arch/x86/Makefile uses scripts/gcc-x86_$(BITS)-has-stack-protector.sh to check if cc1 supports -fstack-protector. When -fPIE is passed to cc1, these scripts fail causing stack protection to be disabled even when it is available. This fix is similar to commit c47efe5548abbf53c2f66e06dcb46183b11d6b22 Reported-by: Kai Dietrich Signed-off-by: Magnus Granberg LKML-Reference: <20100913101319.748A1148E216@opensource.dyc.edu> Signed-off-by: Anthony G. Basile Cc: Andrew Morton Signed-off-by: H. Peter Anvin --- arch/x86/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 8aa1b59b9074..e8c8881351b3 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -74,7 +74,7 @@ endif ifdef CONFIG_CC_STACKPROTECTOR cc_has_sp := $(srctree)/scripts/gcc-x86_$(BITS)-has-stack-protector.sh - ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC) $(biarch)),y) + ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y) stackp-y := -fstack-protector KBUILD_CFLAGS += $(stackp-y) else -- cgit v1.2.3-59-g8ed1b From a89b47639f3e11dd9a8eb78a5d3382e109c876f2 Mon Sep 17 00:00:00 2001 From: Michael Kerrisk Date: Fri, 10 Sep 2010 20:26:56 +0000 Subject: ipv4: enable getsockopt() for IP_NODEFRAG While integrating your man-pages patch for IP_NODEFRAG, I noticed that this option is settable by setsockopt(), but not gettable by getsockopt(). I suppose this is not intended. The (untested, trivial) patch below adds getsockopt() support. Signed-off-by: Michael kerrisk Acked-by: Jiri Olsa Signed-off-by: David S. Miller --- net/ipv4/ip_sockglue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 6c40a8c46e79..64b70ad162e3 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1129,6 +1129,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_HDRINCL: val = inet->hdrincl; break; + case IP_NODEFRAG: + val = inet->nodefrag; + break; case IP_MTU_DISCOVER: val = inet->pmtudisc; break; -- cgit v1.2.3-59-g8ed1b From dbee032295dac88742734ee9988e08a0e4f2f732 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 2 Sep 2010 11:28:39 +0000 Subject: ide: Fix ordering of procfs registry. We must ensure that ide_proc_port_register_devices() occurs on an interface before ide_proc_register_driver() executes for that interfaces drives. Therefore defer the registry of the driver device objects backed by ide_bus_type until after ide_proc_port_register_devices() has run and thus all of the drive->proc procfs directory pointers have been setup. Signed-off-by: Wolfram Sang Signed-off-by: David S. Miller --- drivers/ide/ide-probe.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 4c3d1bfec0c5..068cef0a987a 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1444,14 +1444,6 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_acpi_port_init_devices(hwif); } - ide_host_for_each_port(i, hwif, host) { - if (hwif == NULL) - continue; - - if (hwif->present) - hwif_register_devices(hwif); - } - ide_host_for_each_port(i, hwif, host) { if (hwif == NULL) continue; @@ -1459,8 +1451,10 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_sysfs_register_port(hwif); ide_proc_register_port(hwif); - if (hwif->present) + if (hwif->present) { ide_proc_port_register_devices(hwif); + hwif_register_devices(hwif); + } } return j ? 0 : -1; -- cgit v1.2.3-59-g8ed1b From 0fe7f885043ea0e3e026cc98cfd7f8715018c023 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 9 Sep 2010 21:29:52 +0900 Subject: ARM: S5P: Fix DMA coherent mask for FIMC FIMC driver uses DMA_coherent allocator, which requires proper dma mask to be set. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park [kgene.kim@samsung.com: minor title fix] Signed-off-by: Kukjin Kim --- arch/arm/plat-s5p/dev-fimc0.c | 7 +++++++ arch/arm/plat-s5p/dev-fimc1.c | 7 +++++++ arch/arm/plat-s5p/dev-fimc2.c | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/arch/arm/plat-s5p/dev-fimc0.c b/arch/arm/plat-s5p/dev-fimc0.c index d3f1a9b5d2b5..f9203fa8fe23 100644 --- a/arch/arm/plat-s5p/dev-fimc0.c +++ b/arch/arm/plat-s5p/dev-fimc0.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -28,9 +29,15 @@ static struct resource s5p_fimc0_resource[] = { }, }; +static u64 s5p_fimc0_dma_mask = DMA_BIT_MASK(32); + struct platform_device s5p_device_fimc0 = { .name = "s5p-fimc", .id = 0, .num_resources = ARRAY_SIZE(s5p_fimc0_resource), .resource = s5p_fimc0_resource, + .dev = { + .dma_mask = &s5p_fimc0_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, }; diff --git a/arch/arm/plat-s5p/dev-fimc1.c b/arch/arm/plat-s5p/dev-fimc1.c index 41bd6986d0ad..7ed91a34dd4a 100644 --- a/arch/arm/plat-s5p/dev-fimc1.c +++ b/arch/arm/plat-s5p/dev-fimc1.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -28,9 +29,15 @@ static struct resource s5p_fimc1_resource[] = { }, }; +static u64 s5p_fimc1_dma_mask = DMA_BIT_MASK(32); + struct platform_device s5p_device_fimc1 = { .name = "s5p-fimc", .id = 1, .num_resources = ARRAY_SIZE(s5p_fimc1_resource), .resource = s5p_fimc1_resource, + .dev = { + .dma_mask = &s5p_fimc1_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, }; diff --git a/arch/arm/plat-s5p/dev-fimc2.c b/arch/arm/plat-s5p/dev-fimc2.c index dfddeda6d4a3..5543d637396c 100644 --- a/arch/arm/plat-s5p/dev-fimc2.c +++ b/arch/arm/plat-s5p/dev-fimc2.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -28,9 +29,15 @@ static struct resource s5p_fimc2_resource[] = { }, }; +static u64 s5p_fimc2_dma_mask = DMA_BIT_MASK(32); + struct platform_device s5p_device_fimc2 = { .name = "s5p-fimc", .id = 2, .num_resources = ARRAY_SIZE(s5p_fimc2_resource), .resource = s5p_fimc2_resource, + .dev = { + .dma_mask = &s5p_fimc2_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, }; -- cgit v1.2.3-59-g8ed1b From 80e2f36aab7e69a193926814b73b3609c2f69f20 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 9 Sep 2010 21:31:46 +0900 Subject: ARM: S5P: Decrease IO Registers memory region size on FIMC IO registers region size of all FIMC versions is less than 1kB so there is no need to reserve 1M. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski [kgene.kim@samsung.com: minor title fix] Signed-off-by: Kukjin Kim --- arch/arm/plat-s5p/dev-fimc0.c | 2 +- arch/arm/plat-s5p/dev-fimc1.c | 2 +- arch/arm/plat-s5p/dev-fimc2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/plat-s5p/dev-fimc0.c b/arch/arm/plat-s5p/dev-fimc0.c index f9203fa8fe23..608770fc1531 100644 --- a/arch/arm/plat-s5p/dev-fimc0.c +++ b/arch/arm/plat-s5p/dev-fimc0.c @@ -19,7 +19,7 @@ static struct resource s5p_fimc0_resource[] = { [0] = { .start = S5P_PA_FIMC0, - .end = S5P_PA_FIMC0 + SZ_1M - 1, + .end = S5P_PA_FIMC0 + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/arm/plat-s5p/dev-fimc1.c b/arch/arm/plat-s5p/dev-fimc1.c index 7ed91a34dd4a..76e3a97a87d3 100644 --- a/arch/arm/plat-s5p/dev-fimc1.c +++ b/arch/arm/plat-s5p/dev-fimc1.c @@ -19,7 +19,7 @@ static struct resource s5p_fimc1_resource[] = { [0] = { .start = S5P_PA_FIMC1, - .end = S5P_PA_FIMC1 + SZ_1M - 1, + .end = S5P_PA_FIMC1 + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/arm/plat-s5p/dev-fimc2.c b/arch/arm/plat-s5p/dev-fimc2.c index 5543d637396c..24d29816fa2c 100644 --- a/arch/arm/plat-s5p/dev-fimc2.c +++ b/arch/arm/plat-s5p/dev-fimc2.c @@ -19,7 +19,7 @@ static struct resource s5p_fimc2_resource[] = { [0] = { .start = S5P_PA_FIMC2, - .end = S5P_PA_FIMC2 + SZ_1M - 1, + .end = S5P_PA_FIMC2 + SZ_4K - 1, .flags = IORESOURCE_MEM, }, [1] = { -- cgit v1.2.3-59-g8ed1b From f1c894de475c2455e6cedcc91d0ee4eb04388f3b Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Sat, 21 Aug 2010 09:18:19 +0900 Subject: ARM: S5PV210: Update I2C-1 Clock Register Property. CLK_GATE_IP3[8] is RESERVED. The port "I2C_HDMI_DDC" of CLK_GATE_IP3[10] is used as another I2C port. Therefore, defined the unused I2C-1 as another I2C there was left undefined but used. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv210/clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index af91fefef2c6..825b8681fbb3 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c @@ -357,7 +357,7 @@ static struct clk init_clocks_disable[] = { .id = 1, .parent = &clk_pclk_psys.clk, .enable = s5pv210_clk_ip3_ctrl, - .ctrlbit = (1<<8), + .ctrlbit = (1 << 10), }, { .name = "i2c", .id = 2, -- cgit v1.2.3-59-g8ed1b From a203a13a8843c3ec2d4dbc6285d000079a12afa5 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Sat, 21 Aug 2010 11:48:45 +0900 Subject: ARM: S5PV210: Reduce the iodesc length of systimer It's enough to use 4KiB. Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv210/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c index b9f4d677cf55..77f456c91ad3 100644 --- a/arch/arm/mach-s5pv210/cpu.c +++ b/arch/arm/mach-s5pv210/cpu.c @@ -47,7 +47,7 @@ static struct map_desc s5pv210_iodesc[] __initdata = { { .virtual = (unsigned long)S5P_VA_SYSTIMER, .pfn = __phys_to_pfn(S5PV210_PA_SYSTIMER), - .length = SZ_1M, + .length = SZ_4K, .type = MT_DEVICE, }, { .virtual = (unsigned long)VA_VIC2, -- cgit v1.2.3-59-g8ed1b From 8fe294caf8c868edd9046251824a0af91991bf43 Mon Sep 17 00:00:00 2001 From: Guillaume Chazarain Date: Sun, 12 Sep 2010 21:32:35 +0200 Subject: HID: fix hiddev's use of usb_find_interface My macbook infrared remote control was broken by commit bd25f4dd6972755579d0ea50d1a5ace2e9b00d1a ("HID: hiddev: use usb_find_interface, get rid of BKL"). This device appears in dmesg as: apple 0003:05AC:8242.0001: hiddev0,hidraw0: USB HID v1.11 Device [Apple Computer, Inc. IR Receiver] on usb-0000:00:1d.2-1/input0 It stopped working as lircd was getting ENODEV when opening /dev/usb/hiddev0. AFAICS hiddev_driver is a dummy driver so usb_find_interface(&hiddev_driver) does not find anything. The device is associated with the usbhid driver, so let's do usb_find_interface(&hid_driver) instead. $ ls -l /sys/devices/pci0000:00/0000:00:1d.2/usb7/7-1/7-1:1.0/usb/hiddev0/device/driver lrwxrwxrwx 1 root root 0 2010-09-12 16:28 /sys/devices/pci0000:00/0000:00:1d.2/usb7/7-1/7-1:1.0/usb/hiddev0/device/driver -> ../../../../../../bus/usb/drivers/usbhid Signed-off-by: Guillaume Chazarain Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 5 +++++ drivers/hid/usbhid/hiddev.c | 2 +- drivers/hid/usbhid/usbhid.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ffd6899d4ba0..599041a7f670 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1446,6 +1446,11 @@ static const struct hid_device_id hid_usb_table[] = { { } }; +struct usb_interface *usbhid_find_interface(int minor) +{ + return usb_find_interface(&hid_driver, minor); +} + static struct hid_driver hid_usb_driver = { .name = "generic-usb", .id_table = hid_usb_table, diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 0a29c51114aa..681e620eb95b 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -270,7 +270,7 @@ static int hiddev_open(struct inode *inode, struct file *file) struct hiddev *hiddev; int res; - intf = usb_find_interface(&hiddev_driver, iminor(inode)); + intf = usbhid_find_interface(iminor(inode)); if (!intf) return -ENODEV; hid = usb_get_intfdata(intf); diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 693fd3e720df..89d2e847dcc6 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -42,6 +42,7 @@ void usbhid_submit_report (struct hid_device *hid, struct hid_report *report, unsigned char dir); int usbhid_get_power(struct hid_device *hid); void usbhid_put_power(struct hid_device *hid); +struct usb_interface *usbhid_find_interface(int minor); /* iofl flags */ #define HID_CTRL_RUNNING 1 -- cgit v1.2.3-59-g8ed1b From da01c2f733f5eaa1b0670e7b584f431934c60306 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 10 Sep 2010 19:43:12 +0900 Subject: ARM: S5PV210: Add FIMC clocks These clocks enables FIMC driver to operate on machines, which bootloader power gated FIMC devices to save power on boot. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park [kgene.kim@samsung.com: minor title fix] Signed-off-by: Kukjin Kim --- arch/arm/mach-s5pv210/clock.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index 825b8681fbb3..cfecd70657cb 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c @@ -280,6 +280,24 @@ static struct clk init_clocks_disable[] = { .parent = &clk_hclk_dsys.clk, .enable = s5pv210_clk_ip0_ctrl, .ctrlbit = (1<<29), + }, { + .name = "fimc", + .id = 0, + .parent = &clk_hclk_dsys.clk, + .enable = s5pv210_clk_ip0_ctrl, + .ctrlbit = (1 << 24), + }, { + .name = "fimc", + .id = 1, + .parent = &clk_hclk_dsys.clk, + .enable = s5pv210_clk_ip0_ctrl, + .ctrlbit = (1 << 25), + }, { + .name = "fimc", + .id = 2, + .parent = &clk_hclk_dsys.clk, + .enable = s5pv210_clk_ip0_ctrl, + .ctrlbit = (1 << 26), }, { .name = "otg", .id = -1, -- cgit v1.2.3-59-g8ed1b From 0770e5280efd6f0001972a2b5127dffad0e22591 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Mon, 30 Aug 2010 10:45:54 +0900 Subject: ARM: SAMSUNG: Fix on drive strength value This patch fixes on defined drive strength value for GPIO. According to data sheet, if we want drive strength 1x, the value should be 00(b), if 2x should be 10(b), if 3x should be 01(b), and if 4x should be 11(b). Also fixes comment(from S5C to S5P). Reported-by: Janghyuck Kim Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/include/plat/gpio-cfg.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h index db4112c6f2be..1c6b92947c5d 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h @@ -143,12 +143,12 @@ extern s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin); /* Define values for the drvstr available for each gpio pin. * * These values control the value of the output signal driver strength, - * configurable on most pins on the S5C series. + * configurable on most pins on the S5P series. */ -#define S5P_GPIO_DRVSTR_LV1 ((__force s5p_gpio_drvstr_t)0x00) -#define S5P_GPIO_DRVSTR_LV2 ((__force s5p_gpio_drvstr_t)0x01) -#define S5P_GPIO_DRVSTR_LV3 ((__force s5p_gpio_drvstr_t)0x10) -#define S5P_GPIO_DRVSTR_LV4 ((__force s5p_gpio_drvstr_t)0x11) +#define S5P_GPIO_DRVSTR_LV1 ((__force s5p_gpio_drvstr_t)0x0) +#define S5P_GPIO_DRVSTR_LV2 ((__force s5p_gpio_drvstr_t)0x2) +#define S5P_GPIO_DRVSTR_LV3 ((__force s5p_gpio_drvstr_t)0x1) +#define S5P_GPIO_DRVSTR_LV4 ((__force s5p_gpio_drvstr_t)0x3) /** * s5c_gpio_get_drvstr() - get the driver streght value of a gpio pin -- cgit v1.2.3-59-g8ed1b From cbd2780fcefc370732c1f1526fb784573308177d Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Mon, 30 Aug 2010 12:07:58 +0900 Subject: ARM: SAMSUNG: Fix on s5p_gpio_[get,set]_drvstr This patch fixes bug on gpio drive strength helper function. The offset should be like follwoing. - off = chip->chip.base - pin; + off = pin - chip->chip.base; In the s5p_gpio_get_drvstr(), the second line is unnecessary, because overwrite drvstr. drvstr = __raw_readl(reg); - drvstr = 0xffff & (0x3 << shift); And need 2bit masking before return the drvstr value. drvstr = drvstr >> shift; + drvstr &= 0x3; In the s5p_gpio_set_drvstr(), need relevant bit clear. tmp = __raw_readl(reg); + tmp &= ~(0x3 << shift); tmp |= drvstr << shift; Reported-by: Jaecheol Lee Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/gpio-config.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm/plat-samsung/gpio-config.c b/arch/arm/plat-samsung/gpio-config.c index 57b68a50f45e..e3d41eaed1ff 100644 --- a/arch/arm/plat-samsung/gpio-config.c +++ b/arch/arm/plat-samsung/gpio-config.c @@ -273,13 +273,13 @@ s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) if (!chip) return -EINVAL; - off = chip->chip.base - pin; + off = pin - chip->chip.base; shift = off * 2; reg = chip->base + 0x0C; drvstr = __raw_readl(reg); - drvstr = 0xffff & (0x3 << shift); drvstr = drvstr >> shift; + drvstr &= 0x3; return (__force s5p_gpio_drvstr_t)drvstr; } @@ -296,11 +296,12 @@ int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr) if (!chip) return -EINVAL; - off = chip->chip.base - pin; + off = pin - chip->chip.base; shift = off * 2; reg = chip->base + 0x0C; tmp = __raw_readl(reg); + tmp &= ~(0x3 << shift); tmp |= drvstr << shift; __raw_writel(tmp, reg); -- cgit v1.2.3-59-g8ed1b From 23a07eb0e8ea7d5b6ac41f2cc647e7ae53859292 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 9 Sep 2010 11:12:37 +0900 Subject: ARM: S3C64XX: Fix dev-spi build The irqs.h usage here got missed in the Samsung platform reorganisation. Signed-off-by: Mark Brown Acked-by: Jassi Brar Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/dev-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c64xx/dev-spi.c b/arch/arm/mach-s3c64xx/dev-spi.c index a492b982aa06..bfa3ef770bd8 100644 --- a/arch/arm/mach-s3c64xx/dev-spi.c +++ b/arch/arm/mach-s3c64xx/dev-spi.c @@ -18,10 +18,10 @@ #include #include #include +#include #include #include -#include static char *spi_src_clks[] = { [S3C64XX_SPI_SRCCLK_PCLK] = "pclk", -- cgit v1.2.3-59-g8ed1b From 930a9e283516a3a3595c0c515113f1b78d07f695 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 14 Sep 2010 11:07:23 +0100 Subject: drm: Use a nondestructive mode for output detect when polling (v2) v2: Julien Cristau pointed out that @nondestructive results in double-negatives and confusion when trying to interpret the parameter, so use @force instead. Much easier to type as well. ;-) And fix the miscompilation of vmgfx reported by Sedat Dilek. Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc_helper.c | 4 ++-- drivers/gpu/drm/i915/intel_crt.c | 5 ++--- drivers/gpu/drm/i915/intel_dp.c | 3 +-- drivers/gpu/drm/i915/intel_dvo.c | 3 +-- drivers/gpu/drm/i915/intel_hdmi.c | 3 +-- drivers/gpu/drm/i915/intel_lvds.c | 5 ++--- drivers/gpu/drm/i915/intel_sdvo.c | 5 ++--- drivers/gpu/drm/i915/intel_tv.c | 5 ++--- drivers/gpu/drm/nouveau/nouveau_connector.c | 8 +++----- drivers/gpu/drm/radeon/radeon_connectors.c | 15 +++++---------- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 6 +++--- include/drm/drm_crtc.h | 9 ++++++++- 12 files changed, 32 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index fb6b70fc6572..dcbeb98f195a 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -103,7 +103,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (connector->funcs->force) connector->funcs->force(connector); } else { - connector->status = connector->funcs->detect(connector, false); + connector->status = connector->funcs->detect(connector, true); drm_kms_helper_poll_enable(dev); } @@ -866,7 +866,7 @@ static void output_poll_execute(struct work_struct *work) !(connector->polled & DRM_CONNECTOR_POLL_HPD)) continue; - status = connector->funcs->detect(connector, true); + status = connector->funcs->detect(connector, false); if (old_status != status) changed = true; } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 0350e5d711f8..a02a8df73727 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -401,8 +401,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder } static enum drm_connector_status -intel_crt_detect(struct drm_connector *connector, - bool nondestructive) +intel_crt_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; struct drm_encoder *encoder = intel_attached_encoder(connector); @@ -421,7 +420,7 @@ intel_crt_detect(struct drm_connector *connector, if (intel_crt_detect_ddc(encoder)) return connector_status_connected; - if (nondestructive) + if (!force) return connector->status; /* for pre-945g platforms use load detect */ diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e1a2a05fb838..1a51ee07de3e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1386,8 +1386,7 @@ ironlake_dp_detect(struct drm_connector *connector) * \return false if DP port is disconnected. */ static enum drm_connector_status -intel_dp_detect(struct drm_connector *connector, - bool nondestructive) +intel_dp_detect(struct drm_connector *connector, bool force) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index f0de1addf8a4..7c9ec1472d46 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -222,8 +222,7 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, * Unimplemented. */ static enum drm_connector_status -intel_dvo_detect(struct drm_connector *connector, - bool nondestructive) +intel_dvo_detect(struct drm_connector *connector, bool force) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 2ea123d8d22b..926934a482ec 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -139,8 +139,7 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, } static enum drm_connector_status -intel_hdmi_detect(struct drm_connector *connector, - bool nondestructive) +intel_hdmi_detect(struct drm_connector *connector, bool force) { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index fb1bed8f4071..6ec39a86ed06 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -446,8 +446,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * needed, using lid status notification from the input layer. */ static enum drm_connector_status -intel_lvds_detect(struct drm_connector *connector, - bool nondestructive) +intel_lvds_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; enum drm_connector_status status = connector_status_connected; @@ -543,7 +542,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, */ if (connector) connector->status = connector->funcs->detect(connector, - true); + false); /* Don't force modeset on machines where it causes a GPU lockup */ if (dmi_check_system(intel_no_modeset_on_lid)) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index db6b6d4b8fae..e8e902d614ed 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1417,7 +1417,7 @@ intel_analog_is_connected(struct drm_device *dev) if (!analog_connector) return false; - if (analog_connector->funcs->detect(analog_connector, true) == + if (analog_connector->funcs->detect(analog_connector, false) == connector_status_disconnected) return false; @@ -1487,8 +1487,7 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) } static enum drm_connector_status -intel_sdvo_detect(struct drm_connector *connector, - bool nondestructive) +intel_sdvo_detect(struct drm_connector *connector, bool force) { uint16_t response; struct drm_encoder *encoder = intel_attached_encoder(connector); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index d20b550c0f55..4a117e318a73 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1341,8 +1341,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector) * we have a pipe programmed in order to probe the TV. */ static enum drm_connector_status -intel_tv_detect(struct drm_connector *connector, - bool nondestructive) +intel_tv_detect(struct drm_connector *connector, bool force) { struct drm_display_mode mode; struct drm_encoder *encoder = intel_attached_encoder(connector); @@ -1354,7 +1353,7 @@ intel_tv_detect(struct drm_connector *connector, if (encoder->crtc && encoder->crtc->enabled) { type = intel_tv_detect_type(intel_tv); - } else if (nondestructive) { + } else if (force) { struct drm_crtc *crtc; int dpms_mode; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 67d515cb67e0..87186a4bbf03 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -168,8 +168,7 @@ nouveau_connector_set_encoder(struct drm_connector *connector, } static enum drm_connector_status -nouveau_connector_detect(struct drm_connector *connector, - bool nondestructive) +nouveau_connector_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; struct nouveau_connector *nv_connector = nouveau_connector(connector); @@ -247,8 +246,7 @@ detect_analog: } static enum drm_connector_status -nouveau_connector_detect_lvds(struct drm_connector *connector, - bool nondestructive) +nouveau_connector_detect_lvds(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -269,7 +267,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, /* Try retrieving EDID via DDC */ if (!dev_priv->vbios.fp_no_ddc) { - status = nouveau_connector_detect(connector, nondestructive); + status = nouveau_connector_detect(connector, force); if (status == connector_status_connected) goto out; } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 31d309a8e75b..ecc1a8fafbfd 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -482,8 +482,7 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, } static enum drm_connector_status -radeon_lvds_detect(struct drm_connector *connector, - bool nondestructive) +radeon_lvds_detect(struct drm_connector *connector, bool force) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = radeon_best_single_encoder(connector); @@ -597,8 +596,7 @@ static int radeon_vga_mode_valid(struct drm_connector *connector, } static enum drm_connector_status -radeon_vga_detect(struct drm_connector *connector, - bool nondestructive) +radeon_vga_detect(struct drm_connector *connector, bool force) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; @@ -696,8 +694,7 @@ static int radeon_tv_mode_valid(struct drm_connector *connector, } static enum drm_connector_status -radeon_tv_detect(struct drm_connector *connector, - bool nondestructive) +radeon_tv_detect(struct drm_connector *connector, bool force) { struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; @@ -755,8 +752,7 @@ static int radeon_dvi_get_modes(struct drm_connector *connector) * if its shared we have to set the other connector to disconnected. */ static enum drm_connector_status -radeon_dvi_detect(struct drm_connector *connector, - bool nondestructive) +radeon_dvi_detect(struct drm_connector *connector, bool force) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = NULL; @@ -981,8 +977,7 @@ static int radeon_dp_get_modes(struct drm_connector *connector) } static enum drm_connector_status -radeon_dp_detect(struct drm_connector *connector, - bool nondestructive) +radeon_dp_detect(struct drm_connector *connector, bool force) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); enum drm_connector_status ret = connector_status_disconnected; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index a527c91c0ba6..7083b1a24df3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -336,7 +336,7 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector) static enum drm_connector_status vmw_ldu_connector_detect(struct drm_connector *connector, - bool nondestructive) + bool force) { if (vmw_connector_to_ldu(connector)->pref_active) return connector_status_connected; @@ -517,7 +517,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, DRM_MODE_CONNECTOR_LVDS); - connector->status = vmw_ldu_connector_detect(connector); + connector->status = vmw_ldu_connector_detect(connector, true); drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, DRM_MODE_ENCODER_LVDS); @@ -611,7 +611,7 @@ int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num, ldu->pref_height = 600; ldu->pref_active = false; } - con->status = vmw_ldu_connector_detect(con); + con->status = vmw_ldu_connector_detect(con, true); } mutex_unlock(&dev->mode_config.mutex); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5536223fbac8..3e5a51af757c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -386,8 +386,15 @@ struct drm_connector_funcs { void (*dpms)(struct drm_connector *connector, int mode); void (*save)(struct drm_connector *connector); void (*restore)(struct drm_connector *connector); + + /* Check to see if anything is attached to the connector. + * @force is set to false whilst polling, true when checking the + * connector due to user request. @force can be used by the driver + * to avoid expensive, destructive operations during automated + * probing. + */ enum drm_connector_status (*detect)(struct drm_connector *connector, - bool nondestructive); + bool force); int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); int (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t val); -- cgit v1.2.3-59-g8ed1b From b64c115eb22516ecd187c74ad6de3f1693f1dc7b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 14 Sep 2010 20:14:38 +1000 Subject: drm: fix race between driver loading and userspace open. Not 100% sure this is due to BKL removal, its most likely a combination of that + userspace timing changes in udev/plymouth. The drm adds the sysfs device before the driver has completed internal loading, this causes udev to make the node and plymouth to open it before we've completed loading. The proper solution is to delay the sysfs manipulation until later in loading however this causes knock on issues with sysfs connector nodes, so we can use the global mutex to serialise loading and userspace opens. Reported-by: Toni Spets (hifi on #radeon) Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_pci.c | 4 ++++ drivers/gpu/drm/drm_platform.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index e20f78b542a7..f5bd9e590c80 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -164,6 +164,8 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, dev->hose = pdev->sysdata; #endif + mutex_lock(&drm_global_mutex); + if ((ret = drm_fill_in_dev(dev, ent, driver))) { printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); goto err_g2; @@ -199,6 +201,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, pci_name(pdev), dev->primary->index); + mutex_unlock(&drm_global_mutex); return 0; err_g4: @@ -210,6 +213,7 @@ err_g2: pci_disable_device(pdev); err_g1: kfree(dev); + mutex_unlock(&drm_global_mutex); return ret; } EXPORT_SYMBOL(drm_get_pci_dev); diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 460e9a3afa8d..92d1d0fb7b75 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -53,6 +53,8 @@ int drm_get_platform_dev(struct platform_device *platdev, dev->platformdev = platdev; dev->dev = &platdev->dev; + mutex_lock(&drm_global_mutex); + ret = drm_fill_in_dev(dev, NULL, driver); if (ret) { @@ -87,6 +89,8 @@ int drm_get_platform_dev(struct platform_device *platdev, list_add_tail(&dev->driver_item, &driver->device_list); + mutex_unlock(&drm_global_mutex); + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->primary->index); @@ -100,6 +104,7 @@ err_g2: drm_put_minor(&dev->control); err_g1: kfree(dev); + mutex_unlock(&drm_global_mutex); return ret; } EXPORT_SYMBOL(drm_get_platform_dev); -- cgit v1.2.3-59-g8ed1b From f90087eea44ce5fad139f086bc9d89ca37b0edc2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 7 Sep 2010 11:42:45 -0400 Subject: drm/radeon/kms: force legacy pll algo for RV620 LVDS There has been periodic evidence that LVDS, on at least some panels, prefers the dividers selected by the legacy pll algo. This patch forces the use of the legacy pll algo on RV620 LVDS panels. The old behavior (new pll algo) can be selected by setting the new_pll module parameter to 1. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=30029 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 464a81a1990f..cd0290f946cf 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -539,14 +539,15 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, pll->algo = PLL_ALGO_LEGACY; pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER; } - /* There is some evidence (often anecdotal) that RV515 LVDS + /* There is some evidence (often anecdotal) that RV515/RV620 LVDS * (on some boards at least) prefers the legacy algo. I'm not * sure whether this should handled generically or on a * case-by-case quirk basis. Both algos should work fine in the * majority of cases. */ if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && - (rdev->family == CHIP_RV515)) { + ((rdev->family == CHIP_RV515) || + (rdev->family == CHIP_RV620))) { /* allow the user to overrride just in case */ if (radeon_new_pll == 1) pll->algo = PLL_ALGO_NEW; -- cgit v1.2.3-59-g8ed1b From ee05d6939ed17b55e9c2466af32c208e0d547eb8 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 14 Sep 2010 15:15:52 +0200 Subject: vhost-net: fix range checking in mrg bufs case In mergeable buffer case, we use headcount, log_num and seg as indexes in same-size arrays, and we know that headcount <= seg and log_num equals either 0 or seg. Therefore, the right thing to do is range-check seg, not headcount as we do now: these will be different if guest chains s/g descriptors (this does not happen now, but we can not trust the guest). Long term, we should add BUG_ON checks to verify two other indexes are what we think they should be. Reported-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 29e850a7a2f9..7c8008225ee3 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -243,7 +243,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq, int r, nlogs = 0; while (datalen > 0) { - if (unlikely(headcount >= VHOST_NET_MAX_SG)) { + if (unlikely(seg >= VHOST_NET_MAX_SG)) { r = -ENOBUFS; goto err; } -- cgit v1.2.3-59-g8ed1b From 47023ec774b6f73bb11d9f3b00b21f2bbd87e0f2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Sep 2010 21:24:02 -0700 Subject: sound: Use static const char * const where possible Signed-off-by: Joe Perches Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index e2e73895db12..eb4094270a4f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, #ifdef RULES_DEBUG #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v -char *snd_pcm_hw_param_names[] = { +static const char * const snd_pcm_hw_param_names[] = { HW_PARAM(ACCESS), HW_PARAM(FORMAT), HW_PARAM(SUBFORMAT), -- cgit v1.2.3-59-g8ed1b From a254dba37c5a372fc8b44ba29509ba052d4e859d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 12 Sep 2010 02:41:47 +0100 Subject: ALSA: emux: Add trivial compat ioctl handler Reported-by: Carmen Cru Signed-off-by: Ben Hutchings Signed-off-by: Takashi Iwai --- sound/synth/emux/emux_hwdep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c index ff0b2a8fd25b..5ae1eae9f6db 100644 --- a/sound/synth/emux/emux_hwdep.c +++ b/sound/synth/emux/emux_hwdep.c @@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu) strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; hw->ops.ioctl = snd_emux_hwdep_ioctl; + /* The ioctl parameter types are compatible between 32- and + * 64-bit architectures, so use the same function. */ + hw->ops.ioctl_compat = snd_emux_hwdep_ioctl; hw->exclusive = 1; hw->private_data = emu; if ((err = snd_card_register(emu->card)) < 0) -- cgit v1.2.3-59-g8ed1b From 7b6c3a34e93aafc5dd9adc7dee87c7fa61d8bdbb Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Sat, 11 Sep 2010 13:16:41 +0200 Subject: ALSA: sound/ppc/powermac: remove undefined operations Modifying an object twice without an intervening sequence point is undefined. Signed-off-by: Andreas Schwab Signed-off-by: Takashi Iwai --- sound/ppc/tumbler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 20afdf9772ee..961d98297695 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix) if (! mix->i2c.client) return -ENODEV; if (mix->capture_source) - mix->acs = mix->acs |= 2; + mix->acs |= 2; else mix->acs &= ~2; return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs); -- cgit v1.2.3-59-g8ed1b From 645ef9ef1fc0ff70456495b1e21d3420b7b08541 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Sep 2010 21:53:41 +0200 Subject: sound: autoconvert trivial BKL users to private mutex The usage of the BKL in the OSS sound drivers is trivial, and each of them only locks against itself, so it can be turned into per-driver mutexes. This is the script that was used for the conversion: file=$1 name=$2 if grep -q lock_kernel ${file} ; then if grep -q 'include.*linux.mutex.h' ${file} ; then sed -i '/include.*/d' ${file} else sed -i 's/include.*.*$/include /g' ${file} fi sed -i ${file} \ -e "/^#include.*linux.mutex.h/,$ { 1,/^\(static\|int\|long\)/ { /^\(static\|int\|long\)/istatic DEFINE_MUTEX(${name}_mutex); } }" \ -e "s/\(un\)*lock_kernel\>[ ]*()/mutex_\1lock(\&${name}_mutex)/g" \ -e '/[ ]*cycle_kernel_lock();/d' else sed -i -e '/include.*\/d' ${file} \ -e '/cycle_kernel_lock()/d' fi Signed-off-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/oss/au1550_ac97.c | 30 ++++++++++++++-------------- sound/oss/dmasound/dmasound_core.c | 41 +++++++++++++++++++------------------- sound/oss/msnd_pinnacle.c | 15 +++++++------- sound/oss/sh_dac_audio.c | 13 ++++++------ sound/oss/soundcard.c | 41 +++++++++++++++++++------------------- sound/oss/swarm_cs4297a.c | 20 +++++++++---------- sound/oss/vwsnd.c | 30 ++++++++++++++-------------- 7 files changed, 97 insertions(+), 93 deletions(-) diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index 8a12621d8b3a..a8f626d99c5b 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -77,6 +76,7 @@ /* Boot options * 0 = no VRA, 1 = use VRA if codec supports it */ +static DEFINE_MUTEX(au1550_ac97_mutex); static int vra = 1; module_param(vra, bool, 0); MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); @@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin) static int au1550_open_mixdev(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); file->private_data = &au1550_state; - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return 0; } @@ -824,9 +824,9 @@ au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) struct ac97_codec *codec = s->codec; int ret; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); ret = mixdev_ioctl(codec, cmd, arg); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1255,7 +1255,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size; int ret = 0; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); mutex_lock(&s->sem); if (vma->vm_flags & VM_WRITE) db = &s->dma_dac; @@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) db->mapped = 1; out: mutex_unlock(&s->sem); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); ret = au1550_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file) #endif file->private_data = s; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); /* wait for device to become free */ mutex_lock(&s->open_mutex); while (s->open_mode & file->f_mode) { @@ -1861,7 +1861,7 @@ au1550_open(struct inode *inode, struct file *file) out: mutex_unlock(&s->open_mutex); out2: - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return ret; } @@ -1870,12 +1870,12 @@ au1550_release(struct inode *inode, struct file *file) { struct au1550_state *s = file->private_data; - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); if (file->f_mode & FMODE_WRITE) { - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); drain_dac(s, file->f_flags & O_NONBLOCK); - lock_kernel(); + mutex_lock(&au1550_ac97_mutex); } mutex_lock(&s->open_mutex); @@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file) s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); mutex_unlock(&s->open_mutex); wake_up(&s->open_wait); - unlock_kernel(); + mutex_unlock(&au1550_ac97_mutex); return 0; } diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 6ecd41abb066..87e2c72651f5 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -181,7 +181,7 @@ #include #include #include -#include +#include #include @@ -194,6 +194,7 @@ * Declarations */ +static DEFINE_MUTEX(dmasound_core_mutex); int dmasound_catchRadius = 0; module_param(dmasound_catchRadius, int, 0); @@ -323,22 +324,22 @@ static struct { static int mixer_open(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&dmasound_core_mutex); if (!try_module_get(dmasound.mach.owner)) { - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return -ENODEV; } mixer.busy = 1; - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; } static int mixer_release(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&dmasound_core_mutex); mixer.busy = 0; module_put(dmasound.mach.owner); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; } @@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); ret = mixer_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return ret; } @@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file) { int rc; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); if (!try_module_get(dmasound.mach.owner)) { - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return -ENODEV; } @@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file) sound_set_format(AFMT_MU_LAW); } #endif - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; out: module_put(dmasound.mach.owner); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return rc; } @@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file) { int rc = 0; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); if (file->f_mode & FMODE_WRITE) { if (write_sq.busy) @@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file) write_sq_wake_up(file); /* checks f_mode */ #endif /* blocking open() */ - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return rc; } @@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); ret = sq_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return ret; } @@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file) int len = 0; int ret; - lock_kernel(); + mutex_lock(&dmasound_core_mutex); ret = -EBUSY; if (state.busy) goto out; @@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ; state.len = len; ret = 0; out: - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return ret; } static int state_release(struct inode *inode, struct file *file) { - lock_kernel(); + mutex_lock(&dmasound_core_mutex); state.busy = 0; module_put(dmasound.mach.owner); - unlock_kernel(); + mutex_unlock(&dmasound_core_mutex); return 0; } diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 2e48b17667d0..b4c1eb504c22 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -79,6 +79,7 @@ dev.rec_sample_rate / \ dev.rec_channels) +static DEFINE_MUTEX(msnd_pinnacle_mutex); static multisound_dev_t dev; #ifndef HAVE_DSPCODEH @@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = -EINVAL; - lock_kernel(); + mutex_lock(&msnd_pinnacle_mutex); if (minor == dev.dsp_minor) ret = dsp_ioctl(file, cmd, arg); else if (minor == dev.mixer_minor) ret = mixer_ioctl(cmd, arg); - unlock_kernel(); + mutex_unlock(&msnd_pinnacle_mutex); return ret; } @@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file) int minor = iminor(inode); int err = 0; - lock_kernel(); + mutex_lock(&msnd_pinnacle_mutex); if (minor == dev.dsp_minor) { if ((file->f_mode & FMODE_WRITE && test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || @@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file) } else err = -EINVAL; out: - unlock_kernel(); + mutex_unlock(&msnd_pinnacle_mutex); return err; } @@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file) int minor = iminor(inode); int err = 0; - lock_kernel(); + mutex_lock(&msnd_pinnacle_mutex); if (minor == dev.dsp_minor) err = dsp_release(file); else if (minor == dev.mixer_minor) { /* nothing */ } else err = -EINVAL; - unlock_kernel(); + mutex_unlock(&msnd_pinnacle_mutex); return err; } diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index 479e3025a8a3..53bba16bf709 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -34,6 +34,7 @@ #define BUFFER_SIZE 48000 +static DEFINE_MUTEX(sh_dac_audio_mutex); static int rate; static int empty; static char *data_buffer, *buffer_begin, *buffer_end; @@ -163,9 +164,9 @@ static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&sh_dac_audio_mutex); ret = dac_audio_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&sh_dac_audio_mutex); return ret; } @@ -229,16 +230,16 @@ static int dac_audio_open(struct inode *inode, struct file *file) if (file->f_mode & FMODE_READ) return -ENODEV; - lock_kernel(); + mutex_lock(&sh_dac_audio_mutex); if (in_use) { - unlock_kernel(); + mutex_unlock(&sh_dac_audio_mutex); return -EBUSY; } in_use = 1; dac_audio_start(); - unlock_kernel(); + mutex_unlock(&sh_dac_audio_mutex); return 0; } diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 92aa762ffb7e..938ed94f904f 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include @@ -56,6 +56,7 @@ * Table for permanently allocated memory (used when unloading the module) */ void * sound_mem_blocks[MAX_MEM_BLOCKS]; +static DEFINE_MUTEX(soundcard_mutex); int sound_nblocks = 0; /* Persistent DMA buffers */ @@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof * big one anyway, we might as well bandage here.. */ - lock_kernel(); + mutex_lock(&soundcard_mutex); DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { @@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof case SND_DEV_MIDIN: ret = MIDIbuf_read(dev, file, buf, count); } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou int dev = iminor(file->f_path.dentry->d_inode); int ret = -EINVAL; - lock_kernel(); + mutex_lock(&soundcard_mutex); DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { case SND_DEV_SEQ: @@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou ret = MIDIbuf_write(dev, file, buf, count); break; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file) printk(KERN_ERR "Invalid minor device %d\n", dev); return -ENXIO; } - lock_kernel(); + mutex_lock(&soundcard_mutex); switch (dev & 0x0f) { case SND_DEV_CTL: dev >>= 4; @@ -247,7 +248,7 @@ static int sound_open(struct inode *inode, struct file *file) retval = -ENXIO; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return 0; } @@ -255,7 +256,7 @@ static int sound_release(struct inode *inode, struct file *file) { int dev = iminor(inode); - lock_kernel(); + mutex_lock(&soundcard_mutex); DEB(printk("sound_release(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_CTL: @@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file) default: printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return 0; } @@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cmd == OSS_GETVERSION) return __put_user(SOUND_VERSION, (int __user *)p); - lock_kernel(); + mutex_lock(&soundcard_mutex); if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ (dev & 0x0f) != SND_DEV_CTL) { dtype = dev & 0x0f; @@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = sound_mixer_ioctl(dev >> 4, cmd, p); break; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return ret; } @@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); return -EINVAL; } - lock_kernel(); + mutex_lock(&soundcard_mutex); if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ dmap = audio_devs[dev]->dmap_out; else if (vma->vm_flags & VM_READ) dmap = audio_devs[dev]->dmap_in; else { printk(KERN_ERR "Sound: Undefined mmap() access\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EINVAL; } if (dmap == NULL) { printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EIO; } if (dmap->raw_buf == NULL) { printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EIO; } if (dmap->mapping_flags) { printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EIO; } if (vma->vm_pgoff != 0) { printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EINVAL; } size = vma->vm_end - vma->vm_start; @@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return -EAGAIN; } @@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); - unlock_kernel(); + mutex_unlock(&soundcard_mutex); return 0; } diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index b15840ad2527..44357d877a27 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c @@ -68,7 +68,6 @@ #include #include #include -#include #include #include #include @@ -94,6 +93,7 @@ struct cs4297a_state; +static DEFINE_MUTEX(swarm_cs4297a_mutex); static void stop_dac(struct cs4297a_state *s); static void stop_adc(struct cs4297a_state *s); static void start_dac(struct cs4297a_state *s); @@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n")); - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); list_for_each(entry, &cs4297a_devs) { s = list_entry(entry, struct cs4297a_state, list); @@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n")); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return -ENODEV; } VALIDATE_STATE(s); @@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file) CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n")); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return nonseekable_open(inode, file); } @@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg) { int ret; - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd, arg); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return ret; } @@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg) { int ret; - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); ret = cs4297a_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return ret; } @@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file) { int ret; - lock_kernel(); + mutex_lock(&swarm_cs4297a_mutex); ret = cs4297a_open(inode, file); - unlock_kernel(); + mutex_unlock(&swarm_cs4297a_mutex); return ret; } diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 8cd73cdd88af..643f1113b1d8 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c @@ -145,7 +145,6 @@ #include #include -#include #include #include #include @@ -160,6 +159,7 @@ #ifdef VWSND_DEBUG +static DEFINE_MUTEX(vwsnd_mutex); static int shut_up = 1; /* @@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file, vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data; int ret; - lock_kernel(); + mutex_lock(&vwsnd_mutex); mutex_lock(&devc->io_mutex); ret = vwsnd_audio_do_ioctl(file, cmd, arg); mutex_unlock(&devc->io_mutex); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return ret; } @@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) DBGE("(inode=0x%p, file=0x%p)\n", inode, file); - lock_kernel(); + mutex_lock(&vwsnd_mutex); INC_USE_COUNT; for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F)) @@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) if (devc == NULL) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -ENODEV; } @@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) mutex_unlock(&devc->open_mutex); if (file->f_flags & O_NONBLOCK) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -EBUSY; } interruptible_sleep_on(&devc->open_wait); if (signal_pending(current)) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -ERESTARTSYS; } mutex_lock(&devc->open_mutex); @@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file) file->private_data = devc; DBGRV(); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return 0; } @@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) vwsnd_port_t *wport = NULL, *rport = NULL; int err = 0; - lock_kernel(); + mutex_lock(&vwsnd_mutex); mutex_lock(&devc->io_mutex); { DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); @@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) wake_up(&devc->open_wait); DEC_USE_COUNT; DBGR(); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return err; } @@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file) DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); INC_USE_COUNT; - lock_kernel(); + mutex_lock(&vwsnd_mutex); for (devc = vwsnd_dev_list; devc; devc = devc->next_dev) if (devc->mixer_minor == iminor(inode)) break; if (devc == NULL) { DEC_USE_COUNT; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return -ENODEV; } file->private_data = devc; - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return 0; } @@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file, DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg); - lock_kernel(); + mutex_lock(&vwsnd_mutex); mutex_lock(&devc->mix_mutex); { if ((cmd & ~nrmask) == MIXER_READ(0)) @@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file, retval = -EINVAL; } mutex_unlock(&devc->mix_mutex); - unlock_kernel(); + mutex_unlock(&vwsnd_mutex); return retval; } -- cgit v1.2.3-59-g8ed1b From 9ad0e496519d99eb2c34f01e41500a775122c744 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 14 Sep 2010 23:22:00 +0200 Subject: ALSA: hda - Add input jack layer support to Realtek codec Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 98 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9c2c19c8b059..3b040870365d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "hda_codec.h" #include "hda_local.h" #include "hda_beep.h" @@ -282,6 +283,12 @@ struct alc_mic_route { unsigned char amix_idx; }; +struct alc_jack { + hda_nid_t nid; + int type; + struct snd_jack *jack; +}; + #define MUX_IDX_UNDEF ((unsigned char)-1) struct alc_customize_define { @@ -357,6 +364,9 @@ struct alc_spec { /* PCM information */ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ + /* jack detection */ + struct snd_array jacks; + /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct alc_customize_define cdefine; @@ -990,6 +1000,91 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } +#ifdef CONFIG_SND_HDA_INPUT_JACK +static void alc_free_jack_priv(struct snd_jack *jack) +{ + struct alc_jack *jacks = jack->private_data; + jacks->nid = 0; + jacks->jack = NULL; +} + +static int alc_add_jack(struct hda_codec *codec, + hda_nid_t nid, int type) +{ + struct alc_spec *spec; + struct alc_jack *jack; + const char *name; + int err; + + spec = codec->spec; + snd_array_init(&spec->jacks, sizeof(*jack), 32); + jack = snd_array_new(&spec->jacks); + if (!jack) + return -ENOMEM; + + jack->nid = nid; + jack->type = type; + name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; + + err = snd_jack_new(codec->bus->card, name, type, &jack->jack); + if (err < 0) + return err; + jack->jack->private_data = jack; + jack->jack->private_free = alc_free_jack_priv; + return 0; +} + +static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid) +{ + struct alc_spec *spec = codec->spec; + struct alc_jack *jacks = spec->jacks.list; + + if (jacks) { + int i; + for (i = 0; i < spec->jacks.used; i++) { + if (jacks->nid == nid) { + unsigned int present; + present = snd_hda_jack_detect(codec, nid); + + present = (present) ? jacks->type : 0; + + snd_jack_report(jacks->jack, present); + } + jacks++; + } + } +} + +static int alc_init_jacks(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + unsigned int hp_nid = spec->autocfg.hp_pins[0]; + unsigned int mic_nid = spec->ext_mic.pin; + + err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE); + if (err < 0) + return err; + alc_report_jack(codec, hp_nid); + + err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE); + if (err < 0) + return err; + alc_report_jack(codec, mic_nid); + + return 0; +} +#else +static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid) +{ +} + +static inline int alc_init_jacks(struct hda_codec *codec) +{ + return 0; +} +#endif + static void alc_automute_speaker(struct hda_codec *codec, int pinctl) { struct alc_spec *spec = codec->spec; @@ -1006,6 +1101,7 @@ static void alc_automute_speaker(struct hda_codec *codec, int pinctl) spec->jack_present = 1; break; } + alc_report_jack(codec, spec->autocfg.hp_pins[i]); } mute = spec->jack_present ? HDA_AMP_MUTE : 0; @@ -1111,6 +1207,7 @@ static void alc_mic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, alive->mux_idx); } + alc_report_jack(codec, spec->ext_mic.pin); /* FIXME: analog mixer */ } @@ -14496,6 +14593,7 @@ static void alc269_auto_init(struct hda_codec *codec) alc269_auto_init_hp_out(codec); alc269_auto_init_analog_input(codec); alc_auto_init_digital(codec); + alc_init_jacks(codec); if (spec->unsol_event) alc_inithook(codec); } -- cgit v1.2.3-59-g8ed1b From ab12811c89e88f2e66746790b1fe4469ccb7bdd9 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Fri, 10 Sep 2010 11:43:20 +0000 Subject: bonding: correctly process non-linear skbs It was recently brought to my attention that 802.3ad mode bonds would no longer form when using some network hardware after a driver update. After snooping around I realized that the particular hardware was using page-based skbs and found that skb->data did not contain a valid LACPDU as it was not stored there. That explained the inability to form an 802.3ad-based bond. For balance-alb mode bonds this was also an issue as ARPs would not be properly processed. This patch fixes the issue in my tests and should be applied to 2.6.36 and as far back as anyone cares to add it to stable. Thanks to Alexander Duyck and Jesse Brandeburg for the suggestions on this one. Signed-off-by: Andy Gospodarek CC: Alexander Duyck CC: Jesse Brandeburg CC: stable@kerne.org Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 3 +++ drivers/net/bonding/bond_alb.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 822f586d72af..0ddf4c66afe2 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2466,6 +2466,9 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac if (!(dev->flags & IFF_MASTER)) goto out; + if (!pskb_may_pull(skb, sizeof(struct lacpdu))) + goto out; + read_lock(&bond->lock); slave = bond_get_slave_by_dev((struct bonding *)netdev_priv(dev), orig_dev); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index c746b331771d..26bb118c4533 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -362,6 +362,9 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct goto out; } + if (!pskb_may_pull(skb, arp_hdr_len(bond_dev))) + goto out; + if (skb->len < sizeof(struct arp_pkt)) { pr_debug("Packet is too small to be an ARP\n"); goto out; -- cgit v1.2.3-59-g8ed1b From ef885afbf8a37689afc1d9d545e2f3e7a8276c17 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 13 Sep 2010 12:24:54 +0000 Subject: net: use rcu_barrier() in rollback_registered_many netdev_wait_allrefs() waits that all references to a device vanishes. It currently uses a _very_ pessimistic 250 ms delay between each probe. Some users reported that no more than 4 devices can be dismantled per second, this is a pretty serious problem for some setups. Most of the time, a refcount is about to be released by an RCU callback, that is still in flight because rollback_registered_many() uses a synchronize_rcu() call instead of rcu_barrier(). Problem is visible if number of online cpus is one, because synchronize_rcu() is then a no op. time to remove 50 ipip tunnels on a UP machine : before patch : real 11.910s after patch : real 1.250s Reported-by: Nicolas Dichtel Reported-by: Octavian Purdila Reported-by: Benjamin LaHaise Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index b9b22a3c4c8f..660dd41aaaa6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4845,7 +4845,7 @@ static void rollback_registered_many(struct list_head *head) dev = list_first_entry(head, struct net_device, unreg_list); call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev); - synchronize_net(); + rcu_barrier(); list_for_each_entry(dev, head, unreg_list) dev_put(dev); -- cgit v1.2.3-59-g8ed1b From 3894335876a6257ac46e14845bd37ae6fb0f7c87 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 14 Sep 2010 10:48:59 -0600 Subject: ALSA: patch_nvhdmi.c: Fix supported sample rate list. 22050 isn't a valid HDMI sample rate. 32000 is. Signed-off-by: Stephen Warren Acked-By: Wei Ni Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 69b950d527c3..baa108b9d6aa 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -84,7 +84,7 @@ static struct hda_verb nvhdmi_basic_init_7x[] = { #else /* support all rates and formats */ #define SUPPORTED_RATES \ - (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000) #define SUPPORTED_MAXBPS 24 -- cgit v1.2.3-59-g8ed1b From fddd91016d16277a32727ad272cf2edd3d309c90 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Mon, 13 Sep 2010 22:12:01 +0000 Subject: phylib: fix PAL state machine restart on resume On resume, before starting the PAL state machine, check if the adjust_link() method is well supplied. If not, this would lead to a NULL pointer dereference in the phy_state_machine() function. This scenario can happen if the Ethernet driver call manually the PHY functions instead of using the PAL state machine. The mv643xx_eth driver is a such example. Signed-off-by: Simon Guinot Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 6a6b8199a0d6..6c58da2b882c 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -308,7 +308,7 @@ static int mdio_bus_suspend(struct device *dev) * may call phy routines that try to grab the same lock, and that may * lead to a deadlock. */ - if (phydev->attached_dev) + if (phydev->attached_dev && phydev->adjust_link) phy_stop_machine(phydev); if (!mdio_bus_phy_may_suspend(phydev)) @@ -331,7 +331,7 @@ static int mdio_bus_resume(struct device *dev) return ret; no_resume: - if (phydev->attached_dev) + if (phydev->attached_dev && phydev->adjust_link) phy_start_machine(phydev, NULL); return 0; -- cgit v1.2.3-59-g8ed1b From 8bef9239ee1a42eb37d3f83bacf6a75f019c028d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 14 Sep 2010 15:45:44 -0700 Subject: ceph: correctly set 'follows' in flushsnap messages The 'follows' should match the seq for the snap context for the given snap cap, which is the context under which we have been dirtying and writing data and metadata. The snapshot that _contains_ those updates thus _follows_ that context's seq #. Signed-off-by: Sage Weil --- fs/ceph/snap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 4868b9dcac5a..9e836afba341 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -467,7 +467,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) INIT_LIST_HEAD(&capsnap->ci_item); INIT_LIST_HEAD(&capsnap->flushing_item); - capsnap->follows = snapc->seq - 1; + capsnap->follows = snapc->seq; capsnap->issued = __ceph_caps_issued(ci, NULL); capsnap->dirty = dirty; -- cgit v1.2.3-59-g8ed1b From cfc0bf6640dfd0f43bf8bfec5a475284809baa4d Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 14 Sep 2010 15:50:59 -0700 Subject: ceph: stop sending FLUSHSNAPs when we hit a dirty capsnap Stop sending FLUSHSNAP messages when we hit a capsnap that has dirty_pages or is still writing. We'll send the newer capsnaps only after the older ones complete. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index a2069b6680ae..9fbe9019155c 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1227,7 +1227,7 @@ retry: * pages to be written out. */ if (capsnap->dirty_pages || capsnap->writing) - continue; + break; /* * if cap writeback already occurred, we should have dropped @@ -1276,8 +1276,8 @@ retry: &session->s_cap_snaps_flushing); spin_unlock(&inode->i_lock); - dout("flush_snaps %p cap_snap %p follows %lld size %llu\n", - inode, capsnap, next_follows, capsnap->size); + dout("flush_snaps %p cap_snap %p follows %lld tid %llu\n", + inode, capsnap, capsnap->follows, capsnap->flush_tid); send_cap_msg(session, ceph_vino(inode).ino, 0, CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0, capsnap->dirty, 0, capsnap->flush_tid, 0, mseq, -- cgit v1.2.3-59-g8ed1b From 54ff7e595d763d894104d421b103a89f7becf47c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 14 Sep 2010 22:10:21 +0200 Subject: x86: hpet: Work around hardware stupidity This more or less reverts commits 08be979 (x86: Force HPET readback_cmp for all ATI chipsets) and 30a564be (x86, hpet: Restrict read back to affected ATI chipsets) to the status of commit 8da854c (x86, hpet: Erratum workaround for read after write of HPET comparator). The delta to commit 8da854c is mostly comments and the change from WARN_ONCE to printk_once as we know the call path of this function already. This needs really in depth explanation: First of all the HPET design is a complete failure. Having a counter compare register which generates an interrupt on matching values forces the software to do at least one superfluous readback of the counter register. While it is nice in theory to program "absolute" time events it is practically useless because the timer runs at some absurd frequency which can never be matched to real world units. So we are forced to calculate a relative delta and this forces a readout of the actual counter value, adding the delta and programming the compare register. When the delta is small enough we run into the danger that we program a compare value which is already in the past. Due to the compare for equal nature of HPET we need to read back the counter value after writing the compare rehgister (btw. this is necessary for absolute timeouts as well) to make sure that we did not miss the timer event. We try to work around that by setting the minimum delta to a value which is larger than the theoretical time which elapses between the counter readout and the compare register write, but that's only true in theory. A NMI or SMI which hits between the readout and the write can easily push us beyond that limit. This would result in waiting for the next HPET timer interrupt until the 32bit wraparound of the counter happens which takes about 306 seconds. So we designed the next event function to look like: match = read_cnt() + delta; write_compare_ref(match); return read_cnt() < match ? 0 : -ETIME; At some point we got into trouble with certain ATI chipsets. Even the above "safe" procedure failed. The reason was that the write to the compare register was delayed probably for performance reasons. The theory was that they wanted to avoid the synchronization of the write with the HPET clock, which is understandable. So the write does not hit the compare register directly instead it goes to some intermediate register which is copied to the real compare register in sync with the HPET clock. That opens another window for hitting the dreaded "wait for a wraparound" problem. To work around that "optimization" we added a read back of the compare register which either enforced the update of the just written value or just delayed the readout of the counter enough to avoid the issue. We unfortunately never got any affirmative info from ATI/AMD about this. One thing is sure, that we nuked the performance "optimization" that way completely and I'm pretty sure that the result is worse than before some HW folks came up with those. Just for paranoia reasons I added a check whether the read back compare register value was the same as the value we wrote right before. That paranoia check triggered a couple of years after it was added on an Intel ICH9 chipset. Venki added a workaround (commit 8da854c) which was reading the compare register twice when the first check failed. We considered this to be a penalty in general and restricted the readback (thus the wasted CPU cycles) to the known to be affected ATI chipsets. This turned out to be a utterly wrong decision. 2.6.35 testers experienced massive problems and finally one of them bisected it down to commit 30a564be which spured some further investigation. Finally we got confirmation that the write to the compare register can be delayed by up to two HPET clock cycles which explains the problems nicely. All we can do about this is to go back to Venki's initial workaround in a slightly modified version. Just for the record I need to say, that all of this could have been avoided if hardware designers and of course the HPET committee would have thought about the consequences for a split second. It's out of my comprehension why designing a working timer is so hard. There are two ways to achieve it: 1) Use a counter wrap around aware compare_reg <= counter_reg implementation instead of the easy compare_reg == counter_reg Downsides: - It needs more silicon. - It needs a readout of the counter to apply a relative timeout. This is necessary as the counter does not run in any useful (and adjustable) frequency and there is no guarantee that the counter which is used for timer events is the same which is used for reading the actual time (and therefor for calculating the delta) Upsides: - None 2) Use a simple down counter for relative timer events Downsides: - Absolute timeouts are not possible, which is not a problem at all in the context of an OS and the expected max. latencies/jitter (also see Downsides of #1) Upsides: - It needs less or equal silicon. - It works ALWAYS - It is way faster than a compare register based solution (One write versus one write plus at least one and up to four reads) I would not be so grumpy about all of this, if I would not have been ignored for many years when pointing out these flaws to various hardware folks. I really hate timers (at least those which seem to be designed by janitors). Though finally we got a reasonable explanation plus a solution and I want to thank all the folks involved in chasing it down and providing valuable input to this. Bisected-by: Nix Reported-by: Artur Skawina Reported-by: Damien Wyart Reported-by: John Drescher Cc: Venkatesh Pallipadi Cc: Ingo Molnar Cc: H. Peter Anvin Cc: Arjan van de Ven Cc: Andreas Herrmann Cc: Borislav Petkov Cc: stable@kernel.org Acked-by: Suresh Siddha Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/hpet.h | 1 - arch/x86/kernel/early-quirks.c | 18 ------------------ arch/x86/kernel/hpet.c | 31 +++++++++++++++++-------------- 3 files changed, 17 insertions(+), 33 deletions(-) diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h index 004e6e25e913..1d5c08a1bdfd 100644 --- a/arch/x86/include/asm/hpet.h +++ b/arch/x86/include/asm/hpet.h @@ -68,7 +68,6 @@ extern unsigned long force_hpet_address; extern u8 hpet_blockid; extern int hpet_force_user; extern u8 hpet_msi_disable; -extern u8 hpet_readback_cmp; extern int is_hpet_enabled(void); extern int hpet_enable(void); extern void hpet_disable(void); diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index e5cc7e82e60d..ebdb85cf2686 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -18,7 +18,6 @@ #include #include #include -#include static void __init fix_hypertransport_config(int num, int slot, int func) { @@ -192,21 +191,6 @@ static void __init ati_bugs_contd(int num, int slot, int func) } #endif -/* - * Force the read back of the CMP register in hpet_next_event() - * to work around the problem that the CMP register write seems to be - * delayed. See hpet_next_event() for details. - * - * We do this on all SMBUS incarnations for now until we have more - * information about the affected chipsets. - */ -static void __init ati_hpet_bugs(int num, int slot, int func) -{ -#ifdef CONFIG_HPET_TIMER - hpet_readback_cmp = 1; -#endif -} - #define QFLAG_APPLY_ONCE 0x1 #define QFLAG_APPLIED 0x2 #define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED) @@ -236,8 +220,6 @@ static struct chipset early_qrk[] __initdata = { PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs }, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd }, - { PCI_VENDOR_ID_ATI, PCI_ANY_ID, - PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_hpet_bugs }, {} }; diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 351f9c0fea1f..410fdb3f1939 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -35,7 +35,6 @@ unsigned long hpet_address; u8 hpet_blockid; /* OS timer block num */ u8 hpet_msi_disable; -u8 hpet_readback_cmp; #ifdef CONFIG_PCI_MSI static unsigned long hpet_num_timers; @@ -395,23 +394,27 @@ static int hpet_next_event(unsigned long delta, * at that point and we would wait for the next hpet interrupt * forever. We found out that reading the CMP register back * forces the transfer so we can rely on the comparison with - * the counter register below. + * the counter register below. If the read back from the + * compare register does not match the value we programmed + * then we might have a real hardware problem. We can not do + * much about it here, but at least alert the user/admin with + * a prominent warning. * - * That works fine on those ATI chipsets, but on newer Intel - * chipsets (ICH9...) this triggers due to an erratum: Reading - * the comparator immediately following a write is returning - * the old value. + * An erratum on some chipsets (ICH9,..), results in + * comparator read immediately following a write returning old + * value. Workaround for this is to read this value second + * time, when first read returns old value. * - * We restrict the read back to the affected ATI chipsets (set - * by quirks) and also run it with hpet=verbose for debugging - * purposes. + * In fact the write to the comparator register is delayed up + * to two HPET cycles so the workaround we tried to restrict + * the readback to those known to be borked ATI chipsets + * failed miserably. So we give up on optimizations forever + * and penalize all HPET incarnations unconditionally. */ - if (hpet_readback_cmp || hpet_verbose) { - u32 cmp = hpet_readl(HPET_Tn_CMP(timer)); - - if (cmp != cnt) + if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) { + if (hpet_readl(HPET_Tn_CMP(timer)) != cnt) printk_once(KERN_WARNING - "hpet: compare register read back failed.\n"); + "hpet: compare register read back failed.\n"); } return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; -- cgit v1.2.3-59-g8ed1b From c41d68a513c71e35a14f66d71782d27a79a81ea6 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 7 Sep 2010 16:16:18 -0700 Subject: compat: Make compat_alloc_user_space() incorporate the access_ok() compat_alloc_user_space() expects the caller to independently call access_ok() to verify the returned area. A missing call could introduce problems on some architectures. This patch incorporates the access_ok() check into compat_alloc_user_space() and also adds a sanity check on the length. The existing compat_alloc_user_space() implementations are renamed arch_compat_alloc_user_space() and are used as part of the implementation of the new global function. This patch assumes NULL will cause __get_user()/__put_user() to either fail or access userspace on all architectures. This should be followed by checking the return value of compat_access_user_space() for NULL in the callers, at which time the access_ok() in the callers can also be removed. Reported-by: Ben Hawkes Signed-off-by: H. Peter Anvin Acked-by: Benjamin Herrenschmidt Acked-by: Chris Metcalf Acked-by: David S. Miller Acked-by: Ingo Molnar Acked-by: Thomas Gleixner Acked-by: Tony Luck Cc: Andrew Morton Cc: Arnd Bergmann Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Heiko Carstens Cc: Helge Deller Cc: James Bottomley Cc: Kyle McMartin Cc: Martin Schwidefsky Cc: Paul Mackerras Cc: Ralf Baechle Cc: --- arch/ia64/include/asm/compat.h | 2 +- arch/mips/include/asm/compat.h | 2 +- arch/parisc/include/asm/compat.h | 2 +- arch/powerpc/include/asm/compat.h | 2 +- arch/s390/include/asm/compat.h | 2 +- arch/sparc/include/asm/compat.h | 2 +- arch/tile/include/asm/compat.h | 2 +- arch/x86/include/asm/compat.h | 2 +- include/linux/compat.h | 3 +++ kernel/compat.c | 21 +++++++++++++++++++++ 10 files changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/ia64/include/asm/compat.h b/arch/ia64/include/asm/compat.h index f90edc85b509..9301a2821615 100644 --- a/arch/ia64/include/asm/compat.h +++ b/arch/ia64/include/asm/compat.h @@ -199,7 +199,7 @@ ptr_to_compat(void __user *uptr) } static __inline__ void __user * -compat_alloc_user_space (long len) +arch_compat_alloc_user_space (long len) { struct pt_regs *regs = task_pt_regs(current); return (void __user *) (((regs->r12 & 0xffffffff) & -16) - len); diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h index 613f6912dfc1..dbc51065df5b 100644 --- a/arch/mips/include/asm/compat.h +++ b/arch/mips/include/asm/compat.h @@ -145,7 +145,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) return (u32)(unsigned long)uptr; } -static inline void __user *compat_alloc_user_space(long len) +static inline void __user *arch_compat_alloc_user_space(long len) { struct pt_regs *regs = (struct pt_regs *) ((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1; diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h index 02b77baa5da6..efa0b60c63fe 100644 --- a/arch/parisc/include/asm/compat.h +++ b/arch/parisc/include/asm/compat.h @@ -147,7 +147,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) return (u32)(unsigned long)uptr; } -static __inline__ void __user *compat_alloc_user_space(long len) +static __inline__ void __user *arch_compat_alloc_user_space(long len) { struct pt_regs *regs = ¤t->thread.regs; return (void __user *)regs->gr[30]; diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index 396d21a80058..a11d4eac4f97 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -134,7 +134,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) return (u32)(unsigned long)uptr; } -static inline void __user *compat_alloc_user_space(long len) +static inline void __user *arch_compat_alloc_user_space(long len) { struct pt_regs *regs = current->thread.regs; unsigned long usp = regs->gpr[1]; diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index 104f2007f097..a875c2f542e1 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -181,7 +181,7 @@ static inline int is_compat_task(void) #endif -static inline void __user *compat_alloc_user_space(long len) +static inline void __user *arch_compat_alloc_user_space(long len) { unsigned long stack; diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h index 5016f76ea98a..6f57325bb883 100644 --- a/arch/sparc/include/asm/compat.h +++ b/arch/sparc/include/asm/compat.h @@ -167,7 +167,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) return (u32)(unsigned long)uptr; } -static inline void __user *compat_alloc_user_space(long len) +static inline void __user *arch_compat_alloc_user_space(long len) { struct pt_regs *regs = current_thread_info()->kregs; unsigned long usp = regs->u_regs[UREG_I6]; diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 5a34da6cdd79..345d81ce44bb 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -195,7 +195,7 @@ static inline unsigned long ptr_to_compat_reg(void __user *uptr) return (long)(int)(long __force)uptr; } -static inline void __user *compat_alloc_user_space(long len) +static inline void __user *arch_compat_alloc_user_space(long len) { struct pt_regs *regs = task_pt_regs(current); return (void __user *)regs->sp - len; diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h index 306160e58b48..1d9cd27c2920 100644 --- a/arch/x86/include/asm/compat.h +++ b/arch/x86/include/asm/compat.h @@ -205,7 +205,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr) return (u32)(unsigned long)uptr; } -static inline void __user *compat_alloc_user_space(long len) +static inline void __user *arch_compat_alloc_user_space(long len) { struct pt_regs *regs = task_pt_regs(current); return (void __user *)regs->sp - len; diff --git a/include/linux/compat.h b/include/linux/compat.h index 9ddc8780e8db..5778b559d59c 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -360,5 +360,8 @@ extern ssize_t compat_rw_copy_check_uvector(int type, const struct compat_iovec __user *uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *fast_pointer, struct iovec **ret_pointer); + +extern void __user *compat_alloc_user_space(unsigned long len); + #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ diff --git a/kernel/compat.c b/kernel/compat.c index e167efce8423..c9e2ec0b34a8 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -1126,3 +1126,24 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info) return 0; } + +/* + * Allocate user-space memory for the duration of a single system call, + * in order to marshall parameters inside a compat thunk. + */ +void __user *compat_alloc_user_space(unsigned long len) +{ + void __user *ptr; + + /* If len would occupy more than half of the entire compat space... */ + if (unlikely(len > (((compat_uptr_t)~0) >> 1))) + return NULL; + + ptr = arch_compat_alloc_user_space(len); + + if (unlikely(!access_ok(VERIFY_WRITE, ptr, len))) + return NULL; + + return ptr; +} +EXPORT_SYMBOL_GPL(compat_alloc_user_space); -- cgit v1.2.3-59-g8ed1b From 36d001c70d8a0144ac1d038f6876c484849a74de Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 14 Sep 2010 12:42:41 -0700 Subject: x86-64, compat: Test %rax for the syscall number, not %eax On 64 bits, we always, by necessity, jump through the system call table via %rax. For 32-bit system calls, in theory the system call number is stored in %eax, and the code was testing %eax for a valid system call number. At one point we loaded the stored value back from the stack to enforce zero-extension, but that was removed in checkin d4d67150165df8bf1cc05e532f6efca96f907cab. An actual 32-bit process will not be able to introduce a non-zero-extended number, but it can happen via ptrace. Instead of re-introducing the zero-extension, test what we are actually going to use, i.e. %rax. This only adds a handful of REX prefixes to the code. Reported-by: Ben Hawkes Signed-off-by: H. Peter Anvin Cc: Cc: Roland McGrath Cc: Andrew Morton --- arch/x86/ia32/ia32entry.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index b86feabed69b..84e3a4ef9719 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -153,7 +153,7 @@ ENTRY(ia32_sysenter_target) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) CFI_REMEMBER_STATE jnz sysenter_tracesys - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja ia32_badsys sysenter_do_call: IA32_ARG_FIXUP @@ -195,7 +195,7 @@ sysexit_from_sys_call: movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */ call audit_syscall_entry movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */ - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja ia32_badsys movl %ebx,%edi /* reload 1st syscall arg */ movl RCX-ARGOFFSET(%rsp),%esi /* reload 2nd syscall arg */ @@ -248,7 +248,7 @@ sysenter_tracesys: call syscall_trace_enter LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */ jmp sysenter_do_call CFI_ENDPROC @@ -314,7 +314,7 @@ ENTRY(ia32_cstar_target) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) CFI_REMEMBER_STATE jnz cstar_tracesys - cmpl $IA32_NR_syscalls-1,%eax + cmpq $IA32_NR_syscalls-1,%rax ja ia32_badsys cstar_do_call: IA32_ARG_FIXUP 1 @@ -367,7 +367,7 @@ cstar_tracesys: LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */ RESTORE_REST xchgl %ebp,%r9d - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */ jmp cstar_do_call END(ia32_cstar_target) @@ -425,7 +425,7 @@ ENTRY(ia32_syscall) orl $TS_COMPAT,TI_status(%r10) testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10) jnz ia32_tracesys - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja ia32_badsys ia32_do_call: IA32_ARG_FIXUP @@ -444,7 +444,7 @@ ia32_tracesys: call syscall_trace_enter LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST - cmpl $(IA32_NR_syscalls-1),%eax + cmpq $(IA32_NR_syscalls-1),%rax ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */ jmp ia32_do_call END(ia32_syscall) -- cgit v1.2.3-59-g8ed1b From eefdca043e8391dcd719711716492063030b55ac Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Tue, 14 Sep 2010 12:22:58 -0700 Subject: x86-64, compat: Retruncate rax after ia32 syscall entry tracing In commit d4d6715, we reopened an old hole for a 64-bit ptracer touching a 32-bit tracee in system call entry. A %rax value set via ptrace at the entry tracing stop gets used whole as a 32-bit syscall number, while we only check the low 32 bits for validity. Fix it by truncating %rax back to 32 bits after syscall_trace_enter, in addition to testing the full 64 bits as has already been added. Reported-by: Ben Hawkes Signed-off-by: Roland McGrath Signed-off-by: H. Peter Anvin --- arch/x86/ia32/ia32entry.S | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 84e3a4ef9719..518bb99c3394 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -50,7 +50,12 @@ /* * Reload arg registers from stack in case ptrace changed them. * We don't reload %eax because syscall_trace_enter() returned - * the value it wants us to use in the table lookup. + * the %rax value we should see. Instead, we just truncate that + * value to 32 bits again as we did on entry from user mode. + * If it's a new value set by user_regset during entry tracing, + * this matches the normal truncation of the user-mode value. + * If it's -1 to make us punt the syscall, then (u32)-1 is still + * an appropriately invalid value. */ .macro LOAD_ARGS32 offset, _r9=0 .if \_r9 @@ -60,6 +65,7 @@ movl \offset+48(%rsp),%edx movl \offset+56(%rsp),%esi movl \offset+64(%rsp),%edi + movl %eax,%eax /* zero extension */ .endm .macro CFI_STARTPROC32 simple -- cgit v1.2.3-59-g8ed1b From 460cf3411b858ad509d5255e0dfaf862a83c0299 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 14 Sep 2010 11:38:24 -0400 Subject: cifs: fix potential double put of TCP session reference cifs_get_smb_ses must be called on a server pointer on which it holds an active reference. It first does a search for an existing SMB session. If it finds one, it'll put the server reference and then try to ensure that the negprot is done, etc. If it encounters an error at that point then it'll return an error. There's a potential problem here though. When cifs_get_smb_ses returns an error, the caller will also put the TCP server reference leading to a double-put. Fix this by having cifs_get_smb_ses only put the server reference if it found an existing session that it could use and isn't returning an error. Cc: stable@kernel.org Reviewed-by: Suresh Jayaraman Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/connect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 67dad54fbfa1..88c84a38bccb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1706,9 +1706,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) if (ses) { cFYI(1, "Existing smb sess found (status=%d)", ses->status); - /* existing SMB ses has a server reference already */ - cifs_put_tcp_session(server); - mutex_lock(&ses->session_mutex); rc = cifs_negotiate_protocol(xid, ses); if (rc) { @@ -1731,6 +1728,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) } } mutex_unlock(&ses->session_mutex); + + /* existing SMB ses has a server reference already */ + cifs_put_tcp_session(server); FreeXid(xid); return ses; } -- cgit v1.2.3-59-g8ed1b From 75e1c70fc31490ef8a373ea2a4bea2524099b478 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Fri, 10 Sep 2010 14:16:00 -0700 Subject: aio: check for multiplication overflow in do_io_submit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tavis Ormandy pointed out that do_io_submit does not do proper bounds checking on the passed-in iocb array:        if (unlikely(nr < 0))                return -EINVAL;        if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(iocbpp)))))                return -EFAULT;                      ^^^^^^^^^^^^^^^^^^ The attached patch checks for overflow, and if it is detected, the number of iocbs submitted is scaled down to a number that will fit in the long.  This is an ok thing to do, as sys_io_submit is documented as returning the number of iocbs submitted, so callers should handle a return value of less than the 'nr' argument passed in. Reported-by: Tavis Ormandy Signed-off-by: Jeff Moyer Signed-off-by: Linus Torvalds --- fs/aio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/aio.c b/fs/aio.c index 3006b5bc33d6..1320b2a05fb2 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1659,6 +1659,9 @@ long do_io_submit(aio_context_t ctx_id, long nr, if (unlikely(nr < 0)) return -EINVAL; + if (unlikely(nr > LONG_MAX/sizeof(*iocbpp))) + nr = LONG_MAX/sizeof(*iocbpp); + if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) return -EFAULT; -- cgit v1.2.3-59-g8ed1b From a4128b03ff1ff5bc6ea922518a3f36a09b914379 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 14 Sep 2010 17:59:15 +0100 Subject: MN10300: Fix up the IRQ names for the on-chip serial ports Fix up the IRQ names for the MN10300 on-chip serial ports in the driver as request_interrupt() no longer allows names containing slashes, giving a warning like the following if one is encountered: ------------[ cut here ]------------ WARNING: at fs/proc/generic.c:323 __xlate_proc_name+0x62/0x7c() name 'ttySM0/Rx' Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/mn10300/kernel/mn10300-serial.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c index 9d49073e827a..db509dd80565 100644 --- a/arch/mn10300/kernel/mn10300-serial.c +++ b/arch/mn10300/kernel/mn10300-serial.c @@ -156,17 +156,17 @@ struct mn10300_serial_port mn10300_serial_port_sif0 = { ._intr = &SC0ICR, ._rxb = &SC0RXB, ._txb = &SC0TXB, - .rx_name = "ttySM0/Rx", - .tx_name = "ttySM0/Tx", + .rx_name = "ttySM0:Rx", + .tx_name = "ttySM0:Tx", #ifdef CONFIG_MN10300_TTYSM0_TIMER8 - .tm_name = "ttySM0/Timer8", + .tm_name = "ttySM0:Timer8", ._tmxmd = &TM8MD, ._tmxbr = &TM8BR, ._tmicr = &TM8ICR, .tm_irq = TM8IRQ, .div_timer = MNSCx_DIV_TIMER_16BIT, #else /* CONFIG_MN10300_TTYSM0_TIMER2 */ - .tm_name = "ttySM0/Timer2", + .tm_name = "ttySM0:Timer2", ._tmxmd = &TM2MD, ._tmxbr = (volatile u16 *) &TM2BR, ._tmicr = &TM2ICR, @@ -209,17 +209,17 @@ struct mn10300_serial_port mn10300_serial_port_sif1 = { ._intr = &SC1ICR, ._rxb = &SC1RXB, ._txb = &SC1TXB, - .rx_name = "ttySM1/Rx", - .tx_name = "ttySM1/Tx", + .rx_name = "ttySM1:Rx", + .tx_name = "ttySM1:Tx", #ifdef CONFIG_MN10300_TTYSM1_TIMER9 - .tm_name = "ttySM1/Timer9", + .tm_name = "ttySM1:Timer9", ._tmxmd = &TM9MD, ._tmxbr = &TM9BR, ._tmicr = &TM9ICR, .tm_irq = TM9IRQ, .div_timer = MNSCx_DIV_TIMER_16BIT, #else /* CONFIG_MN10300_TTYSM1_TIMER3 */ - .tm_name = "ttySM1/Timer3", + .tm_name = "ttySM1:Timer3", ._tmxmd = &TM3MD, ._tmxbr = (volatile u16 *) &TM3BR, ._tmicr = &TM3ICR, @@ -260,9 +260,9 @@ struct mn10300_serial_port mn10300_serial_port_sif2 = { .uart.lock = __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock), .name = "ttySM2", - .rx_name = "ttySM2/Rx", - .tx_name = "ttySM2/Tx", - .tm_name = "ttySM2/Timer10", + .rx_name = "ttySM2:Rx", + .tx_name = "ttySM2:Tx", + .tm_name = "ttySM2:Timer10", ._iobase = &SC2CTR, ._control = &SC2CTR, ._status = &SC2STR, -- cgit v1.2.3-59-g8ed1b From fe725d4f22f6bd1e7a5e7074bdf53a8fe0a954ee Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 14 Sep 2010 10:10:47 -0400 Subject: drm/radeon/kms: only warn on mipmap size checks in r600 cs checker (v2) The texture base address registers are in units of 256 bytes. The original CS checker treated these offsets as bytes, so the original check was wrong. I fixed the units in a patch during the 2.6.36 cycle, but this ended up breaking some existing userspace (probably due to a bug in either userspace texture allocation or the drm texture mipmap checker). So for now, until we come up with a better fix, just warn if the mipmap size it too large. This will keep existing userspace working and it should be just as safe as before when we were checking the wrong units. These are GPU MC addresses, so if they fall outside of the VRAM or GART apertures, they end up at the GPU default page, so this should be safe from a security perspective. v2: Just disable the warning. It just spams the log and there's nothing the user can do about it. Signed-off-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r600_cs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index d8864949e387..250a3a918193 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -1170,9 +1170,8 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i /* using get ib will give us the offset into the mipmap bo */ word0 = radeon_get_ib_value(p, idx + 3) << 8; if ((mipmap_size + word0) > radeon_bo_size(mipmap)) { - dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n", - w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture)); - return -EINVAL; + /*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n", + w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));*/ } return 0; } -- cgit v1.2.3-59-g8ed1b From 6dcbc12290abb452a5e42713faa6461b248e2f55 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 14 Sep 2010 21:41:20 -0700 Subject: net: RPS needs to depend upon USE_GENERIC_SMP_HELPERS You cannot invoke __smp_call_function_single() unless the architecture sets this symbol. Reported-by: Daniel Hellstrom Signed-off-by: David S. Miller --- net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/Kconfig b/net/Kconfig index e330594d3709..e926884c1675 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -217,7 +217,7 @@ source "net/dns_resolver/Kconfig" config RPS boolean - depends on SMP && SYSFS + depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS default y menu "Network testing" -- cgit v1.2.3-59-g8ed1b From 1446c5fba73044a1c72153e1203b23b1820431c5 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 15 Sep 2010 08:01:57 +0200 Subject: ALSA: snd-aloop - fix the "PCM Playback Channels" kcontrol Obvious copy-and-paste error. Signed-off-by: Jaroslav Kysela --- sound/drivers/aloop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 3123a15d23f6..f2b8f868d97a 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -809,7 +809,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = loopback->setup[kcontrol->id.subdevice] - [kcontrol->id.device].rate; + [kcontrol->id.device].channels; return 0; } -- cgit v1.2.3-59-g8ed1b From e75e863dd5c7d96b91ebbd241da5328fc38a78cc Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 14 Sep 2010 16:35:14 +0200 Subject: sched: Fix user time incorrectly accounted as system time on 32-bit We have 32-bit variable overflow possibility when multiply in task_times() and thread_group_times() functions. When the overflow happens then the scaled utime value becomes erroneously small and the scaled stime becomes i erroneously big. Reported here: https://bugzilla.redhat.com/show_bug.cgi?id=633037 https://bugzilla.kernel.org/show_bug.cgi?id=16559 Reported-by: Michael Chapman Reported-by: Ciriaco Garcia de Celis Signed-off-by: Stanislaw Gruszka Signed-off-by: Peter Zijlstra Cc: Hidetoshi Seto Cc: # 2.6.32.19+ (partially) and 2.6.33+ LKML-Reference: <20100914143513.GB8415@redhat.com> Signed-off-by: Ingo Molnar --- kernel/sched.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index ed09d4f2a69c..dc85ceb90832 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3513,9 +3513,9 @@ void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st) rtime = nsecs_to_cputime(p->se.sum_exec_runtime); if (total) { - u64 temp; + u64 temp = rtime; - temp = (u64)(rtime * utime); + temp *= utime; do_div(temp, total); utime = (cputime_t)temp; } else @@ -3546,9 +3546,9 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) rtime = nsecs_to_cputime(cputime.sum_exec_runtime); if (total) { - u64 temp; + u64 temp = rtime; - temp = (u64)(rtime * cputime.utime); + temp *= cputime.utime; do_div(temp, total); utime = (cputime_t)temp; } else -- cgit v1.2.3-59-g8ed1b From e6e6c46d759cd013cb57eba112a4129a3a353c4b Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 15 Sep 2010 11:16:05 -0400 Subject: arch/tile: finish const-ifying sys_execve() The sys_execve() implementation was properly const-ified but not the declaration, the syscall wrappers, or the compat version. This change completes the constification process. Signed-off-by: Chris Metcalf --- arch/tile/include/asm/compat.h | 5 +++-- arch/tile/include/asm/syscalls.h | 21 +++++++++++++-------- arch/tile/kernel/process.c | 5 +++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 5a34da6cdd79..070ad0a5ef1c 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -214,8 +214,9 @@ extern int compat_setup_rt_frame(int sig, struct k_sigaction *ka, struct compat_sigaction; struct compat_siginfo; struct compat_sigaltstack; -long compat_sys_execve(char __user *path, compat_uptr_t __user *argv, - compat_uptr_t __user *envp); +long compat_sys_execve(const char __user *path, + const compat_uptr_t __user *argv, + const compat_uptr_t __user *envp); long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act, struct compat_sigaction __user *oact, size_t sigsetsize); diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h index af165a74537f..ce99ffefeacf 100644 --- a/arch/tile/include/asm/syscalls.h +++ b/arch/tile/include/asm/syscalls.h @@ -62,10 +62,12 @@ long sys_fork(void); long _sys_fork(struct pt_regs *regs); long sys_vfork(void); long _sys_vfork(struct pt_regs *regs); -long sys_execve(char __user *filename, char __user * __user *argv, - char __user * __user *envp); -long _sys_execve(char __user *filename, char __user * __user *argv, - char __user * __user *envp, struct pt_regs *regs); +long sys_execve(const char __user *filename, + const char __user *const __user *argv, + const char __user *const __user *envp); +long _sys_execve(const char __user *filename, + const char __user *const __user *argv, + const char __user *const __user *envp, struct pt_regs *regs); /* kernel/signal.c */ long sys_sigaltstack(const stack_t __user *, stack_t __user *); @@ -86,10 +88,13 @@ int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *); #endif #ifdef CONFIG_COMPAT -long compat_sys_execve(char __user *path, compat_uptr_t __user *argv, - compat_uptr_t __user *envp); -long _compat_sys_execve(char __user *path, compat_uptr_t __user *argv, - compat_uptr_t __user *envp, struct pt_regs *regs); +long compat_sys_execve(const char __user *path, + const compat_uptr_t __user *argv, + const compat_uptr_t __user *envp); +long _compat_sys_execve(const char __user *path, + const compat_uptr_t __user *argv, + const compat_uptr_t __user *envp, + struct pt_regs *regs); long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, struct compat_sigaltstack __user *uoss_ptr); long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 985cc28c74c5..88be49e3aa25 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -561,8 +561,9 @@ out: } #ifdef CONFIG_COMPAT -long _compat_sys_execve(char __user *path, compat_uptr_t __user *argv, - compat_uptr_t __user *envp, struct pt_regs *regs) +long _compat_sys_execve(const char __user *path, + const compat_uptr_t __user *argv, + const compat_uptr_t __user *envp, struct pt_regs *regs) { long error; char *filename; -- cgit v1.2.3-59-g8ed1b From 74fca9da097b74117ae2cef9e5f0d9b0e28ccbb7 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 15 Sep 2010 11:16:08 -0400 Subject: arch/tile: Change struct sigcontext to be more useful Rather than just using pt_regs, it now contains the actual saved state explicitly, similar to pt_regs. By doing it this way, we provide a cleaner API for userspace (or equivalently, we avoid the need for libc to provide its own definition of sigcontext). While we're at it, move PT_FLAGS_xxx to where they are not visible from userspace. And always pass siginfo and mcontext to signal handlers, even if they claim they don't need it, since sometimes they actually try to use it anyway in practice. Signed-off-by: Chris Metcalf --- arch/tile/include/asm/ptrace.h | 15 ++++++--------- arch/tile/include/asm/sigcontext.h | 18 +++++++++++++----- arch/tile/include/asm/signal.h | 1 + arch/tile/kernel/signal.c | 27 +++++++++++++++------------ arch/tile/kernel/stack.c | 2 +- 5 files changed, 36 insertions(+), 27 deletions(-) diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h index acdae814e016..4a02bb073979 100644 --- a/arch/tile/include/asm/ptrace.h +++ b/arch/tile/include/asm/ptrace.h @@ -51,10 +51,7 @@ typedef uint_reg_t pt_reg_t; /* * This struct defines the way the registers are stored on the stack during a - * system call/exception. It should be a multiple of 8 bytes to preserve - * normal stack alignment rules. - * - * Must track and + * system call or exception. "struct sigcontext" has the same shape. */ struct pt_regs { /* Saved main processor registers; 56..63 are special. */ @@ -80,11 +77,6 @@ struct pt_regs { #endif /* __ASSEMBLY__ */ -/* Flag bits in pt_regs.flags */ -#define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */ -#define PT_FLAGS_CALLER_SAVES 2 /* caller-save registers are valid */ -#define PT_FLAGS_RESTORE_REGS 4 /* restore callee-save regs on return */ - #define PTRACE_GETREGS 12 #define PTRACE_SETREGS 13 #define PTRACE_GETFPREGS 14 @@ -101,6 +93,11 @@ struct pt_regs { #ifdef __KERNEL__ +/* Flag bits in pt_regs.flags */ +#define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */ +#define PT_FLAGS_CALLER_SAVES 2 /* caller-save registers are valid */ +#define PT_FLAGS_RESTORE_REGS 4 /* restore callee-save regs on return */ + #ifndef __ASSEMBLY__ #define instruction_pointer(regs) ((regs)->pc) diff --git a/arch/tile/include/asm/sigcontext.h b/arch/tile/include/asm/sigcontext.h index 7cd7672e3ad4..5e2d03336f53 100644 --- a/arch/tile/include/asm/sigcontext.h +++ b/arch/tile/include/asm/sigcontext.h @@ -15,13 +15,21 @@ #ifndef _ASM_TILE_SIGCONTEXT_H #define _ASM_TILE_SIGCONTEXT_H -/* NOTE: we can't include due to #include dependencies. */ -#include - -/* Must track */ +#include +/* + * struct sigcontext has the same shape as struct pt_regs, + * but is simplified since we know the fault is from userspace. + */ struct sigcontext { - struct pt_regs regs; + uint_reg_t gregs[53]; /* General-purpose registers. */ + uint_reg_t tp; /* Aliases gregs[TREG_TP]. */ + uint_reg_t sp; /* Aliases gregs[TREG_SP]. */ + uint_reg_t lr; /* Aliases gregs[TREG_LR]. */ + uint_reg_t pc; /* Program counter. */ + uint_reg_t ics; /* In Interrupt Critical Section? */ + uint_reg_t faultnum; /* Fault number. */ + uint_reg_t pad[5]; }; #endif /* _ASM_TILE_SIGCONTEXT_H */ diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h index eb0253f32202..c1ee1d61d44c 100644 --- a/arch/tile/include/asm/signal.h +++ b/arch/tile/include/asm/signal.h @@ -24,6 +24,7 @@ #include #if defined(__KERNEL__) && !defined(__ASSEMBLY__) +struct pt_regs; int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *); int setup_sigcontext(struct sigcontext __user *, struct pt_regs *); void do_signal(struct pt_regs *regs); diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c index 45b66a3c991f..ce183aa1492c 100644 --- a/arch/tile/kernel/signal.c +++ b/arch/tile/kernel/signal.c @@ -61,13 +61,19 @@ int restore_sigcontext(struct pt_regs *regs, /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; + /* + * Enforce that sigcontext is like pt_regs, and doesn't mess + * up our stack alignment rules. + */ + BUILD_BUG_ON(sizeof(struct sigcontext) != sizeof(struct pt_regs)); + BUILD_BUG_ON(sizeof(struct sigcontext) % 8 != 0); + for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) - err |= __get_user(((long *)regs)[i], - &((long __user *)(&sc->regs))[i]); + err |= __get_user(regs->regs[i], &sc->gregs[i]); regs->faultnum = INT_SWINT_1_SIGRETURN; - err |= __get_user(*pr0, &sc->regs.regs[0]); + err |= __get_user(*pr0, &sc->gregs[0]); return err; } @@ -112,8 +118,7 @@ int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) int i, err = 0; for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i) - err |= __put_user(((long *)regs)[i], - &((long __user *)(&sc->regs))[i]); + err |= __put_user(regs->regs[i], &sc->gregs[i]); return err; } @@ -203,19 +208,17 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, * Set up registers for signal handler. * Registers that we don't modify keep the value they had from * user-space at the time we took the signal. + * We always pass siginfo and mcontext, regardless of SA_SIGINFO, + * since some things rely on this (e.g. glibc's debug/segfault.c). */ regs->pc = (unsigned long) ka->sa.sa_handler; regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */ regs->sp = (unsigned long) frame; regs->lr = restorer; regs->regs[0] = (unsigned long) usig; - - if (ka->sa.sa_flags & SA_SIGINFO) { - /* Need extra arguments, so mark to restore caller-saves. */ - regs->regs[1] = (unsigned long) &frame->info; - regs->regs[2] = (unsigned long) &frame->uc; - regs->flags |= PT_FLAGS_CALLER_SAVES; - } + regs->regs[1] = (unsigned long) &frame->info; + regs->regs[2] = (unsigned long) &frame->uc; + regs->flags |= PT_FLAGS_CALLER_SAVES; /* * Notify any tracer that was single-stepping it. diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index 38a68b0b4581..ea2e0ce28380 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c @@ -175,7 +175,7 @@ static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt) pr_err(" \n", frame->info.si_signo); } - return &frame->uc.uc_mcontext.regs; + return (struct pt_regs *)&frame->uc.uc_mcontext; } return NULL; } -- cgit v1.2.3-59-g8ed1b From a802fc685426303ab627b7ad3fd5c97b5dea7e00 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 15 Sep 2010 11:16:10 -0400 Subject: arch/tile: Save and restore extra user state for tilegx During context switch, save and restore a couple of additional bits of tilegx user state that can be persistently modified by userspace. Signed-off-by: Chris Metcalf --- arch/tile/include/arch/chip_tile64.h | 3 +++ arch/tile/include/arch/chip_tilepro.h | 3 +++ arch/tile/include/asm/processor.h | 12 ++++++++++++ arch/tile/kernel/process.c | 23 ++++++++++++++++------- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/arch/tile/include/arch/chip_tile64.h b/arch/tile/include/arch/chip_tile64.h index 1246573be59e..261aaba092d4 100644 --- a/arch/tile/include/arch/chip_tile64.h +++ b/arch/tile/include/arch/chip_tile64.h @@ -150,6 +150,9 @@ /** Is the PROC_STATUS SPR supported? */ #define CHIP_HAS_PROC_STATUS_SPR() 0 +/** Is the DSTREAM_PF SPR supported? */ +#define CHIP_HAS_DSTREAM_PF() 0 + /** Log of the number of mshims we have. */ #define CHIP_LOG_NUM_MSHIMS() 2 diff --git a/arch/tile/include/arch/chip_tilepro.h b/arch/tile/include/arch/chip_tilepro.h index e864c47fc89c..70017699a74c 100644 --- a/arch/tile/include/arch/chip_tilepro.h +++ b/arch/tile/include/arch/chip_tilepro.h @@ -150,6 +150,9 @@ /** Is the PROC_STATUS SPR supported? */ #define CHIP_HAS_PROC_STATUS_SPR() 1 +/** Is the DSTREAM_PF SPR supported? */ +#define CHIP_HAS_DSTREAM_PF() 0 + /** Log of the number of mshims we have. */ #define CHIP_LOG_NUM_MSHIMS() 2 diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index d942d09b252e..ccd5f8425688 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h @@ -103,6 +103,18 @@ struct thread_struct { /* Any other miscellaneous processor state bits */ unsigned long proc_status; #endif +#if !CHIP_HAS_FIXED_INTVEC_BASE() + /* Interrupt base for PL0 interrupts */ + unsigned long interrupt_vector_base; +#endif +#if CHIP_HAS_TILE_RTF_HWM() + /* Tile cache retry fifo high-water mark */ + unsigned long tile_rtf_hwm; +#endif +#if CHIP_HAS_DSTREAM_PF() + /* Data stream prefetch control */ + unsigned long dstream_pf; +#endif #ifdef CONFIG_HARDWALL /* Is this task tied to an activated hardwall? */ struct hardwall_info *hardwall; diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 88be49e3aa25..c37b6e3873c1 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -408,6 +408,15 @@ static void save_arch_state(struct thread_struct *t) #if CHIP_HAS_PROC_STATUS_SPR() t->proc_status = __insn_mfspr(SPR_PROC_STATUS); #endif +#if !CHIP_HAS_FIXED_INTVEC_BASE() + t->interrupt_vector_base = __insn_mfspr(SPR_INTERRUPT_VECTOR_BASE_0); +#endif +#if CHIP_HAS_TILE_RTF_HWM() + t->tile_rtf_hwm = __insn_mfspr(SPR_TILE_RTF_HWM); +#endif +#if CHIP_HAS_DSTREAM_PF() + t->dstream_pf = __insn_mfspr(SPR_DSTREAM_PF); +#endif } static void restore_arch_state(const struct thread_struct *t) @@ -428,14 +437,14 @@ static void restore_arch_state(const struct thread_struct *t) #if CHIP_HAS_PROC_STATUS_SPR() __insn_mtspr(SPR_PROC_STATUS, t->proc_status); #endif +#if !CHIP_HAS_FIXED_INTVEC_BASE() + __insn_mtspr(SPR_INTERRUPT_VECTOR_BASE_0, t->interrupt_vector_base); +#endif #if CHIP_HAS_TILE_RTF_HWM() - /* - * Clear this whenever we switch back to a process in case - * the previous process was monkeying with it. Even if enabled - * in CBOX_MSR1 via TILE_RTF_HWM_MIN, it's still just a - * performance hint, so isn't worth a full save/restore. - */ - __insn_mtspr(SPR_TILE_RTF_HWM, 0); + __insn_mtspr(SPR_TILE_RTF_HWM, t->tile_rtf_hwm); +#endif +#if CHIP_HAS_DSTREAM_PF() + __insn_mtspr(SPR_DSTREAM_PF, t->dstream_pf); #endif } -- cgit v1.2.3-59-g8ed1b From 0fab59e5ddb4e0557825e9ab8e41b66b5f336941 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 15 Sep 2010 11:17:04 -0400 Subject: arch/tile: fix memcpy_fromio()/memcpy_toio() signatures This tripped up a driver (not yet committed to git). Fix it now. Signed-off-by: Chris Metcalf --- arch/tile/include/asm/io.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h index 8c95bef3fa45..ee43328713ab 100644 --- a/arch/tile/include/asm/io.h +++ b/arch/tile/include/asm/io.h @@ -164,22 +164,22 @@ static inline void _tile_writeq(u64 val, unsigned long addr) #define iowrite32 writel #define iowrite64 writeq -static inline void *memcpy_fromio(void *dst, void *src, int len) +static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, + size_t len) { int x; BUG_ON((unsigned long)src & 0x3); for (x = 0; x < len; x += 4) *(u32 *)(dst + x) = readl(src + x); - return dst; } -static inline void *memcpy_toio(void *dst, void *src, int len) +static inline void memcpy_toio(volatile void __iomem *dst, const void *src, + size_t len) { int x; BUG_ON((unsigned long)dst & 0x3); for (x = 0; x < len; x += 4) writel(*(u32 *)(src + x), dst + x); - return dst; } /* -- cgit v1.2.3-59-g8ed1b From 7040dea4d2a0609241c7a98a944b7c432c69db2e Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 15 Sep 2010 11:17:05 -0400 Subject: arch/tile: fix formatting bug in register dumps This cut-and-paste bug was caused by rewriting the register dump code to use only a single printk per line of output. Signed-off-by: Chris Metcalf --- arch/tile/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index c37b6e3873c1..84c29111756c 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -667,7 +667,7 @@ void show_regs(struct pt_regs *regs) regs->regs[51], regs->regs[52], regs->tp); pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr); #else - for (i = 0; i < 52; i += 3) + for (i = 0; i < 52; i += 4) pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT " r%-2d: "REGFMT" r%-2d: "REGFMT"\n", i, regs->regs[i], i+1, regs->regs[i+1], -- cgit v1.2.3-59-g8ed1b From c494bc6c534c78fac2d308ad38073b9226448b0d Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Mon, 30 Aug 2010 08:18:54 +0200 Subject: pcmcia serial_cs.c: fix multifunction card handling We shouldn't overwrite pre-set values, and we should also set the port address to the beginning, and not the end of the 8-port range. CC: linux-serial@vger.kernel.org Reported-by: Komuro Hardware-supplied-by: Jochen Frieling Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/serial/serial_cs.c | 62 +++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 141c69554bd4..7d475b2a79e8 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -335,8 +335,6 @@ static int serial_probe(struct pcmcia_device *link) info->p_dev = link; link->priv = info; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - link->resource[0]->end = 8; link->conf.Attributes = CONF_ENABLE_IRQ; if (do_sound) { link->conf.Attributes |= CONF_ENABLE_SPKR; @@ -411,6 +409,27 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, /*====================================================================*/ +static int pfc_config(struct pcmcia_device *p_dev) +{ + unsigned int port = 0; + struct serial_info *info = p_dev->priv; + + if ((p_dev->resource[1]->end != 0) && + (resource_size(p_dev->resource[1]) == 8)) { + port = p_dev->resource[1]->start; + info->slave = 1; + } else if ((info->manfid == MANFID_OSITECH) && + (resource_size(p_dev->resource[0]) == 0x40)) { + port = p_dev->resource[0]->start + 0x28; + info->slave = 1; + } + if (info->slave) + return setup_serial(p_dev, info, port, p_dev->irq); + + dev_warn(&p_dev->dev, "no usable port range found, giving up\n"); + return -ENODEV; +} + static int simple_config_check(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cf, cistpl_cftable_entry_t *dflt, @@ -461,23 +480,8 @@ static int simple_config(struct pcmcia_device *link) struct serial_info *info = link->priv; int i = -ENODEV, try; - /* If the card is already configured, look up the port and irq */ - if (link->function_config) { - unsigned int port = 0; - if ((link->resource[1]->end != 0) && - (resource_size(link->resource[1]) == 8)) { - port = link->resource[1]->end; - info->slave = 1; - } else if ((info->manfid == MANFID_OSITECH) && - (resource_size(link->resource[0]) == 0x40)) { - port = link->resource[0]->start + 0x28; - info->slave = 1; - } - if (info->slave) { - return setup_serial(link, info, port, - link->irq); - } - } + link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + link->resource[0]->end = 8; /* First pass: look for a config entry that looks normal. * Two tries: without IO aliases, then with aliases */ @@ -491,8 +495,7 @@ static int simple_config(struct pcmcia_device *link) if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) goto found_port; - printk(KERN_NOTICE - "serial_cs: no usable port range found, giving up\n"); + dev_warn(&link->dev, "no usable port range found, giving up\n"); return -1; found_port: @@ -558,6 +561,7 @@ static int multi_config(struct pcmcia_device *link) int i, base2 = 0; /* First, look for a generic full-sized window */ + link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; link->resource[0]->end = info->multi * 8; if (pcmcia_loop_config(link, multi_config_check, &base2)) { /* If that didn't work, look for two windows */ @@ -565,15 +569,14 @@ static int multi_config(struct pcmcia_device *link) info->multi = 2; if (pcmcia_loop_config(link, multi_config_check_notpicky, &base2)) { - printk(KERN_NOTICE "serial_cs: no usable port range" + dev_warn(&link->dev, "no usable port range " "found, giving up\n"); return -ENODEV; } } if (!link->irq) - dev_warn(&link->dev, - "serial_cs: no usable IRQ found, continuing...\n"); + dev_warn(&link->dev, "no usable IRQ found, continuing...\n"); /* * Apply any configuration quirks. @@ -675,6 +678,7 @@ static int serial_config(struct pcmcia_device * link) multifunction cards that ask for appropriate IO port ranges */ if ((info->multi == 0) && (link->has_func_id) && + (link->socket->pcmcia_pfc == 0) && ((link->func_id == CISTPL_FUNCID_MULTI) || (link->func_id == CISTPL_FUNCID_SERIAL))) pcmcia_loop_config(link, serial_check_for_multi, info); @@ -685,7 +689,13 @@ static int serial_config(struct pcmcia_device * link) if (info->quirk && info->quirk->multi != -1) info->multi = info->quirk->multi; - if (info->multi > 1) + dev_info(&link->dev, + "trying to set up [0x%04x:0x%04x] (pfc: %d, multi: %d, quirk: %p)\n", + link->manf_id, link->card_id, + link->socket->pcmcia_pfc, info->multi, info->quirk); + if (link->socket->pcmcia_pfc) + i = pfc_config(link); + else if (info->multi > 1) i = multi_config(link); else i = simple_config(link); @@ -704,7 +714,7 @@ static int serial_config(struct pcmcia_device * link) return 0; failed: - dev_warn(&link->dev, "serial_cs: failed to initialize\n"); + dev_warn(&link->dev, "failed to initialize\n"); serial_remove(link); return -ENODEV; } -- cgit v1.2.3-59-g8ed1b From eb838fe109b8f51ba590802761753a2631c3f7f0 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Mon, 13 Sep 2010 16:51:36 +0200 Subject: pcmcia: per-device, not per-socket debug messages As the iomem / ioport setup differs per device, it is much better to print out the device instead of the socket. Tested-by: Wolfram Sang Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_resource.c | 51 +++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 54aa1c238cb3..a5c176598d95 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -163,7 +163,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev, c = p_dev->function_config; if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&s->dev, "Configuration isnt't locked\n"); + dev_dbg(&p_dev->dev, "Configuration isnt't locked\n"); mutex_unlock(&s->ops_mutex); return -EACCES; } @@ -220,7 +220,7 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh, s->win[w].card_start = offset; ret = s->ops->set_mem_map(s, &s->win[w]); if (ret) - dev_warn(&s->dev, "failed to set_mem_map\n"); + dev_warn(&p_dev->dev, "failed to set_mem_map\n"); mutex_unlock(&s->ops_mutex); return ret; } /* pcmcia_map_mem_page */ @@ -244,18 +244,18 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, c = p_dev->function_config; if (!(s->state & SOCKET_PRESENT)) { - dev_dbg(&s->dev, "No card present\n"); + dev_dbg(&p_dev->dev, "No card present\n"); ret = -ENODEV; goto unlock; } if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&s->dev, "Configuration isnt't locked\n"); + dev_dbg(&p_dev->dev, "Configuration isnt't locked\n"); ret = -EACCES; goto unlock; } if (mod->Attributes & (CONF_IRQ_CHANGE_VALID | CONF_VCC_CHANGE_VALID)) { - dev_dbg(&s->dev, + dev_dbg(&p_dev->dev, "changing Vcc or IRQ is not allowed at this time\n"); ret = -EINVAL; goto unlock; @@ -265,20 +265,22 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) && (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { if (mod->Vpp1 != mod->Vpp2) { - dev_dbg(&s->dev, "Vpp1 and Vpp2 must be the same\n"); + dev_dbg(&p_dev->dev, + "Vpp1 and Vpp2 must be the same\n"); ret = -EINVAL; goto unlock; } s->socket.Vpp = mod->Vpp1; if (s->ops->set_socket(s, &s->socket)) { - dev_printk(KERN_WARNING, &s->dev, + dev_printk(KERN_WARNING, &p_dev->dev, "Unable to set VPP\n"); ret = -EIO; goto unlock; } } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { - dev_dbg(&s->dev, "changing Vcc is not allowed at this time\n"); + dev_dbg(&p_dev->dev, + "changing Vcc is not allowed at this time\n"); ret = -EINVAL; goto unlock; } @@ -401,7 +403,7 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res) win = &s->win[w]; if (!(p_dev->_win & CLIENT_WIN_REQ(w))) { - dev_dbg(&s->dev, "not releasing unknown window\n"); + dev_dbg(&p_dev->dev, "not releasing unknown window\n"); mutex_unlock(&s->ops_mutex); return -EINVAL; } @@ -439,7 +441,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, return -ENODEV; if (req->IntType & INT_CARDBUS) { - dev_dbg(&s->dev, "IntType may not be INT_CARDBUS\n"); + dev_dbg(&p_dev->dev, "IntType may not be INT_CARDBUS\n"); return -EINVAL; } @@ -447,7 +449,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, c = p_dev->function_config; if (c->state & CONFIG_LOCKED) { mutex_unlock(&s->ops_mutex); - dev_dbg(&s->dev, "Configuration is locked\n"); + dev_dbg(&p_dev->dev, "Configuration is locked\n"); return -EACCES; } @@ -455,7 +457,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, s->socket.Vpp = req->Vpp; if (s->ops->set_socket(s, &s->socket)) { mutex_unlock(&s->ops_mutex); - dev_printk(KERN_WARNING, &s->dev, + dev_printk(KERN_WARNING, &p_dev->dev, "Unable to set socket state\n"); return -EINVAL; } @@ -569,19 +571,20 @@ int pcmcia_request_io(struct pcmcia_device *p_dev) int ret = -EINVAL; mutex_lock(&s->ops_mutex); - dev_dbg(&s->dev, "pcmcia_request_io: %pR , %pR", &c->io[0], &c->io[1]); + dev_dbg(&p_dev->dev, "pcmcia_request_io: %pR , %pR", + &c->io[0], &c->io[1]); if (!(s->state & SOCKET_PRESENT)) { - dev_dbg(&s->dev, "pcmcia_request_io: No card present\n"); + dev_dbg(&p_dev->dev, "pcmcia_request_io: No card present\n"); goto out; } if (c->state & CONFIG_LOCKED) { - dev_dbg(&s->dev, "Configuration is locked\n"); + dev_dbg(&p_dev->dev, "Configuration is locked\n"); goto out; } if (c->state & CONFIG_IO_REQ) { - dev_dbg(&s->dev, "IO already configured\n"); + dev_dbg(&p_dev->dev, "IO already configured\n"); goto out; } @@ -601,7 +604,7 @@ int pcmcia_request_io(struct pcmcia_device *p_dev) c->state |= CONFIG_IO_REQ; p_dev->_io = 1; - dev_dbg(&s->dev, "pcmcia_request_io succeeded: %pR , %pR", + dev_dbg(&p_dev->dev, "pcmcia_request_io succeeded: %pR , %pR", &c->io[0], &c->io[1]); out: mutex_unlock(&s->ops_mutex); @@ -800,7 +803,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha int w; if (!(s->state & SOCKET_PRESENT)) { - dev_dbg(&s->dev, "No card present\n"); + dev_dbg(&p_dev->dev, "No card present\n"); return -ENODEV; } @@ -809,12 +812,12 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha req->Size = s->map_size; align = (s->features & SS_CAP_MEM_ALIGN) ? req->Size : s->map_size; if (req->Size & (s->map_size-1)) { - dev_dbg(&s->dev, "invalid map size\n"); + dev_dbg(&p_dev->dev, "invalid map size\n"); return -EINVAL; } if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) || (req->Base & (align-1))) { - dev_dbg(&s->dev, "invalid base address\n"); + dev_dbg(&p_dev->dev, "invalid base address\n"); return -EINVAL; } if (req->Base) @@ -826,7 +829,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha if (!(s->state & SOCKET_WIN_REQ(w))) break; if (w == MAX_WIN) { - dev_dbg(&s->dev, "all windows are used already\n"); + dev_dbg(&p_dev->dev, "all windows are used already\n"); mutex_unlock(&s->ops_mutex); return -EINVAL; } @@ -837,7 +840,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha win->res = pcmcia_find_mem_region(req->Base, req->Size, align, 0, s); if (!win->res) { - dev_dbg(&s->dev, "allocating mem region failed\n"); + dev_dbg(&p_dev->dev, "allocating mem region failed\n"); mutex_unlock(&s->ops_mutex); return -EINVAL; } @@ -851,7 +854,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha win->card_start = 0; if (s->ops->set_mem_map(s, win) != 0) { - dev_dbg(&s->dev, "failed to set memory mapping\n"); + dev_dbg(&p_dev->dev, "failed to set memory mapping\n"); mutex_unlock(&s->ops_mutex); return -EIO; } @@ -874,7 +877,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha if (win->res) request_resource(&iomem_resource, res); - dev_dbg(&s->dev, "request_window results in %pR\n", res); + dev_dbg(&p_dev->dev, "request_window results in %pR\n", res); mutex_unlock(&s->ops_mutex); *wh = res; -- cgit v1.2.3-59-g8ed1b From b76dc0546709aef18f123847680108c2fd33f203 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Mon, 13 Sep 2010 20:23:12 +0200 Subject: pcmcia pcnet_cs: try setting io_lines to 16 if card setup fails Some pcnet_cs compatible cards require an exact 16-lines match of the ioport areas specified in CIS, but set the "iolines" value in the CIS incorrectly. We can easily work around this issue -- same as we do in serial_cs -- by first trying setting iolines to the CIS-specified value, and then trying a 16-line match. Reported-and-tested-by: Wolfram Sang Hardware-supplied-by: Jochen Frieling CC: netdev@vger.kernel.org Signed-off-by: Dominik Brodowski --- drivers/net/pcmcia/pcnet_cs.c | 139 +++++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 56 deletions(-) diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 49279b0ee526..f9b509a6b09a 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -508,7 +508,8 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev, unsigned int vcc, void *priv_data) { - int *has_shmem = priv_data; + int *priv = priv_data; + int try = (*priv & 0x1); int i; cistpl_io_t *io = &cfg->io; @@ -525,77 +526,103 @@ static int pcnet_confcheck(struct pcmcia_device *p_dev, i = p_dev->resource[1]->end = 0; } - *has_shmem = ((cfg->mem.nwin == 1) && - (cfg->mem.win[0].len >= 0x4000)); + *priv &= ((cfg->mem.nwin == 1) && + (cfg->mem.win[0].len >= 0x4000)) ? 0x10 : ~0x10; + p_dev->resource[0]->start = io->win[i].base; p_dev->resource[0]->end = io->win[i].len; - p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; + if (!try) + p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; + else + p_dev->io_lines = 16; if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32) return try_io_port(p_dev); - return 0; + return -EINVAL; +} + +static hw_info_t *pcnet_try_config(struct pcmcia_device *link, + int *has_shmem, int try) +{ + struct net_device *dev = link->priv; + hw_info_t *local_hw_info; + pcnet_dev_t *info = PRIV(dev); + int priv = try; + int ret; + + ret = pcmcia_loop_config(link, pcnet_confcheck, &priv); + if (ret) { + dev_warn(&link->dev, "no useable port range found\n"); + return NULL; + } + *has_shmem = (priv & 0x10); + + if (!link->irq) + return NULL; + + if (resource_size(link->resource[1]) == 8) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + if ((link->manf_id == MANFID_IBM) && + (link->card_id == PRODID_IBM_HOME_AND_AWAY)) + link->conf.ConfigIndex |= 0x10; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + return NULL; + + dev->irq = link->irq; + dev->base_addr = link->resource[0]->start; + + if (info->flags & HAS_MISC_REG) { + if ((if_port == 1) || (if_port == 2)) + dev->if_port = if_port; + else + dev_notice(&link->dev, "invalid if_port requested\n"); + } else + dev->if_port = 0; + + if ((link->conf.ConfigBase == 0x03c0) && + (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) { + dev_info(&link->dev, + "this is an AX88190 card - use axnet_cs instead.\n"); + return NULL; + } + + local_hw_info = get_hwinfo(link); + if (!local_hw_info) + local_hw_info = get_prom(link); + if (!local_hw_info) + local_hw_info = get_dl10019(link); + if (!local_hw_info) + local_hw_info = get_ax88190(link); + if (!local_hw_info) + local_hw_info = get_hwired(link); + + return local_hw_info; } static int pcnet_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; pcnet_dev_t *info = PRIV(dev); - int ret, start_pg, stop_pg, cm_offset; + int start_pg, stop_pg, cm_offset; int has_shmem = 0; hw_info_t *local_hw_info; dev_dbg(&link->dev, "pcnet_config\n"); - ret = pcmcia_loop_config(link, pcnet_confcheck, &has_shmem); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - if (resource_size(link->resource[1]) == 8) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - if ((link->manf_id == MANFID_IBM) && - (link->card_id == PRODID_IBM_HOME_AND_AWAY)) - link->conf.ConfigIndex |= 0x10; - - ret = pcmcia_request_configuration(link, &link->conf); - if (ret) - goto failed; - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - if (info->flags & HAS_MISC_REG) { - if ((if_port == 1) || (if_port == 2)) - dev->if_port = if_port; - else - printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n"); - } else { - dev->if_port = 0; - } - - if ((link->conf.ConfigBase == 0x03c0) && - (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) { - printk(KERN_INFO "pcnet_cs: this is an AX88190 card!\n"); - printk(KERN_INFO "pcnet_cs: use axnet_cs instead.\n"); - goto failed; - } - - local_hw_info = get_hwinfo(link); - if (local_hw_info == NULL) - local_hw_info = get_prom(link); - if (local_hw_info == NULL) - local_hw_info = get_dl10019(link); - if (local_hw_info == NULL) - local_hw_info = get_ax88190(link); - if (local_hw_info == NULL) - local_hw_info = get_hwired(link); - - if (local_hw_info == NULL) { - printk(KERN_NOTICE "pcnet_cs: unable to read hardware net" - " address for io base %#3lx\n", dev->base_addr); - goto failed; + local_hw_info = pcnet_try_config(link, &has_shmem, 0); + if (!local_hw_info) { + /* check whether forcing io_lines to 16 helps... */ + pcmcia_disable_device(link); + local_hw_info = pcnet_try_config(link, &has_shmem, 1); + if (local_hw_info == NULL) { + dev_notice(&link->dev, "unable to read hardware net" + " address for io base %#3lx\n", dev->base_addr); + goto failed; + } } info->flags = local_hw_info->flags; -- cgit v1.2.3-59-g8ed1b From 359f64f7b3997e94ee71039b5fcdc1278b9b77c4 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 15 Sep 2010 10:18:51 -0700 Subject: omap: Fix compile dependency to LEDS_CLASS If we LEDS_CLASS is not selected, we will get undefined reference to `led_classdev_register'. Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index e39a417a368d..a92cb499313f 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -33,7 +33,7 @@ config OMAP_DEBUG_DEVICES config OMAP_DEBUG_LEDS bool depends on OMAP_DEBUG_DEVICES - default y if LEDS + default y if LEDS_CLASS config OMAP_RESET_CLOCKS bool "Reset unused clocks during boot" -- cgit v1.2.3-59-g8ed1b From ae44855ae8b36e4194a0a43eec6351e81f880955 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 21 Aug 2010 18:27:50 +0900 Subject: watchdog: sb_wdog: release irq and reboot notifier in error path and module_exit() irq and reboot notifier are acquired in module_init() but never released. They should be released correctly, otherwise reloading the module or error during module_init() will cause a problem. Signed-off-by: Akinobu Mita Cc: Andrew Sharp Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/sb_wdog.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c index 88c83aa57303..f31493e65b38 100644 --- a/drivers/watchdog/sb_wdog.c +++ b/drivers/watchdog/sb_wdog.c @@ -305,7 +305,7 @@ static int __init sbwdog_init(void) if (ret) { printk(KERN_ERR "%s: failed to request irq 1 - %d\n", ident.identity, ret); - return ret; + goto out; } ret = misc_register(&sbwdog_miscdev); @@ -313,14 +313,20 @@ static int __init sbwdog_init(void) printk(KERN_INFO "%s: timeout is %ld.%ld secs\n", ident.identity, timeout / 1000000, (timeout / 100000) % 10); - } else - free_irq(1, (void *)user_dog); + return 0; + } + free_irq(1, (void *)user_dog); +out: + unregister_reboot_notifier(&sbwdog_notifier); + return ret; } static void __exit sbwdog_exit(void) { misc_deregister(&sbwdog_miscdev); + free_irq(1, (void *)user_dog); + unregister_reboot_notifier(&sbwdog_notifier); } module_init(sbwdog_init); -- cgit v1.2.3-59-g8ed1b From 0e901bed4e053098f1c8411dcbf21324b7f61775 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sun, 29 Aug 2010 13:53:14 +0300 Subject: watchdog: ts72xx_wdt: disable watchdog at probe Since it may be already enabled by bootloader or some other utility. This patch makes sure that the watchdog is disabled before any userspace daemon opens the device. It is also required by the watchdog API. Signed-off-by: Mika Westerberg Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/ts72xx_wdt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index 458c499c1223..18cdeb4c4258 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c @@ -449,6 +449,9 @@ static __devinit int ts72xx_wdt_probe(struct platform_device *pdev) wdt->pdev = pdev; mutex_init(&wdt->lock); + /* make sure that the watchdog is disabled */ + ts72xx_wdt_stop(wdt); + error = misc_register(&ts72xx_wdt_miscdev); if (error) { dev_err(&pdev->dev, "failed to register miscdev\n"); -- cgit v1.2.3-59-g8ed1b From 0a18e15598274b79ce14342ce0bfb76a87dadb45 Mon Sep 17 00:00:00 2001 From: Kevin Wells Date: Tue, 17 Aug 2010 17:45:28 -0700 Subject: watchdog: Enable NXP LPC32XX support in Kconfig (resend) The NXP LPC32XX processor use the same watchdog as the Philips PNX4008 processor. Signed-off-by: Kevin Wells Tested-by: Wolfram Sang Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b036677df8c4..24efd8ea41bb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -213,11 +213,11 @@ config OMAP_WATCHDOG here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer. config PNX4008_WATCHDOG - tristate "PNX4008 Watchdog" - depends on ARCH_PNX4008 + tristate "PNX4008 and LPC32XX Watchdog" + depends on ARCH_PNX4008 || ARCH_LPC32XX help Say Y here if to include support for the watchdog timer - in the PNX4008 processor. + in the PNX4008 or LPC32XX processor. This driver can be built as a module by choosing M. The module will be called pnx4008_wdt. -- cgit v1.2.3-59-g8ed1b From 01f83d69844d307be2aa6fea88b0e8fe5cbdb2f4 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Wed, 15 Sep 2010 10:27:52 -0700 Subject: tcp: Prevent overzealous packetization by SWS logic. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If peer uses tiny MSS (say, 75 bytes) and similarly tiny advertised window, the SWS logic will packetize to half the MSS unnecessarily. This causes problems with some embedded devices. However for large MSS devices we do want to half-MSS packetize otherwise we never get enough packets into the pipe for things like fast retransmit and recovery to work. Be careful also to handle the case where MSS > window, otherwise we'll never send until the probe timer. Reported-by: ツ Leandro Melo de Sales Signed-off-by: David S. Miller --- include/net/tcp.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index eaa9582779d0..3e4b33e36602 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -475,8 +475,22 @@ extern unsigned int tcp_current_mss(struct sock *sk); /* Bound MSS / TSO packet size with the half of the window */ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) { - if (tp->max_window && pktsize > (tp->max_window >> 1)) - return max(tp->max_window >> 1, 68U - tp->tcp_header_len); + int cutoff; + + /* When peer uses tiny windows, there is no use in packetizing + * to sub-MSS pieces for the sake of SWS or making sure there + * are enough packets in the pipe for fast recovery. + * + * On the other hand, for extremely large MSS devices, handling + * smaller than MSS windows in this way does make sense. + */ + if (tp->max_window >= 512) + cutoff = (tp->max_window >> 1); + else + cutoff = tp->max_window; + + if (cutoff && pktsize > cutoff) + return max_t(int, cutoff, 68U - tp->tcp_header_len); else return pktsize; } -- cgit v1.2.3-59-g8ed1b From 84176b7b56704580e008e6cb820dd4ccf622a1fd Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Wed, 15 Sep 2010 00:58:46 +0000 Subject: 3c59x: Remove atomic context inside vortex_{set|get}_wol There is no need to use spinlocks in vortex_{set|get}_wol. This also fixes a bug: [ 254.214993] 3c59x 0000:00:0d.0: PME# enabled [ 254.215021] BUG: sleeping function called from invalid context at kernel/mutex.c:94 [ 254.215030] in_atomic(): 0, irqs_disabled(): 1, pid: 4875, name: ethtool [ 254.215042] Pid: 4875, comm: ethtool Tainted: G W 2.6.36-rc3+ #7 [ 254.215049] Call Trace: [ 254.215050] [] __might_sleep+0xb1/0xb6 [ 254.215050] [] mutex_lock+0x17/0x30 [ 254.215050] [] acpi_enable_wakeup_device_power+0x2b/0xb1 [ 254.215050] [] acpi_pm_device_sleep_wake+0x42/0x7f [ 254.215050] [] acpi_pci_sleep_wake+0x5d/0x63 [ 254.215050] [] platform_pci_sleep_wake+0x1d/0x20 [ 254.215050] [] __pci_enable_wake+0x90/0xd0 [ 254.215050] [] acpi_set_WOL+0x8e/0xf5 [3c59x] [ 254.215050] [] vortex_set_wol+0x4e/0x5e [3c59x] [ 254.215050] [] dev_ethtool+0x1cf/0xb61 [ 254.215050] [] ? debug_mutex_free_waiter+0x45/0x4a [ 254.215050] [] ? __mutex_lock_common+0x204/0x20e [ 254.215050] [] ? __mutex_lock_slowpath+0x12/0x15 [ 254.215050] [] ? mutex_lock+0x23/0x30 [ 254.215050] [] dev_ioctl+0x42c/0x533 [ 254.215050] [] ? _cond_resched+0x8/0x1c [ 254.215050] [] ? lock_page+0x1c/0x30 [ 254.215050] [] ? page_address+0x15/0x7c [ 254.215050] [] ? filemap_fault+0x187/0x2c4 [ 254.215050] [] sock_ioctl+0x1d4/0x1e0 [ 254.215050] [] ? sock_ioctl+0x0/0x1e0 [ 254.215050] [] vfs_ioctl+0x19/0x33 [ 254.215050] [] do_vfs_ioctl+0x424/0x46f [ 254.215050] [] ? selinux_file_ioctl+0x3c/0x40 [ 254.215050] [] sys_ioctl+0x40/0x5a [ 254.215050] [] sysenter_do_call+0x12/0x22 vortex_set_wol protected with a spinlock, but nested acpi_set_WOL acquires a mutex inside atomic context. Ethtool operations are already serialized by RTNL mutex, so it is safe to drop the locks. Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller --- drivers/net/3c59x.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 85671adae455..fa42103b2874 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -635,6 +635,9 @@ struct vortex_private { must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ large_frames:1, /* accept large frames */ handling_irq:1; /* private in_irq indicator */ + /* {get|set}_wol operations are already serialized by rtnl. + * no additional locking is required for the enable_wol and acpi_set_WOL() + */ int drv_flags; u16 status_enable; u16 intr_enable; @@ -2939,13 +2942,11 @@ static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct vortex_private *vp = netdev_priv(dev); - spin_lock_irq(&vp->lock); wol->supported = WAKE_MAGIC; wol->wolopts = 0; if (vp->enable_wol) wol->wolopts |= WAKE_MAGIC; - spin_unlock_irq(&vp->lock); } static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -2954,13 +2955,11 @@ static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; - spin_lock_irq(&vp->lock); if (wol->wolopts & WAKE_MAGIC) vp->enable_wol = 1; else vp->enable_wol = 0; acpi_set_WOL(dev); - spin_unlock_irq(&vp->lock); return 0; } -- cgit v1.2.3-59-g8ed1b From 2d2b6901649a62977452be85df53eda2412def24 Mon Sep 17 00:00:00 2001 From: Petr Tesarik Date: Wed, 15 Sep 2010 15:35:48 -0700 Subject: [IA64] Optimize ticket spinlocks in fsys_rt_sigprocmask Tony's fix (f574c843191728d9407b766a027f779dcd27b272) has a small bug, it incorrectly uses "r3" as a scratch register in the first of the two unlock paths ... it is also inefficient. Optimize the fast path again. Signed-off-by: Petr Tesarik Signed-off-by: Tony Luck --- arch/ia64/kernel/fsys.S | 42 +++++++++++------------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S index 471a1e783aca..331d42bda77a 100644 --- a/arch/ia64/kernel/fsys.S +++ b/arch/ia64/kernel/fsys.S @@ -420,34 +420,31 @@ EX(.fail_efault, ld8 r14=[r33]) // r14 <- *set ;; RSM_PSR_I(p0, r18, r19) // mask interrupt delivery - mov ar.ccv=0 andcm r14=r14,r17 // filter out SIGKILL & SIGSTOP + mov r8=EINVAL // default to EINVAL #ifdef CONFIG_SMP // __ticket_spin_trylock(r31) ld4 r17=[r31] - mov r8=EINVAL // default to EINVAL - ;; - extr r9=r17,17,15 ;; - xor r18=r17,r9 + mov.m ar.ccv=r17 + extr.u r9=r17,17,15 adds r19=1,r17 + extr.u r18=r17,0,15 ;; - extr.u r18=r18,0,15 + cmp.eq p6,p7=r9,r18 ;; - cmp.eq p0,p7=0,r18 +(p6) cmpxchg4.acq r9=[r31],r19,ar.ccv +(p6) dep.z r20=r19,1,15 // next serving ticket for unlock (p7) br.cond.spnt.many .lock_contention - mov.m ar.ccv=r17 - ;; - cmpxchg4.acq r9=[r31],r19,ar.ccv ;; cmp4.eq p0,p7=r9,r17 + adds r31=2,r31 (p7) br.cond.spnt.many .lock_contention ld8 r3=[r2] // re-read current->blocked now that we hold the lock ;; #else ld8 r3=[r2] // re-read current->blocked now that we hold the lock - mov r8=EINVAL // default to EINVAL #endif add r18=IA64_TASK_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r16 add r19=IA64_TASK_SIGNAL_OFFSET,r16 @@ -503,16 +500,8 @@ EX(.fail_efault, ld8 r14=[r33]) // r14 <- *set #ifdef CONFIG_SMP // __ticket_spin_unlock(r31) - adds r31=2,r31 - ;; - ld2.bias r2=[r31] - mov r3=65534 - ;; - adds r2=2,r2 - ;; - and r3=r3,r2 - ;; - st2.rel [r31]=r3 + st2.rel [r31]=r20 + mov r20=0 // i must not leak kernel bits... #endif SSM_PSR_I(p0, p9, r31) ;; @@ -535,16 +524,7 @@ EX(.fail_efault, (p15) st8 [r34]=r3) .sig_pending: #ifdef CONFIG_SMP // __ticket_spin_unlock(r31) - adds r31=2,r31 - ;; - ld2.bias r2=[r31] - mov r3=65534 - ;; - adds r2=2,r2 - ;; - and r3=r3,r2 - ;; - st2.rel [r31]=r3 + st2.rel [r31]=r20 // release the lock #endif SSM_PSR_I(p0, p9, r17) ;; -- cgit v1.2.3-59-g8ed1b From b4aaa78f4c2f9cde2f335b14f4ca30b01f9651ca Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 15 Sep 2010 19:08:24 -0400 Subject: drivers/video/via/ioctl.c: prevent reading uninitialized stack memory The VIAFB_GET_INFO device ioctl allows unprivileged users to read 246 bytes of uninitialized stack memory, because the "reserved" member of the viafb_ioctl_info struct declared on the stack is not altered or zeroed before being copied back to the user. This patch takes care of it. Signed-off-by: Dan Rosenberg Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/ioctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/via/ioctl.c b/drivers/video/via/ioctl.c index da03c074e32a..4d553d0b8d7a 100644 --- a/drivers/video/via/ioctl.c +++ b/drivers/video/via/ioctl.c @@ -25,6 +25,8 @@ int viafb_ioctl_get_viafb_info(u_long arg) { struct viafb_ioctl_info viainfo; + memset(&viainfo, 0, sizeof(struct viafb_ioctl_info)); + viainfo.viafb_id = VIAID; viainfo.vendor_id = PCI_VIA_VENDOR_ID; -- cgit v1.2.3-59-g8ed1b From 801e147cde02f04b5c2f42764cd43a89fc7400a2 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 14 Sep 2010 11:57:11 +0000 Subject: r8169: Handle rxfifo errors on 8168 chips The Thinkpad X100e seems to have some odd behaviour when the display is powered off - the onboard r8169 starts generating rxfifo overflow errors. The root cause of this has not yet been identified and may well be a hardware design bug on the platform, but r8169 should be more resiliant to this. This patch enables the rxfifo interrupt on 8168 devices and removes the MAC version check in the interrupt handler, and the machine no longer crashes when under network load while the screen turns off. Signed-off-by: Matthew Garrett Acked-by: Francois Romieu Signed-off-by: David S. Miller --- drivers/net/r8169.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 078bbf4e6f19..a0da4a17b025 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2934,7 +2934,7 @@ static const struct rtl_cfg_info { .hw_start = rtl_hw_start_8168, .region = 2, .align = 8, - .intr_event = SYSErr | LinkChg | RxOverflow | + .intr_event = SYSErr | RxFIFOOver | LinkChg | RxOverflow | TxErr | TxOK | RxOK | RxErr, .napi_event = TxErr | TxOK | RxOK | RxOverflow, .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI, @@ -4625,8 +4625,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) } /* Work around for rx fifo overflow */ - if (unlikely(status & RxFIFOOver) && - (tp->mac_version == RTL_GIGA_MAC_VER_11)) { + if (unlikely(status & RxFIFOOver)) { netif_stop_queue(dev); rtl8169_tx_timeout(dev); break; -- cgit v1.2.3-59-g8ed1b From 977ddd6b2e63716cfefe669bbdb30ec0bcea1fe4 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 15 Sep 2010 10:02:29 +0200 Subject: ALSA: hda - Set up COEFs for ALC269 to avoid click noises at power-saving For avoiding the click noises at power-saving, set some COEF values for ALC269* codecs. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3b040870365d..ab2947d87232 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1673,6 +1673,15 @@ static int alc_read_coef_idx(struct hda_codec *codec, return val; } +static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx, + unsigned int coef_val) +{ + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, + coef_idx); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, + coef_val); +} + /* set right pin controls for digital I/O */ static void alc_auto_init_digital(struct hda_codec *codec) { @@ -14598,6 +14607,68 @@ static void alc269_auto_init(struct hda_codec *codec) alc_inithook(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc269_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct alc_spec *spec = codec->spec; + int val; + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + val = alc_read_coef_idx(codec, 0x04); + /* Power down output pin */ + alc_write_coef_idx(codec, 0x04, val & ~(1<<11)); + } + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + val = alc_read_coef_idx(codec, 0x04); + /* Power down output pin */ + alc_write_coef_idx(codec, 0x04, val & ~(1<<11)); + msleep(150); + } + + alc_shutup(codec); + if (spec && spec->power_hook) + spec->power_hook(codec); + return 0; +} +#endif +#ifdef SND_HDA_NEEDS_RESUME +static int alc269_resume(struct hda_codec *codec) +{ + int val; + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + val = alc_read_coef_idx(codec, 0x04); + /* Power down output pin */ + alc_write_coef_idx(codec, 0x04, val & ~(1<<11)); + msleep(150); + } + + codec->patch_ops.init(codec); + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + val = alc_read_coef_idx(codec, 0x04); + /* Power up output pin */ + alc_write_coef_idx(codec, 0x04, val | (1<<11)); + msleep(200); + } + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + val = alc_read_coef_idx(codec, 0x04); + /* Power up output pin */ + alc_write_coef_idx(codec, 0x04, val | (1<<11)); + } + + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, 0x01); +#endif + return 0; +} +#endif + enum { ALC269_FIXUP_SONY_VAIO, }; @@ -14814,6 +14885,41 @@ static struct alc_config_preset alc269_presets[] = { }, }; +static int alc269_fill_coef(struct hda_codec *codec) +{ + int val; + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) { + alc_write_coef_idx(codec, 0xf, 0x960b); + alc_write_coef_idx(codec, 0xe, 0x8817); + } + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) { + alc_write_coef_idx(codec, 0xf, 0x960b); + alc_write_coef_idx(codec, 0xe, 0x8814); + } + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { + val = alc_read_coef_idx(codec, 0x04); + /* Power up output pin */ + alc_write_coef_idx(codec, 0x04, val | (1<<11)); + } + + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { + val = alc_read_coef_idx(codec, 0xd); + if ((val & 0x0c00) >> 10 != 0x1) { + /* Capless ramp up clock control */ + alc_write_coef_idx(codec, 0xd, val | 1<<10); + } + val = alc_read_coef_idx(codec, 0x17); + if ((val & 0x01c0) >> 6 != 0x4) { + /* Class D power on reset */ + alc_write_coef_idx(codec, 0x17, val | 1<<7); + } + } + return 0; +} + static int patch_alc269(struct hda_codec *codec) { struct alc_spec *spec; @@ -14839,6 +14945,8 @@ static int patch_alc269(struct hda_codec *codec) } else alc_fix_pll_init(codec, 0x20, 0x04, 15); + alc269_fill_coef(codec); + board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, alc269_models, alc269_cfg_tbl); @@ -14917,6 +15025,12 @@ static int patch_alc269(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; +#ifdef CONFIG_SND_HDA_POWER_SAVE + codec->patch_ops.suspend = alc269_suspend; +#endif +#ifdef SND_HDA_NEEDS_RESUME + codec->patch_ops.resume = alc269_resume; +#endif if (board_config == ALC269_AUTO) spec->init_hook = alc269_auto_init; #ifdef CONFIG_SND_HDA_POWER_SAVE -- cgit v1.2.3-59-g8ed1b From f2e5731dfd3ba08b023d0626d36ccf78f54ab5e7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Sep 2010 10:07:08 +0200 Subject: ALSA: hda - Preliminary support for new Conexant audio codecs This patch adds the preliminary support for new Conexant audio codecs with 14f1:5097, 14f1:5098, 14f1:50a1, 14f1:50a2, 14f1:50ab, 14f1:50ac, 14f1:50b8 and 14f1:50b9. Unlike other Conexant parsers, this is designed to be mostly automatic, parsing from BIOS pin configurations. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 640 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 639 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 972e7c453b3d..7eee0ff65ac9 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -57,6 +57,12 @@ struct conexant_jack { }; +struct pin_dac_pair { + hda_nid_t pin; + hda_nid_t dac; + int type; +}; + struct conexant_spec { struct snd_kcontrol_new *mixers[5]; @@ -77,6 +83,7 @@ struct conexant_spec { unsigned int cur_eapd; unsigned int hp_present; unsigned int auto_mic; + int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ unsigned int need_dac_fix; /* capture */ @@ -110,9 +117,12 @@ struct conexant_spec { struct auto_pin_cfg autocfg; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; + struct pin_dac_pair dac_info[8]; + int dac_info_filled; - unsigned int dell_automute; unsigned int port_d_mode; + unsigned int auto_mute:1; /* used in auto-parser */ + unsigned int dell_automute:1; unsigned int dell_vostro:1; unsigned int ideapad:1; unsigned int thinkpad:1; @@ -3253,6 +3263,610 @@ static int patch_cxt5066(struct hda_codec *codec) return 0; } +/* + * Automatic parser for CX20641 & co + */ + +static hda_nid_t cx_auto_adc_nids[] = { 0x14 }; + +/* get the connection index of @nid in the widget @mux */ +static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, + hda_nid_t nid) +{ + hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + int i, nums; + + nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + for (i = 0; i < nums; i++) + if (conn[i] == nid) + return i; + return -1; +} + +/* get an unassigned DAC from the given list. + * Return the nid if found and reduce the DAC list, or return zero if + * not found + */ +static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t *dacs, int *num_dacs) +{ + int i, nums = *num_dacs; + hda_nid_t ret = 0; + + for (i = 0; i < nums; i++) { + if (get_connection_index(codec, pin, dacs[i]) >= 0) { + ret = dacs[i]; + break; + } + } + if (!ret) + return 0; + if (--nums > 0) + memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t)); + *num_dacs = nums; + return ret; +} + +#define MAX_AUTO_DACS 5 + +/* fill analog DAC list from the widget tree */ +static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs) +{ + hda_nid_t nid, end_nid; + int nums = 0; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int type = get_wcaps_type(wcaps); + if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) { + dacs[nums++] = nid; + if (nums >= MAX_AUTO_DACS) + break; + } + } + return nums; +} + +/* fill pin_dac_pair list from the pin and dac list */ +static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins, + int num_pins, hda_nid_t *dacs, int *rest, + struct pin_dac_pair *filled, int type) +{ + int i, nums; + + nums = 0; + for (i = 0; i < num_pins; i++) { + filled[nums].pin = pins[i]; + filled[nums].type = type; + filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest); + nums++; + } + return nums; +} + +/* parse analog output paths */ +static void cx_auto_parse_output(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t dacs[MAX_AUTO_DACS]; + int i, j, nums, rest; + + rest = fill_cx_auto_dacs(codec, dacs); + /* parse all analog output pins */ + nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs, + dacs, &rest, spec->dac_info, + AUTO_PIN_LINE_OUT); + nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs, + dacs, &rest, spec->dac_info + nums, + AUTO_PIN_HP_OUT); + nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs, + dacs, &rest, spec->dac_info + nums, + AUTO_PIN_SPEAKER_OUT); + spec->dac_info_filled = nums; + /* fill multiout struct */ + for (i = 0; i < nums; i++) { + hda_nid_t dac = spec->dac_info[i].dac; + if (!dac) + continue; + switch (spec->dac_info[i].type) { + case AUTO_PIN_LINE_OUT: + spec->private_dac_nids[spec->multiout.num_dacs] = dac; + spec->multiout.num_dacs++; + break; + case AUTO_PIN_HP_OUT: + case AUTO_PIN_SPEAKER_OUT: + if (!spec->multiout.hp_nid) { + spec->multiout.hp_nid = dac; + break; + } + for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++) + if (!spec->multiout.extra_out_nid[j]) { + spec->multiout.extra_out_nid[j] = dac; + break; + } + break; + } + } + spec->multiout.dac_nids = spec->private_dac_nids; + spec->multiout.max_channels = nums * 2; + + if (cfg->hp_outs > 0) + spec->auto_mute = 1; + spec->vmaster_nid = spec->private_dac_nids[0]; +} + +/* auto-mute/unmute speaker and line outs according to headphone jack */ +static void cx_auto_hp_automute(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, present; + + if (!spec->auto_mute) + return; + present = 0; + for (i = 0; i < cfg->hp_outs; i++) { + if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) { + present = 1; + break; + } + } + for (i = 0; i < cfg->line_outs; i++) { + snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + present ? 0 : PIN_OUT); + } + for (i = 0; i < cfg->speaker_outs; i++) { + snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + present ? 0 : PIN_OUT); + } +} + +/* automatic switch internal and external mic */ +static void cx_auto_automic(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct hda_input_mux *imux = &spec->private_imux; + int ext_idx = spec->auto_mic_ext; + + if (!spec->auto_mic) + return; + if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { + snd_hda_codec_write(codec, spec->adc_nids[0], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[ext_idx].index); + } else { + snd_hda_codec_write(codec, spec->adc_nids[0], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[!ext_idx].index); + } +} + +static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) +{ + int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20; + switch (res >> 26) { + case CONEXANT_HP_EVENT: + cx_auto_hp_automute(codec); + conexant_report_jack(codec, nid); + break; + case CONEXANT_MIC_EVENT: + cx_auto_automic(codec); + conexant_report_jack(codec, nid); + break; + } +} + +static int is_int_mic_conn(unsigned int def_conf) +{ + unsigned int loc = get_defcfg_location(def_conf); + return get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || + (loc & 0x30) == AC_JACK_LOC_INTERNAL; +} + +/* return true if it's an internal-mic pin */ +static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) +{ + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); + return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && + is_int_mic_conn(def_conf); +} + +/* return true if it's an external-mic pin */ +static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) +{ + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); + return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && + !is_int_mic_conn(def_conf); +} + +/* check whether the pin config is suitable for auto-mic switching; + * auto-mic is enabled only when one int-mic and one-ext mic exist + */ +static void cx_auto_check_auto_mic(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (is_ext_mic(codec, cfg->inputs[0].pin) && + is_int_mic(codec, cfg->inputs[1].pin)) { + spec->auto_mic = 1; + spec->auto_mic_ext = 1; + return; + } + if (is_int_mic(codec, cfg->inputs[1].pin) && + is_ext_mic(codec, cfg->inputs[0].pin)) { + spec->auto_mic = 1; + spec->auto_mic_ext = 0; + return; + } +} + +static void cx_auto_parse_input(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct hda_input_mux *imux; + int i; + + imux = &spec->private_imux; + for (i = 0; i < cfg->num_inputs; i++) { + int idx = get_connection_index(codec, spec->adc_nids[0], + cfg->inputs[i].pin); + if (idx >= 0) { + const char *label; + label = hda_get_autocfg_input_label(codec, cfg, i); + snd_hda_add_imux_item(imux, label, idx, NULL); + } + } + if (imux->num_items == 2 && cfg->num_inputs == 2) + cx_auto_check_auto_mic(codec); + if (imux->num_items > 1 && !spec->auto_mic) + spec->input_mux = imux; +} + +/* get digital-input audio widget corresponding to the given pin */ +static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin) +{ + hda_nid_t nid, end_nid; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int type = get_wcaps_type(wcaps); + if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) { + if (get_connection_index(codec, nid, pin) >= 0) + return nid; + } + } + return 0; +} + +static void cx_auto_parse_digital(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + + if (cfg->dig_outs && + snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1) + spec->multiout.dig_out_nid = nid; + if (cfg->dig_in_pin) + spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin); +} + +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static void cx_auto_parse_beep(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + hda_nid_t nid, end_nid; + + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) + if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { + set_beep_amp(spec, nid, 0, HDA_OUTPUT); + break; + } +} +#else +#define cx_auto_parse_beep(codec) +#endif + +static int cx_auto_parse_auto_config(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int err; + + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + + cx_auto_parse_output(codec); + cx_auto_parse_input(codec); + cx_auto_parse_digital(codec); + cx_auto_parse_beep(codec); + return 0; +} + +static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins, + hda_nid_t *pins) +{ + int i; + for (i = 0; i < num_pins; i++) { + if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x02); + } +} + +static void select_connection(struct hda_codec *codec, hda_nid_t pin, + hda_nid_t src) +{ + int idx = get_connection_index(codec, pin, src); + if (idx >= 0) + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_CONNECT_SEL, idx); +} + +static void cx_auto_init_output(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + int i; + + for (i = 0; i < spec->multiout.num_dacs; i++) + snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + for (i = 0; i < cfg->hp_outs; i++) + snd_hda_codec_write(codec, cfg->hp_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); + if (spec->auto_mute) { + for (i = 0; i < cfg->hp_outs; i++) { + snd_hda_codec_write(codec, cfg->hp_pins[i], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_HP_EVENT); + } + cx_auto_hp_automute(codec); + } else { + for (i = 0; i < cfg->line_outs; i++) + snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + for (i = 0; i < cfg->speaker_outs; i++) + snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + } + + for (i = 0; i < spec->dac_info_filled; i++) { + nid = spec->dac_info[i].dac; + if (!nid) + nid = spec->multiout.dac_nids[0]; + select_connection(codec, spec->dac_info[i].pin, nid); + } + + /* turn on EAPD */ + cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins); + cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins); + cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins); +} + +static void cx_auto_init_input(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < spec->num_adc_nids; i++) + snd_hda_codec_write(codec, spec->adc_nids[i], 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)); + + for (i = 0; i < cfg->num_inputs; i++) { + unsigned int type; + if (cfg->inputs[i].type == AUTO_PIN_MIC) + type = PIN_VREF80; + else + type = PIN_IN; + snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, type); + } + + if (spec->auto_mic) { + int ext_idx = spec->auto_mic_ext; + snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | CONEXANT_MIC_EVENT); + cx_auto_automic(codec); + } else { + for (i = 0; i < spec->num_adc_nids; i++) { + snd_hda_codec_write(codec, spec->adc_nids[i], 0, + AC_VERB_SET_CONNECT_SEL, + spec->private_imux.items[0].index); + } + } +} + +static void cx_auto_init_digital(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (spec->multiout.dig_out_nid) + snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + if (spec->dig_in_nid) + snd_hda_codec_write(codec, cfg->dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); +} + +static int cx_auto_init(struct hda_codec *codec) +{ + /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/ + cx_auto_init_output(codec); + cx_auto_init_input(codec); + cx_auto_init_digital(codec); + return 0; +} + +static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, + const char *dir, int cidx, + hda_nid_t nid, int hda_dir) +{ + static char name[32]; + static struct snd_kcontrol_new knew[] = { + HDA_CODEC_VOLUME(name, 0, 0, 0), + HDA_CODEC_MUTE(name, 0, 0, 0), + }; + static char *sfx[2] = { "Volume", "Switch" }; + int i, err; + + for (i = 0; i < 2; i++) { + struct snd_kcontrol *kctl; + knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir); + knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; + knew[i].index = cidx; + snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); + kctl = snd_ctl_new1(&knew[i], codec); + if (!kctl) + return -ENOMEM; + err = snd_hda_ctl_add(codec, nid, kctl); + if (err < 0) + return err; + if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE)) + break; + } + return 0; +} + +#define cx_auto_add_pb_volume(codec, nid, str, idx) \ + cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) + +static int cx_auto_build_output_controls(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int i, err; + int num_line = 0, num_hp = 0, num_spk = 0; + static const char *texts[3] = { "Front", "Surround", "CLFE" }; + + if (spec->dac_info_filled == 1) + return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac, + "Master", 0); + for (i = 0; i < spec->dac_info_filled; i++) { + const char *label; + int idx, type; + if (!spec->dac_info[i].dac) + continue; + type = spec->dac_info[i].type; + if (type == AUTO_PIN_LINE_OUT) + type = spec->autocfg.line_out_type; + switch (type) { + case AUTO_PIN_LINE_OUT: + default: + label = texts[num_line++]; + idx = 0; + break; + case AUTO_PIN_HP_OUT: + label = "Headphone"; + idx = num_hp++; + break; + case AUTO_PIN_SPEAKER_OUT: + label = "Speaker"; + idx = num_spk++; + break; + } + err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac, + label, idx); + if (err < 0) + return err; + } + return 0; +} + +static int cx_auto_build_input_controls(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + static const char *prev_label; + int i, err, cidx; + + err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0], + HDA_INPUT); + if (err < 0) + return err; + prev_label = NULL; + cidx = 0; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + const char *label; + if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + continue; + label = hda_get_autocfg_input_label(codec, cfg, i); + if (label == prev_label) + cidx++; + else + cidx = 0; + prev_label = label; + err = cx_auto_add_volume(codec, label, " Capture", cidx, + nid, HDA_INPUT); + if (err < 0) + return err; + } + return 0; +} + +static int cx_auto_build_controls(struct hda_codec *codec) +{ + int err; + + err = cx_auto_build_output_controls(codec); + if (err < 0) + return err; + err = cx_auto_build_input_controls(codec); + if (err < 0) + return err; + return conexant_build_controls(codec); +} + +static struct hda_codec_ops cx_auto_patch_ops = { + .build_controls = cx_auto_build_controls, + .build_pcms = conexant_build_pcms, + .init = cx_auto_init, + .free = conexant_free, + .unsol_event = cx_auto_unsol_event, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .suspend = conexant_suspend, +#endif + .reboot_notify = snd_hda_shutup_pins, +}; + +static int patch_conexant_auto(struct hda_codec *codec) +{ + struct conexant_spec *spec; + int err; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + codec->spec = spec; + spec->adc_nids = cx_auto_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids); + spec->capsrc_nids = spec->adc_nids; + err = cx_auto_parse_auto_config(codec); + if (err < 0) { + kfree(codec->spec); + codec->spec = NULL; + return err; + } + codec->patch_ops = cx_auto_patch_ops; + if (spec->beep_amp) + snd_hda_attach_beep_device(codec, spec->beep_amp); + return 0; +} + /* */ @@ -3271,6 +3885,22 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5066 }, { .id = 0x14f15069, .name = "CX20585", .patch = patch_cxt5066 }, + { .id = 0x14f15097, .name = "CX20631", + .patch = patch_conexant_auto }, + { .id = 0x14f15098, .name = "CX20632", + .patch = patch_conexant_auto }, + { .id = 0x14f150a1, .name = "CX20641", + .patch = patch_conexant_auto }, + { .id = 0x14f150a2, .name = "CX20642", + .patch = patch_conexant_auto }, + { .id = 0x14f150ab, .name = "CX20651", + .patch = patch_conexant_auto }, + { .id = 0x14f150ac, .name = "CX20652", + .patch = patch_conexant_auto }, + { .id = 0x14f150b8, .name = "CX20664", + .patch = patch_conexant_auto }, + { .id = 0x14f150b9, .name = "CX20665", + .patch = patch_conexant_auto }, {} /* terminator */ }; @@ -3281,6 +3911,14 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066"); MODULE_ALIAS("snd-hda-codec-id:14f15067"); MODULE_ALIAS("snd-hda-codec-id:14f15068"); MODULE_ALIAS("snd-hda-codec-id:14f15069"); +MODULE_ALIAS("snd-hda-codec-id:14f15097"); +MODULE_ALIAS("snd-hda-codec-id:14f15098"); +MODULE_ALIAS("snd-hda-codec-id:14f150a1"); +MODULE_ALIAS("snd-hda-codec-id:14f150a2"); +MODULE_ALIAS("snd-hda-codec-id:14f150ab"); +MODULE_ALIAS("snd-hda-codec-id:14f150ac"); +MODULE_ALIAS("snd-hda-codec-id:14f150b8"); +MODULE_ALIAS("snd-hda-codec-id:14f150b9"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); -- cgit v1.2.3-59-g8ed1b From b686453543fd56332e8730a2abd7bf5bca756149 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Sep 2010 10:17:26 +0200 Subject: ALSA: hda - Reduce pci id list for Intel with class id Most of Intel controllers work as generic HD-audio without quirks, and it'll be hopefully so in future. Let's mark pci id with the PCI_CLASS_MULTIMEDIA_HD_AUDIO for Intel so that the driver will work with any new control chips in future. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 34940a079051..5f6f9039a41a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2735,25 +2735,17 @@ static void __devexit azx_remove(struct pci_dev *pci) /* PCI IDs */ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { - /* ICH 6..10 */ - { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH }, - /* PCH */ - { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH }, - { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH }, /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH }, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH }, + /* Generic Intel */ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), + .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, + .class_mask = 0xffffff, + .driver_data = AZX_DRIVER_ICH }, /* ATI SB 450/600 */ { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI }, { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI }, -- cgit v1.2.3-59-g8ed1b From 3b119f662d9054d734e3c74d662e7de6d7b35687 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Sep 2010 15:53:50 +0200 Subject: ALSA: hda - Add quirk for Acer laptop with CX20585 codec Its pin configuration is compatible with ideapad. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 7eee0ff65ac9..7e22ed14ae8d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3098,6 +3098,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1025, 0x040a, "Acer", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), -- cgit v1.2.3-59-g8ed1b From 1a4e34e67c6de2385d9d493e69c0f6fce886b14d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Sep 2010 07:42:34 +0200 Subject: ALSA: usb-audio - Fix an unused-variable compile warning Used only when CONFIG_SND_DEBUG=y sound/usb/mixer.c: In function 'get_min_max': sound/usb/mixer.c:762: warning: unused variable 'chip' Reported-by: Andrew Morton Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 3ed3901369ce..5f12e294b0f8 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -759,8 +759,6 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl) */ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) { - struct snd_usb_audio *chip = cval->mixer->chip; - /* for failsafe */ cval->min = default_min; cval->max = cval->min + 1; @@ -783,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", - cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id); + cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id); return -EINVAL; } if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { -- cgit v1.2.3-59-g8ed1b From 4437ecdc7190302ed02fb1467c116aff29c325b2 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 16 Sep 2010 10:26:54 +0300 Subject: ALSA: core: Allow card id change to the same string When user want to change the card id to the same string on the card via /sys/class/sound/cardX/id, do not report error. Instead return with success without doing anything. Signed-off-by: Peter Ujfalusi Signed-off-by: Takashi Iwai --- sound/core/init.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/core/init.c b/sound/core/init.c index ec4a50ce5656..2de45fbd70fb 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -607,11 +607,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, return -EEXIST; } for (idx = 0; idx < snd_ecards_limit; idx++) { - if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) - goto __exist; + if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { + if (card == snd_cards[idx]) + goto __ok; + else + goto __exist; + } } strcpy(card->id, buf1); snd_info_card_id_change(card); +__ok: mutex_unlock(&snd_card_mutex); return count; -- cgit v1.2.3-59-g8ed1b From 145a902bfeb1f89a41165bd2d1e633ce070bcb73 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 16 Sep 2010 10:07:53 +0200 Subject: ALSA: HDA: Enable internal speaker on Dell M101z BugLink: http://launchpad.net/bugs/640254 In some cases a magic processing coefficient is needed to enable the internal speaker on Dell M101z. According to Realtek, this processing coefficient is only present on ALC269vb. Cc: stable@kernel.org Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bcbf9160ed81..a1312a6c8af2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14453,6 +14453,7 @@ static void alc269_auto_init(struct hda_codec *codec) enum { ALC269_FIXUP_SONY_VAIO, + ALC269_FIXUP_DELL_M101Z, }; static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = { @@ -14464,11 +14465,20 @@ static const struct alc_fixup alc269_fixups[] = { [ALC269_FIXUP_SONY_VAIO] = { .verbs = alc269_sony_vaio_fixup_verbs }, + [ALC269_FIXUP_DELL_M101Z] = { + .verbs = (const struct hda_verb[]) { + /* Enables internal speaker */ + {0x20, AC_VERB_SET_COEF_INDEX, 13}, + {0x20, AC_VERB_SET_PROC_COEF, 0x4040}, + {} + } + }, }; static struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), {} }; -- cgit v1.2.3-59-g8ed1b From c33f543d320843e1732534c3931da4bbd18e6c14 Mon Sep 17 00:00:00 2001 From: Patrick Simmons Date: Wed, 8 Sep 2010 10:34:28 -0400 Subject: oprofile: Add Support for Intel CPU Family 6 / Model 22 (Intel Celeron 540) This patch adds CPU type detection for the Intel Celeron 540, which is part of the Core 2 family according to Wikipedia; the family and ID pair is absent from the Volume 3B table referenced in the source code comments. I have tested this patch on an Intel Celeron 540 machine reporting itself as Family 6 Model 22, and OProfile runs on the machine without issue. Spec: http://download.intel.com/design/mobile/SPECUPDT/317667.pdf Signed-off-by: Patrick Simmons Acked-by: Andi Kleen Acked-by: Arnd Bergmann Cc: stable@kernel.org Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index cfe4faabb0f6..009b819f48d0 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -671,7 +671,9 @@ static int __init ppro_init(char **cpu_type) case 14: *cpu_type = "i386/core"; break; - case 15: case 23: + case 0x0f: + case 0x16: + case 0x17: *cpu_type = "i386/core_2"; break; case 0x1a: -- cgit v1.2.3-59-g8ed1b From 16d3ea26f82271fef9b1c4523b5e1ea31fa39eec Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 10 Sep 2010 01:20:27 -0400 Subject: [SCSI] Fix VPD inquiry page wrapper Fix two bugs in the VPD page wrapper: - Don't return failure if the user asked for page 0 - The end of buffer check failed to account for the page header size and consequently didn't work Signed-off-by: Martin K. Petersen Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index ad0ed212db4a..348fba0a8976 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1046,13 +1046,13 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, /* If the user actually wanted this page, we can skip the rest */ if (page == 0) - return -EINVAL; + return 0; for (i = 0; i < min((int)buf[3], buf_len - 4); i++) if (buf[i + 4] == page) goto found; - if (i < buf[3] && i > buf_len) + if (i < buf[3] && i >= buf_len - 4) /* ran off the end of the buffer, give us benefit of doubt */ goto found; /* The device claims it doesn't support the requested page */ -- cgit v1.2.3-59-g8ed1b From 5855fb8076e784a657bc2441cd29f166c7c1ea8c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Sep 2010 18:24:02 +0200 Subject: ALSA: hda - Fix initialization of secondary headphone and speaker The secondary or later headphones or speakers aren't initialized preoprly for some codecs. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ab2947d87232..945826da23b6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10634,16 +10634,21 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; hda_nid_t pin, dac; + int i; - pin = spec->autocfg.hp_pins[0]; - if (pin) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { + pin = spec->autocfg.hp_pins[i]; + if (!pin) + break; dac = spec->multiout.hp_nid; if (!dac) dac = spec->multiout.dac_nids[0]; /* to front */ alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); } - pin = spec->autocfg.speaker_pins[0]; - if (pin) { + for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { + pin = spec->autocfg.speaker_pins[i]; + if (!pin) + break; dac = spec->multiout.extra_out_nid[0]; if (!dac) dac = spec->multiout.dac_nids[0]; /* to front */ -- cgit v1.2.3-59-g8ed1b From 30ea098fc000bb05081a1999269658f1a88af36a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Sep 2010 18:47:56 +0200 Subject: ALSA: hda - Fix input-pin setup for Realtek codecs Through the transition of autocfg to individual inputs array, I forgot to rewrite the argument passed to alc_set_input_pin(). This resulted in wrongly setup input pins. Fixed now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 945826da23b6..5df88798895b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5160,7 +5160,7 @@ static void alc880_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; if (alc_is_input_pin(codec, nid)) { - alc_set_input_pin(codec, nid, i); + alc_set_input_pin(codec, nid, cfg->inputs[i].type); if (nid != ALC880_PIN_CD_NID && (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, @@ -6793,7 +6793,7 @@ static void alc260_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; if (nid >= 0x12) { - alc_set_input_pin(codec, nid, i); + alc_set_input_pin(codec, nid, cfg->inputs[i].type); if (nid != ALC260_PIN_CD_NID && (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, @@ -10664,7 +10664,7 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; - alc_set_input_pin(codec, nid, i); + alc_set_input_pin(codec, nid, cfg->inputs[i].type); if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -15856,7 +15856,7 @@ static void alc861_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; if (nid >= 0x0c && nid <= 0x11) - alc_set_input_pin(codec, nid, i); + alc_set_input_pin(codec, nid, cfg->inputs[i].type); } } @@ -16849,7 +16849,7 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; if (alc_is_input_pin(codec, nid)) { - alc_set_input_pin(codec, nid, i); + alc_set_input_pin(codec, nid, cfg->inputs[i].type); if (nid != ALC861VD_PIN_CD_NID && (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, @@ -19086,7 +19086,7 @@ static void alc662_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; if (alc_is_input_pin(codec, nid)) { - alc_set_input_pin(codec, nid, i); + alc_set_input_pin(codec, nid, cfg->inputs[i].type); if (nid != ALC662_PIN_CD_NID && (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) snd_hda_codec_write(codec, nid, 0, -- cgit v1.2.3-59-g8ed1b From 37880c909c6a22674d3c0f83f2737264b4e60fe1 Mon Sep 17 00:00:00 2001 From: christophe leroy Date: Thu, 16 Sep 2010 09:05:25 +0200 Subject: spi/mpc8xxx: fix buffer overrun on large transfers It fixes an issue when sending-only or receiving-only more than PAGE_SIZE bytes. Signed-off-by: christophe leroy Acked-by: Joakim Tjernlund Signed-off-by: Grant Likely --- drivers/spi/spi_mpc8xxx.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c index d31b57f7baaf..1dd86b835cd8 100644 --- a/drivers/spi/spi_mpc8xxx.c +++ b/drivers/spi/spi_mpc8xxx.c @@ -408,11 +408,17 @@ static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) xfer_ofs = mspi->xfer_in_progress->len - mspi->count; - out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs); + if (mspi->rx_dma == mspi->dma_dummy_rx) + out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma); + else + out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs); out_be16(&rx_bd->cbd_datlen, 0); out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP); - out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs); + if (mspi->tx_dma == mspi->dma_dummy_tx) + out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma); + else + out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs); out_be16(&tx_bd->cbd_datlen, xfer_len); out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | BD_SC_LAST); -- cgit v1.2.3-59-g8ed1b From 26e34e9e15aa48e9375ea4e97bc4234ad995b7c8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 16 Sep 2010 20:13:47 +0200 Subject: ALSA: usb/mixer: remove bogus cast "uinfo->value.enumerated.item" is an unsigned int. If it's negative when we do the comparison: if ((int)uinfo->value.enumerated.item >= cval->max) then we would read past the end of the array on the next line. I also changed the strcpy() to strlcpy() out of paranoia. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 5f12e294b0f8..f2d74d654b3c 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1640,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = cval->max; - if ((int)uinfo->value.enumerated.item >= cval->max) + if (uinfo->value.enumerated.item >= cval->max) uinfo->value.enumerated.item = cval->max - 1; - strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]); + strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); return 0; } -- cgit v1.2.3-59-g8ed1b From 8699a0b657b43fa6401537dfe345bee7aa8115ec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Sep 2010 22:52:32 +0200 Subject: ALSA: pcm - Fix unbalanced pm_qos_request The pm_qos_request isn't freed properly when OSS PCM emulation is used because it skips snd_pcm_hw_free() call but directly releases the stream. This resulted in Oops later. Tested-by: Simon Kirby Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 134fc6c2e08d..d4eb2ef80784 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1992,6 +1992,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream) substream->ops->close(substream); substream->hw_opened = 0; } + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); if (substream->pcm_release) { substream->pcm_release(substream); substream->pcm_release = NULL; -- cgit v1.2.3-59-g8ed1b From 901d46d5a8eb821b03ca9e8cf005beb0c92f31ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Sep 2010 23:06:50 +0200 Subject: ALSA: pcm - Fix race with proc files The PCM proc files may open a race against substream close, which can end up with an Oops. Use the open_mutex to protect for it. Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 204af48c5cc1..ac242a377aea 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -372,14 +372,17 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_substream *substream = entry->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_runtime *runtime; + + mutex_lock(&substream->pcm->open_mutex); + runtime = substream->runtime; if (!runtime) { snd_iprintf(buffer, "closed\n"); - return; + goto unlock; } if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); - return; + goto unlock; } snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access)); snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format)); @@ -398,20 +401,25 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames); } #endif + unlock: + mutex_unlock(&substream->pcm->open_mutex); } static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_substream *substream = entry->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_runtime *runtime; + + mutex_lock(&substream->pcm->open_mutex); + runtime = substream->runtime; if (!runtime) { snd_iprintf(buffer, "closed\n"); - return; + goto unlock; } if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); - return; + goto unlock; } snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); snd_iprintf(buffer, "period_step: %u\n", runtime->period_step); @@ -421,24 +429,29 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size); snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary); + unlock: + mutex_unlock(&substream->pcm->open_mutex); } static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_substream *substream = entry->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_runtime *runtime; struct snd_pcm_status status; int err; + + mutex_lock(&substream->pcm->open_mutex); + runtime = substream->runtime; if (!runtime) { snd_iprintf(buffer, "closed\n"); - return; + goto unlock; } memset(&status, 0, sizeof(status)); err = snd_pcm_status(substream, &status); if (err < 0) { snd_iprintf(buffer, "error %d\n", err); - return; + goto unlock; } snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); @@ -452,6 +465,8 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, snd_iprintf(buffer, "-----\n"); snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr); snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr); + unlock: + mutex_unlock(&substream->pcm->open_mutex); } #ifdef CONFIG_SND_PCM_XRUN_DEBUG -- cgit v1.2.3-59-g8ed1b From 8702d33aa6e6d753ef99163afe48aba1323374ef Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Wed, 15 Sep 2010 13:02:44 +0200 Subject: firewire: nosy: fix build when CONFIG_FIREWIRE=N drivers/firewire/nosy* is a stand-alone driver that does not depend on CONFIG_FIREWIRE. Hence let make descend into drivers/firewire/ also if that option is off. The stand-alone driver drivers/ieee1394/init_ohci1394_dma* will soon be moved into drivers/firewire/ too and will require the same makefile fix. Side effect: As mentioned in https://bugzilla.novell.com/show_bug.cgi?id=586172#c24 this influences the order in which either firewire-ohci or ohci1394 is going to be bound to an OHCI-1394 controller in case of a modular build of both drivers if no modprobe blacklist entries are configured. However, a user of such a setup cannot expect deterministic behavior anyway. The Kconfig help and the migration guide at ieee1394.wiki.kernel.org recommend blacklist entries when a dual IEEE 1394 stack build is being used. (The coexistence period of the two stacks is planned to end soon.) Cc: Michal Marek Signed-off-by: Stefan Richter --- drivers/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/Makefile b/drivers/Makefile index 91874e048552..0bbb4561720e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_SPI) += spi/ obj-y += net/ obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_FUSION) += message/ -obj-$(CONFIG_FIREWIRE) += firewire/ +obj-y += firewire/ obj-y += ieee1394/ obj-$(CONFIG_UIO) += uio/ obj-y += cdrom/ -- cgit v1.2.3-59-g8ed1b From ae00d4f37f4df56821331deb1028748110dd6dc9 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 16 Sep 2010 16:26:51 -0700 Subject: ceph: fix cap_snap and realm split The cap_snap creation/queueing relies on both the current i_head_snapc _and_ the i_snap_realm pointers being correct, so that the new cap_snap can properly reference the old context and the new i_head_snapc can be updated to reference the new snaprealm's context. To fix this, we: - move inodes completely to the new (split) realm so that i_snap_realm is correct, and - generate the new snapc's _before_ queueing the cap_snaps in ceph_update_snap_trace(). Signed-off-by: Sage Weil --- fs/ceph/addr.c | 4 +-- fs/ceph/snap.c | 88 +++++++++++++++++++-------------------------------------- fs/ceph/super.h | 2 ++ 3 files changed, 33 insertions(+), 61 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 50461b8c23a4..efbc604001c8 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -411,8 +411,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) if (i_size < page_off + len) len = i_size - page_off; - dout("writepage %p page %p index %lu on %llu~%u\n", - inode, page, page->index, page_off, len); + dout("writepage %p page %p index %lu on %llu~%u snapc %p\n", + inode, page, page->index, page_off, len, snapc); writeback_stat = atomic_long_inc_return(&client->writeback_count); if (writeback_stat > diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 9e836afba341..9e6eef14b7df 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -119,6 +119,7 @@ static struct ceph_snap_realm *ceph_create_snap_realm( INIT_LIST_HEAD(&realm->children); INIT_LIST_HEAD(&realm->child_item); INIT_LIST_HEAD(&realm->empty_item); + INIT_LIST_HEAD(&realm->dirty_item); INIT_LIST_HEAD(&realm->inodes_with_caps); spin_lock_init(&realm->inodes_with_caps_lock); __insert_snap_realm(&mdsc->snap_realms, realm); @@ -604,6 +605,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, struct ceph_snap_realm *realm; int invalidate = 0; int err = -ENOMEM; + LIST_HEAD(dirty_realms); dout("update_snap_trace deletion=%d\n", deletion); more: @@ -626,24 +628,6 @@ more: } } - if (le64_to_cpu(ri->seq) > realm->seq) { - dout("update_snap_trace updating %llx %p %lld -> %lld\n", - realm->ino, realm, realm->seq, le64_to_cpu(ri->seq)); - /* - * if the realm seq has changed, queue a cap_snap for every - * inode with open caps. we do this _before_ we update - * the realm info so that we prepare for writeback under the - * _previous_ snap context. - * - * ...unless it's a snap deletion! - */ - if (!deletion) - queue_realm_cap_snaps(realm); - } else { - dout("update_snap_trace %llx %p seq %lld unchanged\n", - realm->ino, realm, realm->seq); - } - /* ensure the parent is correct */ err = adjust_snap_realm_parent(mdsc, realm, le64_to_cpu(ri->parent)); if (err < 0) @@ -651,6 +635,8 @@ more: invalidate += err; if (le64_to_cpu(ri->seq) > realm->seq) { + dout("update_snap_trace updating %llx %p %lld -> %lld\n", + realm->ino, realm, realm->seq, le64_to_cpu(ri->seq)); /* update realm parameters, snap lists */ realm->seq = le64_to_cpu(ri->seq); realm->created = le64_to_cpu(ri->created); @@ -668,9 +654,17 @@ more: if (err < 0) goto fail; + /* queue realm for cap_snap creation */ + list_add(&realm->dirty_item, &dirty_realms); + invalidate = 1; } else if (!realm->cached_context) { + dout("update_snap_trace %llx %p seq %lld new\n", + realm->ino, realm, realm->seq); invalidate = 1; + } else { + dout("update_snap_trace %llx %p seq %lld unchanged\n", + realm->ino, realm, realm->seq); } dout("done with %llx %p, invalidated=%d, %p %p\n", realm->ino, @@ -683,6 +677,14 @@ more: if (invalidate) rebuild_snap_realms(realm); + /* + * queue cap snaps _after_ we've built the new snap contexts, + * so that i_head_snapc can be set appropriately. + */ + list_for_each_entry(realm, &dirty_realms, dirty_item) { + queue_realm_cap_snaps(realm); + } + __cleanup_empty_realms(mdsc); return 0; @@ -816,6 +818,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, }; struct inode *inode = ceph_find_inode(sb, vino); struct ceph_inode_info *ci; + struct ceph_snap_realm *oldrealm; if (!inode) continue; @@ -841,18 +844,19 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, dout(" will move %p to split realm %llx %p\n", inode, realm->ino, realm); /* - * Remove the inode from the realm's inode - * list, but don't add it to the new realm - * yet. We don't want the cap_snap to be - * queued (again) by ceph_update_snap_trace() - * below. Queue it _now_, under the old context. + * Move the inode to the new realm */ spin_lock(&realm->inodes_with_caps_lock); list_del_init(&ci->i_snap_realm_item); + list_add(&ci->i_snap_realm_item, + &realm->inodes_with_caps); + oldrealm = ci->i_snap_realm; + ci->i_snap_realm = realm; spin_unlock(&realm->inodes_with_caps_lock); spin_unlock(&inode->i_lock); - ceph_queue_cap_snap(ci); + ceph_get_snap_realm(mdsc, realm); + ceph_put_snap_realm(mdsc, oldrealm); iput(inode); continue; @@ -880,43 +884,9 @@ skip_inode: ceph_update_snap_trace(mdsc, p, e, op == CEPH_SNAP_OP_DESTROY); - if (op == CEPH_SNAP_OP_SPLIT) { - /* - * ok, _now_ add the inodes into the new realm. - */ - for (i = 0; i < num_split_inos; i++) { - struct ceph_vino vino = { - .ino = le64_to_cpu(split_inos[i]), - .snap = CEPH_NOSNAP, - }; - struct inode *inode = ceph_find_inode(sb, vino); - struct ceph_inode_info *ci; - - if (!inode) - continue; - ci = ceph_inode(inode); - spin_lock(&inode->i_lock); - if (list_empty(&ci->i_snap_realm_item)) { - struct ceph_snap_realm *oldrealm = - ci->i_snap_realm; - - dout(" moving %p to split realm %llx %p\n", - inode, realm->ino, realm); - spin_lock(&realm->inodes_with_caps_lock); - list_add(&ci->i_snap_realm_item, - &realm->inodes_with_caps); - ci->i_snap_realm = realm; - spin_unlock(&realm->inodes_with_caps_lock); - ceph_get_snap_realm(mdsc, realm); - ceph_put_snap_realm(mdsc, oldrealm); - } - spin_unlock(&inode->i_lock); - iput(inode); - } - + if (op == CEPH_SNAP_OP_SPLIT) /* we took a reference when we created the realm, above */ ceph_put_snap_realm(mdsc, realm); - } __cleanup_empty_realms(mdsc); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c33897ae5725..c80bfbe27b05 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -690,6 +690,8 @@ struct ceph_snap_realm { struct list_head empty_item; /* if i have ref==0 */ + struct list_head dirty_item; /* if realm needs new context */ + /* the current set of snaps for this realm */ struct ceph_snap_context *cached_context; -- cgit v1.2.3-59-g8ed1b From 89e45aac42d40426c97e6901811309bf49c4993f Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 17 Sep 2010 03:24:13 +0200 Subject: x86: Fix instruction breakpoint encoding Lengths and types of breakpoints are encoded in a half byte into CPU registers. However when we extract these values and store them, we add a high half byte part to them: 0x40 to the length and 0x80 to the type. When that gets reloaded to the CPU registers, the high part is masked. While making the instruction breakpoints available for perf, I zapped that high part on instruction breakpoint encoding and that broke the arch -> generic translation used by ptrace instruction breakpoints. Writing dr7 to set an inst breakpoint was then failing. There is no apparent reason for these high parts so we could get rid of them altogether. That's an invasive change though so let's do that later and for now fix the problem by restoring that inst breakpoint high part encoding in this sole patch. Reported-by: Kelvie Wong Signed-off-by: Frederic Weisbecker Cc: Prasad Cc: Mahesh Salgaonkar Cc: Will Deacon --- arch/x86/include/asm/hw_breakpoint.h | 2 +- arch/x86/kernel/hw_breakpoint.c | 40 +++++++++++++++++------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h index 528a11e8d3e3..824ca07860d0 100644 --- a/arch/x86/include/asm/hw_breakpoint.h +++ b/arch/x86/include/asm/hw_breakpoint.h @@ -20,7 +20,7 @@ struct arch_hw_breakpoint { #include /* Available HW breakpoint length encodings */ -#define X86_BREAKPOINT_LEN_X 0x00 +#define X86_BREAKPOINT_LEN_X 0x40 #define X86_BREAKPOINT_LEN_1 0x40 #define X86_BREAKPOINT_LEN_2 0x44 #define X86_BREAKPOINT_LEN_4 0x4c diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index a474ec37c32f..ff15c9dcc25d 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c @@ -206,11 +206,27 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp) int arch_bp_generic_fields(int x86_len, int x86_type, int *gen_len, int *gen_type) { - /* Len */ - switch (x86_len) { - case X86_BREAKPOINT_LEN_X: + /* Type */ + switch (x86_type) { + case X86_BREAKPOINT_EXECUTE: + if (x86_len != X86_BREAKPOINT_LEN_X) + return -EINVAL; + + *gen_type = HW_BREAKPOINT_X; *gen_len = sizeof(long); + return 0; + case X86_BREAKPOINT_WRITE: + *gen_type = HW_BREAKPOINT_W; break; + case X86_BREAKPOINT_RW: + *gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R; + break; + default: + return -EINVAL; + } + + /* Len */ + switch (x86_len) { case X86_BREAKPOINT_LEN_1: *gen_len = HW_BREAKPOINT_LEN_1; break; @@ -229,21 +245,6 @@ int arch_bp_generic_fields(int x86_len, int x86_type, return -EINVAL; } - /* Type */ - switch (x86_type) { - case X86_BREAKPOINT_EXECUTE: - *gen_type = HW_BREAKPOINT_X; - break; - case X86_BREAKPOINT_WRITE: - *gen_type = HW_BREAKPOINT_W; - break; - case X86_BREAKPOINT_RW: - *gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R; - break; - default: - return -EINVAL; - } - return 0; } @@ -316,9 +317,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) ret = -EINVAL; switch (info->len) { - case X86_BREAKPOINT_LEN_X: - align = sizeof(long) -1; - break; case X86_BREAKPOINT_LEN_1: align = 0; break; -- cgit v1.2.3-59-g8ed1b From 068e35eee9ef98eb4cab55181977e24995d273be Mon Sep 17 00:00:00 2001 From: Matt Helsley Date: Mon, 13 Sep 2010 13:01:18 -0700 Subject: hw breakpoints: Fix pid namespace bug Hardware breakpoints can't be registered within pid namespaces because tsk->pid is passed rather than the pid in the current namespace. (See https://bugzilla.kernel.org/show_bug.cgi?id=17281 ) This is a quick fix demonstrating the problem but is not the best method of solving the problem since passing pids internally is not the best way to avoid pid namespace bugs. Subsequent patches will show a better solution. Much thanks to Frederic Weisbecker for doing the bulk of the work finding this bug. Reported-by: Robin Green Signed-off-by: Matt Helsley Signed-off-by: Peter Zijlstra Cc: Prasad Cc: Arnaldo Carvalho de Melo Cc: Steven Rostedt Cc: Will Deacon Cc: Mahesh Salgaonkar Cc: 2.6.33-2.6.35 LKML-Reference: Signed-off-by: Ingo Molnar Signed-off-by: Frederic Weisbecker --- kernel/hw_breakpoint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c index d71a987fd2bf..c7c2aed9e2dc 100644 --- a/kernel/hw_breakpoint.c +++ b/kernel/hw_breakpoint.c @@ -433,7 +433,8 @@ register_user_hw_breakpoint(struct perf_event_attr *attr, perf_overflow_handler_t triggered, struct task_struct *tsk) { - return perf_event_create_kernel_counter(attr, -1, tsk->pid, triggered); + return perf_event_create_kernel_counter(attr, -1, task_pid_vnr(tsk), + triggered); } EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); -- cgit v1.2.3-59-g8ed1b From 126925c090155f13e90b9e7e8c4010e96027c00a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 7 Sep 2010 17:02:47 +1000 Subject: md: call md_update_sb even for 'external' metadata arrays. Now that we depend on md_update_sb to clear variable bits in mddev->flags (rather than trying not to set them) it is important to always call md_update_sb when appropriate. md_check_recovery has this job but explicitly avoids it for ->external metadata arrays. This is not longer appropraite, or needed. However we do want to avoid taking the mddev lock if only MD_CHANGE_PENDING is set as that is not cleared by md_update_sb for external-metadata arrays. Reported-by: "Kwolek, Adam" Signed-off-by: NeilBrown --- drivers/md/md.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 43cf9cc9c1df..bdd9bba577b0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7069,7 +7069,7 @@ void md_check_recovery(mddev_t *mddev) if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) return; if ( ! ( - (mddev->flags && !mddev->external) || + (mddev->flags & ~ (1<recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || (mddev->external == 0 && mddev->safemode == 1) || -- cgit v1.2.3-59-g8ed1b From ddcf3522cf03a147c867a2e0155761652dbd156a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 8 Sep 2010 16:48:17 +1000 Subject: md: fix v1.x metadata update when a disk is missing. If an array with 1.x metadata is assembled with the last disk missing, md doesn't properly record the fact that the disk was missing. This is unlikely to cause a real problem as the event count will be different to the count on the missing disk so it won't be included in the array. However it could still cause confusion. So make sure we clear all the relevant slots, not just the early ones. Signed-off-by: NeilBrown --- drivers/md/md.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index bdd9bba577b0..f20d13e717d5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1643,7 +1643,9 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1; if (rdev->sb_size & bmask) rdev->sb_size = (rdev->sb_size | bmask) + 1; - } + } else + max_dev = le32_to_cpu(sb->max_dev); + for (i=0; idev_roles[i] = cpu_to_le16(0xfffe); -- cgit v1.2.3-59-g8ed1b From e71895a1beff2014534c9660d9ae42e043f11555 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 16 Sep 2010 12:27:50 +0000 Subject: xfrm: dont assume rcu_read_lock in xfrm_output_one() ip_local_out() is called with rcu_read_lock() held from ip_queue_xmit() but not from other call sites. Reported-and-bisected-by: Nick Bowler Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/xfrm/xfrm_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index a3cca0a94346..64f2ae1fdc15 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -101,7 +101,7 @@ resume: err = -EHOSTUNREACH; goto error_nolock; } - skb_dst_set_noref(skb, dst); + skb_dst_set(skb, dst_clone(dst)); x = dst->xfrm; } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)); -- cgit v1.2.3-59-g8ed1b From 7011e660938fc44ed86319c18a5954e95a82ab3e Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 15 Sep 2010 11:43:28 +0000 Subject: drivers/net/usb/hso.c: prevent reading uninitialized memory Fixed formatting (tabs and line breaks). The TIOCGICOUNT device ioctl allows unprivileged users to read uninitialized stack memory, because the "reserved" member of the serial_icounter_struct struct declared on the stack in hso_get_count() is not altered or zeroed before being copied back to the user. This patch takes care of it. Signed-off-by: Dan Rosenberg Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 6efca66b8766..1cd752f9a6e1 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1652,6 +1652,8 @@ static int hso_get_count(struct hso_serial *serial, struct uart_icount cnow; struct hso_tiocmget *tiocmget = serial->tiocmget; + memset(&icount, 0, sizeof(struct serial_icounter_struct)); + if (!tiocmget) return -ENOENT; spin_lock_irq(&serial->serial_lock); -- cgit v1.2.3-59-g8ed1b From 44467187dc22fdd33a1a06ea0ba86ce20be3fe3c Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 15 Sep 2010 11:43:04 +0000 Subject: drivers/net/eql.c: prevent reading uninitialized stack memory Fixed formatting (tabs and line breaks). The EQL_GETMASTRCFG device ioctl allows unprivileged users to read 16 bytes of uninitialized stack memory, because the "master_name" member of the master_config_t struct declared on the stack in eql_g_master_cfg() is not altered or zeroed before being copied back to the user. This patch takes care of it. Signed-off-by: Dan Rosenberg Signed-off-by: David S. Miller --- drivers/net/eql.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/eql.c b/drivers/net/eql.c index dda2c7944da9..0cb1cf9cf4b0 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -555,6 +555,8 @@ static int eql_g_master_cfg(struct net_device *dev, master_config_t __user *mcp) equalizer_t *eql; master_config_t mc; + memset(&mc, 0, sizeof(master_config_t)); + if (eql_is_master(dev)) { eql = netdev_priv(dev); mc.max_slaves = eql->max_slaves; -- cgit v1.2.3-59-g8ed1b From 49c37c0334a9b85d30ab3d6b5d1acb05ef2ef6de Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 15 Sep 2010 11:43:12 +0000 Subject: drivers/net/cxgb3/cxgb3_main.c: prevent reading uninitialized stack memory Fixed formatting (tabs and line breaks). The CHELSIO_GET_QSET_NUM device ioctl allows unprivileged users to read 4 bytes of uninitialized stack memory, because the "addr" member of the ch_reg struct declared on the stack in cxgb_extension_ioctl() is not altered or zeroed before being copied back to the user. This patch takes care of it. Signed-off-by: Dan Rosenberg Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index ad19585d960b..f208712c0b90 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2296,6 +2296,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) case CHELSIO_GET_QSET_NUM:{ struct ch_reg edata; + memset(&edata, 0, sizeof(struct ch_reg)); + edata.cmd = CHELSIO_GET_QSET_NUM; edata.val = pi->nqsets; if (copy_to_user(useraddr, &edata, sizeof(edata))) -- cgit v1.2.3-59-g8ed1b From e443e383242839b0d72efce744b7ba31573b1f99 Mon Sep 17 00:00:00 2001 From: Chris Snook Date: Thu, 16 Sep 2010 22:00:28 -0700 Subject: MAINTAINERS: move atlx discussions to netdev The atlx drivers are sufficiently mature that we no longer need a separate mailing list for them. Move the discussion to netdev, so we can decommission atl1-devel, which is now mostly spam. Signed-off-by: Chris Snook Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b5fb9bdcabb1..44e659530910 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1135,7 +1135,7 @@ ATLX ETHERNET DRIVERS M: Jay Cliburn M: Chris Snook M: Jie Yang -L: atl1-devel@lists.sourceforge.net +L: netdev@vger.kernel.org W: http://sourceforge.net/projects/atl1 W: http://atl1.sourceforge.net S: Maintained -- cgit v1.2.3-59-g8ed1b From 2507136f74f70a4869bd4f525d48715ae66db43d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 16 Sep 2010 08:12:55 +0000 Subject: net/llc: storing negative error codes in unsigned short If the alloc_skb() fails then we return 65431 instead of -ENOBUFS (-105). Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/llc/llc_station.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c index e4dae0244d76..cf4aea3ba30f 100644 --- a/net/llc/llc_station.c +++ b/net/llc/llc_station.c @@ -689,7 +689,7 @@ static void llc_station_rcv(struct sk_buff *skb) int __init llc_station_init(void) { - u16 rc = -ENOBUFS; + int rc = -ENOBUFS; struct sk_buff *skb; struct llc_station_state_ev *ev; -- cgit v1.2.3-59-g8ed1b From 79077319d7c7844d5d836e52099a7a1bcadf9b04 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 12 Sep 2010 19:58:04 +0100 Subject: drm/i915/crt: Downgrade warnings for hotplug failures These are not fatal errors, so do not alarm the user by filling the logs with *** ERROR ***. Especially as we know that g4x CRT detection is a little sticky. On the one hand the errors are valid since they are warning us of a stall -- we poll the register whilst holding the mode lock so not even the mouse will update. On the other hand, those stalls were already present yet nobody complained. Reported-by: Andi Kleen Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=18332 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_crt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 4b7735196cd5..8f6f38c7d84d 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -188,7 +188,7 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 1000, 1)) - DRM_ERROR("timed out waiting for FORCE_TRIGGER"); + DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); if (turn_off_dac) { I915_WRITE(PCH_ADPA, temp); @@ -245,7 +245,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) if (wait_for((I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0, 1000, 1)) - DRM_ERROR("timed out waiting for FORCE_DETECT to go off"); + DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off"); } stat = I915_READ(PORT_HOTPLUG_STAT); -- cgit v1.2.3-59-g8ed1b From e259befd9013e212648c3bd4f6f1fbf92d0dd51d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Sep 2010 00:32:02 +0100 Subject: drm/i915: Fix Sandybridge fence registers With 5 places to update when adding handling for fence registers, it is easy to overlook one or two. Correct that oversight, but fence management should be improved before a new set of registers is added. Bugzilla: https://bugs.freedesktop.org/show_bug?id=30199 Original patch by: Yuanhan Liu Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/gpu/drm/i915/i915_gem.c | 37 ++++++++++++++++++++++++------------- drivers/gpu/drm/i915/i915_suspend.c | 36 +++++++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 16fca1d1799a..cf4ffbee1c00 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2351,14 +2351,21 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) reg->obj = obj; - if (IS_GEN6(dev)) + switch (INTEL_INFO(dev)->gen) { + case 6: sandybridge_write_fence_reg(reg); - else if (IS_I965G(dev)) + break; + case 5: + case 4: i965_write_fence_reg(reg); - else if (IS_I9XX(dev)) + break; + case 3: i915_write_fence_reg(reg); - else + break; + case 2: i830_write_fence_reg(reg); + break; + } trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg, obj_priv->tiling_mode); @@ -2381,22 +2388,26 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[obj_priv->fence_reg]; + uint32_t fence_reg; - if (IS_GEN6(dev)) { + switch (INTEL_INFO(dev)->gen) { + case 6: I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (obj_priv->fence_reg * 8), 0); - } else if (IS_I965G(dev)) { + break; + case 5: + case 4: I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); - } else { - uint32_t fence_reg; - - if (obj_priv->fence_reg < 8) - fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4; + break; + case 3: + if (obj_priv->fence_reg > 8) + fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - 8) * 4; else - fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - - 8) * 4; + case 2: + fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4; I915_WRITE(fence_reg, 0); + break; } reg->obj = NULL; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 2c6b98f2440e..31f08581e93a 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -789,16 +789,25 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); /* Fences */ - if (IS_I965G(dev)) { + switch (INTEL_INFO(dev)->gen) { + case 6: + for (i = 0; i < 16; i++) + dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); + break; + case 5: + case 4: for (i = 0; i < 16; i++) dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); - } else { - for (i = 0; i < 8; i++) - dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); - + break; + case 3: if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) for (i = 0; i < 8; i++) dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); + case 2: + for (i = 0; i < 8; i++) + dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); + break; + } return 0; @@ -815,15 +824,24 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(HWS_PGA, dev_priv->saveHWS); /* Fences */ - if (IS_I965G(dev)) { + switch (INTEL_INFO(dev)->gen) { + case 6: + for (i = 0; i < 16; i++) + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]); + break; + case 5: + case 4: for (i = 0; i < 16; i++) I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]); - } else { - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]); + break; + case 3: + case 2: if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) for (i = 0; i < 8; i++) I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]); + for (i = 0; i < 8; i++) + I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]); + break; } i915_restore_display(dev); -- cgit v1.2.3-59-g8ed1b From 41a51428916ab04587bacee2dda61c4a0c4fc02f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Sep 2010 08:22:30 +0100 Subject: drm/i915,agp/intel: Add second set of PCI-IDs for B43 There is a second revision of B43 (a desktop gen4 part) floating around, functionally equivalent to the original B43, so simply add the new PCI-IDs. Bugzilla: https://bugs.freedesktop.org/show_bugs.cgi?id=30221 Signed-off-by: Chris Wilson Cc: stable@kernel.org --- drivers/char/agp/intel-agp.c | 2 ++ drivers/char/agp/intel-agp.h | 2 ++ drivers/gpu/drm/i915/i915_drv.c | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index eab58db5f91c..cd18493c9527 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -806,6 +806,8 @@ static const struct intel_driver_description { "G45/G43", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG, "B43", NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_B43_1_HB, PCI_DEVICE_ID_INTEL_B43_1_IG, + "B43", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, "G41", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index ee189c74d345..d09b1ab7e8ab 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -186,6 +186,8 @@ #define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2 #define PCI_DEVICE_ID_INTEL_B43_HB 0x2E40 #define PCI_DEVICE_ID_INTEL_B43_IG 0x2E42 +#define PCI_DEVICE_ID_INTEL_B43_1_HB 0x2E90 +#define PCI_DEVICE_ID_INTEL_B43_1_IG 0x2E92 #define PCI_DEVICE_ID_INTEL_GM45_HB 0x2A40 #define PCI_DEVICE_ID_INTEL_GM45_IG 0x2A42 #define PCI_DEVICE_ID_INTEL_EAGLELAKE_HB 0x2E00 diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 216deb579785..6dbe14cc4f74 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -170,6 +170,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), /* G45_G */ INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), /* G41_G */ INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), /* B43_G */ + INTEL_VGA_DEVICE(0x2e92, &intel_g45_info), /* B43_G.1 */ INTEL_VGA_DEVICE(0xa001, &intel_pineview_info), INTEL_VGA_DEVICE(0xa011, &intel_pineview_info), INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info), -- cgit v1.2.3-59-g8ed1b From 9907790aa06bfc04bf78b445e732ea10039c61e4 Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Fri, 17 Sep 2010 10:22:32 +0200 Subject: ALSA: hda - Fix automatic MIC switching and include dock MIC for IDT codecs Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index e4e7d43f911e..7eb359a030de 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -263,6 +263,7 @@ struct sigmatel_spec { struct sigmatel_mic_route ext_mic; struct sigmatel_mic_route int_mic; + struct sigmatel_mic_route dock_mic; const char **spdif_labels; @@ -3488,7 +3489,7 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, } static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *fixed, hda_nid_t *ext) + hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock) { unsigned int cfg; @@ -3496,15 +3497,22 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, return 0; cfg = snd_hda_codec_get_pincfg(codec, nid); switch (get_defcfg_connect(cfg)) { + case AC_JACK_PORT_BOTH: case AC_JACK_PORT_FIXED: if (*fixed) return 1; /* already occupied */ *fixed = nid; break; case AC_JACK_PORT_COMPLEX: - if (*ext) - return 1; /* already occupied */ - *ext = nid; + if ((get_defcfg_location(cfg) & 0xF0) == AC_JACK_LOC_SEPARATE) { + if (*dock) + return 1; /* already occupied */ + *dock = nid; + } else { + if (*ext) + return 1; /* already occupied */ + *ext = nid; + } break; } return 0; @@ -3519,6 +3527,8 @@ static int set_mic_route(struct hda_codec *codec, int i; mic->pin = pin; + if (pin == 0) + return 0; for (i = 0; i < cfg->num_inputs; i++) { if (pin == cfg->inputs[i].pin) break; @@ -3554,26 +3564,29 @@ static int stac_check_auto_mic(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext; + hda_nid_t fixed, ext, dock; int i; for (i = 0; i < cfg->num_inputs; i++) { if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN) return 0; /* must be exclusively mics */ } - fixed = ext = 0; + fixed = ext = dock = 0; for (i = 0; i < cfg->num_inputs; i++) - if (check_mic_pin(codec, cfg->inputs[i].pin, &fixed, &ext)) + if (check_mic_pin(codec, cfg->inputs[i].pin, + &fixed, &ext, &dock)) return 0; for (i = 0; i < spec->num_dmics; i++) - if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext)) + if (check_mic_pin(codec, spec->dmic_nids[i], + &fixed, &ext, &dock)) return 0; - if (!fixed || !ext) - return 0; + if (!fixed && !ext && !dock) + return 0; /* no input to switch */ if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP)) return 0; /* no unsol support */ if (set_mic_route(codec, &spec->ext_mic, ext) || - set_mic_route(codec, &spec->int_mic, fixed)) + set_mic_route(codec, &spec->int_mic, fixed) || + set_mic_route(codec, &spec->dock_mic, dock)) return 0; /* something is wrong */ return 1; } @@ -4281,6 +4294,9 @@ static int stac92xx_init(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, 0); if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) stac_issue_unsol_event(codec, spec->ext_mic.pin); + if (enable_pin_detect(codec, spec->dock_mic.pin, + STAC_MIC_EVENT)) + stac_issue_unsol_event(codec, spec->dock_mic.pin); } for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; @@ -4698,6 +4714,8 @@ static void stac92xx_mic_detect(struct hda_codec *codec) if (get_pin_presence(codec, spec->ext_mic.pin)) mic = &spec->ext_mic; + else if (get_pin_presence(codec, spec->dock_mic.pin)) + mic = &spec->dock_mic; else mic = &spec->int_mic; if (mic->dmux_idx >= 0) -- cgit v1.2.3-59-g8ed1b From 41c89ef3aafea5f35601fa75edba90e7417f604e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Sep 2010 10:26:37 +0200 Subject: ALSA: hda - Fix mic attribute check for internal mics Now Windows claims that the BIOS sets pins for internal mics to be BOTH connection instead of FIXED. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 08d81b873022..9f668efbe420 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4648,8 +4648,11 @@ enum { static int get_mic_pin_attr(unsigned int def_conf) { unsigned int loc = get_defcfg_location(def_conf); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || - (loc & 0x30) == AC_JACK_LOC_INTERNAL) + unsigned int conn = get_defcfg_connect(def_conf); + /* Windows may claim the internal mic to be BOTH, too */ + if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) + return MIC_ATTR_INT; + if ((loc & 0x30) == AC_JACK_LOC_INTERNAL) return MIC_ATTR_INT; if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) return MIC_ATTR_DOCK; -- cgit v1.2.3-59-g8ed1b From 99f76891a33d130776da3b01935d978b1e75fe68 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 13 Sep 2010 13:38:55 +0100 Subject: ARM: 6375/1: plat-nomadik: MTU timer trivial bug fix timer0 to 3 are all on mtu block 0, so don't calculate the clock event rate based upon mtu block 1's clock speed. Acked-by: Alessandro Rubini Signed-off-by: Jonas Aaberg Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/plat-nomadik/timer.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index ea3ca86c5283..d673888af18e 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -131,17 +131,12 @@ void __init nmdk_timer_init(void) { unsigned long rate; struct clk *clk0; - struct clk *clk1; u32 cr; clk0 = clk_get_sys("mtu0", NULL); BUG_ON(IS_ERR(clk0)); - clk1 = clk_get_sys("mtu1", NULL); - BUG_ON(IS_ERR(clk1)); - clk_enable(clk0); - clk_enable(clk1); /* * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500: @@ -170,15 +165,8 @@ void __init nmdk_timer_init(void) pr_err("timer: failed to initialize clock source %s\n", nmdk_clksrc.name); - /* Timer 1 is used for events, fix according to rate */ - cr = MTU_CRn_32BITS; - rate = clk_get_rate(clk1); - if (rate > 16 << 20) { - rate /= 16; - cr |= MTU_CRn_PRESCALE_16; - } else { - cr |= MTU_CRn_PRESCALE_1; - } + /* Timer 1 is used for events */ + clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE); writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */ -- cgit v1.2.3-59-g8ed1b From a0719f52d90aed5b82ecf2f3ed14bc4ced3d1a8a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 13 Sep 2010 13:40:04 +0100 Subject: ARM: 6376/1: plat-nomadik: MTU: Change prescaler limit and comment updates The prescaler 16 is now used only when the timer runs at 32 MHz or more. Some comment updates as well. Acked-by: Alessandro Rubini Signed-off-by: Jonas Aaberg Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/plat-nomadik/timer.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index d673888af18e..aedf9c1d645e 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-nomadik/timer.c + * linux/arch/arm/plat-nomadik/timer.c * * Copyright (C) 2008 STMicroelectronics * Copyright (C) 2010 Alessandro Rubini @@ -75,7 +75,7 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode, cr = readl(mtu_base + MTU_CR(1)); writel(0, mtu_base + MTU_LR(1)); writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(1)); - writel(0x2, mtu_base + MTU_IMSC); + writel(1 << 1, mtu_base + MTU_IMSC); break; case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_UNUSED: @@ -131,7 +131,7 @@ void __init nmdk_timer_init(void) { unsigned long rate; struct clk *clk0; - u32 cr; + u32 cr = MTU_CRn_32BITS; clk0 = clk_get_sys("mtu0", NULL); BUG_ON(IS_ERR(clk0)); @@ -139,12 +139,15 @@ void __init nmdk_timer_init(void) clk_enable(clk0); /* - * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500: - * use a divide-by-16 counter if it's more than 16MHz + * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz + * for ux500. + * Use a divide-by-16 counter if the tick rate is more than 32MHz. + * At 32 MHz, the timer (with 32 bit counter) can be programmed + * to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer + * with 16 gives too low timer resolution. */ - cr = MTU_CRn_32BITS;; rate = clk_get_rate(clk0); - if (rate > 16 << 20) { + if (rate > 32000000) { rate /= 16; cr |= MTU_CRn_PRESCALE_16; } else { -- cgit v1.2.3-59-g8ed1b From 63f469324f999a28e67b90eb27a5fe0e379b7064 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 13 Sep 2010 13:44:47 +0100 Subject: ARM: 6377/1: supply _cansleep gpio function to U300 We have to use _cansleep gpio accessors in the MMCI driver so as to avoid slowpath warnings, now U300 has MMCI but doesn't have these functions in place to siply wrap the existing non-sleeping functions into sleepable variants. Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/mach-u300/include/mach/gpio.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-u300/include/mach/gpio.h b/arch/arm/mach-u300/include/mach/gpio.h index 7b1fc984abb6..d5a71abcbaea 100644 --- a/arch/arm/mach-u300/include/mach/gpio.h +++ b/arch/arm/mach-u300/include/mach/gpio.h @@ -273,6 +273,9 @@ extern void gpio_pullup(unsigned gpio, int value); extern int gpio_get_value(unsigned gpio); extern void gpio_set_value(unsigned gpio, int value); +#define gpio_get_value_cansleep gpio_get_value +#define gpio_set_value_cansleep gpio_set_value + /* wrappers to sleep-enable the previous two functions */ static inline unsigned gpio_to_irq(unsigned gpio) { -- cgit v1.2.3-59-g8ed1b From 6491848d1ab246f6d243ddef25085fc1d836ff2c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 14 Sep 2010 09:50:03 +0100 Subject: ARM: 6387/1: errata: check primary part ID in proc-v7.S Kconfig doesn't have any knowledge of specific v7 cores, so it is possible to select errata workarounds that may cause inadvertent behaviour when executed on a core other than those targetted by the fix. This patch improves the variant and revision checking in proc-v7.S so that the primary part number is also considered when applying errata workarounds. Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/mm/proc-v7.S | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 6a8506d99ee9..1f16f9e3f441 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -204,8 +204,13 @@ __v7_setup: bne 2f and r5, r0, #0x00f00000 @ variant and r6, r0, #0x0000000f @ revision - orr r0, r6, r5, lsr #20-4 @ combine variant and revision + orr r6, r6, r5, lsr #20-4 @ combine variant and revision + ubfx r0, r0, #4, #12 @ primary part number + /* Cortex-A8 Errata */ + ldr r10, =0x00000c08 @ Cortex-A8 primary part number + teq r0, r10 + bne 2f #ifdef CONFIG_ARM_ERRATA_430973 teq r5, #0x00100000 @ only present in r1p* mrceq p15, 0, r10, c1, c0, 1 @ read aux control register @@ -213,14 +218,14 @@ __v7_setup: mcreq p15, 0, r10, c1, c0, 1 @ write aux control register #endif #ifdef CONFIG_ARM_ERRATA_458693 - teq r0, #0x20 @ only present in r2p0 + teq r6, #0x20 @ only present in r2p0 mrceq p15, 0, r10, c1, c0, 1 @ read aux control register orreq r10, r10, #(1 << 5) @ set L1NEON to 1 orreq r10, r10, #(1 << 9) @ set PLDNOP to 1 mcreq p15, 0, r10, c1, c0, 1 @ write aux control register #endif #ifdef CONFIG_ARM_ERRATA_460075 - teq r0, #0x20 @ only present in r2p0 + teq r6, #0x20 @ only present in r2p0 mrceq p15, 1, r10, c9, c0, 2 @ read L2 cache aux ctrl register tsteq r10, #1 << 22 orreq r10, r10, #(1 << 22) @ set the Write Allocate disable bit -- cgit v1.2.3-59-g8ed1b From 9f05027c7cb3cfe56a31892bd83391138d41a667 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 14 Sep 2010 09:51:43 +0100 Subject: ARM: 6388/1: errata: DMB operation may be faulty On versions of the Cortex-A9 up to and including r2p2, under rare circumstances, a DMB instruction between 2 write operations may not ensure the correct visibility ordering of the 2 writes. This workaround sets a bit in the diagnostic register of the Cortex-A9, causing the DMB instruction to behave like a DSB, which functions correctly on the affected cores. Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/Kconfig | 12 ++++++++++++ arch/arm/mm/proc-v7.S | 16 ++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 553b7cf17bfb..ab14c0a5d21e 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1051,6 +1051,18 @@ config ARM_ERRATA_460075 ACTLR register. Note that setting specific bits in the ACTLR register may not be available in non-secure mode. +config ARM_ERRATA_742230 + bool "ARM errata: DMB operation may be faulty" + depends on CPU_V7 && SMP + help + This option enables the workaround for the 742230 Cortex-A9 + (r1p0..r2p2) erratum. Under rare circumstances, a DMB instruction + between two write operations may not ensure the correct visibility + ordering of the two writes. This workaround sets a specific bit in + the diagnostic register of the Cortex-A9 which causes the DMB + instruction to behave as a DSB, ensuring the correct behaviour of + the two writes. + config PL310_ERRATA_588369 bool "Clean & Invalidate maintenance operations do not invalidate clean lines" depends on CACHE_L2X0 && ARCH_OMAP4 diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 1f16f9e3f441..945f36341fa6 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -201,7 +201,7 @@ __v7_setup: mrc p15, 0, r0, c0, c0, 0 @ read main ID register and r10, r0, #0xff000000 @ ARM? teq r10, #0x41000000 - bne 2f + bne 3f and r5, r0, #0x00f00000 @ variant and r6, r0, #0x0000000f @ revision orr r6, r6, r5, lsr #20-4 @ combine variant and revision @@ -231,8 +231,20 @@ __v7_setup: orreq r10, r10, #(1 << 22) @ set the Write Allocate disable bit mcreq p15, 1, r10, c9, c0, 2 @ write the L2 cache aux ctrl register #endif + b 3f + + /* Cortex-A9 Errata */ +2: ldr r10, =0x00000c09 @ Cortex-A9 primary part number + teq r0, r10 + bne 3f +#ifdef CONFIG_ARM_ERRATA_742230 + cmp r6, #0x22 @ only present up to r2p2 + mrcle p15, 0, r10, c15, c0, 1 @ read diagnostic register + orrle r10, r10, #1 << 4 @ set bit #4 + mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register +#endif -2: mov r10, #0 +3: mov r10, #0 #ifdef HARVARD_CACHE mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate #endif -- cgit v1.2.3-59-g8ed1b From a672e99b129e286df2e2697a1b603d82321117f3 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 14 Sep 2010 09:53:02 +0100 Subject: ARM: 6389/1: errata: incorrect hazard handling in the SCU may lead to data corruption On the r2p0, r2p1 and r2p2 versions of the Cortex-A9, data corruption can occur if a shared cache line is replaced on one CPU as another CPU is accessing it. This workaround sets two bits in the diagnostic register of the Cortex-A9, reducing the linefill issuing capabilities of the processor and avoiding the erroneous behaviour. Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/Kconfig | 14 ++++++++++++++ arch/arm/mm/proc-v7.S | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ab14c0a5d21e..0f89335b84c2 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1063,6 +1063,20 @@ config ARM_ERRATA_742230 instruction to behave as a DSB, ensuring the correct behaviour of the two writes. +config ARM_ERRATA_742231 + bool "ARM errata: Incorrect hazard handling in the SCU may lead to data corruption" + depends on CPU_V7 && SMP + help + This option enables the workaround for the 742231 Cortex-A9 + (r2p0..r2p2) erratum. Under certain conditions, specific to the + Cortex-A9 MPCore micro-architecture, two CPUs working in SMP mode, + accessing some data located in the same cache line, may get corrupted + data due to bad handling of the address hazard when the line gets + replaced from one of the CPUs at the same time as another CPU is + accessing it. This workaround sets specific bits in the diagnostic + register of the Cortex-A9 which reduces the linefill issuing + capabilities of the processor. + config PL310_ERRATA_588369 bool "Clean & Invalidate maintenance operations do not invalidate clean lines" depends on CACHE_L2X0 && ARCH_OMAP4 diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 945f36341fa6..080129263eef 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -243,6 +243,15 @@ __v7_setup: orrle r10, r10, #1 << 4 @ set bit #4 mcrle p15, 0, r10, c15, c0, 1 @ write diagnostic register #endif +#ifdef CONFIG_ARM_ERRATA_742231 + teq r6, #0x20 @ present in r2p0 + teqne r6, #0x21 @ present in r2p1 + teqne r6, #0x22 @ present in r2p2 + mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register + orreq r10, r10, #1 << 12 @ set bit #12 + orreq r10, r10, #1 << 22 @ set bit #22 + mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register +#endif 3: mov r10, #0 #ifdef HARVARD_CACHE -- cgit v1.2.3-59-g8ed1b From 1a8e41cd672f894bbd74874eac601e6cedf838fb Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 16 Sep 2010 17:57:17 +0100 Subject: ARM: 6395/1: VExpress: Set bit 22 in the PL310 (cache controller) AuxCtlr register Clearing bit 22 in the PL310 Auxiliary Control register (shared attribute override enable) has the side effect of transforming Normal Shared Non-cacheable reads into Cacheable no-allocate reads. Coherent DMA buffers in Linux always have a Cacheable alias via the kernel linear mapping and the processor can speculatively load cache lines into the PL310 controller. With bit 22 cleared, Non-cacheable reads would unexpectedly hit such cache lines leading to buffer corruption. Cc: Nicolas Pitre Cc: Signed-off-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/mach-vexpress/ct-ca9x4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c index 577df6cccb08..1c9c13e9d074 100644 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ b/arch/arm/mach-vexpress/ct-ca9x4.c @@ -227,7 +227,7 @@ static void ct_ca9x4_init(void) int i; #ifdef CONFIG_CACHE_L2X0 - l2x0_init(MMIO_P2V(CT_CA9X4_L2CC), 0x00000000, 0xfe0fffff); + l2x0_init(MMIO_P2V(CT_CA9X4_L2CC), 0x00400000, 0xfe0fffff); #endif clkdev_add_table(lookups, ARRAY_SIZE(lookups)); -- cgit v1.2.3-59-g8ed1b From 1feba3b7367b333c3fc7deba638a3a1068f22932 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Fri, 17 Sep 2010 10:52:50 +0200 Subject: ALSA: HDA: Fix spelling (change VOSTO to VOSTRO) It was just a boring day. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 7e22ed14ae8d..a12a9f6f795a 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3075,7 +3075,7 @@ enum { CXT5066_LAPTOP, /* Laptops w/ EAPD support */ CXT5066_DELL_LAPTOP, /* Dell Laptop */ CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ - CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ + CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ CXT5066_HP_LAPTOP, /* HP Laptop */ @@ -3086,7 +3086,7 @@ static const char *cxt5066_models[CXT5066_MODELS] = { [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", - [CXT5066_DELL_VOSTO] = "dell-vostro", + [CXT5066_DELL_VOSTRO] = "dell-vostro", [CXT5066_IDEAPAD] = "ideapad", [CXT5066_THINKPAD] = "thinkpad", [CXT5066_HP_LAPTOP] = "hp-laptop", @@ -3099,8 +3099,8 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1025, 0x040a, "Acer", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), - SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), + SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), + SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), @@ -3207,7 +3207,7 @@ static int patch_cxt5066(struct hda_codec *codec) spec->capture_prepare = cxt5066_olpc_capture_prepare; spec->capture_cleanup = cxt5066_olpc_capture_cleanup; break; - case CXT5066_DELL_VOSTO: + case CXT5066_DELL_VOSTRO: codec->patch_ops.init = cxt5066_init; codec->patch_ops.unsol_event = cxt5066_vostro_event; spec->init_verbs[0] = cxt5066_init_verbs_vostro; -- cgit v1.2.3-59-g8ed1b From 5637edb2e1c2d13b276748508ae17f319fb7f066 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Fri, 17 Sep 2010 10:58:03 +0200 Subject: ALSA: HDA: Sort CXT5066 quirk table It was just a boring day. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index a12a9f6f795a..e501a85b5612 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3093,19 +3093,19 @@ static const char *cxt5066_models[CXT5066_MODELS] = { }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { - SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", - CXT5066_LAPTOP), - SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", - CXT5066_DELL_LAPTOP), - SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1025, 0x040a, "Acer", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO), + SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", + CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", + CXT5066_LAPTOP), + SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), -- cgit v1.2.3-59-g8ed1b From 99ae28bea984df4c38234eb6d2f29a552def6c1b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Sep 2010 14:42:34 +0200 Subject: ALSA: hda - Make snd_hda_get_input_pin_attr() helper Make the helper function to give the input-pin attribute for jack connectivity and location. This simplifies checks of input-pin jacks a bit in some places. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 62 +++++++++++++++++------------------------- sound/pci/hda/hda_local.h | 11 ++++++++ sound/pci/hda/patch_cirrus.c | 2 +- sound/pci/hda/patch_conexant.c | 11 ++------ sound/pci/hda/patch_realtek.c | 10 +++---- sound/pci/hda/patch_sigmatel.c | 30 ++++++++++---------- 6 files changed, 59 insertions(+), 67 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9f668efbe420..e15a75751f57 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -4637,44 +4637,26 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); -enum { - MIC_ATTR_INT, - MIC_ATTR_DOCK, - MIC_ATTR_NORMAL, - MIC_ATTR_FRONT, - MIC_ATTR_REAR, -}; - -static int get_mic_pin_attr(unsigned int def_conf) +int snd_hda_get_input_pin_attr(unsigned int def_conf) { unsigned int loc = get_defcfg_location(def_conf); unsigned int conn = get_defcfg_connect(def_conf); + if (conn == AC_JACK_PORT_NONE) + return INPUT_PIN_ATTR_UNUSED; /* Windows may claim the internal mic to be BOTH, too */ if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) - return MIC_ATTR_INT; + return INPUT_PIN_ATTR_INT; if ((loc & 0x30) == AC_JACK_LOC_INTERNAL) - return MIC_ATTR_INT; + return INPUT_PIN_ATTR_INT; if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) - return MIC_ATTR_DOCK; + return INPUT_PIN_ATTR_DOCK; if (loc == AC_JACK_LOC_REAR) - return MIC_ATTR_REAR; + return INPUT_PIN_ATTR_REAR; if (loc == AC_JACK_LOC_FRONT) - return MIC_ATTR_FRONT; - return MIC_ATTR_NORMAL; -} - -enum { - LINE_ATTR_DOCK, - LINE_ATTR_NORMAL, -}; - -static int get_line_pin_attr(unsigned int def_conf) -{ - unsigned int loc = get_defcfg_location(def_conf); - if ((loc & 0xf0) == AC_JACK_LOC_SEPARATE) - return LINE_ATTR_DOCK; - return LINE_ATTR_NORMAL; + return INPUT_PIN_ATTR_FRONT; + return INPUT_PIN_ATTR_NORMAL; } +EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); /** * hda_get_input_pin_label - Give a label for the given input pin @@ -4691,9 +4673,7 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, static const char *mic_names[] = { "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", }; - static const char *line_names[] = { - "Dock Line", "Line", - }; + int attr; def_conf = snd_hda_codec_get_pincfg(codec, pin); @@ -4701,11 +4681,19 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, case AC_JACK_MIC_IN: if (!check_location) return "Mic"; - return mic_names[get_mic_pin_attr(def_conf)]; + attr = snd_hda_get_input_pin_attr(def_conf); + if (!attr) + return "None"; + return mic_names[attr - 1]; case AC_JACK_LINE_IN: if (!check_location) return "Line"; - return line_names[get_line_pin_attr(def_conf)]; + attr = snd_hda_get_input_pin_attr(def_conf); + if (!attr) + return "None"; + if (attr == INPUT_PIN_ATTR_DOCK) + return "Dock Line"; + return "Line"; case AC_JACK_AUX: return "Aux"; case AC_JACK_CD: @@ -4732,16 +4720,16 @@ static int check_mic_location_need(struct hda_codec *codec, int i, attr, attr2; defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin); - attr = get_mic_pin_attr(defc); + attr = snd_hda_get_input_pin_attr(defc); /* for internal or docking mics, we need locations */ - if (attr <= MIC_ATTR_NORMAL) + if (attr <= INPUT_PIN_ATTR_NORMAL) return 1; attr = 0; for (i = 0; i < cfg->num_inputs; i++) { defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin); - attr2 = get_mic_pin_attr(defc); - if (attr2 >= MIC_ATTR_NORMAL) { + attr2 = snd_hda_get_input_pin_attr(defc); + if (attr2 >= INPUT_PIN_ATTR_NORMAL) { if (attr && attr != attr2) return 1; /* different locations found */ attr = attr2; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 6943efc78f66..d7dfa547e2d8 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -395,6 +395,17 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, int index, int *type_index_ret); +enum { + INPUT_PIN_ATTR_UNUSED, /* pin not connected */ + INPUT_PIN_ATTR_INT, /* internal mic/line-in */ + INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */ + INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */ + INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ + INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */ +}; + +int snd_hda_get_input_pin_attr(unsigned int def_conf); + struct auto_pin_cfg { int line_outs; /* sorted in the order of Front/Surr/CLFE/Side */ diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index ae75283a5583..483c3f2d8d39 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -334,7 +334,7 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx) if (!(val & AC_PINCAP_PRES_DETECT)) return 0; val = snd_hda_codec_get_pincfg(codec, pin); - return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); + return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT); } static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e501a85b5612..09d573c59bef 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3462,19 +3462,12 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) } } -static int is_int_mic_conn(unsigned int def_conf) -{ - unsigned int loc = get_defcfg_location(def_conf); - return get_defcfg_connect(def_conf) == AC_JACK_PORT_FIXED || - (loc & 0x30) == AC_JACK_LOC_INTERNAL; -} - /* return true if it's an internal-mic pin */ static int is_int_mic(struct hda_codec *codec, hda_nid_t pin) { unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - is_int_mic_conn(def_conf); + snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT; } /* return true if it's an external-mic pin */ @@ -3482,7 +3475,7 @@ static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) { unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - !is_int_mic_conn(def_conf); + snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT; } /* check whether the pin config is suitable for auto-mic switching; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5df88798895b..6045f281b225 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1403,19 +1403,19 @@ static void alc_init_auto_mic(struct hda_codec *codec) hda_nid_t nid = cfg->inputs[i].pin; unsigned int defcfg; defcfg = snd_hda_codec_get_pincfg(codec, nid); - switch (get_defcfg_connect(defcfg)) { - case AC_JACK_PORT_FIXED: + switch (snd_hda_get_input_pin_attr(defcfg)) { + case INPUT_PIN_ATTR_INT: if (fixed) return; /* already occupied */ fixed = nid; break; - case AC_JACK_PORT_COMPLEX: + case INPUT_PIN_ATTR_UNUSED: + return; /* invalid entry */ + default: if (ext) return; /* already occupied */ ext = nid; break; - default: - return; /* invalid entry */ } } if (!ext || !fixed) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7eb359a030de..6bfbc2fe46ed 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2778,7 +2778,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, struct sigmatel_spec *spec = codec->spec; char name[22]; - if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { + if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD && nid == spec->line_switch) control = STAC_CTL_WIDGET_IO_SWITCH; @@ -2857,7 +2857,7 @@ static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac) def_conf = snd_hda_codec_get_pincfg(codec, nid); /* some laptops have an internal analog microphone * which can't be used as a output */ - if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { + if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { pincap = snd_hda_query_pin_caps(codec, nid); if (pincap & AC_PINCAP_OUT) { *dac = get_unassigned_dac(codec, nid); @@ -3496,23 +3496,23 @@ static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, if (!nid) return 0; cfg = snd_hda_codec_get_pincfg(codec, nid); - switch (get_defcfg_connect(cfg)) { - case AC_JACK_PORT_BOTH: - case AC_JACK_PORT_FIXED: + switch (snd_hda_get_input_pin_attr(cfg)) { + case INPUT_PIN_ATTR_INT: if (*fixed) return 1; /* already occupied */ *fixed = nid; break; - case AC_JACK_PORT_COMPLEX: - if ((get_defcfg_location(cfg) & 0xF0) == AC_JACK_LOC_SEPARATE) { - if (*dock) - return 1; /* already occupied */ - *dock = nid; - } else { - if (*ext) - return 1; /* already occupied */ - *ext = nid; - } + case INPUT_PIN_ATTR_UNUSED: + break; + case INPUT_PIN_ATTR_DOCK: + if (*dock) + return 1; /* already occupied */ + *dock = nid; + break; + default: + if (*ext) + return 1; /* already occupied */ + *ext = nid; break; } return 0; -- cgit v1.2.3-59-g8ed1b From f68b3b291d39f1e3361b194a95459f9cbdaf31e6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Sep 2010 14:45:14 +0200 Subject: ALSA: hda - Check the external mic pin more strictly for Conexant chips The external mic jack for auto-mic switch must be really an external jack and with a presense-detection capability. This patch makes the check more paranoia. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 09d573c59bef..a6c68cb06ddb 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3475,7 +3475,8 @@ static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin) { unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); return get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT; + snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL && + (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT); } /* check whether the pin config is suitable for auto-mic switching; -- cgit v1.2.3-59-g8ed1b From 5f4874903df3562b9d5649fc1cf7b8c6bb238e42 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Thu, 9 Sep 2010 14:45:00 +0100 Subject: GFS2: gfs2_logd should be using interruptible waits Looks like this crept in, in a recent update. Reported-by: Krzysztof Urbaniak Signed-off-by: Steven Whitehouse --- fs/gfs2/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index cde1248a6225..ac750bd31a6f 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -932,7 +932,7 @@ int gfs2_logd(void *data) do { prepare_to_wait(&sdp->sd_logd_waitq, &wait, - TASK_UNINTERRUPTIBLE); + TASK_INTERRUPTIBLE); if (!gfs2_ail_flush_reqd(sdp) && !gfs2_jrnl_flush_reqd(sdp) && !kthread_should_stop()) -- cgit v1.2.3-59-g8ed1b From b2b163bb82b12bae2504a5b31399c37d099ad3cc Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 17 Sep 2010 14:56:16 +0100 Subject: ARM: prevent multiple syscall restarts Al Viro reports that calling "sys_sigsuspend(-ERESTARTNOHAND, 0, 0)" with two signals coming and being handled in kernel space results in the syscall restart being done twice. Avoid this by clearing the 'why' flag when we call the signal handling code to prevent further syscall restarts after the first. Acked-by: Al Viro Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index f05a35a59694..4a560d30793d 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -48,6 +48,8 @@ work_pending: beq no_work_pending mov r0, sp @ 'regs' mov r2, why @ 'syscall' + tst r1, #_TIF_SIGPENDING @ delivering a signal? + movne why, #0 @ prevent further restarts bl do_notify_resume b ret_slow_syscall @ Check work again -- cgit v1.2.3-59-g8ed1b From e835124c2be289515b918f2688ced4249e2de566 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 17 Sep 2010 08:03:08 -0700 Subject: ceph: only send one flushsnap per cap_snap per mds session Sending multiple flushsnap messages is problematic because we ignore the response if the tid doesn't match, and the server may only respond to each one once. It's also a waste. So, skip cap_snaps that are already on the flushing list, unless the caller tells us to resend (because we are reconnecting). Signed-off-by: Sage Weil --- fs/ceph/caps.c | 19 +++++++++++++++---- fs/ceph/snap.c | 2 +- fs/ceph/super.h | 3 ++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 9fbe9019155c..b01c316a8148 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1195,10 +1195,14 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, * asynchronously back to the MDS once sync writes complete and dirty * data is written out. * + * Unless @again is true, skip cap_snaps that were already sent to + * the MDS (i.e., during this session). + * * Called under i_lock. Takes s_mutex as needed. */ void __ceph_flush_snaps(struct ceph_inode_info *ci, - struct ceph_mds_session **psession) + struct ceph_mds_session **psession, + int again) __releases(ci->vfs_inode->i_lock) __acquires(ci->vfs_inode->i_lock) { @@ -1240,6 +1244,13 @@ retry: dout("no auth cap (migrating?), doing nothing\n"); goto out; } + + /* only flush each capsnap once */ + if (!again && !list_empty(&capsnap->flushing_item)) { + dout("already flushed %p, skipping\n", capsnap); + continue; + } + mds = ci->i_auth_cap->session->s_mds; mseq = ci->i_auth_cap->mseq; @@ -1314,7 +1325,7 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci) struct inode *inode = &ci->vfs_inode; spin_lock(&inode->i_lock); - __ceph_flush_snaps(ci, NULL); + __ceph_flush_snaps(ci, NULL, 0); spin_unlock(&inode->i_lock); } @@ -1477,7 +1488,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, /* flush snaps first time around only */ if (!list_empty(&ci->i_cap_snaps)) - __ceph_flush_snaps(ci, &session); + __ceph_flush_snaps(ci, &session, 0); goto retry_locked; retry: spin_lock(&inode->i_lock); @@ -1894,7 +1905,7 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc, if (cap && cap->session == session) { dout("kick_flushing_caps %p cap %p capsnap %p\n", inode, cap, capsnap); - __ceph_flush_snaps(ci, &session); + __ceph_flush_snaps(ci, &session, 1); } else { pr_err("%p auth cap %p not mds%d ???\n", inode, cap, session->s_mds); diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 9e6eef14b7df..190b6c4a6f2b 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -717,7 +717,7 @@ static void flush_snaps(struct ceph_mds_client *mdsc) igrab(inode); spin_unlock(&mdsc->snap_flush_lock); spin_lock(&inode->i_lock); - __ceph_flush_snaps(ci, &session); + __ceph_flush_snaps(ci, &session, 0); spin_unlock(&inode->i_lock); iput(inode); spin_lock(&mdsc->snap_flush_lock); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c80bfbe27b05..b87638e84c4b 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -828,7 +828,8 @@ extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had); extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, struct ceph_snap_context *snapc); extern void __ceph_flush_snaps(struct ceph_inode_info *ci, - struct ceph_mds_session **psession); + struct ceph_mds_session **psession, + int again); extern void ceph_check_caps(struct ceph_inode_info *ci, int flags, struct ceph_mds_session *session); extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc); -- cgit v1.2.3-59-g8ed1b From 5facb097137e7509a1b73448fe20226a4fbfe8cb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 17 Sep 2010 17:24:10 +0200 Subject: hwmon: (lis3lv02d) Prevent NULL pointer dereference If CONFIG_PM was selected and lis3lv02d_platform_data was NULL, the kernel will be panic when halt command run. Reported-by: Yusuke Goda Signed-off-by: Kuninori Morimoto Acked-by: Samu Onkalo Sigend-off-by: Jean Delvare --- drivers/hwmon/lis3lv02d_i2c.c | 4 ++-- drivers/hwmon/lis3lv02d_spi.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c index dc1f5402c1d7..8e5933b72d19 100644 --- a/drivers/hwmon/lis3lv02d_i2c.c +++ b/drivers/hwmon/lis3lv02d_i2c.c @@ -121,7 +121,7 @@ static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg) { struct lis3lv02d *lis3 = i2c_get_clientdata(client); - if (!lis3->pdata->wakeup_flags) + if (!lis3->pdata || !lis3->pdata->wakeup_flags) lis3lv02d_poweroff(lis3); return 0; } @@ -130,7 +130,7 @@ static int lis3lv02d_i2c_resume(struct i2c_client *client) { struct lis3lv02d *lis3 = i2c_get_clientdata(client); - if (!lis3->pdata->wakeup_flags) + if (!lis3->pdata || !lis3->pdata->wakeup_flags) lis3lv02d_poweron(lis3); return 0; } diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c index 82b16808a274..b9be5e3a22b3 100644 --- a/drivers/hwmon/lis3lv02d_spi.c +++ b/drivers/hwmon/lis3lv02d_spi.c @@ -92,7 +92,7 @@ static int lis3lv02d_spi_suspend(struct spi_device *spi, pm_message_t mesg) { struct lis3lv02d *lis3 = spi_get_drvdata(spi); - if (!lis3->pdata->wakeup_flags) + if (!lis3->pdata || !lis3->pdata->wakeup_flags) lis3lv02d_poweroff(&lis3_dev); return 0; @@ -102,7 +102,7 @@ static int lis3lv02d_spi_resume(struct spi_device *spi) { struct lis3lv02d *lis3 = spi_get_drvdata(spi); - if (!lis3->pdata->wakeup_flags) + if (!lis3->pdata || !lis3->pdata->wakeup_flags) lis3lv02d_poweron(lis3); return 0; -- cgit v1.2.3-59-g8ed1b From 9e012c1acc1fd617a708c00ff1fdaa847f9faf67 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 17 Sep 2010 17:24:11 +0200 Subject: hwmon: New subsystem maintainers Guenter Roeck volunteered to adopt the hwmon subsystem as long as he wasn't the only maintainer. As this was also my own condition, we can add the two of us as co-maintainers of the hwmon subsystem. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- MAINTAINERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e7c528ff1013..8540dea232af 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2657,9 +2657,12 @@ S: Maintained F: drivers/media/video/gspca/ HARDWARE MONITORING +M: Jean Delvare +M: Guenter Roeck L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.org/ -S: Orphan +T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/ +S: Maintained F: Documentation/hwmon/ F: drivers/hwmon/ F: include/linux/hwmon*.h -- cgit v1.2.3-59-g8ed1b From 96f3640894012be7dd15a384566bfdc18297bc6c Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Fri, 17 Sep 2010 17:24:11 +0200 Subject: hwmon: (f75375s) Shift control mode to the correct bit position The spec notes that fan0 and fan1 control mode bits are located in bits 7-6 and 5-4 respectively, but the FAN_CTRL_MODE macro was making the bits shift by 5 instead of by 4. Signed-off-by: Guillem Jover Cc: Riku Voipio Cc: stable@kernel.org Signed-off-by: Jean Delvare --- drivers/hwmon/f75375s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 0f58ecc5334d..e5828c009d91 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -79,7 +79,7 @@ enum chips { f75373, f75375 }; #define F75375_REG_PWM2_DROP_DUTY 0x6C #define FAN_CTRL_LINEAR(nr) (4 + nr) -#define FAN_CTRL_MODE(nr) (5 + ((nr) * 2)) +#define FAN_CTRL_MODE(nr) (4 + ((nr) * 2)) /* * Data structures and manipulation thereof -- cgit v1.2.3-59-g8ed1b From c3b327d60bbba3f5ff8fd87d1efc0e95eb6c121b Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Fri, 17 Sep 2010 17:24:12 +0200 Subject: hwmon: (f75375s) Do not overwrite values read from registers All bits in the values read from registers to be used for the next write were getting overwritten, avoid doing so to not mess with the current configuration. Signed-off-by: Guillem Jover Cc: Riku Voipio Cc: stable@kernel.org Signed-off-by: Jean Delvare --- drivers/hwmon/f75375s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index e5828c009d91..9638d58f99fd 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -298,7 +298,7 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) return -EINVAL; fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); - fanmode = ~(3 << FAN_CTRL_MODE(nr)); + fanmode &= ~(3 << FAN_CTRL_MODE(nr)); switch (val) { case 0: /* Full speed */ @@ -350,7 +350,7 @@ static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); conf = f75375_read8(client, F75375_REG_CONFIG1); - conf = ~(1 << FAN_CTRL_LINEAR(nr)); + conf &= ~(1 << FAN_CTRL_LINEAR(nr)); if (val == 0) conf |= (1 << FAN_CTRL_LINEAR(nr)) ; -- cgit v1.2.3-59-g8ed1b From f17c811d1433aa1966f9c5a744841427e9a97ecf Mon Sep 17 00:00:00 2001 From: Yong Wang Date: Fri, 17 Sep 2010 17:24:12 +0200 Subject: hwmon: (emc1403) Remove unnecessary hwmon_device_unregister It is unnecessary and wrong to call hwmon_device_unregister in error handling before hwmon_device_register is called. Signed-off-by: Yong Wang Reviewed-by: Guenter Roeck Cc: stable@kernel.org Signed-off-by: Jean Delvare --- drivers/hwmon/emc1403.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 5b58b20dead1..8dee3f38fdfb 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -308,7 +308,6 @@ static int emc1403_probe(struct i2c_client *client, res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr); if (res) { dev_warn(&client->dev, "create group failed\n"); - hwmon_device_unregister(data->hwmon_dev); goto thermal_error1; } data->hwmon_dev = hwmon_device_register(&client->dev); -- cgit v1.2.3-59-g8ed1b From 022b75a3df2b5aeeb70c5d51bc1fe55722fdd759 Mon Sep 17 00:00:00 2001 From: Jonas Jonsson Date: Fri, 17 Sep 2010 17:24:13 +0200 Subject: hwmon: (w83627ehf) Use proper exit sequence According to the datasheet for Winbond W83627DHG the proper way to exit the Extended Function Mode is to write 0xaa to the EFER(0x2e or 0x4e). Signed-off-by: Jonas Jonsson Signed-off-by: Jean Delvare --- drivers/hwmon/w83627ehf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index e96e69dd36fb..072c58008a63 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -127,6 +127,7 @@ superio_enter(int ioreg) static inline void superio_exit(int ioreg) { + outb(0xaa, ioreg); outb(0x02, ioreg); outb(0x02, ioreg + 1); } -- cgit v1.2.3-59-g8ed1b From a51b9944a1aaca34c9061d3973663fee54e9d1c1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 17 Sep 2010 17:24:14 +0200 Subject: hwmon: (adm1031) Replace update_rate sysfs attribute with update_interval The attribute reflects an interval, not a rate. Signed-off-by: Guenter Roeck Acked-by: Ira W. Snyder Signed-off-by: Jean Delvare --- Documentation/hwmon/sysfs-interface | 7 +++--- drivers/hwmon/adm1031.c | 43 +++++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index ff45d1f837c8..48ceabedf55d 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface @@ -91,12 +91,11 @@ name The chip name. I2C devices get this attribute created automatically. RO -update_rate The rate at which the chip will update readings. +update_interval The interval at which the chip will update readings. Unit: millisecond RW - Some devices have a variable update rate. This attribute - can be used to change the update rate to the desired - frequency. + Some devices have a variable update rate or interval. + This attribute can be used to change it to the desired value. ************ diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 15c1a9616af3..0683e6be662c 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -79,7 +79,7 @@ struct adm1031_data { int chip_type; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - unsigned int update_rate; /* In milliseconds */ + unsigned int update_interval; /* In milliseconds */ /* The chan_select_table contains the possible configurations for * auto fan control. */ @@ -743,23 +743,23 @@ static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12); static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14); -/* Update Rate */ -static const unsigned int update_rates[] = { +/* Update Interval */ +static const unsigned int update_intervals[] = { 16000, 8000, 4000, 2000, 1000, 500, 250, 125, }; -static ssize_t show_update_rate(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_update_interval(struct device *dev, + struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); - return sprintf(buf, "%u\n", data->update_rate); + return sprintf(buf, "%u\n", data->update_interval); } -static ssize_t set_update_rate(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_update_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); @@ -771,12 +771,15 @@ static ssize_t set_update_rate(struct device *dev, if (err) return err; - /* find the nearest update rate from the table */ - for (i = 0; i < ARRAY_SIZE(update_rates) - 1; i++) { - if (val >= update_rates[i]) + /* + * Find the nearest update interval from the table. + * Use it to determine the matching update rate. + */ + for (i = 0; i < ARRAY_SIZE(update_intervals) - 1; i++) { + if (val >= update_intervals[i]) break; } - /* if not found, we point to the last entry (lowest update rate) */ + /* if not found, we point to the last entry (lowest update interval) */ /* set the new update rate while preserving other settings */ reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER); @@ -785,14 +788,14 @@ static ssize_t set_update_rate(struct device *dev, adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg); mutex_lock(&data->update_lock); - data->update_rate = update_rates[i]; + data->update_interval = update_intervals[i]; mutex_unlock(&data->update_lock); return count; } -static DEVICE_ATTR(update_rate, S_IRUGO | S_IWUSR, show_update_rate, - set_update_rate); +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, + set_update_interval); static struct attribute *adm1031_attributes[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, @@ -830,7 +833,7 @@ static struct attribute *adm1031_attributes[] = { &sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr, - &dev_attr_update_rate.attr, + &dev_attr_update_interval.attr, &dev_attr_alarms.attr, NULL @@ -981,7 +984,8 @@ static void adm1031_init_client(struct i2c_client *client) mask = ADM1031_UPDATE_RATE_MASK; read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER); i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT; - data->update_rate = update_rates[i]; + /* Save it as update interval */ + data->update_interval = update_intervals[i]; } static struct adm1031_data *adm1031_update_device(struct device *dev) @@ -993,7 +997,8 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) mutex_lock(&data->update_lock); - next_update = data->last_updated + msecs_to_jiffies(data->update_rate); + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval); if (time_after(jiffies, next_update) || !data->valid) { dev_dbg(&client->dev, "Starting adm1031 update\n"); -- cgit v1.2.3-59-g8ed1b From bc482bf0ce918b39a1fa60b9341f1add9318d833 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 17 Sep 2010 17:24:15 +0200 Subject: hwmon: (lm95241) Replace rate sysfs attribute with update_interval update_interval is the matching attribute defined in the hwmon sysfs ABI. Use it. Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare --- drivers/hwmon/lm95241.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 94741d42112d..464340f25496 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -91,7 +91,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev); struct lm95241_data { struct device *hwmon_dev; struct mutex update_lock; - unsigned long last_updated, rate; /* in jiffies */ + unsigned long last_updated, interval; /* in jiffies */ char valid; /* zero until following fields are valid */ /* registers values */ u8 local_h, local_l; /* local */ @@ -114,23 +114,23 @@ show_temp(local); show_temp(remote1); show_temp(remote2); -static ssize_t show_rate(struct device *dev, struct device_attribute *attr, +static ssize_t show_interval(struct device *dev, struct device_attribute *attr, char *buf) { struct lm95241_data *data = lm95241_update_device(dev); - snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->rate / HZ); + snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval / HZ); return strlen(buf); } -static ssize_t set_rate(struct device *dev, struct device_attribute *attr, +static ssize_t set_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm95241_data *data = i2c_get_clientdata(client); - strict_strtol(buf, 10, &data->rate); - data->rate = data->rate * HZ / 1000; + strict_strtol(buf, 10, &data->interval); + data->interval = data->interval * HZ / 1000; return count; } @@ -286,7 +286,8 @@ static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1); static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2); static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1); static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2); -static DEVICE_ATTR(rate, S_IWUSR | S_IRUGO, show_rate, set_rate); +static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, + set_interval); static struct attribute *lm95241_attributes[] = { &dev_attr_temp1_input.attr, @@ -298,7 +299,7 @@ static struct attribute *lm95241_attributes[] = { &dev_attr_temp3_min.attr, &dev_attr_temp2_max.attr, &dev_attr_temp3_max.attr, - &dev_attr_rate.attr, + &dev_attr_update_interval.attr, NULL }; @@ -376,7 +377,7 @@ static void lm95241_init_client(struct i2c_client *client) { struct lm95241_data *data = i2c_get_clientdata(client); - data->rate = HZ; /* 1 sec default */ + data->interval = HZ; /* 1 sec default */ data->valid = 0; data->config = CFG_CR0076; data->model = 0; @@ -410,7 +411,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev) mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + data->rate) || + if (time_after(jiffies, data->last_updated + data->interval) || !data->valid) { dev_dbg(&client->dev, "Updating lm95241 data.\n"); data->local_h = -- cgit v1.2.3-59-g8ed1b From 14eff1812679c76564b775aa95cdd378965f6cfb Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Fri, 17 Sep 2010 16:42:10 +0100 Subject: ARM: 6398/1: add proc info for ARM11MPCore/Cortex-A9 from ARM Setting of these bits can cause issues on other SMP SoC's not produced by ARM. Acked-by: Catalin Marinas Signed-off-by: Daniel Walker Signed-off-by: Russell King --- arch/arm/mm/proc-v7.S | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 080129263eef..7563ff0141bd 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -186,13 +186,14 @@ cpu_v7_name: * It is assumed that: * - cache type register is implemented */ -__v7_setup: +__v7_ca9mp_setup: #ifdef CONFIG_SMP mrc p15, 0, r0, c1, c0, 1 tst r0, #(1 << 6) @ SMP/nAMP mode enabled? orreq r0, r0, #(1 << 6) | (1 << 0) @ Enable SMP/nAMP mode and mcreq p15, 0, r0, c1, c0, 1 @ TLB ops broadcasting #endif +__v7_setup: adr r12, __v7_setup_stack @ the local stack stmia r12, {r0-r5, r7, r9, r11, lr} bl v7_flush_dcache_all @@ -349,6 +350,29 @@ cpu_elf_name: .section ".proc.info.init", #alloc, #execinstr + .type __v7_ca9mp_proc_info, #object +__v7_ca9mp_proc_info: + .long 0x410fc090 @ Required ID value + .long 0xff0ffff0 @ Mask for ID + .long PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_FLAGS + .long PMD_TYPE_SECT | \ + PMD_SECT_XN | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ + b __v7_ca9mp_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_v7_name + .long v7_processor_functions + .long v7wbi_tlb_fns + .long v6_user_fns + .long v7_cache_fns + .size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info + /* * Match any ARMv7 processor core. */ -- cgit v1.2.3-59-g8ed1b From a43fb73101eaf6db0b33d22c152b338ab8b3edbb Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 17 Sep 2010 09:54:08 -0700 Subject: ceph: check mapping to determine if FILE_CACHE cap is used See if the i_data mapping has any pages to determine if the FILE_CACHE capability is currently in use, instead of assuming it is any time the rdcache_gen value is set (i.e., issued -> used). This allows the MDS RECALL_STATE process work for inodes that have cached pages. Signed-off-by: Sage Weil --- fs/ceph/caps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index b01c316a8148..73c153092f72 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -814,7 +814,7 @@ int __ceph_caps_used(struct ceph_inode_info *ci) used |= CEPH_CAP_PIN; if (ci->i_rd_ref) used |= CEPH_CAP_FILE_RD; - if (ci->i_rdcache_ref || ci->i_rdcache_gen) + if (ci->i_rdcache_ref || ci->vfs_inode.i_data.nrpages) used |= CEPH_CAP_FILE_CACHE; if (ci->i_wr_ref) used |= CEPH_CAP_FILE_WR; -- cgit v1.2.3-59-g8ed1b From 653d48b22166db2d8b1515ebe6f9f0f7c95dfc86 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Sep 2010 14:34:39 +0100 Subject: arm: fix really nasty sigreturn bug If a signal hits us outside of a syscall and another gets delivered when we are in sigreturn (e.g. because it had been in sa_mask for the first one and got sent to us while we'd been in the first handler), we have a chance of returning from the second handler to location one insn prior to where we ought to return. If r0 happens to contain -513 (-ERESTARTNOINTR), sigreturn will get confused into doing restart syscall song and dance. Incredible joy to debug, since it manifests as random, infrequent and very hard to reproduce double execution of instructions in userland code... The fix is simple - mark it "don't bother with restarts" in wrapper, i.e. set r8 to 0 in sys_sigreturn and sys_rt_sigreturn wrappers, suppressing the syscall restart handling on return from these guys. They can't legitimately return a restart-worthy error anyway. Testcase: #include #include #include #include #include void f(int n) { __asm__ __volatile__( "ldr r0, [%0]\n" "b 1f\n" "b 2f\n" "1:b .\n" "2:\n" : : "r"(&n)); } void handler1(int sig) { } void handler2(int sig) { raise(1); } void handler3(int sig) { exit(0); } main() { struct sigaction s = {.sa_handler = handler2}; struct itimerval t1 = { .it_value = {1} }; struct itimerval t2 = { .it_value = {2} }; signal(1, handler1); sigemptyset(&s.sa_mask); sigaddset(&s.sa_mask, 1); sigaction(SIGALRM, &s, NULL); signal(SIGVTALRM, handler3); setitimer(ITIMER_REAL, &t1, NULL); setitimer(ITIMER_VIRTUAL, &t2, NULL); f(-513); /* -ERESTARTNOINTR */ write(1, "buggered\n", 9); return 1; } Signed-off-by: Al Viro Acked-by: Russell King Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- arch/arm/kernel/entry-common.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index f05a35a59694..1b560825e1cf 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -418,11 +418,13 @@ ENDPROC(sys_clone_wrapper) sys_sigreturn_wrapper: add r0, sp, #S_OFF + mov why, #0 @ prevent syscall restart handling b sys_sigreturn ENDPROC(sys_sigreturn_wrapper) sys_rt_sigreturn_wrapper: add r0, sp, #S_OFF + mov why, #0 @ prevent syscall restart handling b sys_rt_sigreturn ENDPROC(sys_rt_sigreturn_wrapper) -- cgit v1.2.3-59-g8ed1b From be4f104dfd3b5e3ae262bff607965cfc38027dec Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 17 Sep 2010 12:30:31 -0700 Subject: ceph: select CRYPTO We select CRYPTO_AES, but not CRYPTO. Signed-off-by: Sage Weil --- fs/ceph/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ceph/Kconfig b/fs/ceph/Kconfig index bc87b9c1d27e..0fcd2640c23f 100644 --- a/fs/ceph/Kconfig +++ b/fs/ceph/Kconfig @@ -3,6 +3,7 @@ config CEPH_FS depends on INET && EXPERIMENTAL select LIBCRC32C select CRYPTO_AES + select CRYPTO help Choose Y or M here to include support for mounting the experimental Ceph distributed file system. Ceph is an extremely -- cgit v1.2.3-59-g8ed1b From 7acc7c683a747689aaaaad4fce1683fc3f85e552 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 8 Sep 2010 08:30:20 -0700 Subject: iwlwifi: do not perferm force reset while doing scan When uCode error condition detected, driver try to perform either rf reset or firmware reload in order bring device back to working condition. If rf reset is required and scan is in process, there is no need to issue rf reset since scan already reset the rf. If firmware reload is required and scan is in process, skip the reload request. There is a possibility firmware reload during scan cause problem. [ 485.804046] WARNING: at net/mac80211/main.c:310 ieee80211_restart_hw+0x28/0x62() [ 485.804049] Hardware name: Latitude E6400 [ 485.804052] ieee80211_restart_hw called with hardware scan in progress [ 485.804054] Modules linked in: iwlagn iwlcore bnep sco rfcomm l2cap crc16 bluetooth [last unloaded: iwlcore] [ 485.804069] Pid: 812, comm: kworker/u:3 Tainted: G W 2.6.36-rc3-wl+ #74 [ 485.804072] Call Trace: [ 485.804079] [] warn_slowpath_common+0x60/0x75 [ 485.804084] [] warn_slowpath_fmt+0x26/0x2a [ 485.804089] [] ieee80211_restart_hw+0x28/0x62 [ 485.804102] [] iwl_bg_restart+0x113/0x150 [iwlagn] [ 485.804108] [] process_one_work+0x181/0x25c [ 485.804119] [] ? iwl_bg_restart+0x0/0x150 [iwlagn] [ 485.804124] [] worker_thread+0xf9/0x1f2 [ 485.804128] [] ? worker_thread+0x0/0x1f2 [ 485.804133] [] kthread+0x64/0x69 [ 485.804137] [] ? kthread+0x0/0x69 [ 485.804141] [] kernel_thread_helper+0x6/0x10 [ 485.804145] ---[ end trace 3d4ebdc02d524bbb ]--- [ 485.804148] WG> 1 [ 485.804153] Pid: 812, comm: kworker/u:3 Tainted: G W 2.6.36-rc3-wl+ #74 [ 485.804156] Call Trace: [ 485.804161] [] ? ieee80211_restart_hw+0x5c/0x62 [ 485.804172] [] iwl_bg_restart+0x118/0x150 [iwlagn] [ 485.804177] [] process_one_work+0x181/0x25c [ 485.804188] [] ? iwl_bg_restart+0x0/0x150 [iwlagn] [ 485.804192] [] worker_thread+0xf9/0x1f2 [ 485.804197] [] ? worker_thread+0x0/0x1f2 [ 485.804201] [] kthread+0x64/0x69 [ 485.804205] [] ? kthread+0x0/0x69 [ 485.804209] [] kernel_thread_helper+0x6/0x10 Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 07dbc2796448..e23c4060a0f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2613,6 +2613,11 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EINVAL; + if (test_bit(STATUS_SCANNING, &priv->status)) { + IWL_DEBUG_INFO(priv, "scan in progress.\n"); + return -EINVAL; + } + if (mode >= IWL_MAX_FORCE_RESET) { IWL_DEBUG_INFO(priv, "invalid reset request.\n"); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 4bdab43323b459900578b200a4b8cf9713ac8fab Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 15 Sep 2010 10:00:26 -0400 Subject: sctp: Do not reset the packet during sctp_packet_config(). sctp_packet_config() is called when getting the packet ready for appending of chunks. The function should not touch the current state, since it's possible to ping-pong between two transports when sending, and that can result packet corruption followed by skb overlfow crash. Reported-by: Thomas Dreibholz Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/output.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sctp/output.c b/net/sctp/output.c index a646681f5acd..bcc4590ccaf2 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -92,7 +92,6 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); - sctp_packet_reset(packet); packet->vtag = vtag; if (ecn_capable && sctp_packet_empty(packet)) { -- cgit v1.2.3-59-g8ed1b From f0f9deae9e7c421fa0c1c627beb8e174325e1ba7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 17 Sep 2010 16:55:03 -0700 Subject: netpoll: Disable IRQ around RCU dereference in netpoll_rx We cannot use rcu_dereference_bh safely in netpoll_rx as we may be called with IRQs disabled. We could however simply disable IRQs as that too causes BH to be disabled and is safe in either case. Thanks to John Linville for discovering this bug and providing a patch. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/netpoll.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 791d5109f34c..50d8009be86c 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -63,20 +63,20 @@ static inline bool netpoll_rx(struct sk_buff *skb) unsigned long flags; bool ret = false; - rcu_read_lock_bh(); + local_irq_save(flags); npinfo = rcu_dereference_bh(skb->dev->npinfo); if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags)) goto out; - spin_lock_irqsave(&npinfo->rx_lock, flags); + spin_lock(&npinfo->rx_lock); /* check rx_flags again with the lock held */ if (npinfo->rx_flags && __netpoll_rx(skb)) ret = true; - spin_unlock_irqrestore(&npinfo->rx_lock, flags); + spin_unlock(&npinfo->rx_lock); out: - rcu_read_unlock_bh(); + local_irq_restore(flags); return ret; } -- cgit v1.2.3-59-g8ed1b From 5343795fda222183c1f77d0f5870f2027713bb0d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 18 Sep 2010 09:54:38 +0900 Subject: ARM: S3C64XX: Prototype SPI devices Avoids build warnings due to the undeclared non-statics. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/dev-spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-s3c64xx/dev-spi.c b/arch/arm/mach-s3c64xx/dev-spi.c index bfa3ef770bd8..405e62128917 100644 --- a/arch/arm/mach-s3c64xx/dev-spi.c +++ b/arch/arm/mach-s3c64xx/dev-spi.c @@ -22,6 +22,7 @@ #include #include +#include static char *spi_src_clks[] = { [S3C64XX_SPI_SRCCLK_PCLK] = "pclk", -- cgit v1.2.3-59-g8ed1b From 591cd25ee35986184870c447ff5c12e78bc80699 Mon Sep 17 00:00:00 2001 From: Darius Augulis Date: Thu, 9 Sep 2010 21:40:22 +0900 Subject: ARM: S3C64XX: Fix coding style errors on mach-real6410 Fix errors reported by checkpatch.pl script Signed-off-by: Darius Augulis [kgene.kim@samsung.com: minor title fix] Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/mach-real6410.c | 104 +++++++++++++++++----------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index 5c07d013b23d..9f79e6bacb59 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -30,73 +30,73 @@ #include #include -#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK -#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB -#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE +#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK) +#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) +#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) static struct s3c2410_uartcfg real6410_uartcfgs[] __initdata = { [0] = { - .hwport = 0, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, + .hwport = 0, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, }, [1] = { - .hwport = 1, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, + .hwport = 1, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, }, [2] = { - .hwport = 2, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, + .hwport = 2, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, }, [3] = { - .hwport = 3, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, + .hwport = 3, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, }, }; /* DM9000AEP 10/100 ethernet controller */ static struct resource real6410_dm9k_resource[] = { - [0] = { - .start = S3C64XX_PA_XM0CSN1, - .end = S3C64XX_PA_XM0CSN1 + 1, - .flags = IORESOURCE_MEM - }, - [1] = { - .start = S3C64XX_PA_XM0CSN1 + 4, - .end = S3C64XX_PA_XM0CSN1 + 5, - .flags = IORESOURCE_MEM - }, - [2] = { - .start = S3C_EINT(7), - .end = S3C_EINT(7), - .flags = IORESOURCE_IRQ, - } + [0] = { + .start = S3C64XX_PA_XM0CSN1, + .end = S3C64XX_PA_XM0CSN1 + 1, + .flags = IORESOURCE_MEM + }, + [1] = { + .start = S3C64XX_PA_XM0CSN1 + 4, + .end = S3C64XX_PA_XM0CSN1 + 5, + .flags = IORESOURCE_MEM + }, + [2] = { + .start = S3C_EINT(7), + .end = S3C_EINT(7), + .flags = IORESOURCE_IRQ, + } }; static struct dm9000_plat_data real6410_dm9k_pdata = { - .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), + .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), }; static struct platform_device real6410_device_eth = { - .name = "dm9000", - .id = -1, - .num_resources = ARRAY_SIZE(real6410_dm9k_resource), - .resource = real6410_dm9k_resource, - .dev = { - .platform_data = &real6410_dm9k_pdata, - }, + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(real6410_dm9k_resource), + .resource = real6410_dm9k_resource, + .dev = { + .platform_data = &real6410_dm9k_pdata, + }, }; static struct platform_device *real6410_devices[] __initdata = { @@ -129,12 +129,12 @@ static void __init real6410_machine_init(void) /* set timing for nCS1 suitable for ethernet chip */ __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) | - (6 << S3C64XX_SROM_BCX__TACP__SHIFT) | - (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) | - (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) | - (13 << S3C64XX_SROM_BCX__TACC__SHIFT) | - (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | - (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); + (6 << S3C64XX_SROM_BCX__TACP__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) | + (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) | + (13 << S3C64XX_SROM_BCX__TACC__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | + (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); platform_add_devices(real6410_devices, ARRAY_SIZE(real6410_devices)); } -- cgit v1.2.3-59-g8ed1b From 4d89ecaae9c145e60b920acb1120f1de3d6eac6e Mon Sep 17 00:00:00 2001 From: Darius Augulis Date: Thu, 9 Sep 2010 21:41:31 +0900 Subject: ARM: S3C64XX: Add IORESOURCE_IRQ_HIGHLEVEL flag to dm9000 on mach-real6410 Add IORESOURCE_IRQ_HIGHLEVEL irq flag to dm9000 driver platform data in board mach-real6410. Signed-off-by: Darius Augulis [kgene.kim@samsung.com: minor title fix] Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/mach-real6410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index 9f79e6bacb59..e130379ba0e8 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -81,7 +81,7 @@ static struct resource real6410_dm9k_resource[] = { [2] = { .start = S3C_EINT(7), .end = S3C_EINT(7), - .flags = IORESOURCE_IRQ, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL } }; -- cgit v1.2.3-59-g8ed1b From 4e8cec269dd9e823804141f25ce37c23e72d3c12 Mon Sep 17 00:00:00 2001 From: "Sosnowski, Maciej" Date: Thu, 16 Sep 2010 06:02:26 +0000 Subject: dca: disable dca on IOAT ver.3.0 multiple-IOH platforms Direct Cache Access is not supported on IOAT ver.3.0 multiple-IOH platforms. This patch blocks registering of dca providers when multiple IOH detected with IOAT ver.3.0. Signed-off-by: Maciej Sosnowski Signed-off-by: David S. Miller --- drivers/dca/dca-core.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index 8661c84a105d..b98c67664ae7 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -39,6 +39,10 @@ static DEFINE_SPINLOCK(dca_lock); static LIST_HEAD(dca_domains); +static BLOCKING_NOTIFIER_HEAD(dca_provider_chain); + +static int dca_providers_blocked; + static struct pci_bus *dca_pci_rc_from_dev(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -70,6 +74,60 @@ static void dca_free_domain(struct dca_domain *domain) kfree(domain); } +static int dca_provider_ioat_ver_3_0(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return ((pdev->vendor == PCI_VENDOR_ID_INTEL) && + ((pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG0) || + (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG1) || + (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG2) || + (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG3) || + (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG4) || + (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG5) || + (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG6) || + (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_TBG7))); +} + +static void unregister_dca_providers(void) +{ + struct dca_provider *dca, *_dca; + struct list_head unregistered_providers; + struct dca_domain *domain; + unsigned long flags; + + blocking_notifier_call_chain(&dca_provider_chain, + DCA_PROVIDER_REMOVE, NULL); + + INIT_LIST_HEAD(&unregistered_providers); + + spin_lock_irqsave(&dca_lock, flags); + + if (list_empty(&dca_domains)) { + spin_unlock_irqrestore(&dca_lock, flags); + return; + } + + /* at this point only one domain in the list is expected */ + domain = list_first_entry(&dca_domains, struct dca_domain, node); + if (!domain) + return; + + list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) { + list_del(&dca->node); + list_add(&dca->node, &unregistered_providers); + } + + dca_free_domain(domain); + + spin_unlock_irqrestore(&dca_lock, flags); + + list_for_each_entry_safe(dca, _dca, &unregistered_providers, node) { + dca_sysfs_remove_provider(dca); + list_del(&dca->node); + } +} + static struct dca_domain *dca_find_domain(struct pci_bus *rc) { struct dca_domain *domain; @@ -90,9 +148,13 @@ static struct dca_domain *dca_get_domain(struct device *dev) domain = dca_find_domain(rc); if (!domain) { - domain = dca_allocate_domain(rc); - if (domain) - list_add(&domain->node, &dca_domains); + if (dca_provider_ioat_ver_3_0(dev) && !list_empty(&dca_domains)) { + dca_providers_blocked = 1; + } else { + domain = dca_allocate_domain(rc); + if (domain) + list_add(&domain->node, &dca_domains); + } } return domain; @@ -293,8 +355,6 @@ void free_dca_provider(struct dca_provider *dca) } EXPORT_SYMBOL_GPL(free_dca_provider); -static BLOCKING_NOTIFIER_HEAD(dca_provider_chain); - /** * register_dca_provider - register a dca provider * @dca - struct created by alloc_dca_provider() @@ -306,6 +366,13 @@ int register_dca_provider(struct dca_provider *dca, struct device *dev) unsigned long flags; struct dca_domain *domain; + spin_lock_irqsave(&dca_lock, flags); + if (dca_providers_blocked) { + spin_unlock_irqrestore(&dca_lock, flags); + return -ENODEV; + } + spin_unlock_irqrestore(&dca_lock, flags); + err = dca_sysfs_add_provider(dca, dev); if (err) return err; @@ -313,7 +380,13 @@ int register_dca_provider(struct dca_provider *dca, struct device *dev) spin_lock_irqsave(&dca_lock, flags); domain = dca_get_domain(dev); if (!domain) { - spin_unlock_irqrestore(&dca_lock, flags); + if (dca_providers_blocked) { + spin_unlock_irqrestore(&dca_lock, flags); + dca_sysfs_remove_provider(dca); + unregister_dca_providers(); + } else { + spin_unlock_irqrestore(&dca_lock, flags); + } return -ENODEV; } list_add(&dca->node, &domain->dca_providers); -- cgit v1.2.3-59-g8ed1b From 04746ff1289f75af26af279eb4b0b3e231677ee4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 17 Sep 2010 22:58:08 -0700 Subject: qlcnic: dont assume NET_IP_ALIGN is 2 qlcnic driver allocates rx skbs and gives to hardware too bytes of extra storage, allowing for corruption of kernel data. NET_IP_ALIGN being 0 on some platforms (including x86), drivers should not assume it's 2. rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN; ... skb = dev_alloc_skb(rds_ring->skb_size); skb_reserve(skb, 2); pci_map_single(pdev, skb->data, rds_ring->dma_size, PCI_DMA_FROMDEVICE); (and rds_ring->skb_size == rds_ring->dma_size) -> bug Because of extra alignment (1500 + 32) -> four extra bytes are available before the struct skb_shared_info, so corruption is not noticed. Note: this driver could use netdev_alloc_skb_ip_align() Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 75ba744b173c..60ab753f809a 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1316,7 +1316,7 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter, return -ENOMEM; } - skb_reserve(skb, 2); + skb_reserve(skb, NET_IP_ALIGN); dma = pci_map_single(pdev, skb->data, rds_ring->dma_size, PCI_DMA_FROMDEVICE); -- cgit v1.2.3-59-g8ed1b From 7cdffc86528ec9c55c83c649b6d64cadeb558136 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 18 Sep 2010 10:19:13 +0200 Subject: pcmcia: preserve configuration information if request_io fails partly If pcmcia_request_io() only fails partly -- for the second of two requested resources -- preserve the configuration settings for the first one. Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_resource.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index a5c176598d95..9ba4dade69a4 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -595,7 +595,13 @@ int pcmcia_request_io(struct pcmcia_device *p_dev) if (c->io[1].end) { ret = alloc_io_space(s, &c->io[1], p_dev->io_lines); if (ret) { + struct resource tmp = c->io[0]; + /* release the previously allocated resource */ release_io_space(s, &c->io[0]); + /* but preserve the settings, for they worked... */ + c->io[0].end = resource_size(&tmp); + c->io[0].start = tmp.start; + c->io[0].flags = tmp.flags; goto out; } } else -- cgit v1.2.3-59-g8ed1b From 50aff040363d31f87e94f38f1710973d99489951 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 21 Aug 2010 14:40:20 +0800 Subject: ocfs2/net: fix uninitialized ret in o2net_send_message_vec() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mmotm/fs/ocfs2/cluster/tcp.c: In function ‘o2net_send_message_vec’: mmotm/fs/ocfs2/cluster/tcp.c:980:6: warning: ‘ret’ may be used uninitialized in this function It seems a real bug introduced by commit 9af0b38ff3 (ocfs2/net: Use wait_event() in o2net_send_message_vec()). cc: Sunil Mushran Signed-off-by: Wu Fengguang Signed-off-by: Joel Becker --- fs/ocfs2/cluster/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 1361997cf205..cbe2f057cc28 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -977,7 +977,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn, int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, size_t caller_veclen, u8 target_node, int *status) { - int ret; + int ret = 0; struct o2net_msg *msg = NULL; size_t veclen, caller_bytes = 0; struct kvec *vec = NULL; -- cgit v1.2.3-59-g8ed1b From 31019075f41c785eff7f38c62e4c700af019fdb7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 14 Sep 2010 04:23:47 -0400 Subject: alpha: Use static const char * const where possible Acked-by: Richard Henderson Signed-off-by: Joe Perches Signed-off-by: Matt Turner --- arch/alpha/kernel/err_ev6.c | 12 +++++++----- arch/alpha/kernel/err_marvel.c | 33 +++++++++++++++++---------------- arch/alpha/kernel/err_titan.c | 35 ++++++++++++++++++++--------------- arch/alpha/kernel/osf_sys.c | 4 ++-- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c index 8ca6345bf131..253cf1a87481 100644 --- a/arch/alpha/kernel/err_ev6.c +++ b/arch/alpha/kernel/err_ev6.c @@ -90,11 +90,13 @@ static int ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn, u64 c_stat, u64 c_sts, int print) { - char *sourcename[] = { "UNKNOWN", "UNKNOWN", "UNKNOWN", - "MEMORY", "BCACHE", "DCACHE", - "BCACHE PROBE", "BCACHE PROBE" }; - char *streamname[] = { "D", "I" }; - char *bitsname[] = { "SINGLE", "DOUBLE" }; + static const char * const sourcename[] = { + "UNKNOWN", "UNKNOWN", "UNKNOWN", + "MEMORY", "BCACHE", "DCACHE", + "BCACHE PROBE", "BCACHE PROBE" + }; + static const char * const streamname[] = { "D", "I" }; + static const char * const bitsname[] = { "SINGLE", "DOUBLE" }; int status = MCHK_DISPOSITION_REPORT; int source = -1, stream = -1, bits = -1; diff --git a/arch/alpha/kernel/err_marvel.c b/arch/alpha/kernel/err_marvel.c index 5c905aaaeccd..648ae88aeb8a 100644 --- a/arch/alpha/kernel/err_marvel.c +++ b/arch/alpha/kernel/err_marvel.c @@ -589,22 +589,23 @@ marvel_print_pox_spl_cmplt(u64 spl_cmplt) static void marvel_print_pox_trans_sum(u64 trans_sum) { - char *pcix_cmd[] = { "Interrupt Acknowledge", - "Special Cycle", - "I/O Read", - "I/O Write", - "Reserved", - "Reserved / Device ID Message", - "Memory Read", - "Memory Write", - "Reserved / Alias to Memory Read Block", - "Reserved / Alias to Memory Write Block", - "Configuration Read", - "Configuration Write", - "Memory Read Multiple / Split Completion", - "Dual Address Cycle", - "Memory Read Line / Memory Read Block", - "Memory Write and Invalidate / Memory Write Block" + static const char * const pcix_cmd[] = { + "Interrupt Acknowledge", + "Special Cycle", + "I/O Read", + "I/O Write", + "Reserved", + "Reserved / Device ID Message", + "Memory Read", + "Memory Write", + "Reserved / Alias to Memory Read Block", + "Reserved / Alias to Memory Write Block", + "Configuration Read", + "Configuration Write", + "Memory Read Multiple / Split Completion", + "Dual Address Cycle", + "Memory Read Line / Memory Read Block", + "Memory Write and Invalidate / Memory Write Block" }; #define IO7__POX_TRANSUM__PCI_ADDR__S (0) diff --git a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c index f7ed97ce0dfd..c3b3781a03de 100644 --- a/arch/alpha/kernel/err_titan.c +++ b/arch/alpha/kernel/err_titan.c @@ -75,8 +75,12 @@ titan_parse_p_serror(int which, u64 serror, int print) int status = MCHK_DISPOSITION_REPORT; #ifdef CONFIG_VERBOSE_MCHECK - char *serror_src[] = {"GPCI", "APCI", "AGP HP", "AGP LP"}; - char *serror_cmd[] = {"DMA Read", "DMA RMW", "SGTE Read", "Reserved"}; + static const char * const serror_src[] = { + "GPCI", "APCI", "AGP HP", "AGP LP" + }; + static const char * const serror_cmd[] = { + "DMA Read", "DMA RMW", "SGTE Read", "Reserved" + }; #endif /* CONFIG_VERBOSE_MCHECK */ #define TITAN__PCHIP_SERROR__LOST_UECC (1UL << 0) @@ -140,14 +144,15 @@ titan_parse_p_perror(int which, int port, u64 perror, int print) int status = MCHK_DISPOSITION_REPORT; #ifdef CONFIG_VERBOSE_MCHECK - char *perror_cmd[] = { "Interrupt Acknowledge", "Special Cycle", - "I/O Read", "I/O Write", - "Reserved", "Reserved", - "Memory Read", "Memory Write", - "Reserved", "Reserved", - "Configuration Read", "Configuration Write", - "Memory Read Multiple", "Dual Address Cycle", - "Memory Read Line","Memory Write and Invalidate" + static const char * const perror_cmd[] = { + "Interrupt Acknowledge", "Special Cycle", + "I/O Read", "I/O Write", + "Reserved", "Reserved", + "Memory Read", "Memory Write", + "Reserved", "Reserved", + "Configuration Read", "Configuration Write", + "Memory Read Multiple", "Dual Address Cycle", + "Memory Read Line", "Memory Write and Invalidate" }; #endif /* CONFIG_VERBOSE_MCHECK */ @@ -273,11 +278,11 @@ titan_parse_p_agperror(int which, u64 agperror, int print) int cmd, len; unsigned long addr; - char *agperror_cmd[] = { "Read (low-priority)", "Read (high-priority)", - "Write (low-priority)", - "Write (high-priority)", - "Reserved", "Reserved", - "Flush", "Fence" + static const char * const agperror_cmd[] = { + "Read (low-priority)", "Read (high-priority)", + "Write (low-priority)", "Write (high-priority)", + "Reserved", "Reserved", + "Flush", "Fence" }; #endif /* CONFIG_VERBOSE_MCHECK */ diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 5d1e6d6ce684..16bc1f5df3e2 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -594,7 +594,7 @@ SYSCALL_DEFINE2(osf_sigstack, struct sigstack __user *, uss, SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) { - char *sysinfo_table[] = { + const char *sysinfo_table[] = { utsname()->sysname, utsname()->nodename, utsname()->release, @@ -606,7 +606,7 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) "dummy", /* secure RPC domain */ }; unsigned long offset; - char *res; + const char *res; long len, err = -EINVAL; offset = command-1; -- cgit v1.2.3-59-g8ed1b From af96f8a340525f24abecc25848a07fff7636a53e Mon Sep 17 00:00:00 2001 From: matt mooney Date: Tue, 14 Sep 2010 05:27:39 -0400 Subject: alpha: remove unnecessary cast from void* in assignment. Acked-by: Jan-Benedict Glaw Signed-off-by: matt mooney Signed-off-by: Matt Turner --- arch/alpha/kernel/pci-sysfs.c | 2 +- arch/alpha/kernel/srm_env.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c index 738fc824e2ea..b899e95f79fd 100644 --- a/arch/alpha/kernel/pci-sysfs.c +++ b/arch/alpha/kernel/pci-sysfs.c @@ -66,7 +66,7 @@ static int pci_mmap_resource(struct kobject *kobj, { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); - struct resource *res = (struct resource *)attr->private; + struct resource *res = attr->private; enum pci_mmap_state mmap_type; struct pci_bus_region bar; int i; diff --git a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c index 4afc1a1e2e5a..f0df3fbd8402 100644 --- a/arch/alpha/kernel/srm_env.c +++ b/arch/alpha/kernel/srm_env.c @@ -87,7 +87,7 @@ static int srm_env_proc_show(struct seq_file *m, void *v) srm_env_t *entry; char *page; - entry = (srm_env_t *)m->private; + entry = m->private; page = (char *)__get_free_page(GFP_USER); if (!page) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From b97f897d60c34adb9a5a37a14033e6a867e86f48 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 14 Sep 2010 09:00:22 -0400 Subject: alpha: fix build breakage in asm/cacheflush.h Alpha SMP flush_icache_user_range() is implemented as an inline function inside include/asm/cacheflush.h. It dereferences @current but doesn't include linux/sched.h and thus causes build failure if linux/sched.h wasn't included previously. Fix it by including the needed header file explicitly. Signed-off-by: Tejun Heo Reported-by: Stephen Rothwell Signed-off-by: Matt Turner --- arch/alpha/include/asm/cacheflush.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/alpha/include/asm/cacheflush.h b/arch/alpha/include/asm/cacheflush.h index 01d71e1c8a9e..012f1243b1c1 100644 --- a/arch/alpha/include/asm/cacheflush.h +++ b/arch/alpha/include/asm/cacheflush.h @@ -43,6 +43,8 @@ extern void smp_imb(void); /* ??? Ought to use this in arch/alpha/kernel/signal.c too. */ #ifndef CONFIG_SMP +#include + extern void __load_new_mm_context(struct mm_struct *); static inline void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, -- cgit v1.2.3-59-g8ed1b From 12e750d956eec8b1778679aff705f617095c46c8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Sep 2010 19:34:56 -0400 Subject: alpha: kill big kernel lock All uses of the BKL on alpha are totally bogus, nothing is really protected by this. Remove the remaining users so we don't have to mark alpha as 'depends on BKL'. Signed-off-by: Arnd Bergmann Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: linux-alpha@vger.kernel.org Signed-off-by: Matt Turner --- arch/alpha/kernel/osf_sys.c | 5 ----- arch/alpha/kernel/traps.c | 3 --- 2 files changed, 8 deletions(-) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 16bc1f5df3e2..547e8b84b2f7 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -69,7 +68,6 @@ SYSCALL_DEFINE4(osf_set_program_attributes, unsigned long, text_start, { struct mm_struct *mm; - lock_kernel(); mm = current->mm; mm->end_code = bss_start + bss_len; mm->start_brk = bss_start + bss_len; @@ -78,7 +76,6 @@ SYSCALL_DEFINE4(osf_set_program_attributes, unsigned long, text_start, printk("set_program_attributes(%lx %lx %lx %lx)\n", text_start, text_len, bss_start, bss_len); #endif - unlock_kernel(); return 0; } @@ -517,7 +514,6 @@ SYSCALL_DEFINE2(osf_proplist_syscall, enum pl_code, code, long error; int __user *min_buf_size_ptr; - lock_kernel(); switch (code) { case PL_SET: if (get_user(error, &args->set.nbytes)) @@ -547,7 +543,6 @@ SYSCALL_DEFINE2(osf_proplist_syscall, enum pl_code, code, error = -EOPNOTSUPP; break; }; - unlock_kernel(); return error; } diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index b14f015008ad..0414e021a91c 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -623,7 +622,6 @@ do_entUna(void * va, unsigned long opcode, unsigned long reg, return; } - lock_kernel(); printk("Bad unaligned kernel access at %016lx: %p %lx %lu\n", pc, va, opcode, reg); do_exit(SIGSEGV); @@ -646,7 +644,6 @@ got_exception: * Yikes! No one to forward the exception to. * Since the registers are in a weird format, dump them ourselves. */ - lock_kernel(); printk("%s(%d): unhandled unaligned exception\n", current->comm, task_pid_nr(current)); -- cgit v1.2.3-59-g8ed1b From 531f0474bf889d489b28ea4b15e87b7cbb77f580 Mon Sep 17 00:00:00 2001 From: Mikael Pettersson Date: Thu, 16 Sep 2010 14:12:55 -0400 Subject: alpha: wire up fanotify and prlimit64 syscalls The 2.6.36-rc kernel added three new system calls: fanotify_init, fanotify_mark, and prlimit64. This patch wires them up on Alpha. Built and booted on an XP900. Untested beyond that. Signed-off-by: Mikael Pettersson Signed-off-by: Matt Turner --- arch/alpha/include/asm/unistd.h | 5 ++++- arch/alpha/kernel/systbls.S | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index 804e5311c841..9a9672f0a346 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h @@ -449,10 +449,13 @@ #define __NR_pwritev 491 #define __NR_rt_tgsigqueueinfo 492 #define __NR_perf_event_open 493 +#define __NR_fanotify_init 494 +#define __NR_fanotify_mark 495 +#define __NR_prlimit64 496 #ifdef __KERNEL__ -#define NR_SYSCALLS 494 +#define NR_SYSCALLS 497 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index 09acb786e72b..ce594ef533cc 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -512,6 +512,9 @@ sys_call_table: .quad sys_pwritev .quad sys_rt_tgsigqueueinfo .quad sys_perf_event_open + .quad sys_fanotify_init + .quad sys_fanotify_mark /* 495 */ + .quad sys_prlimit64 .size sys_call_table, . - sys_call_table .type sys_call_table, @object -- cgit v1.2.3-59-g8ed1b From bdc8b8914b17cf97b53e5f7af8168d68cfb089d6 Mon Sep 17 00:00:00 2001 From: Michael Cree Date: Sun, 19 Sep 2010 02:05:40 -0400 Subject: alpha: Shift perf event pending work earlier in timer interrupt Pending work from the performance event subsystem is executed in the timer interrupt. This patch shifts the call to perf_event_do_pending() before the call to update_process_times() as the latter may call back into the perf event subsystem and it is prudent to have the pending work executed first. Signed-off-by: Michael Cree Signed-off-by: Matt Turner --- arch/alpha/kernel/time.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index eacceb26d9c8..396af1799ea4 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -191,16 +191,16 @@ irqreturn_t timer_interrupt(int irq, void *dev) write_sequnlock(&xtime_lock); -#ifndef CONFIG_SMP - while (nticks--) - update_process_times(user_mode(get_irq_regs())); -#endif - if (test_perf_event_pending()) { clear_perf_event_pending(); perf_event_do_pending(); } +#ifndef CONFIG_SMP + while (nticks--) + update_process_times(user_mode(get_irq_regs())); +#endif + return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From 2deba1bd7126aadb5750beb927c878a6490065e6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Sep 2010 08:38:47 -0400 Subject: alpha: belated ERESTART_RESTARTBLOCK race fix same thing as had been done on other targets back in 2003 - move setting ->restart_block.fn into {rt_,}sigreturn(). Tested-by: Michael Cree Signed-off-by: Al Viro Signed-off-by: Matt Turner --- arch/alpha/kernel/signal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 0932dbb1ef8e..e5b1b3c79ff3 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -239,6 +239,8 @@ restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long usp; long i, err = __get_user(regs->pc, &sc->sc_pc); + current_thread_info()->restart_block.fn = do_no_restart_syscall; + sw->r26 = (unsigned long) ret_from_sys_call; err |= __get_user(regs->r0, sc->sc_regs+0); @@ -591,7 +593,6 @@ syscall_restart(unsigned long r0, unsigned long r19, regs->pc -= 4; break; case ERESTART_RESTARTBLOCK: - current_thread_info()->restart_block.fn = do_no_restart_syscall; regs->r0 = EINTR; break; } -- cgit v1.2.3-59-g8ed1b From 392fb6e35400edbee183baba24b34a0fa2053813 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Sep 2010 08:40:07 -0400 Subject: alpha: unb0rk sigsuspend() and rt_sigsuspend() Old code used to set regs->r0 and regs->r19 to force the right return value. Leaving that after switch to ERESTARTNOHAND was a Bad Idea(tm), since now that screws the restart - if we hit the case when get_signal_to_deliver() returns 0, we will step back to syscall insn, with v0 set to EINTR and a3 to 1. The latter won't matter, since EINTR is 4, aka __NR_write. Testcase: #include #define _GNU_SOURCE #include #include main() { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGCONT); sigprocmask(SIG_SETMASK, &mask, NULL); kill(0, SIGCONT); syscall(__NR_sigsuspend, 1, "b0rken\n", 7); } results on alpha in immediate message to stdout... Fix is obvious; moreover, since we don't need regs anymore, we can switch to normal prototypes for these guys and lose the wrappers. Even better, rt_sigsuspend() is identical to generic version in kernel/signal.c now. Tested-by: Michael Cree Signed-off-by: Al Viro Signed-off-by: Matt Turner --- arch/alpha/include/asm/unistd.h | 1 + arch/alpha/kernel/entry.S | 32 -------------------------------- arch/alpha/kernel/signal.c | 38 +------------------------------------- 3 files changed, 2 insertions(+), 69 deletions(-) diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h index 9a9672f0a346..058937bf5a77 100644 --- a/arch/alpha/include/asm/unistd.h +++ b/arch/alpha/include/asm/unistd.h @@ -466,6 +466,7 @@ #define __ARCH_WANT_SYS_OLD_GETRLIMIT #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING +#define __ARCH_WANT_SYS_RT_SIGSUSPEND /* "Conditional" syscalls. What we want is diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index b45d913a51c3..bceb325fd4c5 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -778,38 +778,6 @@ sys_rt_sigreturn: br ret_from_sys_call .end sys_rt_sigreturn - .align 4 - .globl sys_sigsuspend - .ent sys_sigsuspend -sys_sigsuspend: - .prologue 0 - mov $sp, $17 - br $1, do_switch_stack - mov $sp, $18 - subq $sp, 16, $sp - stq $26, 0($sp) - jsr $26, do_sigsuspend - ldq $26, 0($sp) - lda $sp, SWITCH_STACK_SIZE+16($sp) - ret -.end sys_sigsuspend - - .align 4 - .globl sys_rt_sigsuspend - .ent sys_rt_sigsuspend -sys_rt_sigsuspend: - .prologue 0 - mov $sp, $18 - br $1, do_switch_stack - mov $sp, $19 - subq $sp, 16, $sp - stq $26, 0($sp) - jsr $26, do_rt_sigsuspend - ldq $26, 0($sp) - lda $sp, SWITCH_STACK_SIZE+16($sp) - ret -.end sys_rt_sigsuspend - .align 4 .globl sys_sethae .ent sys_sethae diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index e5b1b3c79ff3..0f6b51ae865a 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -144,8 +144,7 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, /* * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int -do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) +SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask) { mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); @@ -154,41 +153,6 @@ do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - /* Indicate EINTR on return from any possible signal handler, - which will not come back through here, but via sigreturn. */ - regs->r0 = EINTR; - regs->r19 = 1; - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; -} - -asmlinkage int -do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, - struct pt_regs *regs, struct switch_stack *sw) -{ - sigset_t set; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - if (copy_from_user(&set, uset, sizeof(set))) - return -EFAULT; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - /* Indicate EINTR on return from any possible signal handler, - which will not come back through here, but via sigreturn. */ - regs->r0 = EINTR; - regs->r19 = 1; - current->state = TASK_INTERRUPTIBLE; schedule(); set_thread_flag(TIF_RESTORE_SIGMASK); -- cgit v1.2.3-59-g8ed1b From 53293638618f1a8b0b182dfedaab08b28930f992 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Sep 2010 08:41:16 -0400 Subject: alpha: fix a 14 years old bug in sigreturn tracing The way sigreturn() is implemented on alpha breaks PTRACE_SYSCALL, all way back to 1.3.95 when alpha has grown PTRACE_SYSCALL support. What happens is direct return to ret_from_syscall, in order to bypass mangling of a3 (error indicator) and prevent other mutilations of registers (e.g. by syscall restart). That's fine, but... the entire TIF_SYSCALL_TRACE codepath is kept separate on alpha and post-syscall stopping/notifying the tracer is after the syscall. And the normal path we are forcibly switching to doesn't have it. So we end up with *one* stop in traced sigreturn() vs. two in other syscalls. And yes, strace is visibly broken by that; try to strace the following #include #include void f(int sig) {} main() { signal(SIGHUP, f); raise(SIGHUP); write(1, "eeeek\n", 6); } and watch the show. The close(1) = 405 in the end of strace output is coming from return value of write() (6 == __NR_close on alpha) and syscall number of exit_group() (__NR_exit_group == 405 there). The fix is fairly simple - the only thing we end up missing is the call of syscall_trace() and we can tell whether we'd been called from the SYSCALL_TRACE path by checking ra value. Since we are setting the switch_stack up (that's what sys_sigreturn() does), we have the right environment for calling syscall_trace() - just before we call undo_switch_stack() and return. Since undo_switch_stack() will overwrite s0 anyway, we can use it to store the result of "has it been called from SYSCALL_TRACE path?" check. The same thing applies in rt_sigreturn(). Tested-by: Michael Cree Signed-off-by: Al Viro Signed-off-by: Matt Turner --- arch/alpha/kernel/entry.S | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index bceb325fd4c5..a3e9cd85cfee 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -430,6 +430,7 @@ strace: beq $1, 1f ldq $27, 0($2) 1: jsr $26, ($27), sys_gettimeofday +ret_from_straced: ldgp $gp, 0($26) /* check return.. */ @@ -757,11 +758,15 @@ sys_vfork: .ent sys_sigreturn sys_sigreturn: .prologue 0 + lda $9, ret_from_straced + cmpult $26, $9, $9 mov $sp, $17 lda $18, -SWITCH_STACK_SIZE($sp) lda $sp, -SWITCH_STACK_SIZE($sp) jsr $26, do_sigreturn - br $1, undo_switch_stack + bne $9, 1f + jsr $26, syscall_trace +1: br $1, undo_switch_stack br ret_from_sys_call .end sys_sigreturn @@ -770,11 +775,15 @@ sys_sigreturn: .ent sys_rt_sigreturn sys_rt_sigreturn: .prologue 0 + lda $9, ret_from_straced + cmpult $26, $9, $9 mov $sp, $17 lda $18, -SWITCH_STACK_SIZE($sp) lda $sp, -SWITCH_STACK_SIZE($sp) jsr $26, do_rt_sigreturn - br $1, undo_switch_stack + bne $9, 1f + jsr $26, syscall_trace +1: br $1, undo_switch_stack br ret_from_sys_call .end sys_rt_sigreturn -- cgit v1.2.3-59-g8ed1b From 494486a1d2697f2153199b6501ab5b4d6e15a2bb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Sep 2010 08:42:27 -0400 Subject: alpha: deal with multiple simultaneously pending signals Unlike the other targets, alpha sets _one_ sigframe and buggers off until the next syscall/interrupt, even if more signals are pending. It leads to quite a few unpleasant inconsistencies, starting with SIGSEGV potentially arriving not where it should and including e.g. mess with sigsuspend(); consider two pending signals blocked until sigsuspend() unblocks them. We pick the first one; then, if we are hit by interrupt while in the handler, we process the second one as well. If we are not, and if no syscalls had been made, we get out of the first handler and leave the second signal pending; normally sigreturn() would've picked it anyway, but here it starts with restoring the original mask and voila - the second signal is blocked again. On everything else we get both delivered consistently. It's actually easy to fix; the only thing to watch out for is prevention of double syscall restart. Fortunately, the idea I've nicked from arm fix by rmk works just fine... Testcase demonstrating the behaviour in question; on alpha we get one or both flags set (usually one), on everything else both are always set. #include #include int had1, had2; void f1(int sig) { had1 = 1; } void f2(int sig) { had2 = 1; } main() { sigset_t set1, set2; sigemptyset(&set1); sigemptyset(&set2); sigaddset(&set2, 1); sigaddset(&set2, 2); signal(1, f1); signal(2, f2); sigprocmask(SIG_SETMASK, &set2, NULL); raise(1); raise(2); sigsuspend(&set1); printf("had1:%d had2:%d\n", had1, had2); } Tested-by: Michael Cree Signed-off-by: Al Viro Signed-off-by: Matt Turner --- arch/alpha/kernel/entry.S | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index a3e9cd85cfee..ab1ee0ab082b 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -317,14 +317,14 @@ ret_from_sys_call: ldq $0, SP_OFF($sp) and $0, 8, $0 beq $0, restore_all -ret_from_reschedule: +ret_to_user: /* Make sure need_resched and sigpending don't change between sampling and the rti. */ lda $16, 7 call_pal PAL_swpipl ldl $5, TI_FLAGS($8) and $5, _TIF_WORK_MASK, $2 - bne $5, work_pending + bne $2, work_pending restore_all: RESTORE_ALL call_pal PAL_rti @@ -363,7 +363,7 @@ $ret_success: * $8: current. * $19: The old syscall number, or zero if this is not a return * from a syscall that errored and is possibly restartable. - * $20: Error indication. + * $20: The old a3 value */ .align 4 @@ -392,12 +392,18 @@ $work_resched: $work_notifysig: mov $sp, $16 - br $1, do_switch_stack + bsr $1, do_switch_stack mov $sp, $17 mov $5, $18 + mov $19, $9 /* save old syscall number */ + mov $20, $10 /* save old a3 */ + and $5, _TIF_SIGPENDING, $2 + cmovne $2, 0, $9 /* we don't want double syscall restarts */ jsr $26, do_notify_resume + mov $9, $19 + mov $10, $20 bsr $1, undo_switch_stack - br restore_all + br ret_to_user .end work_pending /* -- cgit v1.2.3-59-g8ed1b From 79e27dc0677b969e2d53b76fa0fa58467cce946a Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Sat, 18 Sep 2010 19:55:10 +0100 Subject: ARM: 6400/1: at91: fix arch_gettimeoffset fallout 5cfc8ee0bb51 (ARM: convert arm to arch_gettimeoffset()) marked all of at91 AND at91x40 as needing ARCH_USES_GETTIMEOFFSET, and hence no high res timer support / accurate clock_gettime() - But only at91x40 needs it. Cc: stable@kernel.org Signed-off-by: Peter Korsgaard Acked-by: John Stultz Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Russell King --- arch/arm/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0f89335b84c2..88c97bc7a6f5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -271,7 +271,6 @@ config ARCH_AT91 bool "Atmel AT91" select ARCH_REQUIRE_GPIOLIB select HAVE_CLK - select ARCH_USES_GETTIMEOFFSET help This enables support for systems based on the Atmel AT91RM9200, AT91SAM9 and AT91CAP9 processors. -- cgit v1.2.3-59-g8ed1b From d907387c42e9e39261629890e45a08ef4c3ed3fe Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 13 Sep 2010 16:01:24 +0100 Subject: ARM: 6383/1: Implement phys_mem_access_prot() to avoid attributes aliasing ARMv7 onwards requires that there are no aliases to the same physical location using different memory types (i.e. Normal vs Strongly Ordered). Access to SO mappings when the unaligned accesses are handled in hardware is also Unpredictable (pgprot_noncached() mappings in user space). The /dev/mem driver requires uncached mappings with O_SYNC. The patch implements the phys_mem_access_prot() function which generates Strongly Ordered memory attributes if !pfn_valid() (independent of O_SYNC) and Normal Noncacheable (writecombine) if O_SYNC. Signed-off-by: Catalin Marinas Signed-off-by: Russell King --- arch/arm/include/asm/pgtable.h | 4 ++++ arch/arm/mm/mmu.c | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index ab68cf1ef80f..e90b167ea848 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -317,6 +317,10 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; } #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE #define pgprot_dmacoherent(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_BUFFERABLE) +#define __HAVE_PHYS_MEM_ACCESS_PROT +struct file; +extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + unsigned long size, pgprot_t vma_prot); #else #define pgprot_dmacoherent(prot) \ __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_UNCACHED) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 6e1c4f6a2b3f..a486bd0d97dc 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -498,6 +499,19 @@ static void __init build_mem_type_table(void) } } +#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE +pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, + unsigned long size, pgprot_t vma_prot) +{ + if (!pfn_valid(pfn)) + return pgprot_noncached(vma_prot); + else if (file->f_flags & O_SYNC) + return pgprot_writecombine(vma_prot); + return vma_prot; +} +EXPORT_SYMBOL(phys_mem_access_prot); +#endif + #define vectors_base() (vectors_high() ? 0xffff0000 : 0) static void __init *early_alloc(unsigned long sz) -- cgit v1.2.3-59-g8ed1b From d93c333dc867d04111c9dcebdbcaa9ae8b2d5c2d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 19 Sep 2010 16:16:58 +0100 Subject: ARM: Fix build error when using KCONFIG_CONFIG Jonathan Cameron reports that when using the environment variable KCONFIG_CONFIG, he encounters this error: make[2]: *** No rule to make target `.config', needed by `arch/arm/boot/compressed/vmlinux.lds' Reported-by: Jonathan Cameron Signed-off-by: Russell King --- arch/arm/boot/compressed/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index b23f6bc46cfa..65a7c1c588a9 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -116,5 +116,5 @@ CFLAGS_font.o := -Dstatic= $(obj)/font.c: $(FONTC) $(call cmd,shipped) -$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config +$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG) @sed "$(SEDFLAGS)" < $< > $@ -- cgit v1.2.3-59-g8ed1b From 112d421df2fddc0278584b084f4fcfedd144c5f4 Mon Sep 17 00:00:00 2001 From: Jan Harkes Date: Fri, 17 Sep 2010 23:26:01 -0400 Subject: Coda: mount hangs because of missed REQ_WRITE rename Coda's REQ_* defines were renamed to avoid clashes with the block layer (commit 4aeefdc69f7b: "coda: fixup clash with block layer REQ_* defines"). However one was missed and response messages are no longer matched with requests and waiting threads are no longer woken up. This patch fixes this. Signed-off-by: Jan Harkes [ Also fixed up whitespace while at it -Linus ] Signed-off-by: Linus Torvalds --- fs/coda/psdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index de89645777c7..116af7546cf0 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -184,8 +184,8 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf, } /* adjust outsize. is this useful ?? */ - req->uc_outSize = nbytes; - req->uc_flags |= REQ_WRITE; + req->uc_outSize = nbytes; + req->uc_flags |= CODA_REQ_WRITE; count = nbytes; /* Convert filedescriptor into a file handle */ -- cgit v1.2.3-59-g8ed1b From 38e7afe96c7c0ad900824911c61fdb04078033dc Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sun, 19 Sep 2010 16:25:36 -0700 Subject: Input: uinput - setup MT usage during device creation The input devices created by uinput do not currently handle multitouch properly. All events will appear as if they came from slot zero, and the input event buffers are not adjusted. This patch creates the MT slots during setup, and sets the number of events per packet based on the MT usage. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 0d4266a533a5..360698553eb5 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -404,6 +404,13 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu retval = uinput_validate_absbits(dev); if (retval < 0) goto exit; + if (test_bit(ABS_MT_SLOT, dev->absbit)) { + int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; + input_mt_create_slots(dev, nslot); + input_set_events_per_packet(dev, 6 * nslot); + } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { + input_set_events_per_packet(dev, 60); + } } udev->state = UIST_SETUP_COMPLETE; -- cgit v1.2.3-59-g8ed1b From e4ff1c39ee1122198e8355069da59297038e55bb Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Sun, 22 Aug 2010 22:49:46 +0200 Subject: ARM: kirkwood: Unbreak PCIe I/O port The support for the 2 pcie port of the 6282 has broken i/o port by switching *_IO_PHYS_BASE and *_IO_BUS_BASE. In fact, the patches reintroduced the same bug solved by commit 35f029e2514be209eb0e88c7d927f3bcc42a5cc2. So, I'm adding back *_IO_BUS_BASE in resource declaration and fix definition of KIRKWOOD_PCIE1_IO_BUS_BASE. With this change, the xgi card on my t5325 is working again. Signed-off-by: Arnaud Patard Acked-by: Saeed Bishara Signed-off-by: Nicolas Pitre Cc: stable@kernel.org --- arch/arm/mach-kirkwood/include/mach/kirkwood.h | 2 +- arch/arm/mach-kirkwood/pcie.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h index 93fc2ec95e76..6e924b398919 100644 --- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h +++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h @@ -38,7 +38,7 @@ #define KIRKWOOD_PCIE1_IO_PHYS_BASE 0xf3000000 #define KIRKWOOD_PCIE1_IO_VIRT_BASE 0xfef00000 -#define KIRKWOOD_PCIE1_IO_BUS_BASE 0x00000000 +#define KIRKWOOD_PCIE1_IO_BUS_BASE 0x00100000 #define KIRKWOOD_PCIE1_IO_SIZE SZ_1M #define KIRKWOOD_PCIE_IO_PHYS_BASE 0xf2000000 diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index 55e7f00836b7..513ad3102d7c 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -117,7 +117,7 @@ static void __init pcie0_ioresources_init(struct pcie_port *pp) * IORESOURCE_IO */ pp->res[0].name = "PCIe 0 I/O Space"; - pp->res[0].start = KIRKWOOD_PCIE_IO_PHYS_BASE; + pp->res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE; pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1; pp->res[0].flags = IORESOURCE_IO; @@ -139,7 +139,7 @@ static void __init pcie1_ioresources_init(struct pcie_port *pp) * IORESOURCE_IO */ pp->res[0].name = "PCIe 1 I/O Space"; - pp->res[0].start = KIRKWOOD_PCIE1_IO_PHYS_BASE; + pp->res[0].start = KIRKWOOD_PCIE1_IO_BUS_BASE; pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE1_IO_SIZE - 1; pp->res[0].flags = IORESOURCE_IO; -- cgit v1.2.3-59-g8ed1b From 863636828f1fcd9fdc15e24d620aa53cf18b432f Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Fri, 17 Sep 2010 23:33:51 +0200 Subject: dmaengine: fix interrupt clearing for mv_xor When using simultaneously the two DMA channels on a same engine, some transfers are never completed. For example, an endless lock can occur while writing heavily on a RAID5 array (with async-tx offload support enabled). Note that this issue can also be reproduced by using the DMA test client. On a same engine, the interrupt cause register is shared between two DMA channels. This patch make sure that the cause bit is only cleared for the requested channel. Signed-off-by: Simon Guinot Tested-by: Luc Saillard Acked-by: Saeed Bishara Signed-off-by: Nicolas Pitre --- drivers/dma/mv_xor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 86c5ae9fde34..411d5bf50fc4 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -162,7 +162,7 @@ static int mv_is_err_intr(u32 intr_cause) static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan) { - u32 val = (1 << (1 + (chan->idx * 16))); + u32 val = ~(1 << (chan->idx * 16)); dev_dbg(chan->device->common.dev, "%s, val 0x%08x\n", __func__, val); __raw_writel(val, XOR_INTR_CAUSE(chan)); } -- cgit v1.2.3-59-g8ed1b From c4a90588fa07ea47df7a67fd6cb03d6bc0f99634 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 14 Sep 2010 16:14:15 +0800 Subject: ARM: dove: fix __io() definition to use bus based offset Signed-off-by: Eric Miao Acked-by: Saeed Bishara Signed-off-by: Nicolas Pitre --- arch/arm/mach-dove/include/mach/io.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-dove/include/mach/io.h b/arch/arm/mach-dove/include/mach/io.h index 3b3e4721ce2e..eb4936ff90ad 100644 --- a/arch/arm/mach-dove/include/mach/io.h +++ b/arch/arm/mach-dove/include/mach/io.h @@ -13,8 +13,8 @@ #define IO_SPACE_LIMIT 0xffffffff -#define __io(a) ((void __iomem *)(((a) - DOVE_PCIE0_IO_PHYS_BASE) +\ - DOVE_PCIE0_IO_VIRT_BASE)) -#define __mem_pci(a) (a) +#define __io(a) ((void __iomem *)(((a) - DOVE_PCIE0_IO_BUS_BASE) + \ + DOVE_PCIE0_IO_VIRT_BASE)) +#define __mem_pci(a) (a) #endif -- cgit v1.2.3-59-g8ed1b From f539dfedbd169e5ed47912bb517c75976ab556f3 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Sun, 19 Sep 2010 15:30:59 +0200 Subject: leds: leds-ns2: fix locking This patch replace all the lock functions with the irq safe variant. The ns2_led_{set,get}_mode() functions must be safe in all context. For example, the trigger timer call led_set_brightness() in a softirq context. Signed-off-by: Simon Guinot Signed-off-by: Nicolas Pitre --- drivers/leds/leds-ns2.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 74dce4ba0262..350eb34f049c 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -81,7 +81,7 @@ static int ns2_led_get_mode(struct ns2_led_data *led_dat, int cmd_level; int slow_level; - read_lock(&led_dat->rw_lock); + read_lock_irq(&led_dat->rw_lock); cmd_level = gpio_get_value(led_dat->cmd); slow_level = gpio_get_value(led_dat->slow); @@ -95,7 +95,7 @@ static int ns2_led_get_mode(struct ns2_led_data *led_dat, } } - read_unlock(&led_dat->rw_lock); + read_unlock_irq(&led_dat->rw_lock); return ret; } @@ -104,8 +104,9 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat, enum ns2_led_modes mode) { int i; + unsigned long flags; - write_lock(&led_dat->rw_lock); + write_lock_irqsave(&led_dat->rw_lock, flags); for (i = 0; i < ARRAY_SIZE(ns2_led_modval); i++) { if (mode == ns2_led_modval[i].mode) { @@ -116,7 +117,7 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat, } } - write_unlock(&led_dat->rw_lock); + write_unlock_irqrestore(&led_dat->rw_lock, flags); } static void ns2_led_set(struct led_classdev *led_cdev, -- cgit v1.2.3-59-g8ed1b From 84eb01be18df7012ac31bf678da5aaf1accc6a77 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Sep 2010 12:27:25 +0200 Subject: ALSA: hda - Merge all HDMI modules into the unified module This patch merges all three patch_*hdmi variants to the single HDMI parser. There is only one snd-hda-codec-hdmi module now. In this patch, the behavior of each parser isn't changed much. The old ATI parser still doesn't use the dynamic parser yet. In later patches, they'll be cleaned up. Also, this patch gets rid of the individual snd-hda-eld module and builds into snd-hda-codec-hdmi, since this is referred only from the HDMI parser. Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 39 +-- sound/pci/hda/Makefile | 15 +- sound/pci/hda/hda_eld.c | 7 - sound/pci/hda/patch_atihdmi.c | 224 ------------- sound/pci/hda/patch_hdmi.c | 685 +++++++++++++++++++++++++++++++++++++++- sound/pci/hda/patch_intelhdmi.c | 220 ------------- sound/pci/hda/patch_nvhdmi.c | 608 ----------------------------------- 7 files changed, 691 insertions(+), 1107 deletions(-) delete mode 100644 sound/pci/hda/patch_atihdmi.c delete mode 100644 sound/pci/hda/patch_intelhdmi.c delete mode 100644 sound/pci/hda/patch_nvhdmi.c diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 9194c3c1d04a..0ea5cc60ac78 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA snd-hda-codec-via. This module is automatically loaded at probing. -config SND_HDA_CODEC_ATIHDMI - bool "Build ATI HDMI HD-audio codec support" - default y - help - Say Y here to include ATI HDMI HD-audio codec support in - snd-hda-intel driver, such as ATI RS600 HDMI. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-atihdmi. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_NVHDMI - bool "Build NVIDIA HDMI HD-audio codec support" - default y - help - Say Y here to include NVIDIA HDMI HD-audio codec support in - snd-hda-intel driver, such as NVIDIA MCP78 HDMI. - - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-nvhdmi. - This module is automatically loaded at probing. - -config SND_HDA_CODEC_INTELHDMI - bool "Build INTEL HDMI HD-audio codec support" +config SND_HDA_CODEC_HDMI + bool "Build HDMI/DisplayPort HD-audio codec support" select SND_DYNAMIC_MINORS default y help - Say Y here to include INTEL HDMI HD-audio codec support in - snd-hda-intel driver, such as Eaglelake integrated HDMI. + Say Y here to include HDMI and DisplayPort HD-audio codec + support in snd-hda-intel driver. This includes all AMD/ATI, + Intel and Nvidia HDMI/DisplayPort codecs. When the HD-audio driver is built as a module, the codec support code is also built as another module, - snd-hda-codec-intelhdmi. + snd-hda-codec-hdmi. This module is automatically loaded at probing. -config SND_HDA_ELD - def_bool y - depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI - config SND_HDA_CODEC_CIRRUS bool "Build Cirrus Logic codec support" depends on SND_HDA_INTEL diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 24bc195b02da..17ef3658f34b 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o snd-hda-codec-y := hda_codec.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o -snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o @@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs := patch_cmedia.o snd-hda-codec-analog-objs := patch_analog.o snd-hda-codec-idt-objs := patch_sigmatel.o snd-hda-codec-si3054-objs := patch_si3054.o -snd-hda-codec-atihdmi-objs := patch_atihdmi.o snd-hda-codec-cirrus-objs := patch_cirrus.o snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o -snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o -snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o +snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o # common driver obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o @@ -39,9 +36,6 @@ endif ifdef CONFIG_SND_HDA_CODEC_SI3054 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o endif -ifdef CONFIG_SND_HDA_CODEC_ATIHDMI -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o -endif ifdef CONFIG_SND_HDA_CODEC_CIRRUS obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o endif @@ -54,11 +48,8 @@ endif ifdef CONFIG_SND_HDA_CODEC_VIA obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o endif -ifdef CONFIG_SND_HDA_CODEC_NVHDMI -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o -endif -ifdef CONFIG_SND_HDA_CODEC_INTELHDMI -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o +ifdef CONFIG_SND_HDA_CODEC_HDMI +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o endif # this must be the last entry after codec drivers; diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 26c3ade73583..cb0c23a6b473 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, AC_DIPSIZE_ELD_BUF); } -EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size); int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) @@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, kfree(buf); return ret; } -EXPORT_SYMBOL_HDA(snd_hdmi_get_eld); static void hdmi_show_short_audio_desc(struct cea_sad *a) { @@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) } buf[j] = '\0'; /* necessary when j == 0 */ } -EXPORT_SYMBOL_HDA(snd_print_channel_allocation); void snd_hdmi_show_eld(struct hdmi_eld *e) { @@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) for (i = 0; i < e->sad_count; i++) hdmi_show_short_audio_desc(e->sad + i); } -EXPORT_SYMBOL_HDA(snd_hdmi_show_eld); #ifdef CONFIG_PROC_FS @@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, return 0; } -EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new); void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) { @@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) eld->proc_entry = NULL; } } -EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); #endif /* CONFIG_PROC_FS */ @@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm, pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max); pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps); } -EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info); diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c deleted file mode 100644 index fb684f00156b..000000000000 --- a/sound/pci/hda/patch_atihdmi.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for ATI HDMI codecs - * - * Copyright (c) 2006 ATI Technologies Inc. - * - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -struct atihdmi_spec { - struct hda_multi_out multiout; - - struct hda_pcm pcm_rec; -}; - -#define CVT_NID 0x02 /* audio converter */ -#define PIN_NID 0x03 /* HDMI output pin */ - -static struct hda_verb atihdmi_basic_init[] = { - /* enable digital output on pin widget */ - { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {} /* terminator */ -}; - -/* - * Controls - */ -static int atihdmi_build_controls(struct hda_codec *codec) -{ - struct atihdmi_spec *spec = codec->spec; - int err; - - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; - - return 0; -} - -static int atihdmi_init(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, atihdmi_basic_init); - /* SI codec requires to unmute the pin */ - if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, PIN_NID, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - return 0; -} - -/* - * Digital out - */ -static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct atihdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct atihdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct atihdmi_spec *spec = codec->spec; - int chans = substream->runtime->channels; - int i, err; - - err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); - if (err < 0) - return err; - snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT, - chans - 1); - /* FIXME: XXX */ - for (i = 0; i < chans; i++) { - snd_hda_codec_write(codec, CVT_NID, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, - (i << 4) | i); - } - return 0; -} - -static struct hda_pcm_stream atihdmi_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = CVT_NID, /* NID to query formats and rates and setup streams */ - .ops = { - .open = atihdmi_dig_playback_pcm_open, - .close = atihdmi_dig_playback_pcm_close, - .prepare = atihdmi_dig_playback_pcm_prepare - }, -}; - -static int atihdmi_build_pcms(struct hda_codec *codec) -{ - struct atihdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; - unsigned int chans; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "ATI HDMI"; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; - - /* FIXME: we must check ELD and change the PCM parameters dynamically - */ - chans = get_wcaps(codec, CVT_NID); - chans = get_wcaps_channels(chans); - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; - - return 0; -} - -static void atihdmi_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} - -static struct hda_codec_ops atihdmi_patch_ops = { - .build_controls = atihdmi_build_controls, - .build_pcms = atihdmi_build_pcms, - .init = atihdmi_init, - .free = atihdmi_free, -}; - -static int patch_atihdmi(struct hda_codec *codec) -{ - struct atihdmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 2; - /* NID for copying analog to digital, - * seems to be unused in pure-digital - * case. - */ - spec->multiout.dig_out_nid = CVT_NID; - - codec->patch_ops = atihdmi_patch_ops; - - return 0; -} - -/* - * patch entries - */ -static struct hda_codec_preset snd_hda_preset_atihdmi[] = { - { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, - { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, - { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, - { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, - { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, - { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:1002793c"); -MODULE_ALIAS("snd-hda-codec-id:10027919"); -MODULE_ALIAS("snd-hda-codec-id:1002791a"); -MODULE_ALIAS("snd-hda-codec-id:1002aa01"); -MODULE_ALIAS("snd-hda-codec-id:10951390"); -MODULE_ALIAS("snd-hda-codec-id:17e80047"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ATI HDMI HD-audio codec"); - -static struct hda_codec_preset_list atihdmi_list = { - .preset = snd_hda_preset_atihdmi, - .owner = THIS_MODULE, -}; - -static int __init patch_atihdmi_init(void) -{ - return snd_hda_add_codec_preset(&atihdmi_list); -} - -static void __exit patch_atihdmi_exit(void) -{ - snd_hda_delete_codec_preset(&atihdmi_list); -} - -module_init(patch_atihdmi_init) -module_exit(patch_atihdmi_exit) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index afd6022a96a7..cb997ca0fdfa 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -3,6 +3,9 @@ * patch_hdmi.c - routines for HDMI/DisplayPort codecs * * Copyright(c) 2008-2010 Intel Corporation. All rights reserved. + * Copyright (c) 2006 ATI Technologies Inc. + * Copyright (c) 2008 NVIDIA Corp. All rights reserved. + * Copyright (c) 2008 Wei Ni * * Authors: * Wu Fengguang @@ -25,6 +28,22 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +/* + * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device + * could support two independent pipes, each of them can be connected to one or + * more ports (DVI, HDMI or DisplayPort). + * + * The HDA correspondence of pipes/ports are converter/pin nodes. + */ +#define MAX_HDMI_CVTS 3 +#define MAX_HDMI_PINS 3 struct hdmi_spec { int num_cvts; @@ -49,10 +68,10 @@ struct hdmi_spec { struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS]; /* - * nvhdmi specific + * ati/nvhdmi specific */ struct hda_multi_out multiout; - unsigned int codec_type; + struct hda_pcm_stream *pcm_playback; /* misc flags */ /* PD bit indicates only the update, not the current state */ @@ -791,7 +810,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, /* * HDA/HDMI auto parsing */ - static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; @@ -922,3 +940,664 @@ static int hdmi_parse_codec(struct hda_codec *codec) return 0; } +/* + */ +static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = { + "HDMI 0", + "HDMI 1", + "HDMI 2", +}; + +/* + * HDMI callbacks + */ + +static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + hdmi_set_channel_count(codec, hinfo->nid, + substream->runtime->channels); + + hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); + + return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); +} + +static struct hda_pcm_stream generic_hdmi_pcm_playback = { + .substreams = 1, + .channels_min = 2, + .ops = { + .open = hdmi_pcm_open, + .prepare = generic_hdmi_playback_pcm_prepare, + }, +}; + +static int generic_hdmi_build_pcms(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + int i; + + codec->num_pcms = spec->num_cvts; + codec->pcm_info = info; + + for (i = 0; i < codec->num_pcms; i++, info++) { + unsigned int chans; + struct hda_pcm_stream *pstr; + + chans = get_wcaps(codec, spec->cvt[i]); + chans = get_wcaps_channels(chans); + + info->name = generic_hdmi_pcm_names[i]; + info->pcm_type = HDA_PCM_TYPE_HDMI; + pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; + if (spec->pcm_playback) + *pstr = *spec->pcm_playback; + else + *pstr = generic_hdmi_pcm_playback; + pstr->nid = spec->cvt[i]; + if (pstr->channels_max <= 2 && chans && chans <= 16) + pstr->channels_max = chans; + } + + return 0; +} + +static int generic_hdmi_build_controls(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int err; + int i; + + for (i = 0; i < codec->num_pcms; i++) { + err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); + if (err < 0) + return err; + } + + return 0; +} + +static int generic_hdmi_init(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int i; + + for (i = 0; spec->pin[i]; i++) { + hdmi_enable_output(codec, spec->pin[i]); + snd_hda_codec_write(codec, spec->pin[i], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | spec->pin[i]); + } + return 0; +} + +static void generic_hdmi_free(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); + + kfree(spec); +} + +static struct hda_codec_ops generic_hdmi_patch_ops = { + .init = generic_hdmi_init, + .free = generic_hdmi_free, + .build_pcms = generic_hdmi_build_pcms, + .build_controls = generic_hdmi_build_controls, + .unsol_event = hdmi_unsol_event, +}; + +static int patch_generic_hdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int i; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + if (hdmi_parse_codec(codec) < 0) { + codec->spec = NULL; + kfree(spec); + return -EINVAL; + } + codec->patch_ops = generic_hdmi_patch_ops; + + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); + + init_channel_allocations(); + + return 0; +} + +/* + * Nvidia specific implementations + */ + +#define Nv_VERB_SET_Channel_Allocation 0xF79 +#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A +#define Nv_VERB_SET_Audio_Protection_On 0xF98 +#define Nv_VERB_SET_Audio_Protection_Off 0xF99 + +#define nvhdmi_master_con_nid_7x 0x04 +#define nvhdmi_master_pin_nid_7x 0x05 + +static hda_nid_t nvhdmi_con_nids_7x[4] = { + /*front, rear, clfe, rear_surr */ + 0x6, 0x8, 0xa, 0xc, +}; + +static struct hda_verb nvhdmi_basic_init_7x[] = { + /* set audio protect on */ + { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, + /* enable digital output on pin widget */ + { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, + {} /* terminator */ +}; + +#ifdef LIMITED_RATE_FMT_SUPPORT +/* support only the safe format and rate */ +#define SUPPORTED_RATES SNDRV_PCM_RATE_48000 +#define SUPPORTED_MAXBPS 16 +#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE +#else +/* support all rates and formats */ +#define SUPPORTED_RATES \ + (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) +#define SUPPORTED_MAXBPS 24 +#define SUPPORTED_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) +#endif + +static int nvhdmi_7x_init(struct hda_codec *codec) +{ + snd_hda_sequence_write(codec, nvhdmi_basic_init_7x); + return 0; +} + +static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + int i; + + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, + 0, AC_VERB_SET_CHANNEL_STREAMID, 0); + for (i = 0; i < 4; i++) { + /* set the stream id */ + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + /* set the stream format */ + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, + AC_VERB_SET_STREAM_FORMAT, 0); + } + + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + int chs; + unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; + int i; + + mutex_lock(&codec->spdif_mutex); + + chs = substream->runtime->channels; + chan = chs ? (chs - 1) : 1; + + switch (chs) { + default: + case 0: + case 2: + chanmask = 0x00; + break; + case 4: + chanmask = 0x08; + break; + case 6: + chanmask = 0x0b; + break; + case 8: + chanmask = 0x13; + break; + } + dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; + dataDCC2 = 0x2; + + /* set the Audio InforFrame Channel Allocation */ + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Channel_Allocation, chanmask); + + /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) + snd_hda_codec_write(codec, + nvhdmi_master_con_nid_7x, + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); + + /* set the stream id */ + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, + AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); + + /* set the stream format */ + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, + AC_VERB_SET_STREAM_FORMAT, format); + + /* turn on again (if needed) */ + /* enable and set the channel status audio/data flag */ + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { + snd_hda_codec_write(codec, + nvhdmi_master_con_nid_7x, + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); + snd_hda_codec_write(codec, + nvhdmi_master_con_nid_7x, + 0, + AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); + } + + for (i = 0; i < 4; i++) { + if (chs == 2) + channel_id = 0; + else + channel_id = i * 2; + + /* turn off SPDIF once; + *otherwise the IEC958 bits won't be updated + */ + if (codec->spdif_status_reset && + (codec->spdif_ctls & AC_DIG1_ENABLE)) + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); + /* set the stream id */ + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_CHANNEL_STREAMID, + (stream_tag << 4) | channel_id); + /* set the stream format */ + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_STREAM_FORMAT, + format); + /* turn on again (if needed) */ + /* enable and set the channel status audio/data flag */ + if (codec->spdif_status_reset && + (codec->spdif_ctls & AC_DIG1_ENABLE)) { + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_DIGI_CONVERT_1, + codec->spdif_ctls & 0xff); + snd_hda_codec_write(codec, + nvhdmi_con_nids_7x[i], + 0, + AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); + } + } + + /* set the Audio Info Frame Checksum */ + snd_hda_codec_write(codec, 0x1, 0, + Nv_VERB_SET_Info_Frame_Checksum, + (0x71 - chan - chanmask)); + + mutex_unlock(&codec->spdif_mutex); + return 0; +} + +static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .nid = nvhdmi_master_con_nid_7x, + .rates = SUPPORTED_RATES, + .maxbps = SUPPORTED_MAXBPS, + .formats = SUPPORTED_FORMATS, + .ops = { + .open = simple_playback_pcm_open, + .close = nvhdmi_8ch_7x_pcm_close, + .prepare = nvhdmi_8ch_7x_pcm_prepare + }, +}; + +static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = nvhdmi_master_con_nid_7x, + .rates = SUPPORTED_RATES, + .maxbps = SUPPORTED_MAXBPS, + .formats = SUPPORTED_FORMATS, + .ops = { + .open = simple_playback_pcm_open, + .close = simple_playback_pcm_close, + .prepare = simple_playback_pcm_prepare + }, +}; + +static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, + .init = nvhdmi_7x_init, + .free = generic_hdmi_free, +}; + +static struct hda_codec_ops nvhdmi_patch_ops_2ch = { + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, + .init = nvhdmi_7x_init, + .free = generic_hdmi_free, +}; + +static int patch_nvhdmi_8ch_89(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err = patch_generic_hdmi(codec); + + if (err < 0) + return err; + spec = codec->spec; + spec->old_pin_detect = 1; + return 0; +} + +static int patch_nvhdmi_2ch(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 2; + spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; + spec->old_pin_detect = 1; + spec->num_cvts = 1; + spec->cvt[0] = nvhdmi_master_con_nid_7x; + spec->pcm_playback = &nvhdmi_pcm_playback_2ch; + + codec->patch_ops = nvhdmi_patch_ops_2ch; + + return 0; +} + +static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err = patch_nvhdmi_2ch(codec); + + if (err < 0) + return err; + spec = codec->spec; + spec->multiout.max_channels = 8; + spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x; + codec->patch_ops = nvhdmi_patch_ops_8ch_7x; + return 0; +} + +/* + * ATI-specific implementations + * + * FIXME: we may omit the whole this and use the generic code once after + * it's confirmed to work. + */ + +#define ATIHDMI_CVT_NID 0x02 /* audio converter */ +#define ATIHDMI_PIN_NID 0x03 /* HDMI output pin */ + +static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + int chans = substream->runtime->channels; + int i, err; + + err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format, + substream); + if (err < 0) + return err; + snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT, + chans - 1); + /* FIXME: XXX */ + for (i = 0; i < chans; i++) { + snd_hda_codec_write(codec, spec->cvt[0], 0, + AC_VERB_SET_HDMI_CHAN_SLOT, + (i << 4) | i); + } + return 0; +} + +static struct hda_pcm_stream atihdmi_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = ATIHDMI_CVT_NID, + .ops = { + .open = simple_playback_pcm_open, + .close = simple_playback_pcm_close, + .prepare = atihdmi_playback_pcm_prepare + }, +}; + +static struct hda_verb atihdmi_basic_init[] = { + /* enable digital output on pin widget */ + { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + {} /* terminator */ +}; + +static int atihdmi_init(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + + snd_hda_sequence_write(codec, atihdmi_basic_init); + /* SI codec requires to unmute the pin */ + if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, spec->pin[0], 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + return 0; +} + +static struct hda_codec_ops atihdmi_patch_ops = { + .build_controls = generic_hdmi_build_controls, + .build_pcms = generic_hdmi_build_pcms, + .init = atihdmi_init, + .free = generic_hdmi_free, +}; + + +static int patch_atihdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 2; + spec->multiout.dig_out_nid = ATIHDMI_CVT_NID; + spec->num_cvts = 1; + spec->cvt[0] = ATIHDMI_CVT_NID; + spec->pin[0] = ATIHDMI_PIN_NID; + spec->pcm_playback = &atihdmi_pcm_digital_playback; + + codec->patch_ops = atihdmi_patch_ops; + + return 0; +} + + +/* + * patch entries + */ +static struct hda_codec_preset snd_hda_preset_hdmi[] = { +{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, +{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, +{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, +{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, +{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, +{ .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, +{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, +{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, +{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, +{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, +{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, +{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, +{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, +{} /* terminator */ +}; + +MODULE_ALIAS("snd-hda-codec-id:1002793c"); +MODULE_ALIAS("snd-hda-codec-id:10027919"); +MODULE_ALIAS("snd-hda-codec-id:1002791a"); +MODULE_ALIAS("snd-hda-codec-id:1002aa01"); +MODULE_ALIAS("snd-hda-codec-id:10951390"); +MODULE_ALIAS("snd-hda-codec-id:10951392"); +MODULE_ALIAS("snd-hda-codec-id:10de0002"); +MODULE_ALIAS("snd-hda-codec-id:10de0003"); +MODULE_ALIAS("snd-hda-codec-id:10de0005"); +MODULE_ALIAS("snd-hda-codec-id:10de0006"); +MODULE_ALIAS("snd-hda-codec-id:10de0007"); +MODULE_ALIAS("snd-hda-codec-id:10de000a"); +MODULE_ALIAS("snd-hda-codec-id:10de000b"); +MODULE_ALIAS("snd-hda-codec-id:10de000c"); +MODULE_ALIAS("snd-hda-codec-id:10de000d"); +MODULE_ALIAS("snd-hda-codec-id:10de0010"); +MODULE_ALIAS("snd-hda-codec-id:10de0011"); +MODULE_ALIAS("snd-hda-codec-id:10de0012"); +MODULE_ALIAS("snd-hda-codec-id:10de0013"); +MODULE_ALIAS("snd-hda-codec-id:10de0014"); +MODULE_ALIAS("snd-hda-codec-id:10de0018"); +MODULE_ALIAS("snd-hda-codec-id:10de0019"); +MODULE_ALIAS("snd-hda-codec-id:10de001a"); +MODULE_ALIAS("snd-hda-codec-id:10de001b"); +MODULE_ALIAS("snd-hda-codec-id:10de001c"); +MODULE_ALIAS("snd-hda-codec-id:10de0040"); +MODULE_ALIAS("snd-hda-codec-id:10de0041"); +MODULE_ALIAS("snd-hda-codec-id:10de0042"); +MODULE_ALIAS("snd-hda-codec-id:10de0043"); +MODULE_ALIAS("snd-hda-codec-id:10de0044"); +MODULE_ALIAS("snd-hda-codec-id:10de0067"); +MODULE_ALIAS("snd-hda-codec-id:10de8001"); +MODULE_ALIAS("snd-hda-codec-id:17e80047"); +MODULE_ALIAS("snd-hda-codec-id:80860054"); +MODULE_ALIAS("snd-hda-codec-id:80862801"); +MODULE_ALIAS("snd-hda-codec-id:80862802"); +MODULE_ALIAS("snd-hda-codec-id:80862803"); +MODULE_ALIAS("snd-hda-codec-id:80862804"); +MODULE_ALIAS("snd-hda-codec-id:80862805"); +MODULE_ALIAS("snd-hda-codec-id:808629fb"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("HDMI HD-audio codec"); +MODULE_ALIAS("snd-hda-codec-intelhdmi"); +MODULE_ALIAS("snd-hda-codec-nvhdmi"); +MODULE_ALIAS("snd-hda-codec-atihdmi"); + +static struct hda_codec_preset_list intel_list = { + .preset = snd_hda_preset_hdmi, + .owner = THIS_MODULE, +}; + +static int __init patch_hdmi_init(void) +{ + return snd_hda_add_codec_preset(&intel_list); +} + +static void __exit patch_hdmi_exit(void) +{ + snd_hda_delete_codec_preset(&intel_list); +} + +module_init(patch_hdmi_init) +module_exit(patch_hdmi_exit) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c deleted file mode 100644 index 36a9b83a6174..000000000000 --- a/sound/pci/hda/patch_intelhdmi.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * - * patch_intelhdmi.c - Patch for Intel HDMI codecs - * - * Copyright(c) 2008 Intel Corporation. All rights reserved. - * - * Authors: - * Jiang Zhe - * Wu Fengguang - * - * Maintained by: - * Wu Fengguang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -/* - * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device - * could support two independent pipes, each of them can be connected to one or - * more ports (DVI, HDMI or DisplayPort). - * - * The HDA correspondence of pipes/ports are converter/pin nodes. - */ -#define MAX_HDMI_CVTS 3 -#define MAX_HDMI_PINS 3 - -#include "patch_hdmi.c" - -static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = { - "INTEL HDMI 0", - "INTEL HDMI 1", - "INTEL HDMI 2", -}; - -/* - * HDMI callbacks - */ - -static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - hdmi_set_channel_count(codec, hinfo->nid, - substream->runtime->channels); - - hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); - - return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); -} - -static struct hda_pcm_stream intel_hdmi_pcm_playback = { - .substreams = 1, - .channels_min = 2, - .ops = { - .open = hdmi_pcm_open, - .prepare = intel_hdmi_playback_pcm_prepare, - }, -}; - -static int intel_hdmi_build_pcms(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - int i; - - codec->num_pcms = spec->num_cvts; - codec->pcm_info = info; - - for (i = 0; i < codec->num_pcms; i++, info++) { - unsigned int chans; - - chans = get_wcaps(codec, spec->cvt[i]); - chans = get_wcaps_channels(chans); - - info->name = intel_hdmi_pcm_names[i]; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - intel_hdmi_pcm_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; - } - - return 0; -} - -static int intel_hdmi_build_controls(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int err; - int i; - - for (i = 0; i < codec->num_pcms; i++) { - err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); - if (err < 0) - return err; - } - - return 0; -} - -static int intel_hdmi_init(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int i; - - for (i = 0; spec->pin[i]; i++) { - hdmi_enable_output(codec, spec->pin[i]); - snd_hda_codec_write(codec, spec->pin[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | spec->pin[i]); - } - return 0; -} - -static void intel_hdmi_free(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_pins; i++) - snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); - - kfree(spec); -} - -static struct hda_codec_ops intel_hdmi_patch_ops = { - .init = intel_hdmi_init, - .free = intel_hdmi_free, - .build_pcms = intel_hdmi_build_pcms, - .build_controls = intel_hdmi_build_controls, - .unsol_event = hdmi_unsol_event, -}; - -static int patch_intel_hdmi(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int i; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - if (hdmi_parse_codec(codec) < 0) { - codec->spec = NULL; - kfree(spec); - return -EINVAL; - } - codec->patch_ops = intel_hdmi_patch_ops; - - for (i = 0; i < spec->num_pins; i++) - snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); - - init_channel_allocations(); - - return 0; -} - -static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { -{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_intel_hdmi }, -{ .id = 0x80862801, .name = "Bearlake HDMI", .patch = patch_intel_hdmi }, -{ .id = 0x80862802, .name = "Cantiga HDMI", .patch = patch_intel_hdmi }, -{ .id = 0x80862803, .name = "Eaglelake HDMI", .patch = patch_intel_hdmi }, -{ .id = 0x80862804, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, -{ .id = 0x80860054, .name = "IbexPeak HDMI", .patch = patch_intel_hdmi }, -{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_intel_hdmi }, -{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, -{} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:808629fb"); -MODULE_ALIAS("snd-hda-codec-id:80862801"); -MODULE_ALIAS("snd-hda-codec-id:80862802"); -MODULE_ALIAS("snd-hda-codec-id:80862803"); -MODULE_ALIAS("snd-hda-codec-id:80862804"); -MODULE_ALIAS("snd-hda-codec-id:80862805"); -MODULE_ALIAS("snd-hda-codec-id:80860054"); -MODULE_ALIAS("snd-hda-codec-id:10951392"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Intel HDMI HD-audio codec"); - -static struct hda_codec_preset_list intel_list = { - .preset = snd_hda_preset_intelhdmi, - .owner = THIS_MODULE, -}; - -static int __init patch_intelhdmi_init(void) -{ - return snd_hda_add_codec_preset(&intel_list); -} - -static void __exit patch_intelhdmi_exit(void) -{ - snd_hda_delete_codec_preset(&intel_list); -} - -module_init(patch_intelhdmi_init) -module_exit(patch_intelhdmi_exit) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c deleted file mode 100644 index baa108b9d6aa..000000000000 --- a/sound/pci/hda/patch_nvhdmi.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Universal Interface for Intel High Definition Audio Codec - * - * HD audio interface patch for NVIDIA HDMI codecs - * - * Copyright (c) 2008 NVIDIA Corp. All rights reserved. - * Copyright (c) 2008 Wei Ni - * - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" - -#define MAX_HDMI_CVTS 1 -#define MAX_HDMI_PINS 1 - -#include "patch_hdmi.c" - -static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = { - "NVIDIA HDMI", -}; - -/* define below to restrict the supported rates and formats */ -/* #define LIMITED_RATE_FMT_SUPPORT */ - -enum HDACodec { - HDA_CODEC_NVIDIA_MCP7X, - HDA_CODEC_NVIDIA_MCP89, - HDA_CODEC_NVIDIA_GT21X, - HDA_CODEC_INVALID -}; - -#define Nv_VERB_SET_Channel_Allocation 0xF79 -#define Nv_VERB_SET_Info_Frame_Checksum 0xF7A -#define Nv_VERB_SET_Audio_Protection_On 0xF98 -#define Nv_VERB_SET_Audio_Protection_Off 0xF99 - -#define nvhdmi_master_con_nid_7x 0x04 -#define nvhdmi_master_pin_nid_7x 0x05 - -#define nvhdmi_master_con_nid_89 0x04 -#define nvhdmi_master_pin_nid_89 0x05 - -static hda_nid_t nvhdmi_con_nids_7x[4] = { - /*front, rear, clfe, rear_surr */ - 0x6, 0x8, 0xa, 0xc, -}; - -static struct hda_verb nvhdmi_basic_init_7x[] = { - /* set audio protect on */ - { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, - /* enable digital output on pin widget */ - { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, - {} /* terminator */ -}; - -#ifdef LIMITED_RATE_FMT_SUPPORT -/* support only the safe format and rate */ -#define SUPPORTED_RATES SNDRV_PCM_RATE_48000 -#define SUPPORTED_MAXBPS 16 -#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE -#else -/* support all rates and formats */ -#define SUPPORTED_RATES \ - (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ - SNDRV_PCM_RATE_192000) -#define SUPPORTED_MAXBPS 24 -#define SUPPORTED_FORMATS \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) -#endif - -/* - * Controls - */ -static int nvhdmi_build_controls(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int err; - int i; - - if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) - || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { - for (i = 0; i < codec->num_pcms; i++) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->cvt[i]); - if (err < 0) - return err; - } - } else { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - } - - return 0; -} - -static int nvhdmi_init(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int i; - if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) - || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { - for (i = 0; spec->pin[i]; i++) { - hdmi_enable_output(codec, spec->pin[i]); - snd_hda_codec_write(codec, spec->pin[i], 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | spec->pin[i]); - } - } else { - snd_hda_sequence_write(codec, nvhdmi_basic_init_7x); - } - return 0; -} - -static void nvhdmi_free(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - int i; - - if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) - || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { - for (i = 0; i < spec->num_pins; i++) - snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); - } - - kfree(spec); -} - -/* - * Digital out - */ -static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - int i; - - snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, - 0, AC_VERB_SET_CHANNEL_STREAMID, 0); - for (i = 0; i < 4; i++) { - /* set the stream id */ - snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, - AC_VERB_SET_CHANNEL_STREAMID, 0); - /* set the stream format */ - snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, - AC_VERB_SET_STREAM_FORMAT, 0); - } - - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - hdmi_set_channel_count(codec, hinfo->nid, - substream->runtime->channels); - - hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); - - return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); -} - -static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - int chs; - unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; - int i; - - mutex_lock(&codec->spdif_mutex); - - chs = substream->runtime->channels; - chan = chs ? (chs - 1) : 1; - - switch (chs) { - default: - case 0: - case 2: - chanmask = 0x00; - break; - case 4: - chanmask = 0x08; - break; - case 6: - chanmask = 0x0b; - break; - case 8: - chanmask = 0x13; - break; - } - dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; - dataDCC2 = 0x2; - - /* set the Audio InforFrame Channel Allocation */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Channel_Allocation, chanmask); - - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, - nvhdmi_master_con_nid_7x, - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); - - /* set the stream id */ - snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, - AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); - - /* set the stream format */ - snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, - AC_VERB_SET_STREAM_FORMAT, format); - - /* turn on again (if needed) */ - /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { - snd_hda_codec_write(codec, - nvhdmi_master_con_nid_7x, - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & 0xff); - snd_hda_codec_write(codec, - nvhdmi_master_con_nid_7x, - 0, - AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); - } - - for (i = 0; i < 4; i++) { - if (chs == 2) - channel_id = 0; - else - channel_id = i * 2; - - /* turn off SPDIF once; - *otherwise the IEC958 bits won't be updated - */ - if (codec->spdif_status_reset && - (codec->spdif_ctls & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); - /* set the stream id */ - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_CHANNEL_STREAMID, - (stream_tag << 4) | channel_id); - /* set the stream format */ - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_STREAM_FORMAT, - format); - /* turn on again (if needed) */ - /* enable and set the channel status audio/data flag */ - if (codec->spdif_status_reset && - (codec->spdif_ctls & AC_DIG1_ENABLE)) { - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_DIGI_CONVERT_1, - codec->spdif_ctls & 0xff); - snd_hda_codec_write(codec, - nvhdmi_con_nids_7x[i], - 0, - AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); - } - } - - /* set the Audio Info Frame Checksum */ - snd_hda_codec_write(codec, 0x1, 0, - Nv_VERB_SET_Info_Frame_Checksum, - (0x71 - chan - chanmask)); - - mutex_unlock(&codec->spdif_mutex); - return 0; -} - -static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct hdmi_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { - .substreams = 1, - .channels_min = 2, - .ops = { - .open = hdmi_pcm_open, - .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, - }, -}; - -static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = nvhdmi_master_con_nid_7x, - .rates = SUPPORTED_RATES, - .maxbps = SUPPORTED_MAXBPS, - .formats = SUPPORTED_FORMATS, - .ops = { - .open = nvhdmi_dig_playback_pcm_open, - .close = nvhdmi_dig_playback_pcm_close_8ch_7x, - .prepare = nvhdmi_dig_playback_pcm_prepare_8ch - }, -}; - -static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = nvhdmi_master_con_nid_7x, - .rates = SUPPORTED_RATES, - .maxbps = SUPPORTED_MAXBPS, - .formats = SUPPORTED_FORMATS, - .ops = { - .open = nvhdmi_dig_playback_pcm_open, - .close = nvhdmi_dig_playback_pcm_close_2ch, - .prepare = nvhdmi_dig_playback_pcm_prepare_2ch - }, -}; - -static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - int i; - - codec->num_pcms = spec->num_cvts; - codec->pcm_info = info; - - for (i = 0; i < codec->num_pcms; i++, info++) { - unsigned int chans; - - chans = get_wcaps(codec, spec->cvt[i]); - chans = get_wcaps_channels(chans); - - info->name = nvhdmi_pcm_names[i]; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] - = nvhdmi_pcm_digital_playback_8ch_89; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; - } - - return 0; -} - -static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "NVIDIA HDMI"; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] - = nvhdmi_pcm_digital_playback_8ch_7x; - - return 0; -} - -static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) -{ - struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "NVIDIA HDMI"; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] - = nvhdmi_pcm_digital_playback_2ch; - - return 0; -} - -static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = { - .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms_8ch_89, - .init = nvhdmi_init, - .free = nvhdmi_free, - .unsol_event = hdmi_unsol_event, -}; - -static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { - .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms_8ch_7x, - .init = nvhdmi_init, - .free = nvhdmi_free, -}; - -static struct hda_codec_ops nvhdmi_patch_ops_2ch = { - .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms_2ch, - .init = nvhdmi_init, - .free = nvhdmi_free, -}; - -static int patch_nvhdmi_8ch_89(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - int i; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - spec->codec_type = HDA_CODEC_NVIDIA_MCP89; - spec->old_pin_detect = 1; - - if (hdmi_parse_codec(codec) < 0) { - codec->spec = NULL; - kfree(spec); - return -EINVAL; - } - codec->patch_ops = nvhdmi_patch_ops_8ch_89; - - for (i = 0; i < spec->num_pins; i++) - snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); - - init_channel_allocations(); - - return 0; -} - -static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; - spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; - spec->old_pin_detect = 1; - - codec->patch_ops = nvhdmi_patch_ops_8ch_7x; - - return 0; -} - -static int patch_nvhdmi_2ch(struct hda_codec *codec) -{ - struct hdmi_spec *spec; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 2; - spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; - spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; - spec->old_pin_detect = 1; - - codec->patch_ops = nvhdmi_patch_ops_2ch; - - return 0; -} - -/* - * patch entries - */ -static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, - { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, - { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, - { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, - {} /* terminator */ -}; - -MODULE_ALIAS("snd-hda-codec-id:10de0002"); -MODULE_ALIAS("snd-hda-codec-id:10de0003"); -MODULE_ALIAS("snd-hda-codec-id:10de0005"); -MODULE_ALIAS("snd-hda-codec-id:10de0006"); -MODULE_ALIAS("snd-hda-codec-id:10de0007"); -MODULE_ALIAS("snd-hda-codec-id:10de000a"); -MODULE_ALIAS("snd-hda-codec-id:10de000b"); -MODULE_ALIAS("snd-hda-codec-id:10de000c"); -MODULE_ALIAS("snd-hda-codec-id:10de000d"); -MODULE_ALIAS("snd-hda-codec-id:10de0010"); -MODULE_ALIAS("snd-hda-codec-id:10de0011"); -MODULE_ALIAS("snd-hda-codec-id:10de0012"); -MODULE_ALIAS("snd-hda-codec-id:10de0013"); -MODULE_ALIAS("snd-hda-codec-id:10de0014"); -MODULE_ALIAS("snd-hda-codec-id:10de0018"); -MODULE_ALIAS("snd-hda-codec-id:10de0019"); -MODULE_ALIAS("snd-hda-codec-id:10de001a"); -MODULE_ALIAS("snd-hda-codec-id:10de001b"); -MODULE_ALIAS("snd-hda-codec-id:10de001c"); -MODULE_ALIAS("snd-hda-codec-id:10de0040"); -MODULE_ALIAS("snd-hda-codec-id:10de0041"); -MODULE_ALIAS("snd-hda-codec-id:10de0042"); -MODULE_ALIAS("snd-hda-codec-id:10de0043"); -MODULE_ALIAS("snd-hda-codec-id:10de0044"); -MODULE_ALIAS("snd-hda-codec-id:10de0067"); -MODULE_ALIAS("snd-hda-codec-id:10de8001"); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec"); - -static struct hda_codec_preset_list nvhdmi_list = { - .preset = snd_hda_preset_nvhdmi, - .owner = THIS_MODULE, -}; - -static int __init patch_nvhdmi_init(void) -{ - return snd_hda_add_codec_preset(&nvhdmi_list); -} - -static void __exit patch_nvhdmi_exit(void) -{ - snd_hda_delete_codec_preset(&nvhdmi_list); -} - -module_init(patch_nvhdmi_init) -module_exit(patch_nvhdmi_exit) -- cgit v1.2.3-59-g8ed1b From f6837bbd599c2a4e1f621441f84286434bcc91ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Sep 2010 14:56:32 +0200 Subject: ALSA: hda - Fix up autocfg output pin numbers in realtek parser When quirks are applied, the numbers of output pins in autocfg aren't set up properly but only pin arrays are changed. Let's fix it up so that the rest of the parser can use autocfg.line_outs & co safely. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6045f281b225..bb3cf3b7282b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -876,6 +876,28 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } +static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (!cfg->line_outs) { + while (cfg->line_outs < AUTO_CFG_MAX_OUTS && + cfg->line_out_pins[cfg->line_outs]) + cfg->line_outs++; + } + if (!cfg->speaker_outs) { + while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS && + cfg->speaker_pins[cfg->speaker_outs]) + cfg->speaker_outs++; + } + if (!cfg->hp_outs) { + while (cfg->hp_outs < AUTO_CFG_MAX_OUTS && + cfg->hp_pins[cfg->hp_outs]) + cfg->hp_outs++; + } +} + /* */ static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix) @@ -944,6 +966,8 @@ static void setup_preset(struct hda_codec *codec, if (preset->setup) preset->setup(codec); + + alc_fixup_autocfg_pin_nums(codec); } /* Enable GPIO mask and set output */ -- cgit v1.2.3-59-g8ed1b From e1ca7b4ea29707920650d86b22afdb7e94ad5986 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Sep 2010 14:58:57 +0200 Subject: ALSA: hda - Fix initialization of multiple output pins for ALC268/269 When multiple pins are assigned to headphones or speakers, they haven't been initialized properly. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bb3cf3b7282b..c4d9ad70fde7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -13484,8 +13484,10 @@ static void alc268_auto_set_output_and_unmute(struct hda_codec *codec, static void alc268_auto_init_multi_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t nid = spec->autocfg.line_out_pins[0]; - if (nid) { + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) { + hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); alc268_auto_set_output_and_unmute(codec, nid, pin_type); } @@ -13495,13 +13497,19 @@ static void alc268_auto_init_hp_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; hda_nid_t pin; + int i; - pin = spec->autocfg.hp_pins[0]; - if (pin) + for (i = 0; i < spec->autocfg.hp_outs; i++) { + pin = spec->autocfg.hp_pins[i]; alc268_auto_set_output_and_unmute(codec, pin, PIN_HP); - pin = spec->autocfg.speaker_pins[0]; - if (pin) + } + for (i = 0; i < spec->autocfg.speaker_outs; i++) { + pin = spec->autocfg.speaker_pins[i]; alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT); + } + if (spec->autocfg.mono_out_pin) + snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) -- cgit v1.2.3-59-g8ed1b From d433a67831ab2c470cc53a3ff9b60f656767be15 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Sep 2010 15:11:54 +0200 Subject: ALSA: hda - Optimize the check of ALC269 codec variants Don't call the COEF check for checking ACL269 codec variants at each time in init but remember the type at the initialization. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c4d9ad70fde7..9bcf34eab679 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -393,6 +393,7 @@ struct alc_spec { unsigned int no_analog :1; /* digital I/O only */ unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */ int init_amp; + int codec_variant; /* flag for other variants */ /* for virtual master */ hda_nid_t vmaster_nid; @@ -14568,6 +14569,13 @@ static int alc275_setup_dual_adc(struct hda_codec *codec) return 0; } +/* different alc269-variants */ +enum { + ALC269_TYPE_NORMAL, + ALC269_TYPE_ALC259, + ALC269_TYPE_ALC271X, +}; + /* * BIOS auto configuration */ @@ -14596,7 +14604,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (spec->kctls.list) add_mixer(spec, spec->kctls.list); - if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) { + if (spec->codec_variant != ALC269_TYPE_NORMAL) { add_verb(spec, alc269vb_init_verbs); alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21); } else { @@ -14962,7 +14970,6 @@ static int patch_alc269(struct hda_codec *codec) struct alc_spec *spec; int board_config; int err; - int is_alc269vb = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -14974,11 +14981,13 @@ static int patch_alc269(struct hda_codec *codec) if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ if (codec->bus->pci->subsystem_vendor == 0x1025 && - spec->cdefine.platform_type == 1) + spec->cdefine.platform_type == 1) { alc_codec_rename(codec, "ALC271X"); - else + spec->codec_variant = ALC269_TYPE_ALC271X; + } else { alc_codec_rename(codec, "ALC259"); - is_alc269vb = 1; + spec->codec_variant = ALC269_TYPE_ALC259; + } } else alc_fix_pll_init(codec, 0x20, 0x04, 15); @@ -15040,7 +15049,7 @@ static int patch_alc269(struct hda_codec *codec) spec->stream_digital_capture = &alc269_pcm_digital_capture; if (!spec->adc_nids) { /* wasn't filled automatically? use default */ - if (!is_alc269vb) { + if (spec->codec_variant != ALC269_TYPE_NORMAL) { spec->adc_nids = alc269_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; -- cgit v1.2.3-59-g8ed1b From f3550d1b052a8acf4159b407dbdd1def47f223f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Sep 2010 15:09:03 +0200 Subject: ALSA: hda - Fix capture widget for ALC269vb and co ALC269vb and other variants don't use the widgets 0x24 but prefer the widget 0x22 instead. We need to fix the input parser. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9bcf34eab679..4abe3da1240c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14593,7 +14593,11 @@ static int alc269_parse_auto_config(struct hda_codec *codec) err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - err = alc269_auto_create_input_ctls(codec, &spec->autocfg); + if (spec->codec_variant == ALC269_TYPE_NORMAL) + err = alc269_auto_create_input_ctls(codec, &spec->autocfg); + else + err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0, + 0x22, 0); if (err < 0) return err; -- cgit v1.2.3-59-g8ed1b From 0ec33d1f952934ea3251cefc6d108b47818eedd0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 20 Sep 2010 15:20:52 +0200 Subject: ALSA: hda - Refactor ALC269 power-ups/downs in PM callbacks Create a helper function to simplify the code. Also, cleaned up the ifdef SND_HDA_NEEDS_RESUME and CONFIG_SND_HDA_POWER_SAVE. The former is always defined when the latter is set. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 51 ++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4abe3da1240c..8689216fdcce 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4128,10 +4128,8 @@ static int alc_resume(struct hda_codec *codec) codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE if (codec->patch_ops.check_power_status) codec->patch_ops.check_power_status(codec, 0x01); -#endif return 0; } #endif @@ -14656,22 +14654,26 @@ static void alc269_auto_init(struct hda_codec *codec) alc_inithook(codec); } +#ifdef SND_HDA_NEEDS_RESUME +static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) +{ + int val = alc_read_coef_idx(codec, 0x04); + if (power_up) + val |= 1 << 11; + else + val &= ~(1 << 11); + alc_write_coef_idx(codec, 0x04, val); +} + #ifdef CONFIG_SND_HDA_POWER_SAVE static int alc269_suspend(struct hda_codec *codec, pm_message_t state) { struct alc_spec *spec = codec->spec; - int val; - - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { - val = alc_read_coef_idx(codec, 0x04); - /* Power down output pin */ - alc_write_coef_idx(codec, 0x04, val & ~(1<<11)); - } + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) + alc269_toggle_power_output(codec, 0); if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - val = alc_read_coef_idx(codec, 0x04); - /* Power down output pin */ - alc_write_coef_idx(codec, 0x04, val & ~(1<<11)); + alc269_toggle_power_output(codec, 0); msleep(150); } @@ -14680,43 +14682,32 @@ static int alc269_suspend(struct hda_codec *codec, pm_message_t state) spec->power_hook(codec); return 0; } -#endif -#ifdef SND_HDA_NEEDS_RESUME +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + static int alc269_resume(struct hda_codec *codec) { - int val; - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - val = alc_read_coef_idx(codec, 0x04); - /* Power down output pin */ - alc_write_coef_idx(codec, 0x04, val & ~(1<<11)); + alc269_toggle_power_output(codec, 0); msleep(150); } codec->patch_ops.init(codec); if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) { - val = alc_read_coef_idx(codec, 0x04); - /* Power up output pin */ - alc_write_coef_idx(codec, 0x04, val | (1<<11)); + alc269_toggle_power_output(codec, 1); msleep(200); } - if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { - val = alc_read_coef_idx(codec, 0x04); - /* Power up output pin */ - alc_write_coef_idx(codec, 0x04, val | (1<<11)); - } + if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) + alc269_toggle_power_output(codec, 1); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE if (codec->patch_ops.check_power_status) codec->patch_ops.check_power_status(codec, 0x01); -#endif return 0; } -#endif +#endif /* SND_HDA_NEEDS_RESUME */ enum { ALC269_FIXUP_SONY_VAIO, -- cgit v1.2.3-59-g8ed1b From 842c74bffcdb1d305ccd9e61e417cceae86b9963 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 20 Sep 2010 10:06:12 -0700 Subject: ip_gre: CONFIG_IPV6_MODULE support ipv6 can be a module, we should test CONFIG_IPV6 and CONFIG_IPV6_MODULE to enable ipv6 bits in ip_gre. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 945b20a5ad50..35c93e8b6a46 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -45,7 +45,7 @@ #include #include -#ifdef CONFIG_IPV6 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #include #include #include @@ -699,7 +699,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; } -#ifdef CONFIG_IPV6 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (skb->protocol == htons(ETH_P_IPV6)) { struct in6_addr *addr6; int addr_type; @@ -774,7 +774,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev goto tx_error; } } -#ifdef CONFIG_IPV6 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (skb->protocol == htons(ETH_P_IPV6)) { struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); @@ -850,7 +850,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev if ((iph->ttl = tiph->ttl) == 0) { if (skb->protocol == htons(ETH_P_IP)) iph->ttl = old_iph->ttl; -#ifdef CONFIG_IPV6 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (skb->protocol == htons(ETH_P_IPV6)) iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit; #endif -- cgit v1.2.3-59-g8ed1b From df6d02300f7c2fbd0fbe626d819c8e5237d72c62 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 17 Sep 2010 00:38:25 +0200 Subject: wext: fix potential private ioctl memory content leak When a driver doesn't fill the entire buffer, old heap contents may remain, and if it also doesn't update the length properly, this old heap content will be copied back to userspace. It is very unlikely that this happens in any of the drivers using private ioctls since it would show up as junk being reported by iwpriv, but it seems better to be safe here, so use kzalloc. Reported-by: Jeff Mahoney Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/wext-priv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/wext-priv.c b/net/wireless/wext-priv.c index 3feb28e41c53..674d426a9d24 100644 --- a/net/wireless/wext-priv.c +++ b/net/wireless/wext-priv.c @@ -152,7 +152,7 @@ static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, } else if (!iwp->pointer) return -EFAULT; - extra = kmalloc(extra_size, GFP_KERNEL); + extra = kzalloc(extra_size, GFP_KERNEL); if (!extra) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 31c4a3d3a0f84a5847665f8aa0552d188389f791 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Sun, 19 Sep 2010 19:40:22 -0700 Subject: mm: further fix swapin race condition Commit 4969c1192d15 ("mm: fix swapin race condition") is now agreed to be incomplete. There's a race, not very much less likely than the original race envisaged, in which it is further necessary to check that the swapcache page's swap has not changed. Here's the reasoning: cast in terms of reuse_swap_page(), but probably could be reformulated to rely on try_to_free_swap() instead, or on swapoff+swapon. A, faults into do_swap_page(): does page1 = lookup_swap_cache(swap1) and comes through the lock_page(page1). B, a racing thread of the same process, faults on the same address: does page1 = lookup_swap_cache(swap1) and now waits in lock_page(page1), but for whatever reason is unlucky not to get the lock any time soon. A carries on through do_swap_page(), a write fault, but cannot reuse the swap page1 (another reference to swap1). Unlocks the page1 (but B doesn't get it yet), does COW in do_wp_page(), page2 now in that pte. C, perhaps the parent of A+B, comes in and write faults the same swap page1 into its mm, reuse_swap_page() succeeds this time, swap1 is freed. kswapd comes in after some time (B still unlucky) and swaps out some pages from A+B and C: it allocates the original swap1 to page2 in A+B, and some other swap2 to the original page1 now in C. But does not immediately free page1 (actually it couldn't: B holds a reference), leaving it in swap cache for now. B at last gets the lock on page1, hooray! Is PageSwapCache(page1)? Yes. Is pte_same(*page_table, orig_pte)? Yes, because page2 has now been given the swap1 which page1 used to have. So B proceeds to insert page1 into A+B's page_table, though its content now belongs to C, quite different from what A wrote there. B ought to have checked that page1's swap was still swap1. Signed-off-by: Hugh Dickins Reviewed-by: Rik van Riel Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- mm/memory.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 71b161b73bb5..0e18b4d649ec 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2680,10 +2680,12 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, delayacct_clear_flag(DELAYACCT_PF_SWAPIN); /* - * Make sure try_to_free_swap didn't release the swapcache - * from under us. The page pin isn't enough to prevent that. + * Make sure try_to_free_swap or reuse_swap_page or swapoff did not + * release the swapcache from under us. The page pin, and pte_same + * test below, are not enough to exclude that. Even if it is still + * swapcache, we need to check that the page's swap has not changed. */ - if (unlikely(!PageSwapCache(page))) + if (unlikely(!PageSwapCache(page) || page_private(page) != entry.val)) goto out_page; if (ksm_might_need_to_copy(page, vma, address)) { -- cgit v1.2.3-59-g8ed1b From 20cd514d0f3d288d968217028ca67b70e707d896 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Sep 2010 15:13:04 +0100 Subject: frv: restart_block.fn needs to be reset on sigreturn Reset restart_block.fn on executing a sigreturn such that any currently pending system call restarts will be forced to return -EINTR. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/frv/kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 0974c0ecc594..7fc29615ef01 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -121,6 +121,9 @@ static int restore_sigcontext(struct sigcontext __user *sc, int *_gr8) struct user_context *user = current->thread.user; unsigned long tbr, psr; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + tbr = user->i.tbr; psr = user->i.psr; if (copy_from_user(user, &sc->sc_context, sizeof(sc->sc_context))) -- cgit v1.2.3-59-g8ed1b From 5f4ad04a1e805d14de080ff9d5384b4d20518a9a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Sep 2010 15:13:09 +0100 Subject: frv: fix address verification holes in setup_frame/setup_rt_frame a) sa_handler might be maliciously set to point to kernel memory; blindly dereferencing it in FDPIC case is a Bad Idea(tm). b) I'm not sure you need that set_fs(USER_DS) there at all, but if you do, you'd better do it *before* checking the frame you've decided to use with access_ok(), lest sigaltstack() becomes a convenient roothole. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/frv/kernel/signal.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 7fc29615ef01..5fb2d0661c78 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -253,6 +253,8 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) struct sigframe __user *frame; int rsig; + set_fs(USER_DS); + frame = get_sigframe(ka, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) @@ -296,22 +298,23 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) (unsigned long) (frame->retcode + 2)); } - /* set up registers for signal handler */ - __frame->sp = (unsigned long) frame; - __frame->lr = (unsigned long) &frame->retcode; - __frame->gr8 = sig; - + /* Set up registers for the signal handler */ if (current->personality & FDPIC_FUNCPTRS) { struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; - __get_user(__frame->pc, &funcptr->text); - __get_user(__frame->gr15, &funcptr->GOT); + struct fdpic_func_descriptor desc; + if (copy_from_user(&desc, funcptr, sizeof(desc))) + goto give_sigsegv; + __frame->pc = desc.text; + __frame->gr15 = desc.GOT; } else { __frame->pc = (unsigned long) ka->sa.sa_handler; __frame->gr15 = 0; } - set_fs(USER_DS); + __frame->sp = (unsigned long) frame; + __frame->lr = (unsigned long) &frame->retcode; + __frame->gr8 = sig; /* the tracer may want to single-step inside the handler */ if (test_thread_flag(TIF_SINGLESTEP)) @@ -341,6 +344,8 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, struct rt_sigframe __user *frame; int rsig; + set_fs(USER_DS); + frame = get_sigframe(ka, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) @@ -395,22 +400,23 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } /* Set up registers for signal handler */ - __frame->sp = (unsigned long) frame; - __frame->lr = (unsigned long) &frame->retcode; - __frame->gr8 = sig; - __frame->gr9 = (unsigned long) &frame->info; - if (current->personality & FDPIC_FUNCPTRS) { struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; - __get_user(__frame->pc, &funcptr->text); - __get_user(__frame->gr15, &funcptr->GOT); + struct fdpic_func_descriptor desc; + if (copy_from_user(&desc, funcptr, sizeof(desc))) + goto give_sigsegv; + __frame->pc = desc.text; + __frame->gr15 = desc.GOT; } else { __frame->pc = (unsigned long) ka->sa.sa_handler; __frame->gr15 = 0; } - set_fs(USER_DS); + __frame->sp = (unsigned long) frame; + __frame->lr = (unsigned long) &frame->retcode; + __frame->gr8 = sig; + __frame->gr9 = (unsigned long) &frame->info; /* the tracer may want to single-step inside the handler */ if (test_thread_flag(TIF_SINGLESTEP)) -- cgit v1.2.3-59-g8ed1b From ad0acab4557a91a60251b3ffe3478fad572d6f61 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Sep 2010 15:13:14 +0100 Subject: frv: avoid infinite loop of SIGSEGV delivery Use force_sigsegv() rather than force_sig(SIGSEGV, ...) as the former resets the SEGV handler pointer which will kill the process, rather than leaving it open to an infinite loop if the SEGV handler itself caused a SEGV signal. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/frv/kernel/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 5fb2d0661c78..48203c68e39f 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -329,7 +329,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) return 0; give_sigsegv: - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); return -EFAULT; } /* end setup_frame() */ @@ -431,7 +431,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return 0; give_sigsegv: - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); return -EFAULT; } /* end setup_rt_frame() */ -- cgit v1.2.3-59-g8ed1b From 44c7afffa429a7cdcd1755019ab76566ff41e66d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Sep 2010 15:13:19 +0100 Subject: frv: handling of restart into restart_syscall is fscked do_signal() should place the syscall number in gr7, not gr8 when handling ERESTART_WOULDBLOCK. Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/frv/kernel/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 48203c68e39f..bd13b57a5c9b 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -547,7 +547,7 @@ no_signal: break; case -ERESTART_RESTARTBLOCK: - __frame->gr8 = __NR_restart_syscall; + __frame->gr7 = __NR_restart_syscall; __frame->pc -= 4; break; } -- cgit v1.2.3-59-g8ed1b From ed1cde68365c1251b920900c51e73675ff38dc66 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Sep 2010 15:13:25 +0100 Subject: frv: double syscall restarts, syscall restart in sigreturn() We need to make sure that only the first do_signal() to be handled on the way out syscall will bother with syscall restarts; additionally, the check on the "signal has user handler" path had been wrong - compare with restart prevention in sigreturn()... Signed-off-by: Al Viro Signed-off-by: David Howells Signed-off-by: Linus Torvalds --- arch/frv/kernel/signal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index bd13b57a5c9b..bab01298b58e 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -446,7 +446,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info, int ret; /* Are we from a system call? */ - if (in_syscall(__frame)) { + if (__frame->syscallno != -1) { /* If so, check system call restarting.. */ switch (__frame->gr8) { case -ERESTART_RESTARTBLOCK: @@ -465,6 +465,7 @@ static int handle_signal(unsigned long sig, siginfo_t *info, __frame->gr8 = __frame->orig_gr8; __frame->pc -= 4; } + __frame->syscallno = -1; } /* Set up the stack frame */ @@ -551,6 +552,7 @@ no_signal: __frame->pc -= 4; break; } + __frame->syscallno = -1; } /* if there's no signal to deliver, we just put the saved sigmask -- cgit v1.2.3-59-g8ed1b From 8444cf712c5f71845cba9dc30d8f530ff0d5ff83 Mon Sep 17 00:00:00 2001 From: Thomas Egerer Date: Mon, 20 Sep 2010 11:11:38 -0700 Subject: xfrm: Allow different selector family in temporary state The family parameter xfrm_state_find is used to find a state matching a certain policy. This value is set to the template's family (encap_family) right before xfrm_state_find is called. The family parameter is however also used to construct a temporary state in xfrm_state_find itself which is wrong for inter-family scenarios because it produces a selector for the wrong family. Since this selector is included in the xfrm_user_acquire structure, user space programs misinterpret IPv6 addresses as IPv4 and vice versa. This patch splits up the original init_tempsel function into a part that initializes the selector respectively the props and id of the temporary state, to allow for differing ip address families whithin the state. Signed-off-by: Thomas Egerer Signed-off-by: Steffen Klassert Signed-off-by: David S. Miller --- include/net/xfrm.h | 4 ++-- net/ipv4/xfrm4_state.c | 33 +++++++++++++++++++-------------- net/ipv6/xfrm6_state.c | 33 +++++++++++++++++++-------------- net/xfrm/xfrm_policy.c | 5 ++--- net/xfrm/xfrm_state.c | 45 +++++++++++++++++++++++++++------------------ 5 files changed, 69 insertions(+), 51 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index fc8f36dd0f5c..4f53532d4c2f 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -298,8 +298,8 @@ struct xfrm_state_afinfo { const struct xfrm_type *type_map[IPPROTO_MAX]; struct xfrm_mode *mode_map[XFRM_MODE_MAX]; int (*init_flags)(struct xfrm_state *x); - void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, - struct xfrm_tmpl *tmpl, + void (*init_tempsel)(struct xfrm_selector *sel, struct flowi *fl); + void (*init_temprop)(struct xfrm_state *x, struct xfrm_tmpl *tmpl, xfrm_address_t *daddr, xfrm_address_t *saddr); int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 1ef1366a0a03..47947624eccc 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -21,21 +21,25 @@ static int xfrm4_init_flags(struct xfrm_state *x) } static void -__xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, - struct xfrm_tmpl *tmpl, - xfrm_address_t *daddr, xfrm_address_t *saddr) +__xfrm4_init_tempsel(struct xfrm_selector *sel, struct flowi *fl) +{ + sel->daddr.a4 = fl->fl4_dst; + sel->saddr.a4 = fl->fl4_src; + sel->dport = xfrm_flowi_dport(fl); + sel->dport_mask = htons(0xffff); + sel->sport = xfrm_flowi_sport(fl); + sel->sport_mask = htons(0xffff); + sel->family = AF_INET; + sel->prefixlen_d = 32; + sel->prefixlen_s = 32; + sel->proto = fl->proto; + sel->ifindex = fl->oif; +} + +static void +xfrm4_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr) { - x->sel.daddr.a4 = fl->fl4_dst; - x->sel.saddr.a4 = fl->fl4_src; - x->sel.dport = xfrm_flowi_dport(fl); - x->sel.dport_mask = htons(0xffff); - x->sel.sport = xfrm_flowi_sport(fl); - x->sel.sport_mask = htons(0xffff); - x->sel.family = AF_INET; - x->sel.prefixlen_d = 32; - x->sel.prefixlen_s = 32; - x->sel.proto = fl->proto; - x->sel.ifindex = fl->oif; x->id = tmpl->id; if (x->id.daddr.a4 == 0) x->id.daddr.a4 = daddr->a4; @@ -70,6 +74,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = { .owner = THIS_MODULE, .init_flags = xfrm4_init_flags, .init_tempsel = __xfrm4_init_tempsel, + .init_temprop = xfrm4_init_temprop, .output = xfrm4_output, .extract_input = xfrm4_extract_input, .extract_output = xfrm4_extract_output, diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index f417b77fa0e1..a67575d472a3 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -20,23 +20,27 @@ #include static void -__xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, - struct xfrm_tmpl *tmpl, - xfrm_address_t *daddr, xfrm_address_t *saddr) +__xfrm6_init_tempsel(struct xfrm_selector *sel, struct flowi *fl) { /* Initialize temporary selector matching only * to current session. */ - ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst); - ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src); - x->sel.dport = xfrm_flowi_dport(fl); - x->sel.dport_mask = htons(0xffff); - x->sel.sport = xfrm_flowi_sport(fl); - x->sel.sport_mask = htons(0xffff); - x->sel.family = AF_INET6; - x->sel.prefixlen_d = 128; - x->sel.prefixlen_s = 128; - x->sel.proto = fl->proto; - x->sel.ifindex = fl->oif; + ipv6_addr_copy((struct in6_addr *)&sel->daddr, &fl->fl6_dst); + ipv6_addr_copy((struct in6_addr *)&sel->saddr, &fl->fl6_src); + sel->dport = xfrm_flowi_dport(fl); + sel->dport_mask = htons(0xffff); + sel->sport = xfrm_flowi_sport(fl); + sel->sport_mask = htons(0xffff); + sel->family = AF_INET6; + sel->prefixlen_d = 128; + sel->prefixlen_s = 128; + sel->proto = fl->proto; + sel->ifindex = fl->oif; +} + +static void +xfrm6_init_temprop(struct xfrm_state *x, struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr) +{ x->id = tmpl->id; if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); @@ -168,6 +172,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = { .eth_proto = htons(ETH_P_IPV6), .owner = THIS_MODULE, .init_tempsel = __xfrm6_init_tempsel, + .init_temprop = xfrm6_init_temprop, .tmpl_sort = __xfrm6_tmpl_sort, .state_sort = __xfrm6_state_sort, .output = xfrm6_output, diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 2b3ed7ad4933..cbab6e1a8c9c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1175,9 +1175,8 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, tmpl->mode == XFRM_MODE_BEET) { remote = &tmpl->id.daddr; local = &tmpl->saddr; - family = tmpl->encap_family; - if (xfrm_addr_any(local, family)) { - error = xfrm_get_saddr(net, &tmp, remote, family); + if (xfrm_addr_any(local, tmpl->encap_family)) { + error = xfrm_get_saddr(net, &tmp, remote, tmpl->encap_family); if (error) goto fail; local = &tmp; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 5208b12fbfb4..eb96ce52f178 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -656,15 +656,23 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) EXPORT_SYMBOL(xfrm_sad_getinfo); static int -xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, - struct xfrm_tmpl *tmpl, - xfrm_address_t *daddr, xfrm_address_t *saddr, - unsigned short family) +xfrm_init_tempstate(struct xfrm_state *x, struct flowi *fl, + struct xfrm_tmpl *tmpl, + xfrm_address_t *daddr, xfrm_address_t *saddr, + unsigned short family) { struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); if (!afinfo) return -1; - afinfo->init_tempsel(x, fl, tmpl, daddr, saddr); + afinfo->init_tempsel(&x->sel, fl); + + if (family != tmpl->encap_family) { + xfrm_state_put_afinfo(afinfo); + afinfo = xfrm_state_get_afinfo(tmpl->encap_family); + if (!afinfo) + return -1; + } + afinfo->init_temprop(x, tmpl, daddr, saddr); xfrm_state_put_afinfo(afinfo); return 0; } @@ -790,37 +798,38 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, int error = 0; struct xfrm_state *best = NULL; u32 mark = pol->mark.v & pol->mark.m; + unsigned short encap_family = tmpl->encap_family; to_put = NULL; spin_lock_bh(&xfrm_state_lock); - h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family); + h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { - if (x->props.family == family && + if (x->props.family == encap_family && x->props.reqid == tmpl->reqid && (mark & x->mark.m) == x->mark.v && !(x->props.flags & XFRM_STATE_WILDRECV) && - xfrm_state_addr_check(x, daddr, saddr, family) && + xfrm_state_addr_check(x, daddr, saddr, encap_family) && tmpl->mode == x->props.mode && tmpl->id.proto == x->id.proto && (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) - xfrm_state_look_at(pol, x, fl, family, daddr, saddr, + xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr, &best, &acquire_in_progress, &error); } if (best) goto found; - h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family); + h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { - if (x->props.family == family && + if (x->props.family == encap_family && x->props.reqid == tmpl->reqid && (mark & x->mark.m) == x->mark.v && !(x->props.flags & XFRM_STATE_WILDRECV) && - xfrm_state_addr_check(x, daddr, saddr, family) && + xfrm_state_addr_check(x, daddr, saddr, encap_family) && tmpl->mode == x->props.mode && tmpl->id.proto == x->id.proto && (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) - xfrm_state_look_at(pol, x, fl, family, daddr, saddr, + xfrm_state_look_at(pol, x, fl, encap_family, daddr, saddr, &best, &acquire_in_progress, &error); } @@ -829,7 +838,7 @@ found: if (!x && !error && !acquire_in_progress) { if (tmpl->id.spi && (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, - tmpl->id.proto, family)) != NULL) { + tmpl->id.proto, encap_family)) != NULL) { to_put = x0; error = -EEXIST; goto out; @@ -839,9 +848,9 @@ found: error = -ENOMEM; goto out; } - /* Initialize temporary selector matching only + /* Initialize temporary state matching only * to current session. */ - xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); + xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); memcpy(&x->mark, &pol->mark, sizeof(x->mark)); error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); @@ -856,10 +865,10 @@ found: x->km.state = XFRM_STATE_ACQ; list_add(&x->km.all, &net->xfrm.state_all); hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); - h = xfrm_src_hash(net, daddr, saddr, family); + h = xfrm_src_hash(net, daddr, saddr, encap_family); hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h); if (x->id.spi) { - h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family); + h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); } x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; -- cgit v1.2.3-59-g8ed1b From af6261031317f646d22f994c0b467521e47aa49f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 20 Sep 2010 10:31:40 +0100 Subject: drm/i915: Hold a reference to the object whilst unbinding the eviction list During heavy aperture thrashing we may be forced to wait upon several active objects during eviction. The active list may be the last reference to these objects and so the action of waiting upon one of them may cause another to be freed (and itself unbound). To prevent the object disappearing underneath us, we need to acquire and hold a reference whilst unbinding. This should fix the reported page refcount OOPS: kernel BUG at drivers/gpu/drm/i915/i915_gem.c:1444! ... RIP: 0010:[] [] i915_gem_object_put_pages+0x25/0xf5 [i915] Call Trace: [] i915_gem_object_unbind+0xc5/0x1a7 [i915] [] i915_gem_evict_something+0x3bd/0x409 [i915] [] ? drm_gem_object_lookup+0x27/0x57 [drm] [] i915_gem_object_bind_to_gtt+0x1d3/0x279 [i915] [] i915_gem_object_pin+0xa3/0x146 [i915] [] ? drm_gem_object_lookup+0x4c/0x57 [drm] [] i915_gem_do_execbuffer+0x50d/0xe32 [i915] Reported-by: Shawn Starr Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=18902 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem_evict.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 72cae3cccad8..e85246ef691c 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -79,6 +79,7 @@ mark_free(struct drm_i915_gem_object *obj_priv, struct list_head *unwind) { list_add(&obj_priv->evict_list, unwind); + drm_gem_object_reference(&obj_priv->base); return drm_mm_scan_add_block(obj_priv->gtt_space); } @@ -165,6 +166,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignmen list_for_each_entry(obj_priv, &unwind_list, evict_list) { ret = drm_mm_scan_remove_block(obj_priv->gtt_space); BUG_ON(ret); + drm_gem_object_unreference(&obj_priv->base); } /* We expect the caller to unpin, evict all and try again, or give up. @@ -181,18 +183,21 @@ found: * scanning, therefore store to be evicted objects on a * temporary list. */ list_move(&obj_priv->evict_list, &eviction_list); - } + } else + drm_gem_object_unreference(&obj_priv->base); } /* Unbinding will emit any required flushes */ list_for_each_entry_safe(obj_priv, tmp_obj_priv, &eviction_list, evict_list) { #if WATCH_LRU - DRM_INFO("%s: evicting %p\n", __func__, obj); + DRM_INFO("%s: evicting %p\n", __func__, &obj_priv->base); #endif ret = i915_gem_object_unbind(&obj_priv->base); if (ret) return ret; + + drm_gem_object_unreference(&obj_priv->base); } /* The just created free hole should be on the top of the free stack -- cgit v1.2.3-59-g8ed1b From 9828e6e6e3f19efcb476c567b9999891d051f52f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 20 Sep 2010 15:40:35 -0700 Subject: rose: Fix signedness issues wrt. digi count. Just use explicit casts, since we really can't change the types of structures exported to userspace which have been around for 15 years or so. Reported-by: Dan Rosenberg Signed-off-by: David S. Miller --- net/rose/af_rose.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 8e45e76a95f5..d952e7eac188 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -679,7 +679,7 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1) return -EINVAL; - if (addr->srose_ndigis > ROSE_MAX_DIGIS) + if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS) return -EINVAL; if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) { @@ -739,7 +739,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1) return -EINVAL; - if (addr->srose_ndigis > ROSE_MAX_DIGIS) + if ((unsigned int) addr->srose_ndigis > ROSE_MAX_DIGIS) return -EINVAL; /* Source + Destination digis should not exceed ROSE_MAX_DIGIS */ -- cgit v1.2.3-59-g8ed1b From a4d258036ed9b2a1811c3670c6099203a0f284a0 Mon Sep 17 00:00:00 2001 From: Tom Marshall Date: Mon, 20 Sep 2010 15:42:05 -0700 Subject: tcp: Fix race in tcp_poll If a RST comes in immediately after checking sk->sk_err, tcp_poll will return POLLIN but not POLLOUT. Fix this by checking sk->sk_err at the end of tcp_poll. Additionally, ensure the correct order of operations on SMP machines with memory barriers. Signed-off-by: Tom Marshall Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 7 +++++-- net/ipv4/tcp_input.c | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 3fb1428e526e..95d75d443927 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -386,8 +386,6 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) */ mask = 0; - if (sk->sk_err) - mask = POLLERR; /* * POLLHUP is certainly not done right. But poll() doesn't @@ -457,6 +455,11 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) if (tp->urg_data & TCP_URG_VALID) mask |= POLLPRI; } + /* This barrier is coupled with smp_wmb() in tcp_reset() */ + smp_rmb(); + if (sk->sk_err) + mask |= POLLERR; + return mask; } EXPORT_SYMBOL(tcp_poll); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e663b78a2ef6..149e79ac2891 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4048,6 +4048,8 @@ static void tcp_reset(struct sock *sk) default: sk->sk_err = ECONNRESET; } + /* This barrier is coupled with smp_rmb() in tcp_poll() */ + smp_wmb(); if (!sock_flag(sk, SOCK_DEAD)) sk->sk_error_report(sk); -- cgit v1.2.3-59-g8ed1b From 024cfa5943a7e89565c60b612d698c2bfb3da66a Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Mon, 6 Sep 2010 13:52:01 +0300 Subject: usb: musb_debugfs: don't use the struct file private_data field with seq_files seq_files use the private_data field of a file struct for storing a seq_file structure, data should be stored in seq_file's own private field (e.g. file->private_data->private) Otherwise seq_release() will free the private data when the file is closed. Signed-off-by: Mathias Nyman Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_debugfs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index c79a5e30d437..9e8639d4e862 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -195,15 +195,14 @@ static const struct file_operations musb_regdump_fops = { static int musb_test_mode_open(struct inode *inode, struct file *file) { - file->private_data = inode->i_private; - return single_open(file, musb_test_mode_show, inode->i_private); } static ssize_t musb_test_mode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { - struct musb *musb = file->private_data; + struct seq_file *s = file->private_data; + struct musb *musb = s->private; u8 test = 0; char buf[18]; -- cgit v1.2.3-59-g8ed1b From fc9282506114d4be188a464af2d373db31dd781c Mon Sep 17 00:00:00 2001 From: Alek Du Date: Mon, 6 Sep 2010 14:50:57 +0100 Subject: USB: EHCI: Disable langwell/penwell LPM capability We have to do so due to HW limitation. Signed-off-by: Alek Du Signed-off-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 58b72d741d93..a1e8d273103f 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -119,6 +119,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ehci->broken_periodic = 1; ehci_info(ehci, "using broken periodic workaround\n"); } + if (pdev->device == 0x0806 || pdev->device == 0x0811 + || pdev->device == 0x0829) { + ehci_info(ehci, "disable lpm for langwell/penwell\n"); + ehci->has_lpm = 0; + } break; case PCI_VENDOR_ID_TDI: if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { -- cgit v1.2.3-59-g8ed1b From fc8f2a7608d855b911e35a33e771e6358c705c43 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 6 Sep 2010 23:27:09 +0800 Subject: USB: otg: twl4030: fix phy initialization(v1) Commit 461c317705eca5cac09a360f488715927fd0a927(into 2.6.36-v3) is put forward to power down phy if no usb cable is connected, but does introduce the two issues below: 1), phy is not into work state if usb cable is connected with PC during poweron, so musb device mode is not usable in such case, follows the reasons: -twl4030_phy_resume is not called, so regulators are not enabled i2c access are not enabled usb mode not configurated 2), The kernel warings[1] of regulators 'unbalanced disables' is caused if poweron without usb cable connected with PC or b-device. This patch fixes the two issues above: -power down phy only if no usb cable is connected with PC and b-device -do phy initialization(via __twl4030_phy_resume) if usb cable is connected with PC(vbus event) or another b-device(ID event) in twl4030_usb_probe. This patch also doesn't put VUSB3V1 LDO into active mode in twl4030_usb_ldo_init until VBUS/ID change detected, so we can save more power consumption than before. This patch is verified OK on Beagle board either connected with usb cable or not when poweron. [1]. warnings of 'unbalanced disables' of regulators. [root@OMAP3EVM /]# dmesg ------------[ cut here ]------------ WARNING: at drivers/regulator/core.c:1357 _regulator_disable+0x38/0x128() unbalanced disables for VUSB1V8 Modules linked in: Backtrace: [] (dump_backtrace+0x0/0x110) from [] (dump_stack+0x18/0x1c) r7:c78179d8 r6:c01ed6b8 r5:c0410822 r4:0000054d [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x54/0x6c) [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_fmt+0x38/0x40) r9:00000000 r8:00000000 r7:c78e6608 r6:00000000 r5:fffffffb r4:c78e6c00 [] (warn_slowpath_fmt+0x0/0x40) from [] (_regulator_disable+0x38/0x128) r3:c0410e53 r2:c0410ad5 [] (_regulator_disable+0x0/0x128) from [] (regulator_disable+0x24/0x38) r7:c78e6608 r6:00000000 r5:c78e6c40 r4:c78e6c00 [] (regulator_disable+0x0/0x38) from [] (twl4030_phy_power+0x15c/0x17c) r5:c78595c0 r4:00000000 [] (twl4030_phy_power+0x0/0x17c) from [] (twl4030_phy_suspend+0x20/0x2c) r6:00000000 r5:c78595c0 r4:c78595c0 [] (twl4030_phy_suspend+0x0/0x2c) from [] (twl4030_usb_irq+0x11c/0x16c) r5:c78595c0 r4:00000040 [] (twl4030_usb_irq+0x0/0x16c) from [] (twl4030_usb_probe+0x2c4/0x32c) r6:00000000 r5:00000000 r4:c78595c0 [] (twl4030_usb_probe+0x0/0x32c) from [] (platform_drv_probe+0x20/0x24) r7:00000000 r6:c047d49c r5:c78e6608 r4:c047d49c [] (platform_drv_probe+0x0/0x24) from [] (driver_probe_device+0xd0/0x190) [] (driver_probe_device+0x0/0x190) from [] (__device_attach+0x44/0x48) r7:00000000 r6:c78e6608 r5:c78e6608 r4:c047d49c [] (__device_attach+0x0/0x48) from [] (bus_for_each_drv+0x50/0x90) r5:c0214390 r4:00000000 [] (bus_for_each_drv+0x0/0x90) from [] (device_attach+0x70/0x94) r6:c78e663c r5:c78e6608 r4:c78e6608 [] (device_attach+0x0/0x94) from [] (bus_probe_device+0x2c/0x48) r7:00000000 r6:00000002 r5:c78e6608 r4:c78e6600 [] (bus_probe_device+0x0/0x48) from [] (device_add+0x340/0x4b4) [] (device_add+0x0/0x4b4) from [] (platform_device_add+0x110/0x16c) [] (platform_device_add+0x0/0x16c) from [] (add_numbered_child+0xd8/0x118) r7:00000000 r6:c045f15c r5:c78e6600 r4:00000000 [] (add_numbered_child+0x0/0x118) from [] (twl_probe+0x3a4/0x72c) [] (twl_probe+0x0/0x72c) from [] (i2c_device_probe+0x7c/0xa4) [] (i2c_device_probe+0x0/0xa4) from [] (driver_probe_device+0xd0/0x190) r5:c7856e20 r4:c047c860 [] (driver_probe_device+0x0/0x190) from [] (__device_attach+0x44/0x48) r7:c7856e04 r6:c7856e20 r5:c7856e20 r4:c047c860 [] (__device_attach+0x0/0x48) from [] (bus_for_each_drv+0x50/0x90) r5:c0214390 r4:00000000 [] (bus_for_each_drv+0x0/0x90) from [] (device_attach+0x70/0x94) r6:c7856e54 r5:c7856e20 r4:c7856e20 [] (device_attach+0x0/0x94) from [] (bus_probe_device+0x2c/0x48) r7:c7856e04 r6:c78fd048 r5:c7856e20 r4:c7856e20 [] (bus_probe_device+0x0/0x48) from [] (device_add+0x340/0x4b4) [] (device_add+0x0/0x4b4) from [] (device_register+0x1c/0x20) [] (device_register+0x0/0x20) from [] (i2c_new_device+0xec/0x150) r5:c7856e00 r4:c7856e20 [] (i2c_new_device+0x0/0x150) from [] (i2c_register_adapter+0xa0/0x1c4) r7:00000000 r6:c78fd078 r5:c78fd048 r4:c781d5c0 [] (i2c_register_adapter+0x0/0x1c4) from [] (i2c_add_numbered_adapter+0x9c/0xb4) r7:00000a28 r6:c04600a8 r5:c78fd048 r4:00000000 [] (i2c_add_numbered_adapter+0x0/0xb4) from [] (omap_i2c_probe+0x324/0x3e8) r5:00000000 r4:c78fd000 [] (omap_i2c_probe+0x0/0x3e8) from [] (platform_drv_probe+0x20/0x24) [] (platform_drv_probe+0x0/0x24) from [] (driver_probe_device+0xd0/0x190) [] (driver_probe_device+0x0/0x190) from [] (__driver_attach+0x68/0x8c) r7:c78b2140 r6:c047e214 r5:c04600e4 r4:c04600b0 [] (__driver_attach+0x0/0x8c) from [] (bus_for_each_dev+0x50/0x84) r7:c78b2140 r6:c047e214 r5:c0214304 r4:00000000 [] (bus_for_each_dev+0x0/0x84) from [] (driver_attach+0x20/0x28) r6:c047e214 r5:c047e214 r4:c00270d0 [] (driver_attach+0x0/0x28) from [] (bus_add_driver+0xa8/0x228) [] (bus_add_driver+0x0/0x228) from [] (driver_register+0xb0/0x13c) [] (driver_register+0x0/0x13c) from [] (platform_driver_register+0x4c/0x60) r9:00000000 r8:c001f688 r7:00000013 r6:c005b6fc r5:c00083dc r4:c00270d0 [] (platform_driver_register+0x0/0x60) from [] (omap_i2c_init_driver+0x14/0x1c) [] (omap_i2c_init_driver+0x0/0x1c) from [] (do_one_initcall+0xd0/0x1a4) [] (do_one_initcall+0x0/0x1a4) from [] (kernel_init+0x9c/0x154) [] (kernel_init+0x0/0x154) from [] (do_exit+0x0/0x688) r5:c00083dc r4:00000000 ---[ end trace 1b75b31a2719ed1d ]--- Signed-off-by: Ming Lei Cc: David Brownell Cc: Felipe Balbi Cc: Anand Gadiyar Cc: Mike Frysinger Cc: Sergei Shtylyov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/otg/twl4030-usb.c | 78 ++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 05aaac1c3861..0bc97698af15 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -347,11 +347,20 @@ static void twl4030_i2c_access(struct twl4030_usb *twl, int on) } } -static void twl4030_phy_power(struct twl4030_usb *twl, int on) +static void __twl4030_phy_power(struct twl4030_usb *twl, int on) { - u8 pwr; + u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); + + if (on) + pwr &= ~PHY_PWR_PHYPWD; + else + pwr |= PHY_PWR_PHYPWD; - pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); + WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); +} + +static void twl4030_phy_power(struct twl4030_usb *twl, int on) +{ if (on) { regulator_enable(twl->usb3v1); regulator_enable(twl->usb1v8); @@ -365,15 +374,13 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on) twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); regulator_enable(twl->usb1v5); - pwr &= ~PHY_PWR_PHYPWD; - WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); + __twl4030_phy_power(twl, 1); twl4030_usb_write(twl, PHY_CLK_CTRL, twl4030_usb_read(twl, PHY_CLK_CTRL) | (PHY_CLK_CTRL_CLOCKGATING_EN | PHY_CLK_CTRL_CLK32K_EN)); - } else { - pwr |= PHY_PWR_PHYPWD; - WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); + } else { + __twl4030_phy_power(twl, 0); regulator_disable(twl->usb1v5); regulator_disable(twl->usb1v8); regulator_disable(twl->usb3v1); @@ -387,19 +394,25 @@ static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off) twl4030_phy_power(twl, 0); twl->asleep = 1; + dev_dbg(twl->dev, "%s\n", __func__); } -static void twl4030_phy_resume(struct twl4030_usb *twl) +static void __twl4030_phy_resume(struct twl4030_usb *twl) { - if (!twl->asleep) - return; - twl4030_phy_power(twl, 1); twl4030_i2c_access(twl, 1); twl4030_usb_set_mode(twl, twl->usb_mode); if (twl->usb_mode == T2_USB_MODE_ULPI) twl4030_i2c_access(twl, 0); +} + +static void twl4030_phy_resume(struct twl4030_usb *twl) +{ + if (!twl->asleep) + return; + __twl4030_phy_resume(twl); twl->asleep = 0; + dev_dbg(twl->dev, "%s\n", __func__); } static int twl4030_usb_ldo_init(struct twl4030_usb *twl) @@ -408,8 +421,8 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl) twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY); twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY); - /* put VUSB3V1 LDO in active state */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); + /* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/ + /*twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/ /* input to VUSB3V1 LDO is from VBAT, not VBUS */ twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); @@ -502,6 +515,26 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) return IRQ_HANDLED; } +static void twl4030_usb_phy_init(struct twl4030_usb *twl) +{ + int status; + + status = twl4030_usb_linkstat(twl); + if (status >= 0) { + if (status == USB_EVENT_NONE) { + __twl4030_phy_power(twl, 0); + twl->asleep = 1; + } else { + __twl4030_phy_resume(twl); + twl->asleep = 0; + } + + blocking_notifier_call_chain(&twl->otg.notifier, status, + twl->otg.gadget); + } + sysfs_notify(&twl->dev->kobj, NULL, "vbus"); +} + static int twl4030_set_suspend(struct otg_transceiver *x, int suspend) { struct twl4030_usb *twl = xceiv_to_twl(x); @@ -550,7 +583,6 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) struct twl4030_usb_data *pdata = pdev->dev.platform_data; struct twl4030_usb *twl; int status, err; - u8 pwr; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); @@ -569,10 +601,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) twl->otg.set_peripheral = twl4030_set_peripheral; twl->otg.set_suspend = twl4030_set_suspend; twl->usb_mode = pdata->usb_mode; - - pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); - - twl->asleep = (pwr & PHY_PWR_PHYPWD); + twl->asleep = 1; /* init spinlock for workqueue */ spin_lock_init(&twl->lock); @@ -610,15 +639,10 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) return status; } - /* The IRQ handler just handles changes from the previous states - * of the ID and VBUS pins ... in probe() we must initialize that - * previous state. The easy way: fake an IRQ. - * - * REVISIT: a real IRQ might have happened already, if PREEMPT is - * enabled. Else the IRQ may not yet be configured or enabled, - * because of scheduling delays. + /* Power down phy or make it work according to + * current link state. */ - twl4030_usb_irq(twl->irq, twl); + twl4030_usb_phy_init(twl); dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); return 0; -- cgit v1.2.3-59-g8ed1b From a0846f1868b11cd827bdfeaf4527d8b1b1c0b098 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 15 Sep 2010 17:44:16 -0400 Subject: USB: serial/mos*: prevent reading uninitialized stack memory The TIOCGICOUNT device ioctl in both mos7720.c and mos7840.c allows unprivileged users to read uninitialized stack memory, because the "reserved" member of the serial_icounter_struct struct declared on the stack is not altered or zeroed before being copied back to the user. This patch takes care of it. Signed-off-by: Dan Rosenberg Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mos7720.c | 3 +++ drivers/usb/serial/mos7840.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 30922a7e3347..aa665817a272 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -2024,6 +2024,9 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file, case TIOCGICOUNT: cnow = mos7720_port->icount; + + memset(&icount, 0, sizeof(struct serial_icounter_struct)); + icount.cts = cnow.cts; icount.dsr = cnow.dsr; icount.rng = cnow.rng; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 1c9b6e9b2386..1a42bc213799 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2285,6 +2285,9 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file, case TIOCGICOUNT: cnow = mos7840_port->icount; smp_rmb(); + + memset(&icount, 0, sizeof(struct serial_icounter_struct)); + icount.cts = cnow.cts; icount.dsr = cnow.dsr; icount.rng = cnow.rng; -- cgit v1.2.3-59-g8ed1b From f299470a15ab3057afbf598cec59246a90ade449 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 9 Sep 2010 09:04:25 +0300 Subject: USB: musb: MAINTAINERS: Fix my mail address If we don't, contributors to musb and any USB OMAP code will be sending mails to an unexistent inbox. Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 411b0d04f69b..50b8148448fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3942,7 +3942,7 @@ F: drivers/char/isicom.c F: include/linux/isicom.h MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER -M: Felipe Balbi +M: Felipe Balbi L: linux-usb@vger.kernel.org T: git git://gitorious.org/usb/usb.git S: Maintained @@ -4240,7 +4240,7 @@ S: Maintained F: drivers/char/hw_random/omap-rng.c OMAP USB SUPPORT -M: Felipe Balbi +M: Felipe Balbi M: David Brownell L: linux-usb@vger.kernel.org L: linux-omap@vger.kernel.org -- cgit v1.2.3-59-g8ed1b From 476f771cb9b6cd4845dcd18f16a2f03a89ee63fc Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Sat, 4 Sep 2010 10:23:23 +0300 Subject: serial: amba-pl010: fix set_ldisc Commit d87d9b7d1 ("tty: serial - fix tty referencing in set_ldisc") changed set_ldisc to take ldisc number as parameter. This patch fixes AMBA PL010 driver according the new prototype. Signed-off-by: Mika Westerberg Cc: Alan Cox Cc: Russell King Signed-off-by: Greg Kroah-Hartman --- drivers/serial/amba-pl010.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 50441ffe8e38..2904aa044126 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -472,14 +472,9 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&uap->port.lock, flags); } -static void pl010_set_ldisc(struct uart_port *port) +static void pl010_set_ldisc(struct uart_port *port, int new) { - int line = port->line; - - if (line >= port->state->port.tty->driver->num) - return; - - if (port->state->port.tty->ldisc->ops->num == N_PPS) { + if (new == N_PPS) { port->flags |= UPF_HARDPPS_CD; pl010_enable_ms(port); } else -- cgit v1.2.3-59-g8ed1b From e3671ac429fe50cf0c1b4f1dc4b7237207f1d956 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Mon, 6 Sep 2010 13:41:02 +0100 Subject: serial: mfd: fix bug in serial_hsu_remove() Medfield HSU driver deal with 4 pci devices(3 uart ports + 1 dma controller), so in pci remove func, we need handle them differently Signed-off-by: Feng Tang Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/serial/mfd.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/serial/mfd.c b/drivers/serial/mfd.c index bc9af503907f..324c385a653d 100644 --- a/drivers/serial/mfd.c +++ b/drivers/serial/mfd.c @@ -1423,7 +1423,6 @@ static void hsu_global_init(void) } phsu = hsu; - hsu_debugfs_init(hsu); return; @@ -1435,18 +1434,20 @@ err_free_region: static void serial_hsu_remove(struct pci_dev *pdev) { - struct hsu_port *hsu; - int i; + void *priv = pci_get_drvdata(pdev); + struct uart_hsu_port *up; - hsu = pci_get_drvdata(pdev); - if (!hsu) + if (!priv) return; - for (i = 0; i < 3; i++) - uart_remove_one_port(&serial_hsu_reg, &hsu->port[i].port); + /* For port 0/1/2, priv is the address of uart_hsu_port */ + if (pdev->device != 0x081E) { + up = priv; + uart_remove_one_port(&serial_hsu_reg, &up->port); + } pci_set_drvdata(pdev, NULL); - free_irq(hsu->irq, hsu); + free_irq(pdev->irq, priv); pci_disable_device(pdev); } -- cgit v1.2.3-59-g8ed1b From 350aede603f7db7a9b4c1a340fbe89ccae6523a2 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 5 Sep 2010 01:58:18 +0200 Subject: Revert: "Staging: batman-adv: Adding netfilter-bridge hooks" This reverts commit 96d592ed599434d2d5f339a1d282871bc6377d2c. The netfilter hook seems to be misused and may leak skbs in situations when NF_HOOK returns NF_STOLEN. It may not filter everything as expected. Also the ethernet bridge tables are not yet capable to understand batman-adv packet correctly. It was only added for testing purposes and can be removed again. Reported-by: Vasiliy Kulikov Signed-off-by: Sven Eckelmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/hard-interface.c | 13 ------------- drivers/staging/batman-adv/send.c | 8 ++------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c index baa8b05b9e8d..6e973a79aa25 100644 --- a/drivers/staging/batman-adv/hard-interface.c +++ b/drivers/staging/batman-adv/hard-interface.c @@ -30,7 +30,6 @@ #include "hash.h" #include -#include #define MIN(x, y) ((x) < (y) ? (x) : (y)) @@ -431,11 +430,6 @@ out: return NOTIFY_DONE; } -static int batman_skb_recv_finish(struct sk_buff *skb) -{ - return NF_ACCEPT; -} - /* receive a packet with the batman ethertype coming on a hard * interface */ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, @@ -456,13 +450,6 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, if (atomic_read(&module_state) != MODULE_ACTIVE) goto err_free; - /* if netfilter/ebtables wants to block incoming batman - * packets then give them a chance to do so here */ - ret = NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, dev, NULL, - batman_skb_recv_finish); - if (ret != 1) - goto err_out; - /* packet should hold at least type and version */ if (unlikely(skb_headlen(skb) < 2)) goto err_free; diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index 055edee7b4e4..da3c82e47bbd 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -29,7 +29,6 @@ #include "vis.h" #include "aggregation.h" -#include static void send_outstanding_bcast_packet(struct work_struct *work); @@ -92,12 +91,9 @@ int send_skb_packet(struct sk_buff *skb, /* dev_queue_xmit() returns a negative result on error. However on * congestion and traffic shaping, it drops and returns NET_XMIT_DROP - * (which is > 0). This will not be treated as an error. - * Also, if netfilter/ebtables wants to block outgoing batman - * packets then giving them a chance to do so here */ + * (which is > 0). This will not be treated as an error. */ - return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - dev_queue_xmit); + return dev_queue_xmit(skb); send_skb_err: kfree_skb(skb); return NET_XMIT_DROP; -- cgit v1.2.3-59-g8ed1b From dd173abfead903c7df54e977535973f3312cd307 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Sep 2010 14:32:30 +0200 Subject: Staging: vt6655: fix buffer overflow "param->u.wpa_associate.wpa_ie_len" comes from the user. We should check it so that the copy_from_user() doesn't overflow the buffer. Also further down in the function, we assume that if "param->u.wpa_associate.wpa_ie_len" is set then "abyWPAIE[0]" is initialized. To make that work, I changed the test here to say that if "wpa_ie_len" is set then "wpa_ie" has to be a valid pointer or we return -EINVAL. Oddly, we only use the first element of the abyWPAIE[] array. So I suspect there may be some other issues in this function. Signed-off-by: Dan Carpenter Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/wpactl.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c index 0142338bcafe..4bdb8362de82 100644 --- a/drivers/staging/vt6655/wpactl.c +++ b/drivers/staging/vt6655/wpactl.c @@ -766,9 +766,14 @@ static int wpa_set_associate(PSDevice pDevice, DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ie_len = %d\n", param->u.wpa_associate.wpa_ie_len); - if (param->u.wpa_associate.wpa_ie && - copy_from_user(&abyWPAIE[0], param->u.wpa_associate.wpa_ie, param->u.wpa_associate.wpa_ie_len)) - return -EINVAL; + if (param->u.wpa_associate.wpa_ie_len) { + if (!param->u.wpa_associate.wpa_ie) + return -EINVAL; + if (param->u.wpa_associate.wpa_ie_len > sizeof(abyWPAIE)) + return -EINVAL; + if (copy_from_user(&abyWPAIE[0], param->u.wpa_associate.wpa_ie, param->u.wpa_associate.wpa_ie_len)) + return -EFAULT; + } if (param->u.wpa_associate.mode == 1) pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA; -- cgit v1.2.3-59-g8ed1b From b30a3f6257ed2105259b404d419b4964e363928c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 20 Sep 2010 16:56:53 -0700 Subject: Linux 2.6.36-rc5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 92ab33f16cf0..3133a5772eeb 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 36 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Sheep on Meth # *DOCUMENTATION* -- cgit v1.2.3-59-g8ed1b From 6df7aadcd9290807c464675098b5dd2dc9da5075 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 16 Sep 2010 14:43:08 +0530 Subject: virtio: console: Fix poll blocking even though there is data to read I found this while working on a Linux agent for spice, the symptom I was seeing was select blocking on the spice vdagent virtio serial port even though there were messages queued up there. virtio_console's port_fops_poll checks port->inbuf != NULL to determine if read won't block. However if an application reads enough bytes from inbuf through port_fops_read, to empty the current port->inbuf, port->inbuf will be NULL even though there may be buffers left in the virtqueue. This causes poll() to block even though there is data to be read, this patch fixes this by using will_read_block(port) instead of the port->inbuf != NULL check. Signed-off-By: Hans de Goede Signed-off-by: Amit Shah Signed-off-by: Rusty Russell Cc: stable@kernel.org --- drivers/char/virtio_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 942a9826bd23..2f2e31b58b34 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -642,7 +642,7 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait) poll_wait(filp, &port->waitqueue, wait); ret = 0; - if (port->inbuf) + if (!will_read_block(port)) ret |= POLLIN | POLLRDNORM; if (!will_write_block(port)) ret |= POLLOUT; -- cgit v1.2.3-59-g8ed1b From 65745422a898741ee0e7068ef06624ab06e8aefa Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Tue, 14 Sep 2010 13:26:16 +0530 Subject: virtio: console: Prevent userspace from submitting NULL buffers A userspace could submit a buffer with 0 length to be written to the host. Prevent such a situation. This was not needed previously, but recent changes in the way write() works exposed this condition to trigger a virtqueue event to the host, causing a NULL buffer to be sent across. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell CC: stable@kernel.org --- drivers/char/virtio_console.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 2f2e31b58b34..c810481a5bc2 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -596,6 +596,10 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, ssize_t ret; bool nonblock; + /* Userspace could be out to fool us */ + if (!count) + return 0; + port = filp->private_data; nonblock = filp->f_flags & O_NONBLOCK; -- cgit v1.2.3-59-g8ed1b From 9b6efcd2e2275e13403700913b7a1da92cf11ad2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 21 Sep 2010 10:54:01 -0600 Subject: lguest: update comments to reflect LHCALL_LOAD_GDT_ENTRY. We used to have a hypercall which reloaded the entire GDT, then we switched to one which loaded a single entry (to match the IDT code). Some comments were not updated, so fix them. Signed-off-by: Rusty Russell Reported by: Eviatar Khen --- arch/x86/lguest/boot.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 9257510b4836..9d5f55848455 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -324,9 +324,8 @@ static void lguest_load_gdt(const struct desc_ptr *desc) } /* - * For a single GDT entry which changes, we do the lazy thing: alter our GDT, - * then tell the Host to reload the entire thing. This operation is so rare - * that this naive implementation is reasonable. + * For a single GDT entry which changes, we simply change our copy and + * then tell the host about it. */ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum, const void *desc, int type) @@ -338,9 +337,13 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum, } /* - * OK, I lied. There are three "thread local storage" GDT entries which change + * There are three "thread local storage" GDT entries which change * on every context switch (these three entries are how glibc implements - * __thread variables). So we have a hypercall specifically for this case. + * __thread variables). As an optimization, we have a hypercall + * specifically for this case. + * + * Wouldn't it be nicer to have a general LOAD_GDT_ENTRIES hypercall + * which took a range of entries? */ static void lguest_load_tls(struct thread_struct *t, unsigned int cpu) { -- cgit v1.2.3-59-g8ed1b From 46b30ea9bc3698bc1d1e6fd726c9601d46fa0a91 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 21 Sep 2010 07:57:19 +0200 Subject: percpu: fix pcpu_last_unit_cpu pcpu_first/last_unit_cpu are used to track which cpu has the first and last units assigned. This in turn is used to determine the span of a chunk for man/unmap cache flushes and whether an address belongs to the first chunk or not in per_cpu_ptr_to_phys(). When the number of possible CPUs isn't power of two, a chunk may contain unassigned units towards the end of a chunk. The logic to determine pcpu_last_unit_cpu was incorrect when there was an unused unit at the end of a chunk. It failed to ignore the unused unit and assigned the unused marker NR_CPUS to pcpu_last_unit_cpu. This was discovered through kdump failure which was caused by malfunctioning per_cpu_ptr_to_phys() on a kvm setup with 50 possible CPUs by CAI Qian. Signed-off-by: Tejun Heo Reported-by: CAI Qian Cc: stable@kernel.org --- mm/percpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/percpu.c b/mm/percpu.c index 58c572b18b07..c76ef3891e0d 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1401,9 +1401,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, if (pcpu_first_unit_cpu == NR_CPUS) pcpu_first_unit_cpu = cpu; + pcpu_last_unit_cpu = cpu; } } - pcpu_last_unit_cpu = cpu; pcpu_nr_units = unit; for_each_possible_cpu(cpu) -- cgit v1.2.3-59-g8ed1b From 05c5e7698bdc54b3079a3517d86077f49ebcc788 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 20 Sep 2010 23:24:52 -0700 Subject: sparc64: Fix race in signal instruction flushing. If another cpu does a very wide munmap() on the signal frame area, it can tear down the page table hierarchy from underneath us. Borrow an idea from the 64-bit fault path's get_user_insn(), and disable cross call interrupts during the page table traversal to lock them in place while we operate. Reported-by: Al Viro Signed-off-by: David S. Miller --- arch/sparc/kernel/signal32.c | 102 +++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 42 deletions(-) diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index ea22cd373c64..76b67c4c6aa4 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -453,6 +453,64 @@ static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) return err; } +/* The I-cache flush instruction only works in the primary ASI, which + * right now is the nucleus, aka. kernel space. + * + * Therefore we have to kick the instructions out using the kernel + * side linear mapping of the physical address backing the user + * instructions. + */ +static void flush_signal_insns(unsigned long address) +{ + unsigned long pstate, paddr; + pte_t *ptep, pte; + pgd_t *pgdp; + pud_t *pudp; + pmd_t *pmdp; + + /* Commit all stores of the instructions we are about to flush. */ + wmb(); + + /* Disable cross-call reception. In this way even a very wide + * munmap() on another cpu can't tear down the page table + * hierarchy from underneath us, since that can't complete + * until the IPI tlb flush returns. + */ + + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); + __asm__ __volatile__("wrpr %0, %1, %%pstate" + : : "r" (pstate), "i" (PSTATE_IE)); + + pgdp = pgd_offset(current->mm, address); + if (pgd_none(*pgdp)) + goto out_irqs_on; + pudp = pud_offset(pgdp, address); + if (pud_none(*pudp)) + goto out_irqs_on; + pmdp = pmd_offset(pudp, address); + if (pmd_none(*pmdp)) + goto out_irqs_on; + + ptep = pte_offset_map(pmdp, address); + pte = *ptep; + if (!pte_present(pte)) + goto out_unmap; + + paddr = (unsigned long) page_address(pte_page(pte)); + + __asm__ __volatile__("flush %0 + %1" + : /* no outputs */ + : "r" (paddr), + "r" (address & (PAGE_SIZE - 1)) + : "memory"); + +out_unmap: + pte_unmap(ptep); +out_irqs_on: + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); + +} + static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset) { @@ -547,13 +605,7 @@ static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, if (ka->ka_restorer) { regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; } else { - /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); - pgd_t *pgdp = pgd_offset(current->mm, address); - pud_t *pudp = pud_offset(pgdp, address); - pmd_t *pmdp = pmd_offset(pudp, address); - pte_t *ptep; - pte_t pte; regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); @@ -562,22 +614,7 @@ static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, if (err) goto sigsegv; - preempt_disable(); - ptep = pte_offset_map(pmdp, address); - pte = *ptep; - if (pte_present(pte)) { - unsigned long page = (unsigned long) - page_address(pte_page(pte)); - - wmb(); - __asm__ __volatile__("flush %0 + %1" - : /* no outputs */ - : "r" (page), - "r" (address & (PAGE_SIZE - 1)) - : "memory"); - } - pte_unmap(ptep); - preempt_enable(); + flush_signal_insns(address); } return; @@ -687,12 +724,7 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, if (ka->ka_restorer) regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; else { - /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); - pgd_t *pgdp = pgd_offset(current->mm, address); - pud_t *pudp = pud_offset(pgdp, address); - pmd_t *pmdp = pmd_offset(pudp, address); - pte_t *ptep; regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); @@ -704,21 +736,7 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, if (err) goto sigsegv; - preempt_disable(); - ptep = pte_offset_map(pmdp, address); - if (pte_present(*ptep)) { - unsigned long page = (unsigned long) - page_address(pte_page(*ptep)); - - wmb(); - __asm__ __volatile__("flush %0 + %1" - : /* no outputs */ - : "r" (page), - "r" (address & (PAGE_SIZE - 1)) - : "memory"); - } - pte_unmap(ptep); - preempt_enable(); + flush_signal_insns(address); } return; -- cgit v1.2.3-59-g8ed1b From 53d7d69d8ffdfa60c5b66cc2e9ee0774aaaef5c0 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 21 Sep 2010 14:25:49 +0800 Subject: ALSA: hdmi - support infoframe for DisplayPort DisplayPort works mostly in the same way as HDMI, except that it expects a slightly different audio infoframe format. Citations from "HDA036-A: Display Port Support and HDMI Miscellaneous Corrections": The HDMI specification defines a data island packet with a header of 4 bytes (3 bytes content + 1 byte ECC) and packet body of 32 bytes (28 bytes content and 4 bytes ECC). Display Port specification on the other hand defines a data island packet (secondary data packet) with header of 4 bytes protected by 4 bytes of parity, and data of theoretically up to 1024 bytes with each 16 bytes chunk of data protected by 4 bytes of parity. Note that the ECC or parity bytes are not present in the DIP content populated by software and are hardware generated. It tests DP connection based on the ELD conn_type field, which will be set by the graphics driver and can be overriden manually by users through the /proc/asound/card0/eld* interface. The DP infoframe is tested OK on Intel SandyBridge/CougarPoint platform. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 110 ++++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index cb997ca0fdfa..1f4ae1aeca44 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -84,13 +84,25 @@ struct hdmi_audio_infoframe { u8 ver; /* 0x01 */ u8 len; /* 0x0a */ - u8 checksum; /* PB0 */ + u8 checksum; + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ u8 SS01_SF24; u8 CXT04; u8 CA; u8 LFEPBL01_LSV36_DM_INH7; - u8 reserved[5]; /* PB6 - PB10 */ +}; + +struct dp_audio_infoframe { + u8 type; /* 0x84 */ + u8 len; /* 0x1b */ + u8 ver; /* 0x11 << 2 */ + + u8 CC02_CT47; /* match with HDMI infoframe from this on */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; }; /* @@ -194,7 +206,7 @@ static int hdmi_channel_mapping[0x32][8] = { * This is an ordered list! * * The preceding ones have better chances to be selected by - * hdmi_setup_channel_allocation(). + * hdmi_channel_allocation(). */ static struct cea_channel_speaker_allocation channel_allocations[] = { /* channel: 7 6 5 4 3 2 1 0 */ @@ -371,14 +383,14 @@ static void init_channel_allocations(void) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, - struct hdmi_audio_infoframe *ai) +static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid, + int channels) { struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld; int i; + int ca = 0; int spk_mask = 0; - int channels = 1 + (ai->CC02_CT47 & 0x7); char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; /* @@ -416,16 +428,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, if (channels == channel_allocations[i].channels && (spk_mask & channel_allocations[i].spk_mask) == channel_allocations[i].spk_mask) { - ai->CA = channel_allocations[i].ca_index; + ca = channel_allocations[i].ca_index; break; } } snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", - ai->CA, channels, buf); + ca, channels, buf); - return ai->CA; + return ca; } static void hdmi_debug_channel_mapping(struct hda_codec *codec, @@ -447,10 +459,9 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_audio_infoframe *ai) + int ca) { int i; - int ca = ai->CA; int err; if (hdmi_channel_mapping[ca][1] == 0) { @@ -547,41 +558,37 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) #endif } -static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai) +static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai) { - u8 *bytes = (u8 *)ai; + u8 *bytes = (u8 *)hdmi_ai; u8 sum = 0; int i; - ai->checksum = 0; + hdmi_ai->checksum = 0; - for (i = 0; i < sizeof(*ai); i++) + for (i = 0; i < sizeof(*hdmi_ai); i++) sum += bytes[i]; - ai->checksum = -sum; + hdmi_ai->checksum = -sum; } static void hdmi_fill_audio_infoframe(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_audio_infoframe *ai) + u8 *dip, int size) { - u8 *bytes = (u8 *)ai; int i; hdmi_debug_dip_size(codec, pin_nid); hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ - hdmi_checksum_audio_infoframe(ai); - hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - for (i = 0; i < sizeof(*ai); i++) - hdmi_write_dip_byte(codec, pin_nid, bytes[i]); + for (i = 0; i < size; i++) + hdmi_write_dip_byte(codec, pin_nid, dip[i]); } static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, - struct hdmi_audio_infoframe *ai) + u8 *dip, int size) { - u8 *bytes = (u8 *)ai; u8 val; int i; @@ -590,10 +597,10 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, return false; hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - for (i = 0; i < sizeof(*ai); i++) { + for (i = 0; i < size; i++) { val = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_DATA, 0); - if (val != bytes[i]) + if (val != dip[i]) return false; } @@ -605,15 +612,13 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, { struct hdmi_spec *spec = codec->spec; hda_nid_t pin_nid; + int channels = substream->runtime->channels; + int ca; int i; - struct hdmi_audio_infoframe ai = { - .type = 0x84, - .ver = 0x01, - .len = 0x0a, - .CC02_CT47 = substream->runtime->channels - 1, - }; + u8 ai[max(sizeof(struct hdmi_audio_infoframe), + sizeof(struct dp_audio_infoframe))]; - hdmi_setup_channel_allocation(codec, nid, &ai); + ca = hdmi_channel_allocation(codec, nid, channels); for (i = 0; i < spec->num_pins; i++) { if (spec->pin_cvt[i] != nid) @@ -622,14 +627,45 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, continue; pin_nid = spec->pin[i]; - if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { + + memset(ai, 0, sizeof(ai)); + if (spec->sink_eld[i].conn_type == 0) { /* HDMI */ + struct hdmi_audio_infoframe *hdmi_ai; + + hdmi_ai = (struct hdmi_audio_infoframe *)ai; + hdmi_ai->type = 0x84; + hdmi_ai->ver = 0x01; + hdmi_ai->len = 0x0a; + hdmi_ai->CC02_CT47 = channels - 1; + hdmi_checksum_audio_infoframe(hdmi_ai); + } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */ + struct dp_audio_infoframe *dp_ai; + + dp_ai = (struct dp_audio_infoframe *)ai; + dp_ai->type = 0x84; + dp_ai->len = 0x1b; + dp_ai->ver = 0x11 << 2; + dp_ai->CC02_CT47 = channels - 1; + } else { + snd_printd("HDMI: unknown connection type at pin %d\n", + pin_nid); + continue; + } + + /* + * sizeof(ai) is used instead of sizeof(*hdmi_ai) or + * sizeof(*dp_ai) to avoid partial match/update problems when + * the user switches between HDMI/DP monitors. + */ + if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) { snd_printdd("hdmi_setup_audio_infoframe: " "cvt=%d pin=%d channels=%d\n", nid, pin_nid, - substream->runtime->channels); - hdmi_setup_channel_mapping(codec, pin_nid, &ai); + channels); + hdmi_setup_channel_mapping(codec, pin_nid, ca); hdmi_stop_infoframe_trans(codec, pin_nid); - hdmi_fill_audio_infoframe(codec, pin_nid, &ai); + hdmi_fill_audio_infoframe(codec, pin_nid, + ai, sizeof(ai)); hdmi_start_infoframe_trans(codec, pin_nid); } } -- cgit v1.2.3-59-g8ed1b From 9396d3174b761685d6fefb1103e66b96a2e5db6d Mon Sep 17 00:00:00 2001 From: Jerry Zhou Date: Tue, 21 Sep 2010 14:44:51 +0800 Subject: ALSA: hdmi - fix surround41 channel mapping Channel 2 and channel 3 were all wrongly mapped to HDMI slot 4. This shows up as a bug that one channel is "lost" when playing in surround41 mode. Signed-off-by: Jerry Zhou Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 1f4ae1aeca44..d3e49aa5b9ec 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -193,7 +193,7 @@ static int hdmi_channel_mapping[0x32][8] = { /* 4ch */ [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 }, /* surround41 */ - [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 }, + [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 }, /* surround50 */ [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 }, /* surround51 */ -- cgit v1.2.3-59-g8ed1b From d2520a426dc3033c00077e923a553fc6c98c7564 Mon Sep 17 00:00:00 2001 From: Kenneth Waters Date: Tue, 21 Sep 2010 00:58:23 -0700 Subject: Input: joydev - fix JSIOCSAXMAP ioctl Fixed JSIOCSAXMAP ioctl to update absmap, the map from hardware axis to event axis in addition to abspam. This fixes a regression introduced by 999b874f. Signed-off-by: Kenneth Waters Cc: stable@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index d85bd8a7967d..22239e988498 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -483,6 +483,9 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev, memcpy(joydev->abspam, abspam, len); + for (i = 0; i < joydev->nabs; i++) + joydev->absmap[joydev->abspam[i]] = i; + out: kfree(abspam); return retval; -- cgit v1.2.3-59-g8ed1b From 9e5341b92d1d2dde11691b394721b45b36416bef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Sep 2010 09:57:06 +0200 Subject: ALSA: hda - Introduce hda_call_check_power_status() helper Replace the explicit ifdef check and call of check_power_status ops with a new helper function, hda_call_check_power_status(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 5 +---- sound/pci/hda/hda_codec.h | 12 ++++++++++++ sound/pci/hda/patch_realtek.c | 11 +++-------- sound/pci/hda/patch_sigmatel.c | 12 ++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e15a75751f57..053f827d2c2c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2228,10 +2228,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, HDA_AMP_MUTE, *valp ? 0 : HDA_AMP_MUTE); -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (codec->patch_ops.check_power_status) - codec->patch_ops.check_power_status(codec, nid); -#endif + hda_call_check_power_status(codec, nid); snd_hda_power_down(codec); return change; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 62c702240108..ebf8eb02e3c2 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -989,6 +989,18 @@ int snd_hda_suspend(struct hda_bus *bus); int snd_hda_resume(struct hda_bus *bus); #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE +static inline +int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + if (codec->patch_ops.check_power_status) + return codec->patch_ops.check_power_status(codec, nid); + return 0; +} +#else +#define hda_call_check_power_status(codec, nid) 0 +#endif + /* * get widget information */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8689216fdcce..9bedca073e9a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3729,10 +3729,7 @@ static int alc_init(struct hda_codec *codec) if (spec->init_hook) spec->init_hook(codec); -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (codec->patch_ops.check_power_status) - codec->patch_ops.check_power_status(codec, 0x01); -#endif + hda_call_check_power_status(codec, 0x01); return 0; } @@ -4128,8 +4125,7 @@ static int alc_resume(struct hda_codec *codec) codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - if (codec->patch_ops.check_power_status) - codec->patch_ops.check_power_status(codec, 0x01); + hda_call_check_power_status(codec, 0x01); return 0; } #endif @@ -14703,8 +14699,7 @@ static int alc269_resume(struct hda_codec *codec) snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - if (codec->patch_ops.check_power_status) - codec->patch_ops.check_power_status(codec, 0x01); + hda_call_check_power_status(codec, 0x01); return 0; } #endif /* SND_HDA_NEEDS_RESUME */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6bfbc2fe46ed..a90327b0cc3e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4372,11 +4372,9 @@ static int stac92xx_init(struct hda_codec *codec) stac_issue_unsol_event(codec, nid); } -#ifdef CONFIG_SND_HDA_POWER_SAVE /* sync mute LED */ - if (spec->gpio_led && codec->patch_ops.check_power_status) - codec->patch_ops.check_power_status(codec, 0x01); -#endif + if (spec->gpio_led) + hda_call_check_power_status(codec, 0x01); if (spec->dac_list) stac92xx_power_down(codec); return 0; @@ -4958,11 +4956,9 @@ static int stac92xx_resume(struct hda_codec *codec) stac_issue_unsol_event(codec, spec->autocfg.line_out_pins[0]); } -#ifdef CONFIG_SND_HDA_POWER_SAVE /* sync mute LED */ - if (spec->gpio_led && codec->patch_ops.check_power_status) - codec->patch_ops.check_power_status(codec, 0x01); -#endif + if (spec->gpio_led) + hda_call_check_power_status(codec, 0x01); return 0; } -- cgit v1.2.3-59-g8ed1b From 0f9f1ee9d1412d45a22bfd69dfd4d4324b506e9e Mon Sep 17 00:00:00 2001 From: Luke Yelavich Date: Tue, 21 Sep 2010 17:05:46 +1000 Subject: ALSA: hda - Add Dell Latitude E6400 model quirk BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/643891 Set the Dell Latitude E6400 (1028:0233) SSID to use AD1984_DELL_DESKTOP Cc: stable@kernel.org Signed-off-by: Luke Yelavich Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index b697fd2a6f8b..10bbbaf6ebc3 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3641,6 +3641,7 @@ static struct snd_pci_quirk ad1984_cfg_tbl[] = { /* Lenovo Thinkpad T61/X61 */ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), + SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), {} }; -- cgit v1.2.3-59-g8ed1b From 265a02478db5217eda8063004ded1ef0a461c240 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Sep 2010 11:26:21 +0200 Subject: ALSA: hda - Check invalid NIDs in alc_init_jacks() The headphone and external-mic pin NIDs can be null, and the jack input elements should be skipped in such a case. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9bedca073e9a..f5ccba0fd189 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1087,15 +1087,19 @@ static int alc_init_jacks(struct hda_codec *codec) unsigned int hp_nid = spec->autocfg.hp_pins[0]; unsigned int mic_nid = spec->ext_mic.pin; - err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE); - if (err < 0) - return err; - alc_report_jack(codec, hp_nid); + if (hp_nid) { + err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE); + if (err < 0) + return err; + alc_report_jack(codec, hp_nid); + } - err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE); - if (err < 0) - return err; - alc_report_jack(codec, mic_nid); + if (mic_nid) { + err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE); + if (err < 0) + return err; + alc_report_jack(codec, mic_nid); + } return 0; } -- cgit v1.2.3-59-g8ed1b From b0722cb1ac84863f57471d2b254457c100319300 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 13 Sep 2010 14:09:33 +0200 Subject: cciss: freeing uninitialized data on error path The "h->scatter_list" is allocated inside a for loop. If any of those allocations fail, then the rest of the list is uninitialized data. When we free it we should start from the top and free backwards so that we don't call kfree() on uninitialized pointers. Also if the allocation for "h->scatter_list" fails then we would get an Oops here. I should have noticed this when I send: 4ee69851c "cciss: handle allocation failure." but I didn't. Sorry about that. Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 6124c2fd2d33..5e4fadcdece9 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4792,7 +4792,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, clean4: kfree(h->cmd_pool_bits); /* Free up sg elements */ - for (k = 0; k < h->nr_cmds; k++) + for (k-- ; k >= 0; k--) kfree(h->scatter_list[k]); kfree(h->scatter_list); cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); -- cgit v1.2.3-59-g8ed1b From a45dc2d2b8d1afa57c91dcfac224e50ffcd3f805 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Mon, 13 Sep 2010 21:32:19 +0200 Subject: block: fix blk_rq_map_kern bio direction flag This bug was introduced in 7b6d91daee5cac6402186ff224c3af39d79f4a0e "block: unify flags for struct bio and struct request" Cc: Boaz Harrosh Signed-off-by: Benny Halevy Signed-off-by: Jens Axboe --- block/blk-map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-map.c b/block/blk-map.c index c65d7593f7f1..ade0a08c9099 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -307,7 +307,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, return PTR_ERR(bio); if (rq_data_dir(rq) == WRITE) - bio->bi_rw |= (1 << REQ_WRITE); + bio->bi_rw |= REQ_WRITE; if (do_copy) rq->cmd_flags |= REQ_COPY_USER; -- cgit v1.2.3-59-g8ed1b From 180be2a0420a0d680285e9352c0db85016b9ed2a Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Tue, 14 Sep 2010 08:47:11 +0200 Subject: cfq-iosched: fix a kernel OOPs when usb key is inserted Mike reported a kernel crash when a usb key hotplug is performed while all kernel thrads are not in a root cgroup and are running in one of the child cgroups of blkio controller. BUG: unable to handle kernel NULL pointer dereference at 0000002c IP: [] cfq_get_queue+0x232/0x412 *pde = 00000000 Oops: 0000 [#1] PREEMPT last sysfs file: /sys/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host3/scsi_host/host3/uevent [..] Pid: 30039, comm: scsi_scan_3 Not tainted 2.6.35.2-fg.roam #1 Volvi2 /Aspire 4315 EIP: 0060:[] EFLAGS: 00010086 CPU: 0 EIP is at cfq_get_queue+0x232/0x412 EAX: f705f9c0 EBX: e977abac ECX: 00000000 EDX: 00000000 ESI: f00da400 EDI: f00da4ec EBP: e977a800 ESP: dff8fd00 DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 Process scsi_scan_3 (pid: 30039, ti=dff8e000 task=f6b6c9a0 task.ti=dff8e000) Stack: 00000000 00000000 00000001 01ff0000 f00da508 00000000 f00da524 f00da540 <0> e7994940 dd631750 f705f9c0 e977a820 e977ac44 f00da4d0 00000001 f6b6c9a0 <0> 00000010 00008010 0000000b 00000000 00000001 e977a800 dd76fac0 00000246 Call Trace: [] ? cfq_set_request+0x228/0x34c [] ? cfq_set_request+0x0/0x34c [] ? elv_set_request+0xf/0x1c [] ? get_request+0x1ad/0x22f [] ? get_request_wait+0x1f/0x11a [] ? kvasprintf+0x33/0x3b [] ? scsi_execute+0x1d/0x103 [] ? scsi_execute_req+0x58/0x83 [] ? scsi_probe_and_add_lun+0x188/0x7c2 [] ? attribute_container_add_device+0x15/0xfa [] ? kobject_get+0xf/0x13 [] ? get_device+0x10/0x14 [] ? scsi_alloc_target+0x217/0x24d [] ? __scsi_scan_target+0x95/0x480 [] ? dequeue_entity+0x14/0x1fe [] ? update_curr+0x165/0x1ab [] ? update_curr+0x165/0x1ab [] ? scsi_scan_channel+0x4a/0x76 [] ? scsi_scan_host_selected+0x77/0xad [] ? do_scan_async+0x0/0x11a [] ? do_scsi_scan_host+0x51/0x56 [] ? do_scan_async+0x0/0x11a [] ? do_scan_async+0xe/0x11a [] ? do_scan_async+0x0/0x11a [] ? kthread+0x5e/0x63 [] ? kthread+0x0/0x63 [] ? kernel_thread_helper+0x6/0x10 Code: 44 24 1c 54 83 44 24 18 54 83 fa 03 75 94 8b 06 c7 86 64 02 00 00 01 00 00 00 83 e0 03 09 f0 89 06 8b 44 24 28 8b 90 58 01 00 00 <8b> 42 2c 85 c0 75 03 8b 42 08 8d 54 24 48 52 8d 4c 24 50 51 68 EIP: [] cfq_get_queue+0x232/0x412 SS:ESP 0068:dff8fd00 CR2: 000000000000002c ---[ end trace 9a88306573f69b12 ]--- The problem here is that we don't have bdi->dev information available when thread does some IO. Hence when dev_name() tries to access bdi->dev, it crashes. This problem does not happen if kernel threads are in root group as root group is statically allocated at device initialization time and we don't hit this piece of code. Fix it by delaying the filling of major and minor number information of device in blk_group. Initially a blk_group is created with 0 as device information and this information is filled later once some more IO comes in from same group. Reported-by: Mike Kazantsev Signed-off-by: Vivek Goyal Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index f65c6f01c475..9eba291eb6fd 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1019,10 +1019,20 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create) */ atomic_set(&cfqg->ref, 1); - /* Add group onto cgroup list */ - sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); - cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, + /* + * Add group onto cgroup list. It might happen that bdi->dev is + * not initiliazed yet. Initialize this new group without major + * and minor info and this info will be filled in once a new thread + * comes for IO. See code above. + */ + if (bdi->dev) { + sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); + cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, MKDEV(major, minor)); + } else + cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd, + 0); + cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev); /* Add group on cfqd list */ -- cgit v1.2.3-59-g8ed1b From bb7ab785ad05a97a2c9ffb3a06547ed39f3133e8 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 21 Sep 2010 03:26:35 -0400 Subject: oprofile: Add Support for Intel CPU Family 6 / Model 29 This patch adds CPU type detection for dunnington processor (Family 6 / Model 29) to be identified as core 2 family cpu type (wikipedia source). I tested oprofile on Intel(R) Xeon(R) CPU E7440 reporting itself as model 29, and it runs without an issue. Spec: http://www.intel.com/Assets/en_US/PDF/specupdate/320336.pdf Signed-off-by: Jiri Olsa Acked-by: Andi Kleen Cc: stable@kernel.org Signed-off-by: Robert Richter --- arch/x86/oprofile/nmi_int.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 009b819f48d0..f1575c9a2572 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -674,6 +674,7 @@ static int __init ppro_init(char **cpu_type) case 0x0f: case 0x16: case 0x17: + case 0x1d: *cpu_type = "i386/core_2"; break; case 0x1a: -- cgit v1.2.3-59-g8ed1b From f6c3f1686e7ec1dd8725a9a3dcb857dfd0c7a5bf Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Mon, 13 Sep 2010 11:02:21 -0700 Subject: sched: Fix nohz balance kick There's a situation where the nohz balancer will try to wake itself: cpu-x is idle which is also ilb_cpu got a scheduler tick during idle and the nohz_kick_needed() in trigger_load_balance() checks for rq_x->nr_running which might not be zero (because of someone waking a task on this rq etc) and this leads to the situation of the cpu-x sending a kick to itself. And this can cause a lockup. Avoid this by not marking ourself eligible for kicking. Signed-off-by: Suresh Siddha Signed-off-by: Peter Zijlstra LKML-Reference: <1284400941.2684.19.camel@sbsiddha-MOBL3.sc.intel.com> Signed-off-by: Ingo Molnar --- kernel/sched_fair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index a171138a9402..db3f674ca49d 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c @@ -3630,7 +3630,7 @@ static inline int nohz_kick_needed(struct rq *rq, int cpu) if (time_before(now, nohz.next_balance)) return 0; - if (!rq->nr_running) + if (rq->idle_at_tick) return 0; first_pick_cpu = atomic_read(&nohz.first_pick_cpu); -- cgit v1.2.3-59-g8ed1b From abdd8f510686da0a58e475bc0143d1069e5f53da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Sep 2010 17:38:14 +0200 Subject: ALSA: hda - Apply ALC269 VAIO fix-up to all Sony laptops with ALC269 We've applied a fix-up for ALC269 VAIO only for two models. But all Sony VAIO models with ALC269 codec seem to require the similar fix. Let's apply it with vendor-id mask. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f2a30447f26f..eea88b7ddb9f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14731,8 +14731,7 @@ static const struct alc_fixup alc269_fixups[] = { }; static struct snd_pci_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), - SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), + SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), {} }; -- cgit v1.2.3-59-g8ed1b From 83d9f65bdae6f6b34d75282c6618d3f50846849a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 29 Aug 2010 18:12:24 -0700 Subject: x86, setup: Fix earlyprintk=serial,ttyS0,115200 Torsten reported that there is garbage output, after commit 8fee13a48e4879fba57725f6d9513df4bfa8e9f3 (x86, setup: enable early console output from the decompressor) It turns out we missed the offset for that case. Reported-by: Torsten Kaiser Signed-off-by: Yinghai Lu LKML-Reference: <4C7B0578.8090807@kernel.org> Signed-off-by: H. Peter Anvin --- arch/x86/boot/early_serial_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/boot/early_serial_console.c b/arch/x86/boot/early_serial_console.c index 030f4b93e255..407a8e26f0a7 100644 --- a/arch/x86/boot/early_serial_console.c +++ b/arch/x86/boot/early_serial_console.c @@ -58,7 +58,7 @@ static void parse_earlyprintk(void) if (arg[pos] == ',') pos++; - if (!strncmp(arg, "ttyS", 4)) { + if (!strncmp(arg + pos, "ttyS", 4)) { static const int bases[] = { 0x3f8, 0x2f8 }; int idx = 0; -- cgit v1.2.3-59-g8ed1b From 74b3c444a963ba55aef89b33a1bcaada9a4c206f Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sun, 29 Aug 2010 18:13:10 -0700 Subject: x86, setup: Fix earlyprintk=serial,0x3f8,115200 earlyprintk can take and I/O port, so we need to handle this case in the setup code too, otherwise 0x3f8 will be treated as a baud rate. Signed-off-by: Yinghai Lu LKML-Reference: <4C7B05A6.4010801@kernel.org> Signed-off-by: H. Peter Anvin --- arch/x86/boot/early_serial_console.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/x86/boot/early_serial_console.c b/arch/x86/boot/early_serial_console.c index 407a8e26f0a7..5df2869c874b 100644 --- a/arch/x86/boot/early_serial_console.c +++ b/arch/x86/boot/early_serial_console.c @@ -58,7 +58,19 @@ static void parse_earlyprintk(void) if (arg[pos] == ',') pos++; - if (!strncmp(arg + pos, "ttyS", 4)) { + /* + * make sure we have + * "serial,0x3f8,115200" + * "serial,ttyS0,115200" + * "ttyS0,115200" + */ + if (pos == 7 && !strncmp(arg + pos, "0x", 2)) { + port = simple_strtoull(arg + pos, &e, 16); + if (port == 0 || arg + pos == e) + port = DEFAULT_SERIAL_PORT; + else + pos = e - arg; + } else if (!strncmp(arg + pos, "ttyS", 4)) { static const int bases[] = { 0x3f8, 0x2f8 }; int idx = 0; -- cgit v1.2.3-59-g8ed1b From 8df8fd27123054b02007361bd5483775db84b4a8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 20 Sep 2010 02:28:59 +0000 Subject: qlcnic: dont set skb->truesize skb->truesize is set in core network. Dont change it unless dealing with fragments. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic_init.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c index 60ab753f809a..2c7cf0b64811 100644 --- a/drivers/net/qlcnic/qlcnic_init.c +++ b/drivers/net/qlcnic/qlcnic_init.c @@ -1404,7 +1404,6 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, if (pkt_offset) skb_pull(skb, pkt_offset); - skb->truesize = skb->len + sizeof(struct sk_buff); skb->protocol = eth_type_trans(skb, netdev); napi_gro_receive(&sds_ring->napi, skb); @@ -1466,8 +1465,6 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, skb_put(skb, lro_length + data_offset); - skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb); - skb_pull(skb, l2_hdr_offset); skb->protocol = eth_type_trans(skb, netdev); @@ -1700,8 +1697,6 @@ qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, if (pkt_offset) skb_pull(skb, pkt_offset); - skb->truesize = skb->len + sizeof(struct sk_buff); - if (!qlcnic_check_loopback_buff(skb->data)) adapter->diag_cnt++; -- cgit v1.2.3-59-g8ed1b From 7e96dc7045bff8758804b047c0dfb6868f182500 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Sep 2010 13:04:04 -0700 Subject: netxen: dont set skb->truesize skb->truesize is set in core network. Dont change it unless dealing with fragments. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index cabae7bb1fc6..b075a35b85d4 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1540,7 +1540,6 @@ netxen_process_rcv(struct netxen_adapter *adapter, if (pkt_offset) skb_pull(skb, pkt_offset); - skb->truesize = skb->len + sizeof(struct sk_buff); skb->protocol = eth_type_trans(skb, netdev); napi_gro_receive(&sds_ring->napi, skb); @@ -1602,8 +1601,6 @@ netxen_process_lro(struct netxen_adapter *adapter, skb_put(skb, lro_length + data_offset); - skb->truesize = skb->len + sizeof(struct sk_buff) + skb_headroom(skb); - skb_pull(skb, l2_hdr_offset); skb->protocol = eth_type_trans(skb, netdev); -- cgit v1.2.3-59-g8ed1b From 9eecabcb9a924f1e11ba670365fd4babe423045c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 21 Sep 2010 22:28:23 +0100 Subject: intel-iommu: Abort IOMMU setup for igfx if BIOS gave no shadow GTT space Yet another BIOS bug; Lenovo this time (X201). Red Hat bug #593516. Signed-off-by: David Woodhouse --- drivers/pci/intel-iommu.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index c3ceebb5be84..dee88c6cb3ef 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3761,6 +3761,23 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); +static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev) +{ + unsigned short ggc; + + if (pci_read_config_word(dev, 0x52, &ggc)) + return; + + if (!(ggc & 0x800)) { + printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n"); + dmar_map_gfx = 0; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt); + /* On Tylersburg chipsets, some BIOSes have been known to enable the ISOCH DMAR unit for the Azalia sound device, but not give it any TLB entries, which causes it to deadlock. Check for that. We do -- cgit v1.2.3-59-g8ed1b From eecfd57f6429d9d8e10be186566ef99fced55163 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Wed, 25 Aug 2010 21:17:34 +0100 Subject: intel-iommu: Use symbolic values instead of magic numbers in Lenovo w/a Commit 9eecabcb9a924f1e11ba670365fd4babe423045c ("intel-iommu: Abort IOMMU setup for igfx if BIOS gave no shadow GTT space") uses a bunch of magic numbers. Provide #defines for those to make it look slightly saner. Signed-off-by: Adam Jackson Signed-off-by: David Woodhouse --- drivers/pci/intel-iommu.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index dee88c6cb3ef..4dfce3dad6ab 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3761,14 +3761,24 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf); +#define GGC 0x52 +#define GGC_MEMORY_SIZE_MASK (0xf << 8) +#define GGC_MEMORY_SIZE_NONE (0x0 << 8) +#define GGC_MEMORY_SIZE_1M (0x1 << 8) +#define GGC_MEMORY_SIZE_2M (0x3 << 8) +#define GGC_MEMORY_VT_ENABLED (0x8 << 8) +#define GGC_MEMORY_SIZE_2M_VT (0x9 << 8) +#define GGC_MEMORY_SIZE_3M_VT (0xa << 8) +#define GGC_MEMORY_SIZE_4M_VT (0xb << 8) + static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev) { unsigned short ggc; - if (pci_read_config_word(dev, 0x52, &ggc)) + if (pci_read_config_word(dev, GGC, &ggc)) return; - if (!(ggc & 0x800)) { + if (!(ggc & GGC_MEMORY_VT_ENABLED)) { printk(KERN_INFO "DMAR: BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n"); dmar_map_gfx = 0; } -- cgit v1.2.3-59-g8ed1b From 3d13008e7345fa7a79d8f6438150dc15d6ba6e9d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Sep 2010 08:47:45 +0000 Subject: ip: fix truesize mismatch in ip fragmentation Special care should be taken when slow path is hit in ip_fragment() : When walking through frags, we transfert truesize ownership from skb to frags. Then if we hit a slow_path condition, we must undo this or risk uncharging frags->truesize twice, and in the end, having negative socket sk_wmem_alloc counter, or even freeing socket sooner than expected. Many thanks to Nick Bowler, who provided a very clean bug report and test program. Thanks to Jarek for reviewing my first patch and providing a V2 While Nick bisection pointed to commit 2b85a34e911 (net: No more expensive sock_hold()/sock_put() on each tx), underlying bug is older (2.6.12-rc5) A side effect is to extend work done in commit b2722b1c3a893e (ip_fragment: also adjust skb->truesize for packets not owned by a socket) to ipv6 as well. Reported-and-bisected-by: Nick Bowler Tested-by: Nick Bowler Signed-off-by: Eric Dumazet CC: Jarek Poplawski CC: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/ip_output.c | 19 +++++++++++++------ net/ipv6/ip6_output.c | 18 +++++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 04b69896df5f..7649d7750075 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -488,9 +488,8 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) * we can switch to copy when see the first bad fragment. */ if (skb_has_frags(skb)) { - struct sk_buff *frag; + struct sk_buff *frag, *frag2; int first_len = skb_pagelen(skb); - int truesizes = 0; if (first_len - hlen > mtu || ((first_len - hlen) & 7) || @@ -503,18 +502,18 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) if (frag->len > mtu || ((frag->len & 7) && frag->next) || skb_headroom(frag) < hlen) - goto slow_path; + goto slow_path_clean; /* Partially cloned skb? */ if (skb_shared(frag)) - goto slow_path; + goto slow_path_clean; BUG_ON(frag->sk); if (skb->sk) { frag->sk = skb->sk; frag->destructor = sock_wfree; } - truesizes += frag->truesize; + skb->truesize -= frag->truesize; } /* Everything is OK. Generate! */ @@ -524,7 +523,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) frag = skb_shinfo(skb)->frag_list; skb_frag_list_init(skb); skb->data_len = first_len - skb_headlen(skb); - skb->truesize -= truesizes; skb->len = first_len; iph->tot_len = htons(first_len); iph->frag_off = htons(IP_MF); @@ -576,6 +574,15 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) } IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); return err; + +slow_path_clean: + skb_walk_frags(skb, frag2) { + if (frag2 == frag) + break; + frag2->sk = NULL; + frag2->destructor = NULL; + skb->truesize += frag2->truesize; + } } slow_path: diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d40b330c0ee6..980912ed7a38 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -639,7 +639,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) if (skb_has_frags(skb)) { int first_len = skb_pagelen(skb); - int truesizes = 0; + struct sk_buff *frag2; if (first_len - hlen > mtu || ((first_len - hlen) & 7) || @@ -651,18 +651,18 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) if (frag->len > mtu || ((frag->len & 7) && frag->next) || skb_headroom(frag) < hlen) - goto slow_path; + goto slow_path_clean; /* Partially cloned skb? */ if (skb_shared(frag)) - goto slow_path; + goto slow_path_clean; BUG_ON(frag->sk); if (skb->sk) { frag->sk = skb->sk; frag->destructor = sock_wfree; - truesizes += frag->truesize; } + skb->truesize -= frag->truesize; } err = 0; @@ -693,7 +693,6 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) first_len = skb_pagelen(skb); skb->data_len = first_len - skb_headlen(skb); - skb->truesize -= truesizes; skb->len = first_len; ipv6_hdr(skb)->payload_len = htons(first_len - sizeof(struct ipv6hdr)); @@ -756,6 +755,15 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) IPSTATS_MIB_FRAGFAILS); dst_release(&rt->dst); return err; + +slow_path_clean: + skb_walk_frags(skb, frag2) { + if (frag2 == frag) + break; + frag2->sk = NULL; + frag2->destructor = NULL; + skb->truesize += frag2->truesize; + } } slow_path: -- cgit v1.2.3-59-g8ed1b From 5c64eb26ed5c5550fbabd345e573af3fc6a7f775 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 26 Aug 2010 07:36:44 +0000 Subject: i2c-omap: Make sure i2c bus is free before setting it to idle If the i2c bus receives an interrupt with both BB (bus busy) and ARDY (register access ready) statuses set during the tranfer of the last message the bus was put to idle while still busy. This caused bus to timeout. Signed-off-by: Mathias Nyman Acked-by: Tony Lindgren Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-omap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7674efb55378..b33c78586bfc 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -680,6 +680,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r == 0) r = num; + + omap_i2c_wait_for_bb(dev); out: omap_i2c_idle(dev); return r; -- cgit v1.2.3-59-g8ed1b From 8b15575cae7a93a784c3005c42b069edd9ba64dd Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 21 Sep 2010 14:35:37 -0700 Subject: fs: {lock,unlock}_flocks() stubs to prepare for BKL removal The lock structs are currently protected by the BKL, but are accessed by code in fs/locks.c and misc file system and DLM code. These stubs will allow all users to switch to the new interface before the implementation is changed to a spinlock. Acked-by: Arnd Bergmann Signed-off-by: Sage Weil Signed-off-by: Linus Torvalds --- include/linux/fs.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/fs.h b/include/linux/fs.h index 76041b614758..63d069bd80b7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1093,6 +1093,10 @@ struct file_lock { #include +/* temporary stubs for BKL removal */ +#define lock_flocks() lock_kernel() +#define unlock_flocks() unlock_kernel() + extern void send_sigio(struct fown_struct *fown, int fd, int band); #ifdef CONFIG_FILE_LOCKING -- cgit v1.2.3-59-g8ed1b From 5222454cf941b09205d502242dd1e44fd62aa551 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 22 Sep 2010 12:31:46 +1000 Subject: drm/radeon: don't allow device to be opened if powered down If the switcheroo has switched the device off, don't let X open it. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 5eee3c41d124..8fbbe1c6ebbd 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -203,6 +203,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) */ int radeon_driver_firstopen_kms(struct drm_device *dev) { + struct radeon_device *rdev = dev->dev_private; + + if (rdev->powered_down) + return -EINVAL; return 0; } -- cgit v1.2.3-59-g8ed1b From 0fbecd400dd0a82d465b3086f209681e8c54cb0f Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Tue, 21 Sep 2010 02:15:15 +0200 Subject: drm/ttm: Clear the ghost cpu_writers flag on ttm_buffer_object_transfer. It makes sense for a BO to move after a process has requested exclusive RW access on it (e.g. because the BO used to be located in unmappable VRAM and we intercepted the CPU access from the fault handler). If we let the ghost object inherit cpu_writers from the original object, ttm_bo_release_list() will raise a kernel BUG when the ghost object is destroyed. This can be reproduced with the nouveau driver on nv5x. Reported-by: Marcin Slusarz Reviewed-by: Jerome Glisse Tested-by: Marcin Slusarz Signed-off-by: Francisco Jerez Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo_util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 7cffb3e04232..3451a82adba7 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -351,6 +351,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, INIT_LIST_HEAD(&fbo->lru); INIT_LIST_HEAD(&fbo->swap); fbo->vm_node = NULL; + atomic_set(&fbo->cpu_writers, 0); fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); kref_init(&fbo->list_kref); -- cgit v1.2.3-59-g8ed1b From 392c21802ee3aa85cee0e703105f797a8a7b9416 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 21 Sep 2010 21:41:12 -0700 Subject: sparc: Don't mask signal when we can't setup signal frame. Don't invoke the signal handler tracehook in that situation either. Reported-by: Al Viro Signed-off-by: David S. Miller --- arch/sparc/kernel/signal32.c | 55 ++++++++++++++++++++++++++----------------- arch/sparc/kernel/signal_32.c | 53 +++++++++++++++++++++++++---------------- arch/sparc/kernel/signal_64.c | 43 ++++++++++++++++++++------------- 3 files changed, 93 insertions(+), 58 deletions(-) diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 76b67c4c6aa4..643a354795cc 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -511,8 +511,8 @@ out_irqs_on: } -static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, - int signo, sigset_t *oldset) +static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct signal_frame32 __user *sf; int sigframe_size; @@ -620,13 +620,16 @@ static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, sigill: do_exit(SIGILL); + return -EINVAL; + sigsegv: force_sigsegv(signo, current); + return -EFAULT; } -static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, - unsigned long signr, sigset_t *oldset, - siginfo_t *info) +static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, + unsigned long signr, sigset_t *oldset, + siginfo_t *info) { struct rt_signal_frame32 __user *sf; int sigframe_size; @@ -738,22 +741,30 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, flush_signal_insns(address); } - return; + return 0; sigill: do_exit(SIGILL); + return -EINVAL; + sigsegv: force_sigsegv(signr, current); + return -EFAULT; } -static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, - siginfo_t *info, - sigset_t *oldset, struct pt_regs *regs) +static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka, + siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) { + int err; + if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame32(ka, regs, signr, oldset, info); + err = setup_rt_frame32(ka, regs, signr, oldset, info); else - setup_frame32(ka, regs, signr, oldset); + err = setup_frame32(ka, regs, signr, oldset); + + if (err) + return err; spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -761,6 +772,10 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, sigaddset(¤t->blocked,signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + tracehook_signal_handler(signr, info, ka, regs, 0); + + return 0; } static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, @@ -807,16 +822,14 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs, if (signr > 0) { if (restart_syscall) syscall_restart32(orig_i0, regs, &ka.sa); - handle_signal32(signr, &ka, &info, oldset, regs); - - /* A signal was successfully delivered; the saved - * sigmask will have been stored in the signal frame, - * and will be restored by sigreturn, so we can simply - * clear the TS_RESTORE_SIGMASK flag. - */ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - - tracehook_signal_handler(signr, &info, &ka, regs, 0); + if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) { + /* A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + } return; } if (restart_syscall && diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 9882df92ba0a..99c85e99bbcf 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -315,8 +315,8 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) return err; } -static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs, - int signo, sigset_t *oldset) +static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct signal_frame __user *sf; int sigframe_size, err; @@ -384,16 +384,19 @@ static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs, /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); } - return; + return 0; sigill_and_return: do_exit(SIGILL); + return -EINVAL; + sigsegv: force_sigsegv(signo, current); + return -EFAULT; } -static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, - int signo, sigset_t *oldset, siginfo_t *info) +static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset, siginfo_t *info) { struct rt_signal_frame __user *sf; int sigframe_size; @@ -466,22 +469,30 @@ static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); } - return; + return 0; sigill: do_exit(SIGILL); + return -EINVAL; + sigsegv: force_sigsegv(signo, current); + return -EFAULT; } -static inline void +static inline int handle_signal(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { + int err; + if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(ka, regs, signr, oldset, info); + err = setup_rt_frame(ka, regs, signr, oldset, info); else - setup_frame(ka, regs, signr, oldset); + err = setup_frame(ka, regs, signr, oldset); + + if (err) + return err; spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -489,6 +500,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka, sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + tracehook_signal_handler(signr, info, ka, regs, 0); + + return 0; } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -546,17 +561,15 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) if (signr > 0) { if (restart_syscall) syscall_restart(orig_i0, regs, &ka.sa); - handle_signal(signr, &ka, &info, oldset, regs); - - /* a signal was successfully delivered; the saved - * sigmask will have been stored in the signal frame, - * and will be restored by sigreturn, so we can simply - * clear the TIF_RESTORE_SIGMASK flag. - */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); - - tracehook_signal_handler(signr, &info, &ka, regs, 0); + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } return; } if (restart_syscall && diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 9fa48c30037e..3f19e673e2cd 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -409,7 +409,7 @@ static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs * return (void __user *) sp; } -static inline void +static inline int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { @@ -483,26 +483,37 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, } /* 4. return to kernel instructions */ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; - return; + return 0; sigill: do_exit(SIGILL); + return -EINVAL; + sigsegv: force_sigsegv(signo, current); + return -EFAULT; } -static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, - siginfo_t *info, - sigset_t *oldset, struct pt_regs *regs) +static inline int handle_signal(unsigned long signr, struct k_sigaction *ka, + siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) { - setup_rt_frame(ka, regs, signr, oldset, - (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); + int err; + + err = setup_rt_frame(ka, regs, signr, oldset, + (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); + if (err) + return err; spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NOMASK)) sigaddset(¤t->blocked,signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + tracehook_signal_handler(signr, info, ka, regs, 0); + + return 0; } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -571,16 +582,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) if (signr > 0) { if (restart_syscall) syscall_restart(orig_i0, regs, &ka.sa); - handle_signal(signr, &ka, &info, oldset, regs); - - /* A signal was successfully delivered; the saved - * sigmask will have been stored in the signal frame, - * and will be restored by sigreturn, so we can simply - * clear the TS_RESTORE_SIGMASK flag. - */ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; - - tracehook_signal_handler(signr, &info, &ka, regs, 0); + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { + /* A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + } return; } if (restart_syscall && -- cgit v1.2.3-59-g8ed1b From c27852597829128a9c9d96d79ec454a83c6b0da5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 21 Sep 2010 22:30:13 -0700 Subject: sparc: Prevent no-handler signal syscall restart recursion. Explicitly clear the "in-syscall" bit when we have no signal handler and back up the program counters to back up the system call. Reported-by: Al Viro Signed-off-by: David S. Miller --- arch/sparc/kernel/signal32.c | 4 +++- arch/sparc/kernel/signal_32.c | 2 ++ arch/sparc/kernel/signal_64.c | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 643a354795cc..75fad425e249 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -616,7 +616,7 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, flush_signal_insns(address); } - return; + return 0; sigill: do_exit(SIGILL); @@ -840,12 +840,14 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs, regs->u_regs[UREG_I0] = orig_i0; regs->tpc -= 4; regs->tnpc -= 4; + pt_regs_clear_syscall(regs); } if (restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->tpc -= 4; regs->tnpc -= 4; + pt_regs_clear_syscall(regs); } /* If there's no signal to deliver, we just put the saved sigmask diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 99c85e99bbcf..5e5c5fd03783 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -580,12 +580,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) regs->u_regs[UREG_I0] = orig_i0; regs->pc -= 4; regs->npc -= 4; + pt_regs_clear_syscall(regs); } if (restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->pc -= 4; regs->npc -= 4; + pt_regs_clear_syscall(regs); } /* if there's no signal to deliver, we just put the saved sigmask diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 3f19e673e2cd..006fe4515886 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -600,12 +600,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) regs->u_regs[UREG_I0] = orig_i0; regs->tpc -= 4; regs->tnpc -= 4; + pt_regs_clear_syscall(regs); } if (restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->tpc -= 4; regs->tnpc -= 4; + pt_regs_clear_syscall(regs); } /* If there's no signal to deliver, we just put the saved sigmask -- cgit v1.2.3-59-g8ed1b From 976e48f8a5b02fc33f3e5cad87fb3fcea041a49c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 21 Sep 2010 11:48:55 +0200 Subject: bdi: Initialize noop_backing_dev_info properly Properly initialize this backing dev info so that writeback code does not barf when getting to it e.g. via sb->s_bdi. Cc: stable@kernel.org Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- mm/backing-dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/backing-dev.c b/mm/backing-dev.c index c2bf86f470ed..65d420499a61 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -30,6 +30,7 @@ EXPORT_SYMBOL_GPL(default_backing_dev_info); struct backing_dev_info noop_backing_dev_info = { .name = "noop", + .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, }; EXPORT_SYMBOL_GPL(noop_backing_dev_info); @@ -243,6 +244,7 @@ static int __init default_bdi_init(void) err = bdi_init(&default_backing_dev_info); if (!err) bdi_register(&default_backing_dev_info, NULL, "default"); + err = bdi_init(&noop_backing_dev_info); return err; } -- cgit v1.2.3-59-g8ed1b From 371d217ee1ff8b418b8f73fb2a34990f951ec2d4 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 21 Sep 2010 11:49:01 +0200 Subject: char: Mark /dev/zero and /dev/kmem as not capable of writeback These devices don't do any writeback but their device inodes still can get dirty so mark bdi appropriately so that bdi code does the right thing and files inodes to lists of bdi carrying the device inodes. Cc: stable@kernel.org Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- drivers/char/mem.c | 3 ++- fs/char_dev.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index a398ecdbd758..1f528fad3516 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -788,10 +788,11 @@ static const struct file_operations zero_fops = { /* * capabilities for /dev/zero * - permits private mappings, "copies" are taken of the source of zeros + * - no writeback happens */ static struct backing_dev_info zero_bdi = { .name = "char/mem", - .capabilities = BDI_CAP_MAP_COPY, + .capabilities = BDI_CAP_MAP_COPY | BDI_CAP_NO_ACCT_AND_WRITEBACK, }; static const struct file_operations full_fops = { diff --git a/fs/char_dev.c b/fs/char_dev.c index f80a4f25123c..143d393881cb 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -40,7 +40,9 @@ struct backing_dev_info directly_mappable_cdev_bdi = { #endif /* permit direct mmap, for read, write or exec */ BDI_CAP_MAP_DIRECT | - BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP), + BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP | + /* no writeback happens */ + BDI_CAP_NO_ACCT_AND_WRITEBACK), }; static struct kobj_map *cdev_map; -- cgit v1.2.3-59-g8ed1b From 692ebd17c2905313fff3c504c249c6a0faad16ec Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 21 Sep 2010 11:51:01 +0200 Subject: bdi: Fix warnings in __mark_inode_dirty for /dev/zero and friends Inodes of devices such as /dev/zero can get dirty for example via utime(2) syscall or due to atime update. Backing device of such inodes (zero_bdi, etc.) is however unable to handle dirty inodes and thus __mark_inode_dirty complains. In fact, inode should be rather dirtied against backing device of the filesystem holding it. This is generally a good rule except for filesystems such as 'bdev' or 'mtd_inodefs'. Inodes in these pseudofilesystems are referenced from ordinary filesystem inodes and carry mapping with real data of the device. Thus for these inodes we have to use inode->i_mapping->backing_dev_info as we did so far. We distinguish these filesystems by checking whether sb->s_bdi points to a non-trivial backing device or not. Example: Assume we have an ext3 filesystem on /dev/sda1 mounted on /. There's a device inode A described by a path "/dev/sdb" on this filesystem. This inode will be dirtied against backing device "8:0" after this patch. bdev filesystem contains block device inode B coupled with our inode A. When someone modifies a page of /dev/sdb, it's B that gets dirtied and the dirtying happens against the backing device "8:16". Thus both inodes get filed to a correct bdi list. Cc: stable@kernel.org Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- fs/fs-writeback.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 81e086d8aa57..5581122bd2c0 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -52,8 +52,6 @@ struct wb_writeback_work { #define CREATE_TRACE_POINTS #include -#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) - /* * We don't actually have pdflush, but this one is exported though /proc... */ @@ -71,6 +69,27 @@ int writeback_in_progress(struct backing_dev_info *bdi) return test_bit(BDI_writeback_running, &bdi->state); } +static inline struct backing_dev_info *inode_to_bdi(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct backing_dev_info *bdi = inode->i_mapping->backing_dev_info; + + /* + * For inodes on standard filesystems, we use superblock's bdi. For + * inodes on virtual filesystems, we want to use inode mapping's bdi + * because they can possibly point to something useful (think about + * block_dev filesystem). + */ + if (sb->s_bdi && sb->s_bdi != &noop_backing_dev_info) { + /* Some device inodes could play dirty tricks. Catch them... */ + WARN(bdi != sb->s_bdi && bdi_cap_writeback_dirty(bdi), + "Dirtiable inode bdi %s != sb bdi %s\n", + bdi->name, sb->s_bdi->name); + return sb->s_bdi; + } + return bdi; +} + static void bdi_queue_work(struct backing_dev_info *bdi, struct wb_writeback_work *work) { -- cgit v1.2.3-59-g8ed1b From 0873a5ae747847ee55a63db409dff3476e45bcd9 Mon Sep 17 00:00:00 2001 From: "Erik J. Staab" Date: Wed, 22 Sep 2010 11:07:41 +0200 Subject: ALSA: oxygen: fix analog capture on Claro halo cards On the HT-Omega Claro halo card, the ADC data must be captured from the second I2S input. Using the default first input, which isn't connected to anything, would result in silence. Signed-off-by: Erik J. Staab Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 289cb4dacfc7..6c0a11adb2a8 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -543,6 +543,10 @@ static int __devinit get_oxygen_model(struct oxygen *chip, chip->model.suspend = claro_suspend; chip->model.resume = claro_resume; chip->model.set_adc_params = set_ak5385_params; + chip->model.device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2 | + CAPTURE_1_FROM_SPDIF; break; } if (id->driver_data == MODEL_MERIDIAN || -- cgit v1.2.3-59-g8ed1b From 5786aee8bf6d747ea59595601a19e78ad33d6929 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 22 Sep 2010 12:31:53 +0200 Subject: vhost: fix log ctx signalling The log eventfd signalling got put in dead code. We didn't notice because qemu currently does polling instead of eventfd select. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c579dcc9200c..dd3d6f7406f8 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -858,11 +858,12 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, if (r < 0) return r; len -= l; - if (!len) + if (!len) { + if (vq->log_ctx) + eventfd_signal(vq->log_ctx, 1); return 0; + } } - if (vq->log_ctx) - eventfd_signal(vq->log_ctx, 1); /* Length written exceeds what we have stored. This is a bug. */ BUG(); return 0; -- cgit v1.2.3-59-g8ed1b From 9a81c16b527528ad307843be5571111aa8d35a80 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Sep 2010 21:48:57 +0100 Subject: powerpc: fix double syscall restarts Make sigreturn zero regs->trap, make do_signal() do the same on all paths. As it is, signal interrupting e.g. read() from fd 512 (== ERESTARTSYS) with another signal getting unblocked when the first handler finishes will lead to restart one insn earlier than it ought to. Same for multiple signals with in-kernel handlers interrupting that sucker at the same time. Same for multiple signals of any kind interrupting that sucker on 64bit... Signed-off-by: Al Viro Acked-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/powerpc/kernel/signal.c | 2 ++ arch/powerpc/kernel/signal_32.c | 3 +-- arch/powerpc/kernel/signal_64.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 7109f5b1baa8..2300426e531a 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -138,6 +138,7 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) ti->local_flags &= ~_TLF_RESTORE_SIGMASK; sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } + regs->trap = 0; return 0; /* no signals delivered */ } @@ -164,6 +165,7 @@ static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) ret = handle_rt_signal64(signr, &ka, &info, oldset, regs); } + regs->trap = 0; if (ret) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked, ¤t->blocked, diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 266610119f66..b96a3a010c26 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -511,6 +511,7 @@ static long restore_user_regs(struct pt_regs *regs, if (!sig) save_r2 = (unsigned int)regs->gpr[2]; err = restore_general_regs(regs, sr); + regs->trap = 0; err |= __get_user(msr, &sr->mc_gregs[PT_MSR]); if (!sig) regs->gpr[2] = (unsigned long) save_r2; @@ -884,7 +885,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, regs->nip = (unsigned long) ka->sa.sa_handler; /* enter the signal handler in big-endian mode */ regs->msr &= ~MSR_LE; - regs->trap = 0; return 1; badframe: @@ -1228,7 +1228,6 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, regs->nip = (unsigned long) ka->sa.sa_handler; /* enter the signal handler in big-endian mode */ regs->msr &= ~MSR_LE; - regs->trap = 0; return 1; diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 2fe6fc64b614..27c4a4584f80 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -178,7 +178,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]); err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]); /* skip SOFTE */ - err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]); + regs->trap = 0; err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]); err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]); err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]); -- cgit v1.2.3-59-g8ed1b From d485d500cf6b13a33bc7a6c09091deea7ea603ca Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Sep 2010 21:17:29 +0000 Subject: netfilter: tproxy: nf_tproxy_assign_sock() can handle tw sockets transparent field of a socket is either inet_twsk(sk)->tw_transparent for timewait sockets, or inet_sk(sk)->transparent for other sockets (TCP/UDP). Signed-off-by: Eric Dumazet Acked-by: David S. Miller Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_tproxy_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_tproxy_core.c b/net/netfilter/nf_tproxy_core.c index 5490fc37c92d..daab8c4a903c 100644 --- a/net/netfilter/nf_tproxy_core.c +++ b/net/netfilter/nf_tproxy_core.c @@ -70,7 +70,11 @@ nf_tproxy_destructor(struct sk_buff *skb) int nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk) { - if (inet_sk(sk)->transparent) { + bool transparent = (sk->sk_state == TCP_TIME_WAIT) ? + inet_twsk(sk)->tw_transparent : + inet_sk(sk)->transparent; + + if (transparent) { skb_orphan(skb); skb->sk = sk; skb->destructor = nf_tproxy_destructor; -- cgit v1.2.3-59-g8ed1b From 7874896a26624214bd7c05eeba7c8ab01548b1b5 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 21 Sep 2010 21:17:30 +0000 Subject: netfilter: nf_ct_sip: default to NF_ACCEPT in sip_help_tcp() I initially noticed this because of the compiler warning below, but it does seem to be a valid concern in the case where ct_sip_get_header() returns 0 in the first iteration of the while loop. net/netfilter/nf_conntrack_sip.c: In function 'sip_help_tcp': net/netfilter/nf_conntrack_sip.c:1379: warning: 'ret' may be used uninitialized in this function Signed-off-by: Simon Horman [Patrick: changed NF_DROP to NF_ACCEPT] Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 53d892210a04..f64de9544866 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -1376,7 +1376,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, unsigned int msglen, origlen; const char *dptr, *end; s16 diff, tdiff = 0; - int ret; + int ret = NF_ACCEPT; typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; if (ctinfo != IP_CT_ESTABLISHED && -- cgit v1.2.3-59-g8ed1b From b46ffb854554ff939701bdd492b81558da5706fc Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Tue, 21 Sep 2010 21:17:31 +0000 Subject: netfilter: fix ipt_REJECT TCP RST routing for indev == outdev ip_route_me_harder can't create the route cache when the outdev is the same with the indev for the skbs whichout a valid protocol set. __mkroute_input functions has this check: 1998 if (skb->protocol != htons(ETH_P_IP)) { 1999 /* Not IP (i.e. ARP). Do not create route, if it is 2000 * invalid for proxy arp. DNAT routes are always valid. 2001 * 2002 * Proxy arp feature have been extended to allow, ARP 2003 * replies back to the same interface, to support 2004 * Private VLAN switch technologies. See arp.c. 2005 */ 2006 if (out_dev == in_dev && 2007 IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) { 2008 err = -EINVAL; 2009 goto cleanup; 2010 } 2011 } This patch gives the new skb a valid protocol to bypass this check. In order to make ipt_REJECT work with bridges, you also need to enable ip_forward. This patch also fixes a regression. When we used skb_copy_expand(), we didn't have this issue stated above, as the protocol was properly set. Signed-off-by: Changli Gao Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_REJECT.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index b254dafaf429..43eec80c0e7c 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -112,6 +112,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) /* ip_route_me_harder expects skb->dst to be set */ skb_dst_set_noref(nskb, skb_dst(oldskb)); + nskb->protocol = htons(ETH_P_IP); if (ip_route_me_harder(nskb, addr_type)) goto free_nskb; -- cgit v1.2.3-59-g8ed1b From 15cdeadaa5d76009e20c7792aed69f5a73808f97 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Sep 2010 21:17:32 +0000 Subject: netfilter: fix a race in nf_ct_ext_create() As soon as rcu_read_unlock() is called, there is no guarantee current thread can safely derefence t pointer, rcu protected. Fix is to copy t->alloc_size in a temporary variable. Signed-off-by: Eric Dumazet Reviewed-by: Paul E. McKenney Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_extend.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 7dcf7a404190..8d9e4c949b96 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c @@ -48,15 +48,17 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp) { unsigned int off, len; struct nf_ct_ext_type *t; + size_t alloc_size; rcu_read_lock(); t = rcu_dereference(nf_ct_ext_types[id]); BUG_ON(t == NULL); off = ALIGN(sizeof(struct nf_ct_ext), t->align); len = off + t->len; + alloc_size = t->alloc_size; rcu_read_unlock(); - *ext = kzalloc(t->alloc_size, gfp); + *ext = kzalloc(alloc_size, gfp); if (!*ext) return NULL; -- cgit v1.2.3-59-g8ed1b From d6120b8afacec587f5feb37781bc751bc5d68a10 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 21 Sep 2010 21:17:33 +0000 Subject: netfilter: nf_nat_snmp: fix checksum calculation (v4) Fix checksum calculation in nf_nat_snmp_basic. Based on patches by Clark Wang and Stephen Hemminger . https://bugzilla.kernel.org/show_bug.cgi?id=17622 Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_snmp_basic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 1679e2c0963d..ee5f419d0a56 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -893,13 +893,15 @@ static void fast_csum(__sum16 *csum, unsigned char s[4]; if (offset & 1) { - s[0] = s[2] = 0; + s[0] = ~0; s[1] = ~*optr; + s[2] = 0; s[3] = *nptr; } else { - s[1] = s[3] = 0; s[0] = ~*optr; + s[1] = ~0; s[2] = *nptr; + s[3] = 0; } *csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum))); -- cgit v1.2.3-59-g8ed1b From cbdd769ab9de26764bde0520a91536caa1587e13 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 21 Sep 2010 21:17:34 +0000 Subject: netfilter: nf_conntrack_defrag: check socket type before touching nodefrag flag we need to check proper socket type within ipv4_conntrack_defrag function before referencing the nodefrag flag. For example the tun driver receive path produces skbs with AF_UNSPEC socket type, and so current code is causing unwanted fragmented packets going out. Signed-off-by: Jiri Olsa Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_defrag_ipv4.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index eab8de32f200..f3a9b42b16c6 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -66,9 +66,11 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { + struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(skb->sk); - if (inet && inet->nodefrag) + if (sk && (sk->sk_family == PF_INET) && + inet->nodefrag) return NF_ACCEPT; #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) -- cgit v1.2.3-59-g8ed1b From 56b49f4b8f6728b91d10c556c116175051b77b60 Mon Sep 17 00:00:00 2001 From: Ollie Wild Date: Wed, 22 Sep 2010 05:54:54 +0000 Subject: net: Move "struct net" declaration inside the __KERNEL__ macro guard This patch reduces namespace pollution by moving the "struct net" declaration out of the userspace-facing portion of linux/netlink.h. It has no impact on the kernel. (This came up because we have several C++ applications which use "net" as a namespace name.) Signed-off-by: Ollie Wild Signed-off-by: David S. Miller --- include/linux/netlink.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 59d066936ab9..123566912d73 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -27,8 +27,6 @@ #define MAX_LINKS 32 -struct net; - struct sockaddr_nl { sa_family_t nl_family; /* AF_NETLINK */ unsigned short nl_pad; /* zero */ @@ -151,6 +149,8 @@ struct nlattr { #include #include +struct net; + static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb) { return (struct nlmsghdr *)skb->data; -- cgit v1.2.3-59-g8ed1b From ec5a32f67c603b11d68eb283d94eb89a4f6cfce1 Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Wed, 22 Sep 2010 10:41:58 +0000 Subject: atl1: fix resume adapter->cmb.cmb is initialized when the device is opened and freed when it's closed. Accessing it unconditionally during resume results either in a crash (NULL pointer dereference, when the interface has not been opened yet) or data corruption (when the interface has been used and brought down adapter->cmb.cmb points to a deallocated memory area). Cc: stable@kernel.org Signed-off-by: Luca Tettamanti Acked-by: Chris Snook Signed-off-by: David S. Miller --- drivers/net/atlx/atl1.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 63b9ba0cc67e..bbd6e3009be0 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -2847,10 +2847,11 @@ static int atl1_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3cold, 0); atl1_reset_hw(&adapter->hw); - adapter->cmb.cmb->int_stats = 0; - if (netif_running(netdev)) + if (netif_running(netdev)) { + adapter->cmb.cmb->int_stats = 0; atl1_up(adapter); + } netif_device_attach(netdev); return 0; -- cgit v1.2.3-59-g8ed1b From 3f5a2a713aad28480d86b0add00c68484b54febc Mon Sep 17 00:00:00 2001 From: Luca Tettamanti Date: Wed, 22 Sep 2010 10:42:31 +0000 Subject: atl1: zero out CMB and SBM in atl1_free_ring_resources They are allocated in atl1_setup_ring_resources, zero out the pointers in atl1_free_ring_resources (like the other resources). Signed-off-by: Luca Tettamanti Acked-by: Chris Snook Signed-off-by: David S. Miller --- drivers/net/atlx/atl1.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index bbd6e3009be0..c73be2848319 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -1251,6 +1251,12 @@ static void atl1_free_ring_resources(struct atl1_adapter *adapter) rrd_ring->desc = NULL; rrd_ring->dma = 0; + + adapter->cmb.dma = 0; + adapter->cmb.cmb = NULL; + + adapter->smb.dma = 0; + adapter->smb.smb = NULL; } static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter) -- cgit v1.2.3-59-g8ed1b From 9f9ff20d46c6728b092f34b6a642e1e81ab5e254 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 14 Aug 2010 11:01:45 +0200 Subject: dma/shdma: move dereference below the NULL check "param" can be NULL here, so only dereference it after the check. Signed-off-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/dma/shdma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index fb64cf36ba61..eb6b54dbb806 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -580,7 +580,6 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg( sh_chan = to_sh_chan(chan); param = chan->private; - slave_addr = param->config->addr; /* Someone calling slave DMA on a public channel? */ if (!param || !sg_len) { @@ -589,6 +588,8 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg( return NULL; } + slave_addr = param->config->addr; + /* * if (param != NULL), this is a successfully requested slave channel, * therefore param->config != NULL too. -- cgit v1.2.3-59-g8ed1b From d3f3cf859db17cc5f8156c5bfcd032413e44483b Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Sat, 14 Aug 2010 15:02:44 +0200 Subject: missing inline keyword for static function in linux/dmaengine.h Add a missing inline keyword for static function in linux/dmaengine.h to avoid duplicate symbol definitions. Signed-off-by: Mathieu Lacage Signed-off-by: Dan Williams --- include/linux/dmaengine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index c61d4ca27bcc..e2106495cc11 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -548,7 +548,7 @@ static inline bool dma_dev_has_pq_continue(struct dma_device *dma) return (dma->max_pq & DMA_HAS_PQ_CONTINUE) == DMA_HAS_PQ_CONTINUE; } -static unsigned short dma_dev_to_maxpq(struct dma_device *dma) +static inline unsigned short dma_dev_to_maxpq(struct dma_device *dma) { return dma->max_pq & ~DMA_HAS_PQ_CONTINUE; } -- cgit v1.2.3-59-g8ed1b From 767b68e96993e29e3480d7ecdd9c4b84667c5762 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Wed, 22 Sep 2010 14:32:56 -0400 Subject: Prevent freeing uninitialized pointer in compat_do_readv_writev In 32-bit compatibility mode, the error handling for compat_do_readv_writev() may free an uninitialized pointer, potentially leading to all sorts of ugly memory corruption. This is reliably triggerable by unprivileged users by invoking the readv()/writev() syscalls with an invalid iovec pointer. The below patch fixes this to emulate the non-compat version. Introduced by commit b83733639a49 ("compat: factor out compat_rw_copy_check_uvector from compat_do_readv_writev") Signed-off-by: Dan Rosenberg Cc: stable@kernel.org (2.6.35) Cc: Al Viro Signed-off-by: Linus Torvalds --- fs/compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/compat.c b/fs/compat.c index 718c7062aec1..0644a154672b 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -1153,7 +1153,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, { compat_ssize_t tot_len; struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov; + struct iovec *iov = iovstack; ssize_t ret; io_fn_t fn; iov_fn_t fnv; -- cgit v1.2.3-59-g8ed1b From f19e8aa11afa24036c6273428da51949b5acf30c Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 22 Sep 2010 13:04:52 -0700 Subject: oom: always return a badness score of non-zero for eligible tasks A task's badness score is roughly a proportion of its rss and swap compared to the system's capacity. The scale ranges from 0 to 1000 with the highest score chosen for kill. Thus, this scale operates on a resolution of 0.1% of RAM + swap. Admin tasks are also given a 3% bonus, so the badness score of an admin task using 3% of memory, for example, would still be 0. It's possible that an exceptionally large number of tasks will combine to exhaust all resources but never have a single task that uses more than 0.1% of RAM and swap (or 3.0% for admin tasks). This patch ensures that the badness score of any eligible task is never 0 so the machine doesn't unnecessarily panic because it cannot find a task to kill. Signed-off-by: David Rientjes Cc: Dave Hansen Cc: Nitin Gupta Cc: Pekka Enberg Cc: Minchan Kim Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/oom_kill.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index fc81cb22869e..859250c7dc06 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -208,8 +208,13 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem, */ points += p->signal->oom_score_adj; - if (points < 0) - return 0; + /* + * Never return 0 for an eligible task that may be killed since it's + * possible that no single user task uses more than 0.1% of memory and + * no single admin tasks uses more than 3.0%. + */ + if (points <= 0) + return 1; return (points < 1000) ? points : 1000; } -- cgit v1.2.3-59-g8ed1b From a9e31765e7d528858e1b0c202b823cf4df7577ca Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 22 Sep 2010 13:04:53 -0700 Subject: ipmi: fix acpi probe print After d9e1b6c45059ccf ("ipmi: fix ACPI detection with regspacing") we get [ 11.026326] ipmi_si: probing via ACPI [ 11.030019] ipmi_si 00:09: (null) regsize 1 spacing 1 irq 0 [ 11.035594] ipmi_si: Adding ACPI-specified kcs state machine on an old system with only one range for ipmi kcs range. Try to fix it by adding another res pointer. Signed-off-by: Yinghai Lu Signed-off-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 3822b4f49c84..2be457a0c0c3 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2126,7 +2126,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, { struct acpi_device *acpi_dev; struct smi_info *info; - struct resource *res; + struct resource *res, *res_second; acpi_handle handle; acpi_status status; unsigned long long tmp; @@ -2182,13 +2182,13 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, info->io.addr_data = res->start; info->io.regspacing = DEFAULT_REGSPACING; - res = pnp_get_resource(dev, + res_second = pnp_get_resource(dev, (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? IORESOURCE_IO : IORESOURCE_MEM, 1); - if (res) { - if (res->start > info->io.addr_data) - info->io.regspacing = res->start - info->io.addr_data; + if (res_second) { + if (res_second->start > info->io.addr_data) + info->io.regspacing = res_second->start - info->io.addr_data; } info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = 0; -- cgit v1.2.3-59-g8ed1b From c227e69028473c7c7994a9b0a2cc0034f3f7e0fe Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 22 Sep 2010 13:04:54 -0700 Subject: /proc/vmcore: fix seeking Commit 73296bc611 ("procfs: Use generic_file_llseek in /proc/vmcore") broke seeking on /proc/vmcore. This changes it back to use default_llseek in order to restore the original behaviour. The problem with generic_file_llseek is that it only allows seeks up to inode->i_sb->s_maxbytes, which is zero on procfs and some other virtual file systems. We should merge generic_file_llseek and default_llseek some day and clean this up in a proper way, but for 2.6.35/36, reverting vmcore is the safer solution. Signed-off-by: Arnd Bergmann Cc: Frederic Weisbecker Reported-by: CAI Qian Tested-by: CAI Qian Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/vmcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 91c817ff02c3..2367fb3f70bc 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -163,7 +163,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, static const struct file_operations proc_vmcore_operations = { .read = read_vmcore, - .llseek = generic_file_llseek, + .llseek = default_llseek, }; static struct vmcore* __init get_new_element(void) -- cgit v1.2.3-59-g8ed1b From 710224fa2750cf449c02dd115548acebfdd2c86a Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 22 Sep 2010 13:04:55 -0700 Subject: arm: fix "arm: fix pci_set_consistent_dma_mask for dmabounce devices" This fixes the regression caused by the commit 6fee48cd330c68 ("dma-mapping: arm: use generic pci_set_dma_mask and pci_set_consistent_dma_mask"). ARM needs to clip the dma coherent mask for dmabounce devices. This restores the old trick. Note that strictly speaking, the DMA API doesn't allow architectures to do such but I'm not sure it's worth adding the new API to set the dma mask that allows architectures to clip it. Reported-by: Krzysztof Halasa Signed-off-by: FUJITA Tomonori Acked-by: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/common/it8152.c | 8 ++++++++ arch/arm/mach-ixp4xx/common-pci.c | 8 ++++++++ arch/arm/mach-ixp4xx/include/mach/hardware.h | 2 ++ arch/arm/mach-pxa/include/mach/hardware.h | 2 +- arch/arm/mach-pxa/include/mach/io.h | 2 ++ include/linux/dma-mapping.h | 4 ++++ 6 files changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index 7974baacafce..1bec96e85196 100644 --- a/arch/arm/common/it8152.c +++ b/arch/arm/common/it8152.c @@ -271,6 +271,14 @@ int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); } +int dma_set_coherent_mask(struct device *dev, u64 mask) +{ + if (mask >= PHYS_OFFSET + SZ_64M - 1) + return 0; + + return -EIO; +} + int __init it8152_pci_setup(int nr, struct pci_sys_data *sys) { it8152_io.start = IT8152_IO_BASE + 0x12000; diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index 61cd4d64b985..24498a932ba6 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -503,6 +503,14 @@ struct pci_bus * __devinit ixp4xx_scan_bus(int nr, struct pci_sys_data *sys) return pci_scan_bus(sys->busnr, &ixp4xx_ops, sys); } +int dma_set_coherent_mask(struct device *dev, u64 mask) +{ + if (mask >= SZ_64M - 1) + return 0; + + return -EIO; +} + EXPORT_SYMBOL(ixp4xx_pci_read); EXPORT_SYMBOL(ixp4xx_pci_write); diff --git a/arch/arm/mach-ixp4xx/include/mach/hardware.h b/arch/arm/mach-ixp4xx/include/mach/hardware.h index f91ca6d4fbe8..8138371c406e 100644 --- a/arch/arm/mach-ixp4xx/include/mach/hardware.h +++ b/arch/arm/mach-ixp4xx/include/mach/hardware.h @@ -26,6 +26,8 @@ #define PCIBIOS_MAX_MEM 0x4BFFFFFF #endif +#define ARCH_HAS_DMA_SET_COHERENT_MASK + #define pcibios_assign_all_busses() 1 /* Register locations and bits */ diff --git a/arch/arm/mach-pxa/include/mach/hardware.h b/arch/arm/mach-pxa/include/mach/hardware.h index 7f64d24cd564..428cc7bda9a4 100644 --- a/arch/arm/mach-pxa/include/mach/hardware.h +++ b/arch/arm/mach-pxa/include/mach/hardware.h @@ -309,7 +309,7 @@ extern unsigned long get_clock_tick_rate(void); #define PCIBIOS_MIN_IO 0 #define PCIBIOS_MIN_MEM 0 #define pcibios_assign_all_busses() 1 +#define ARCH_HAS_DMA_SET_COHERENT_MASK #endif - #endif /* _ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-pxa/include/mach/io.h b/arch/arm/mach-pxa/include/mach/io.h index 262691fb97d8..fdca3be47d9b 100644 --- a/arch/arm/mach-pxa/include/mach/io.h +++ b/arch/arm/mach-pxa/include/mach/io.h @@ -6,6 +6,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#include + #define IO_SPACE_LIMIT 0xffffffff /* diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index ce29b8151198..ba8319ae5fcc 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -102,6 +102,9 @@ static inline u64 dma_get_mask(struct device *dev) return DMA_BIT_MASK(32); } +#ifdef ARCH_HAS_DMA_SET_COHERENT_MASK +int dma_set_coherent_mask(struct device *dev, u64 mask); +#else static inline int dma_set_coherent_mask(struct device *dev, u64 mask) { if (!dma_supported(dev, mask)) @@ -109,6 +112,7 @@ static inline int dma_set_coherent_mask(struct device *dev, u64 mask) dev->coherent_dma_mask = mask; return 0; } +#endif extern u64 dma_get_required_mask(struct device *dev); -- cgit v1.2.3-59-g8ed1b From d544b7a40ad3423676b8876aad64fc5f87296b2d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 22 Sep 2010 13:04:57 -0700 Subject: vmware balloon: rename module In an effort to minimize customer confusion we want to unify naming convention for VMware-provided kernel modules. This change renames the balloon driver from vmware_ballon to vmw_balloon. We expect to follow this naming convention (vmw_) for all modules that are part of mainline kernel and/or being distributed by VMware, with the sole exception of vmxnet3 driver (since the name of mainline driver happens to match with the name used in VMware Tools). Signed-off-by: Dmitry Torokhov Acked-by: Bhavesh Davda Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 2 +- drivers/misc/Makefile | 2 +- drivers/misc/vmw_balloon.c | 844 ++++++++++++++++++++++++++++++++++++++++++ drivers/misc/vmware_balloon.c | 844 ------------------------------------------ 4 files changed, 846 insertions(+), 846 deletions(-) create mode 100644 drivers/misc/vmw_balloon.c delete mode 100644 drivers/misc/vmware_balloon.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0b591b658243..b74331260744 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -368,7 +368,7 @@ config VMWARE_BALLOON If unsure, say N. To compile this driver as a module, choose M here: the - module will be called vmware_balloon. + module will be called vmw_balloon. config ARM_CHARLCD bool "ARM Ltd. Character LCD Driver" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 255a80dc9d73..42eab95cde2a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -33,5 +33,5 @@ obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ obj-$(CONFIG_HMC6352) += hmc6352.o obj-y += eeprom/ obj-y += cb710/ -obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o +obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c new file mode 100644 index 000000000000..2a1e804a71aa --- /dev/null +++ b/drivers/misc/vmw_balloon.c @@ -0,0 +1,844 @@ +/* + * VMware Balloon driver. + * + * Copyright (C) 2000-2010, VMware, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Maintained by: Dmitry Torokhov + */ + +/* + * This is VMware physical memory management driver for Linux. The driver + * acts like a "balloon" that can be inflated to reclaim physical pages by + * reserving them in the guest and invalidating them in the monitor, + * freeing up the underlying machine pages so they can be allocated to + * other guests. The balloon can also be deflated to allow the guest to + * use more physical memory. Higher level policies can control the sizes + * of balloons in VMs in order to manage physical memory resources. + */ + +//#define DEBUG +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("VMware, Inc."); +MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); +MODULE_VERSION("1.2.1.1-k"); +MODULE_ALIAS("dmi:*:svnVMware*:*"); +MODULE_ALIAS("vmware_vmmemctl"); +MODULE_LICENSE("GPL"); + +/* + * Various constants controlling rate of inflaint/deflating balloon, + * measured in pages. + */ + +/* + * Rate of allocating memory when there is no memory pressure + * (driver performs non-sleeping allocations). + */ +#define VMW_BALLOON_NOSLEEP_ALLOC_MAX 16384U + +/* + * Rates of memory allocaton when guest experiences memory pressure + * (driver performs sleeping allocations). + */ +#define VMW_BALLOON_RATE_ALLOC_MIN 512U +#define VMW_BALLOON_RATE_ALLOC_MAX 2048U +#define VMW_BALLOON_RATE_ALLOC_INC 16U + +/* + * Rates for releasing pages while deflating balloon. + */ +#define VMW_BALLOON_RATE_FREE_MIN 512U +#define VMW_BALLOON_RATE_FREE_MAX 16384U +#define VMW_BALLOON_RATE_FREE_INC 16U + +/* + * When guest is under memory pressure, use a reduced page allocation + * rate for next several cycles. + */ +#define VMW_BALLOON_SLOW_CYCLES 4 + +/* + * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't + * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use + * __GFP_NOWARN, to suppress page allocation failure warnings. + */ +#define VMW_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM|__GFP_NOWARN) + +/* + * Use GFP_HIGHUSER when executing in a separate kernel thread + * context and allocation can sleep. This is less stressful to + * the guest memory system, since it allows the thread to block + * while memory is reclaimed, and won't take pages from emergency + * low-memory pools. + */ +#define VMW_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER) + +/* Maximum number of page allocations without yielding processor */ +#define VMW_BALLOON_YIELD_THRESHOLD 1024 + +/* Maximum number of refused pages we accumulate during inflation cycle */ +#define VMW_BALLOON_MAX_REFUSED 16 + +/* + * Hypervisor communication port definitions. + */ +#define VMW_BALLOON_HV_PORT 0x5670 +#define VMW_BALLOON_HV_MAGIC 0x456c6d6f +#define VMW_BALLOON_PROTOCOL_VERSION 2 +#define VMW_BALLOON_GUEST_ID 1 /* Linux */ + +#define VMW_BALLOON_CMD_START 0 +#define VMW_BALLOON_CMD_GET_TARGET 1 +#define VMW_BALLOON_CMD_LOCK 2 +#define VMW_BALLOON_CMD_UNLOCK 3 +#define VMW_BALLOON_CMD_GUEST_ID 4 + +/* error codes */ +#define VMW_BALLOON_SUCCESS 0 +#define VMW_BALLOON_FAILURE -1 +#define VMW_BALLOON_ERROR_CMD_INVALID 1 +#define VMW_BALLOON_ERROR_PPN_INVALID 2 +#define VMW_BALLOON_ERROR_PPN_LOCKED 3 +#define VMW_BALLOON_ERROR_PPN_UNLOCKED 4 +#define VMW_BALLOON_ERROR_PPN_PINNED 5 +#define VMW_BALLOON_ERROR_PPN_NOTNEEDED 6 +#define VMW_BALLOON_ERROR_RESET 7 +#define VMW_BALLOON_ERROR_BUSY 8 + +#define VMWARE_BALLOON_CMD(cmd, data, result) \ +({ \ + unsigned long __stat, __dummy1, __dummy2; \ + __asm__ __volatile__ ("inl (%%dx)" : \ + "=a"(__stat), \ + "=c"(__dummy1), \ + "=d"(__dummy2), \ + "=b"(result) : \ + "0"(VMW_BALLOON_HV_MAGIC), \ + "1"(VMW_BALLOON_CMD_##cmd), \ + "2"(VMW_BALLOON_HV_PORT), \ + "3"(data) : \ + "memory"); \ + result &= -1UL; \ + __stat & -1UL; \ +}) + +#ifdef CONFIG_DEBUG_FS +struct vmballoon_stats { + unsigned int timer; + + /* allocation statustics */ + unsigned int alloc; + unsigned int alloc_fail; + unsigned int sleep_alloc; + unsigned int sleep_alloc_fail; + unsigned int refused_alloc; + unsigned int refused_free; + unsigned int free; + + /* monitor operations */ + unsigned int lock; + unsigned int lock_fail; + unsigned int unlock; + unsigned int unlock_fail; + unsigned int target; + unsigned int target_fail; + unsigned int start; + unsigned int start_fail; + unsigned int guest_type; + unsigned int guest_type_fail; +}; + +#define STATS_INC(stat) (stat)++ +#else +#define STATS_INC(stat) +#endif + +struct vmballoon { + + /* list of reserved physical pages */ + struct list_head pages; + + /* transient list of non-balloonable pages */ + struct list_head refused_pages; + unsigned int n_refused_pages; + + /* balloon size in pages */ + unsigned int size; + unsigned int target; + + /* reset flag */ + bool reset_required; + + /* adjustment rates (pages per second) */ + unsigned int rate_alloc; + unsigned int rate_free; + + /* slowdown page allocations for next few cycles */ + unsigned int slow_allocation_cycles; + +#ifdef CONFIG_DEBUG_FS + /* statistics */ + struct vmballoon_stats stats; + + /* debugfs file exporting statistics */ + struct dentry *dbg_entry; +#endif + + struct sysinfo sysinfo; + + struct delayed_work dwork; +}; + +static struct vmballoon balloon; +static struct workqueue_struct *vmballoon_wq; + +/* + * Send "start" command to the host, communicating supported version + * of the protocol. + */ +static bool vmballoon_send_start(struct vmballoon *b) +{ + unsigned long status, dummy; + + STATS_INC(b->stats.start); + + status = VMWARE_BALLOON_CMD(START, VMW_BALLOON_PROTOCOL_VERSION, dummy); + if (status == VMW_BALLOON_SUCCESS) + return true; + + pr_debug("%s - failed, hv returns %ld\n", __func__, status); + STATS_INC(b->stats.start_fail); + return false; +} + +static bool vmballoon_check_status(struct vmballoon *b, unsigned long status) +{ + switch (status) { + case VMW_BALLOON_SUCCESS: + return true; + + case VMW_BALLOON_ERROR_RESET: + b->reset_required = true; + /* fall through */ + + default: + return false; + } +} + +/* + * Communicate guest type to the host so that it can adjust ballooning + * algorithm to the one most appropriate for the guest. This command + * is normally issued after sending "start" command and is part of + * standard reset sequence. + */ +static bool vmballoon_send_guest_id(struct vmballoon *b) +{ + unsigned long status, dummy; + + status = VMWARE_BALLOON_CMD(GUEST_ID, VMW_BALLOON_GUEST_ID, dummy); + + STATS_INC(b->stats.guest_type); + + if (vmballoon_check_status(b, status)) + return true; + + pr_debug("%s - failed, hv returns %ld\n", __func__, status); + STATS_INC(b->stats.guest_type_fail); + return false; +} + +/* + * Retrieve desired balloon size from the host. + */ +static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) +{ + unsigned long status; + unsigned long target; + unsigned long limit; + u32 limit32; + + /* + * si_meminfo() is cheap. Moreover, we want to provide dynamic + * max balloon size later. So let us call si_meminfo() every + * iteration. + */ + si_meminfo(&b->sysinfo); + limit = b->sysinfo.totalram; + + /* Ensure limit fits in 32-bits */ + limit32 = (u32)limit; + if (limit != limit32) + return false; + + /* update stats */ + STATS_INC(b->stats.target); + + status = VMWARE_BALLOON_CMD(GET_TARGET, limit, target); + if (vmballoon_check_status(b, status)) { + *new_target = target; + return true; + } + + pr_debug("%s - failed, hv returns %ld\n", __func__, status); + STATS_INC(b->stats.target_fail); + return false; +} + +/* + * Notify the host about allocated page so that host can use it without + * fear that guest will need it. Host may reject some pages, we need to + * check the return value and maybe submit a different page. + */ +static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) +{ + unsigned long status, dummy; + u32 pfn32; + + pfn32 = (u32)pfn; + if (pfn32 != pfn) + return false; + + STATS_INC(b->stats.lock); + + status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); + if (vmballoon_check_status(b, status)) + return true; + + pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); + STATS_INC(b->stats.lock_fail); + return false; +} + +/* + * Notify the host that guest intends to release given page back into + * the pool of available (to the guest) pages. + */ +static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn) +{ + unsigned long status, dummy; + u32 pfn32; + + pfn32 = (u32)pfn; + if (pfn32 != pfn) + return false; + + STATS_INC(b->stats.unlock); + + status = VMWARE_BALLOON_CMD(UNLOCK, pfn, dummy); + if (vmballoon_check_status(b, status)) + return true; + + pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); + STATS_INC(b->stats.unlock_fail); + return false; +} + +/* + * Quickly release all pages allocated for the balloon. This function is + * called when host decides to "reset" balloon for one reason or another. + * Unlike normal "deflate" we do not (shall not) notify host of the pages + * being released. + */ +static void vmballoon_pop(struct vmballoon *b) +{ + struct page *page, *next; + unsigned int count = 0; + + list_for_each_entry_safe(page, next, &b->pages, lru) { + list_del(&page->lru); + __free_page(page); + STATS_INC(b->stats.free); + b->size--; + + if (++count >= b->rate_free) { + count = 0; + cond_resched(); + } + } +} + +/* + * Perform standard reset sequence by popping the balloon (in case it + * is not empty) and then restarting protocol. This operation normally + * happens when host responds with VMW_BALLOON_ERROR_RESET to a command. + */ +static void vmballoon_reset(struct vmballoon *b) +{ + /* free all pages, skipping monitor unlock */ + vmballoon_pop(b); + + if (vmballoon_send_start(b)) { + b->reset_required = false; + if (!vmballoon_send_guest_id(b)) + pr_err("failed to send guest ID to the host\n"); + } +} + +/* + * Allocate (or reserve) a page for the balloon and notify the host. If host + * refuses the page put it on "refuse" list and allocate another one until host + * is satisfied. "Refused" pages are released at the end of inflation cycle + * (when we allocate b->rate_alloc pages). + */ +static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) +{ + struct page *page; + gfp_t flags; + bool locked = false; + + do { + if (!can_sleep) + STATS_INC(b->stats.alloc); + else + STATS_INC(b->stats.sleep_alloc); + + flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP; + page = alloc_page(flags); + if (!page) { + if (!can_sleep) + STATS_INC(b->stats.alloc_fail); + else + STATS_INC(b->stats.sleep_alloc_fail); + return -ENOMEM; + } + + /* inform monitor */ + locked = vmballoon_send_lock_page(b, page_to_pfn(page)); + if (!locked) { + STATS_INC(b->stats.refused_alloc); + + if (b->reset_required) { + __free_page(page); + return -EIO; + } + + /* + * Place page on the list of non-balloonable pages + * and retry allocation, unless we already accumulated + * too many of them, in which case take a breather. + */ + list_add(&page->lru, &b->refused_pages); + if (++b->n_refused_pages >= VMW_BALLOON_MAX_REFUSED) + return -EIO; + } + } while (!locked); + + /* track allocated page */ + list_add(&page->lru, &b->pages); + + /* update balloon size */ + b->size++; + + return 0; +} + +/* + * Release the page allocated for the balloon. Note that we first notify + * the host so it can make sure the page will be available for the guest + * to use, if needed. + */ +static int vmballoon_release_page(struct vmballoon *b, struct page *page) +{ + if (!vmballoon_send_unlock_page(b, page_to_pfn(page))) + return -EIO; + + list_del(&page->lru); + + /* deallocate page */ + __free_page(page); + STATS_INC(b->stats.free); + + /* update balloon size */ + b->size--; + + return 0; +} + +/* + * Release pages that were allocated while attempting to inflate the + * balloon but were refused by the host for one reason or another. + */ +static void vmballoon_release_refused_pages(struct vmballoon *b) +{ + struct page *page, *next; + + list_for_each_entry_safe(page, next, &b->refused_pages, lru) { + list_del(&page->lru); + __free_page(page); + STATS_INC(b->stats.refused_free); + } + + b->n_refused_pages = 0; +} + +/* + * Inflate the balloon towards its target size. Note that we try to limit + * the rate of allocation to make sure we are not choking the rest of the + * system. + */ +static void vmballoon_inflate(struct vmballoon *b) +{ + unsigned int goal; + unsigned int rate; + unsigned int i; + unsigned int allocations = 0; + int error = 0; + bool alloc_can_sleep = false; + + pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); + + /* + * First try NOSLEEP page allocations to inflate balloon. + * + * If we do not throttle nosleep allocations, we can drain all + * free pages in the guest quickly (if the balloon target is high). + * As a side-effect, draining free pages helps to inform (force) + * the guest to start swapping if balloon target is not met yet, + * which is a desired behavior. However, balloon driver can consume + * all available CPU cycles if too many pages are allocated in a + * second. Therefore, we throttle nosleep allocations even when + * the guest is not under memory pressure. OTOH, if we have already + * predicted that the guest is under memory pressure, then we + * slowdown page allocations considerably. + */ + + goal = b->target - b->size; + /* + * Start with no sleep allocation rate which may be higher + * than sleeping allocation rate. + */ + rate = b->slow_allocation_cycles ? + b->rate_alloc : VMW_BALLOON_NOSLEEP_ALLOC_MAX; + + pr_debug("%s - goal: %d, no-sleep rate: %d, sleep rate: %d\n", + __func__, goal, rate, b->rate_alloc); + + for (i = 0; i < goal; i++) { + + error = vmballoon_reserve_page(b, alloc_can_sleep); + if (error) { + if (error != -ENOMEM) { + /* + * Not a page allocation failure, stop this + * cycle. Maybe we'll get new target from + * the host soon. + */ + break; + } + + if (alloc_can_sleep) { + /* + * CANSLEEP page allocation failed, so guest + * is under severe memory pressure. Quickly + * decrease allocation rate. + */ + b->rate_alloc = max(b->rate_alloc / 2, + VMW_BALLOON_RATE_ALLOC_MIN); + break; + } + + /* + * NOSLEEP page allocation failed, so the guest is + * under memory pressure. Let us slow down page + * allocations for next few cycles so that the guest + * gets out of memory pressure. Also, if we already + * allocated b->rate_alloc pages, let's pause, + * otherwise switch to sleeping allocations. + */ + b->slow_allocation_cycles = VMW_BALLOON_SLOW_CYCLES; + + if (i >= b->rate_alloc) + break; + + alloc_can_sleep = true; + /* Lower rate for sleeping allocations. */ + rate = b->rate_alloc; + } + + if (++allocations > VMW_BALLOON_YIELD_THRESHOLD) { + cond_resched(); + allocations = 0; + } + + if (i >= rate) { + /* We allocated enough pages, let's take a break. */ + break; + } + } + + /* + * We reached our goal without failures so try increasing + * allocation rate. + */ + if (error == 0 && i >= b->rate_alloc) { + unsigned int mult = i / b->rate_alloc; + + b->rate_alloc = + min(b->rate_alloc + mult * VMW_BALLOON_RATE_ALLOC_INC, + VMW_BALLOON_RATE_ALLOC_MAX); + } + + vmballoon_release_refused_pages(b); +} + +/* + * Decrease the size of the balloon allowing guest to use more memory. + */ +static void vmballoon_deflate(struct vmballoon *b) +{ + struct page *page, *next; + unsigned int i = 0; + unsigned int goal; + int error; + + pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); + + /* limit deallocation rate */ + goal = min(b->size - b->target, b->rate_free); + + pr_debug("%s - goal: %d, rate: %d\n", __func__, goal, b->rate_free); + + /* free pages to reach target */ + list_for_each_entry_safe(page, next, &b->pages, lru) { + error = vmballoon_release_page(b, page); + if (error) { + /* quickly decrease rate in case of error */ + b->rate_free = max(b->rate_free / 2, + VMW_BALLOON_RATE_FREE_MIN); + return; + } + + if (++i >= goal) + break; + } + + /* slowly increase rate if there were no errors */ + b->rate_free = min(b->rate_free + VMW_BALLOON_RATE_FREE_INC, + VMW_BALLOON_RATE_FREE_MAX); +} + +/* + * Balloon work function: reset protocol, if needed, get the new size and + * adjust balloon as needed. Repeat in 1 sec. + */ +static void vmballoon_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct vmballoon *b = container_of(dwork, struct vmballoon, dwork); + unsigned int target; + + STATS_INC(b->stats.timer); + + if (b->reset_required) + vmballoon_reset(b); + + if (b->slow_allocation_cycles > 0) + b->slow_allocation_cycles--; + + if (vmballoon_send_get_target(b, &target)) { + /* update target, adjust size */ + b->target = target; + + if (b->size < target) + vmballoon_inflate(b); + else if (b->size > target) + vmballoon_deflate(b); + } + + queue_delayed_work(vmballoon_wq, dwork, round_jiffies_relative(HZ)); +} + +/* + * DEBUGFS Interface + */ +#ifdef CONFIG_DEBUG_FS + +static int vmballoon_debug_show(struct seq_file *f, void *offset) +{ + struct vmballoon *b = f->private; + struct vmballoon_stats *stats = &b->stats; + + /* format size info */ + seq_printf(f, + "target: %8d pages\n" + "current: %8d pages\n", + b->target, b->size); + + /* format rate info */ + seq_printf(f, + "rateNoSleepAlloc: %8d pages/sec\n" + "rateSleepAlloc: %8d pages/sec\n" + "rateFree: %8d pages/sec\n", + VMW_BALLOON_NOSLEEP_ALLOC_MAX, + b->rate_alloc, b->rate_free); + + seq_printf(f, + "\n" + "timer: %8u\n" + "start: %8u (%4u failed)\n" + "guestType: %8u (%4u failed)\n" + "lock: %8u (%4u failed)\n" + "unlock: %8u (%4u failed)\n" + "target: %8u (%4u failed)\n" + "primNoSleepAlloc: %8u (%4u failed)\n" + "primCanSleepAlloc: %8u (%4u failed)\n" + "primFree: %8u\n" + "errAlloc: %8u\n" + "errFree: %8u\n", + stats->timer, + stats->start, stats->start_fail, + stats->guest_type, stats->guest_type_fail, + stats->lock, stats->lock_fail, + stats->unlock, stats->unlock_fail, + stats->target, stats->target_fail, + stats->alloc, stats->alloc_fail, + stats->sleep_alloc, stats->sleep_alloc_fail, + stats->free, + stats->refused_alloc, stats->refused_free); + + return 0; +} + +static int vmballoon_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, vmballoon_debug_show, inode->i_private); +} + +static const struct file_operations vmballoon_debug_fops = { + .owner = THIS_MODULE, + .open = vmballoon_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init vmballoon_debugfs_init(struct vmballoon *b) +{ + int error; + + b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, + &vmballoon_debug_fops); + if (IS_ERR(b->dbg_entry)) { + error = PTR_ERR(b->dbg_entry); + pr_err("failed to create debugfs entry, error: %d\n", error); + return error; + } + + return 0; +} + +static void __exit vmballoon_debugfs_exit(struct vmballoon *b) +{ + debugfs_remove(b->dbg_entry); +} + +#else + +static inline int vmballoon_debugfs_init(struct vmballoon *b) +{ + return 0; +} + +static inline void vmballoon_debugfs_exit(struct vmballoon *b) +{ +} + +#endif /* CONFIG_DEBUG_FS */ + +static int __init vmballoon_init(void) +{ + int error; + + /* + * Check if we are running on VMware's hypervisor and bail out + * if we are not. + */ + if (x86_hyper != &x86_hyper_vmware) + return -ENODEV; + + vmballoon_wq = create_freezeable_workqueue("vmmemctl"); + if (!vmballoon_wq) { + pr_err("failed to create workqueue\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&balloon.pages); + INIT_LIST_HEAD(&balloon.refused_pages); + + /* initialize rates */ + balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX; + balloon.rate_free = VMW_BALLOON_RATE_FREE_MAX; + + INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); + + /* + * Start balloon. + */ + if (!vmballoon_send_start(&balloon)) { + pr_err("failed to send start command to the host\n"); + error = -EIO; + goto fail; + } + + if (!vmballoon_send_guest_id(&balloon)) { + pr_err("failed to send guest ID to the host\n"); + error = -EIO; + goto fail; + } + + error = vmballoon_debugfs_init(&balloon); + if (error) + goto fail; + + queue_delayed_work(vmballoon_wq, &balloon.dwork, 0); + + return 0; + +fail: + destroy_workqueue(vmballoon_wq); + return error; +} +module_init(vmballoon_init); + +static void __exit vmballoon_exit(void) +{ + cancel_delayed_work_sync(&balloon.dwork); + destroy_workqueue(vmballoon_wq); + + vmballoon_debugfs_exit(&balloon); + + /* + * Deallocate all reserved memory, and reset connection with monitor. + * Reset connection before deallocating memory to avoid potential for + * additional spurious resets from guest touching deallocated pages. + */ + vmballoon_send_start(&balloon); + vmballoon_pop(&balloon); +} +module_exit(vmballoon_exit); diff --git a/drivers/misc/vmware_balloon.c b/drivers/misc/vmware_balloon.c deleted file mode 100644 index 2a1e804a71aa..000000000000 --- a/drivers/misc/vmware_balloon.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * VMware Balloon driver. - * - * Copyright (C) 2000-2010, VMware, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained by: Dmitry Torokhov - */ - -/* - * This is VMware physical memory management driver for Linux. The driver - * acts like a "balloon" that can be inflated to reclaim physical pages by - * reserving them in the guest and invalidating them in the monitor, - * freeing up the underlying machine pages so they can be allocated to - * other guests. The balloon can also be deflated to allow the guest to - * use more physical memory. Higher level policies can control the sizes - * of balloons in VMs in order to manage physical memory resources. - */ - -//#define DEBUG -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("VMware, Inc."); -MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); -MODULE_VERSION("1.2.1.1-k"); -MODULE_ALIAS("dmi:*:svnVMware*:*"); -MODULE_ALIAS("vmware_vmmemctl"); -MODULE_LICENSE("GPL"); - -/* - * Various constants controlling rate of inflaint/deflating balloon, - * measured in pages. - */ - -/* - * Rate of allocating memory when there is no memory pressure - * (driver performs non-sleeping allocations). - */ -#define VMW_BALLOON_NOSLEEP_ALLOC_MAX 16384U - -/* - * Rates of memory allocaton when guest experiences memory pressure - * (driver performs sleeping allocations). - */ -#define VMW_BALLOON_RATE_ALLOC_MIN 512U -#define VMW_BALLOON_RATE_ALLOC_MAX 2048U -#define VMW_BALLOON_RATE_ALLOC_INC 16U - -/* - * Rates for releasing pages while deflating balloon. - */ -#define VMW_BALLOON_RATE_FREE_MIN 512U -#define VMW_BALLOON_RATE_FREE_MAX 16384U -#define VMW_BALLOON_RATE_FREE_INC 16U - -/* - * When guest is under memory pressure, use a reduced page allocation - * rate for next several cycles. - */ -#define VMW_BALLOON_SLOW_CYCLES 4 - -/* - * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't - * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use - * __GFP_NOWARN, to suppress page allocation failure warnings. - */ -#define VMW_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM|__GFP_NOWARN) - -/* - * Use GFP_HIGHUSER when executing in a separate kernel thread - * context and allocation can sleep. This is less stressful to - * the guest memory system, since it allows the thread to block - * while memory is reclaimed, and won't take pages from emergency - * low-memory pools. - */ -#define VMW_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER) - -/* Maximum number of page allocations without yielding processor */ -#define VMW_BALLOON_YIELD_THRESHOLD 1024 - -/* Maximum number of refused pages we accumulate during inflation cycle */ -#define VMW_BALLOON_MAX_REFUSED 16 - -/* - * Hypervisor communication port definitions. - */ -#define VMW_BALLOON_HV_PORT 0x5670 -#define VMW_BALLOON_HV_MAGIC 0x456c6d6f -#define VMW_BALLOON_PROTOCOL_VERSION 2 -#define VMW_BALLOON_GUEST_ID 1 /* Linux */ - -#define VMW_BALLOON_CMD_START 0 -#define VMW_BALLOON_CMD_GET_TARGET 1 -#define VMW_BALLOON_CMD_LOCK 2 -#define VMW_BALLOON_CMD_UNLOCK 3 -#define VMW_BALLOON_CMD_GUEST_ID 4 - -/* error codes */ -#define VMW_BALLOON_SUCCESS 0 -#define VMW_BALLOON_FAILURE -1 -#define VMW_BALLOON_ERROR_CMD_INVALID 1 -#define VMW_BALLOON_ERROR_PPN_INVALID 2 -#define VMW_BALLOON_ERROR_PPN_LOCKED 3 -#define VMW_BALLOON_ERROR_PPN_UNLOCKED 4 -#define VMW_BALLOON_ERROR_PPN_PINNED 5 -#define VMW_BALLOON_ERROR_PPN_NOTNEEDED 6 -#define VMW_BALLOON_ERROR_RESET 7 -#define VMW_BALLOON_ERROR_BUSY 8 - -#define VMWARE_BALLOON_CMD(cmd, data, result) \ -({ \ - unsigned long __stat, __dummy1, __dummy2; \ - __asm__ __volatile__ ("inl (%%dx)" : \ - "=a"(__stat), \ - "=c"(__dummy1), \ - "=d"(__dummy2), \ - "=b"(result) : \ - "0"(VMW_BALLOON_HV_MAGIC), \ - "1"(VMW_BALLOON_CMD_##cmd), \ - "2"(VMW_BALLOON_HV_PORT), \ - "3"(data) : \ - "memory"); \ - result &= -1UL; \ - __stat & -1UL; \ -}) - -#ifdef CONFIG_DEBUG_FS -struct vmballoon_stats { - unsigned int timer; - - /* allocation statustics */ - unsigned int alloc; - unsigned int alloc_fail; - unsigned int sleep_alloc; - unsigned int sleep_alloc_fail; - unsigned int refused_alloc; - unsigned int refused_free; - unsigned int free; - - /* monitor operations */ - unsigned int lock; - unsigned int lock_fail; - unsigned int unlock; - unsigned int unlock_fail; - unsigned int target; - unsigned int target_fail; - unsigned int start; - unsigned int start_fail; - unsigned int guest_type; - unsigned int guest_type_fail; -}; - -#define STATS_INC(stat) (stat)++ -#else -#define STATS_INC(stat) -#endif - -struct vmballoon { - - /* list of reserved physical pages */ - struct list_head pages; - - /* transient list of non-balloonable pages */ - struct list_head refused_pages; - unsigned int n_refused_pages; - - /* balloon size in pages */ - unsigned int size; - unsigned int target; - - /* reset flag */ - bool reset_required; - - /* adjustment rates (pages per second) */ - unsigned int rate_alloc; - unsigned int rate_free; - - /* slowdown page allocations for next few cycles */ - unsigned int slow_allocation_cycles; - -#ifdef CONFIG_DEBUG_FS - /* statistics */ - struct vmballoon_stats stats; - - /* debugfs file exporting statistics */ - struct dentry *dbg_entry; -#endif - - struct sysinfo sysinfo; - - struct delayed_work dwork; -}; - -static struct vmballoon balloon; -static struct workqueue_struct *vmballoon_wq; - -/* - * Send "start" command to the host, communicating supported version - * of the protocol. - */ -static bool vmballoon_send_start(struct vmballoon *b) -{ - unsigned long status, dummy; - - STATS_INC(b->stats.start); - - status = VMWARE_BALLOON_CMD(START, VMW_BALLOON_PROTOCOL_VERSION, dummy); - if (status == VMW_BALLOON_SUCCESS) - return true; - - pr_debug("%s - failed, hv returns %ld\n", __func__, status); - STATS_INC(b->stats.start_fail); - return false; -} - -static bool vmballoon_check_status(struct vmballoon *b, unsigned long status) -{ - switch (status) { - case VMW_BALLOON_SUCCESS: - return true; - - case VMW_BALLOON_ERROR_RESET: - b->reset_required = true; - /* fall through */ - - default: - return false; - } -} - -/* - * Communicate guest type to the host so that it can adjust ballooning - * algorithm to the one most appropriate for the guest. This command - * is normally issued after sending "start" command and is part of - * standard reset sequence. - */ -static bool vmballoon_send_guest_id(struct vmballoon *b) -{ - unsigned long status, dummy; - - status = VMWARE_BALLOON_CMD(GUEST_ID, VMW_BALLOON_GUEST_ID, dummy); - - STATS_INC(b->stats.guest_type); - - if (vmballoon_check_status(b, status)) - return true; - - pr_debug("%s - failed, hv returns %ld\n", __func__, status); - STATS_INC(b->stats.guest_type_fail); - return false; -} - -/* - * Retrieve desired balloon size from the host. - */ -static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) -{ - unsigned long status; - unsigned long target; - unsigned long limit; - u32 limit32; - - /* - * si_meminfo() is cheap. Moreover, we want to provide dynamic - * max balloon size later. So let us call si_meminfo() every - * iteration. - */ - si_meminfo(&b->sysinfo); - limit = b->sysinfo.totalram; - - /* Ensure limit fits in 32-bits */ - limit32 = (u32)limit; - if (limit != limit32) - return false; - - /* update stats */ - STATS_INC(b->stats.target); - - status = VMWARE_BALLOON_CMD(GET_TARGET, limit, target); - if (vmballoon_check_status(b, status)) { - *new_target = target; - return true; - } - - pr_debug("%s - failed, hv returns %ld\n", __func__, status); - STATS_INC(b->stats.target_fail); - return false; -} - -/* - * Notify the host about allocated page so that host can use it without - * fear that guest will need it. Host may reject some pages, we need to - * check the return value and maybe submit a different page. - */ -static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) -{ - unsigned long status, dummy; - u32 pfn32; - - pfn32 = (u32)pfn; - if (pfn32 != pfn) - return false; - - STATS_INC(b->stats.lock); - - status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); - if (vmballoon_check_status(b, status)) - return true; - - pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); - STATS_INC(b->stats.lock_fail); - return false; -} - -/* - * Notify the host that guest intends to release given page back into - * the pool of available (to the guest) pages. - */ -static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn) -{ - unsigned long status, dummy; - u32 pfn32; - - pfn32 = (u32)pfn; - if (pfn32 != pfn) - return false; - - STATS_INC(b->stats.unlock); - - status = VMWARE_BALLOON_CMD(UNLOCK, pfn, dummy); - if (vmballoon_check_status(b, status)) - return true; - - pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); - STATS_INC(b->stats.unlock_fail); - return false; -} - -/* - * Quickly release all pages allocated for the balloon. This function is - * called when host decides to "reset" balloon for one reason or another. - * Unlike normal "deflate" we do not (shall not) notify host of the pages - * being released. - */ -static void vmballoon_pop(struct vmballoon *b) -{ - struct page *page, *next; - unsigned int count = 0; - - list_for_each_entry_safe(page, next, &b->pages, lru) { - list_del(&page->lru); - __free_page(page); - STATS_INC(b->stats.free); - b->size--; - - if (++count >= b->rate_free) { - count = 0; - cond_resched(); - } - } -} - -/* - * Perform standard reset sequence by popping the balloon (in case it - * is not empty) and then restarting protocol. This operation normally - * happens when host responds with VMW_BALLOON_ERROR_RESET to a command. - */ -static void vmballoon_reset(struct vmballoon *b) -{ - /* free all pages, skipping monitor unlock */ - vmballoon_pop(b); - - if (vmballoon_send_start(b)) { - b->reset_required = false; - if (!vmballoon_send_guest_id(b)) - pr_err("failed to send guest ID to the host\n"); - } -} - -/* - * Allocate (or reserve) a page for the balloon and notify the host. If host - * refuses the page put it on "refuse" list and allocate another one until host - * is satisfied. "Refused" pages are released at the end of inflation cycle - * (when we allocate b->rate_alloc pages). - */ -static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) -{ - struct page *page; - gfp_t flags; - bool locked = false; - - do { - if (!can_sleep) - STATS_INC(b->stats.alloc); - else - STATS_INC(b->stats.sleep_alloc); - - flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP; - page = alloc_page(flags); - if (!page) { - if (!can_sleep) - STATS_INC(b->stats.alloc_fail); - else - STATS_INC(b->stats.sleep_alloc_fail); - return -ENOMEM; - } - - /* inform monitor */ - locked = vmballoon_send_lock_page(b, page_to_pfn(page)); - if (!locked) { - STATS_INC(b->stats.refused_alloc); - - if (b->reset_required) { - __free_page(page); - return -EIO; - } - - /* - * Place page on the list of non-balloonable pages - * and retry allocation, unless we already accumulated - * too many of them, in which case take a breather. - */ - list_add(&page->lru, &b->refused_pages); - if (++b->n_refused_pages >= VMW_BALLOON_MAX_REFUSED) - return -EIO; - } - } while (!locked); - - /* track allocated page */ - list_add(&page->lru, &b->pages); - - /* update balloon size */ - b->size++; - - return 0; -} - -/* - * Release the page allocated for the balloon. Note that we first notify - * the host so it can make sure the page will be available for the guest - * to use, if needed. - */ -static int vmballoon_release_page(struct vmballoon *b, struct page *page) -{ - if (!vmballoon_send_unlock_page(b, page_to_pfn(page))) - return -EIO; - - list_del(&page->lru); - - /* deallocate page */ - __free_page(page); - STATS_INC(b->stats.free); - - /* update balloon size */ - b->size--; - - return 0; -} - -/* - * Release pages that were allocated while attempting to inflate the - * balloon but were refused by the host for one reason or another. - */ -static void vmballoon_release_refused_pages(struct vmballoon *b) -{ - struct page *page, *next; - - list_for_each_entry_safe(page, next, &b->refused_pages, lru) { - list_del(&page->lru); - __free_page(page); - STATS_INC(b->stats.refused_free); - } - - b->n_refused_pages = 0; -} - -/* - * Inflate the balloon towards its target size. Note that we try to limit - * the rate of allocation to make sure we are not choking the rest of the - * system. - */ -static void vmballoon_inflate(struct vmballoon *b) -{ - unsigned int goal; - unsigned int rate; - unsigned int i; - unsigned int allocations = 0; - int error = 0; - bool alloc_can_sleep = false; - - pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); - - /* - * First try NOSLEEP page allocations to inflate balloon. - * - * If we do not throttle nosleep allocations, we can drain all - * free pages in the guest quickly (if the balloon target is high). - * As a side-effect, draining free pages helps to inform (force) - * the guest to start swapping if balloon target is not met yet, - * which is a desired behavior. However, balloon driver can consume - * all available CPU cycles if too many pages are allocated in a - * second. Therefore, we throttle nosleep allocations even when - * the guest is not under memory pressure. OTOH, if we have already - * predicted that the guest is under memory pressure, then we - * slowdown page allocations considerably. - */ - - goal = b->target - b->size; - /* - * Start with no sleep allocation rate which may be higher - * than sleeping allocation rate. - */ - rate = b->slow_allocation_cycles ? - b->rate_alloc : VMW_BALLOON_NOSLEEP_ALLOC_MAX; - - pr_debug("%s - goal: %d, no-sleep rate: %d, sleep rate: %d\n", - __func__, goal, rate, b->rate_alloc); - - for (i = 0; i < goal; i++) { - - error = vmballoon_reserve_page(b, alloc_can_sleep); - if (error) { - if (error != -ENOMEM) { - /* - * Not a page allocation failure, stop this - * cycle. Maybe we'll get new target from - * the host soon. - */ - break; - } - - if (alloc_can_sleep) { - /* - * CANSLEEP page allocation failed, so guest - * is under severe memory pressure. Quickly - * decrease allocation rate. - */ - b->rate_alloc = max(b->rate_alloc / 2, - VMW_BALLOON_RATE_ALLOC_MIN); - break; - } - - /* - * NOSLEEP page allocation failed, so the guest is - * under memory pressure. Let us slow down page - * allocations for next few cycles so that the guest - * gets out of memory pressure. Also, if we already - * allocated b->rate_alloc pages, let's pause, - * otherwise switch to sleeping allocations. - */ - b->slow_allocation_cycles = VMW_BALLOON_SLOW_CYCLES; - - if (i >= b->rate_alloc) - break; - - alloc_can_sleep = true; - /* Lower rate for sleeping allocations. */ - rate = b->rate_alloc; - } - - if (++allocations > VMW_BALLOON_YIELD_THRESHOLD) { - cond_resched(); - allocations = 0; - } - - if (i >= rate) { - /* We allocated enough pages, let's take a break. */ - break; - } - } - - /* - * We reached our goal without failures so try increasing - * allocation rate. - */ - if (error == 0 && i >= b->rate_alloc) { - unsigned int mult = i / b->rate_alloc; - - b->rate_alloc = - min(b->rate_alloc + mult * VMW_BALLOON_RATE_ALLOC_INC, - VMW_BALLOON_RATE_ALLOC_MAX); - } - - vmballoon_release_refused_pages(b); -} - -/* - * Decrease the size of the balloon allowing guest to use more memory. - */ -static void vmballoon_deflate(struct vmballoon *b) -{ - struct page *page, *next; - unsigned int i = 0; - unsigned int goal; - int error; - - pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); - - /* limit deallocation rate */ - goal = min(b->size - b->target, b->rate_free); - - pr_debug("%s - goal: %d, rate: %d\n", __func__, goal, b->rate_free); - - /* free pages to reach target */ - list_for_each_entry_safe(page, next, &b->pages, lru) { - error = vmballoon_release_page(b, page); - if (error) { - /* quickly decrease rate in case of error */ - b->rate_free = max(b->rate_free / 2, - VMW_BALLOON_RATE_FREE_MIN); - return; - } - - if (++i >= goal) - break; - } - - /* slowly increase rate if there were no errors */ - b->rate_free = min(b->rate_free + VMW_BALLOON_RATE_FREE_INC, - VMW_BALLOON_RATE_FREE_MAX); -} - -/* - * Balloon work function: reset protocol, if needed, get the new size and - * adjust balloon as needed. Repeat in 1 sec. - */ -static void vmballoon_work(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct vmballoon *b = container_of(dwork, struct vmballoon, dwork); - unsigned int target; - - STATS_INC(b->stats.timer); - - if (b->reset_required) - vmballoon_reset(b); - - if (b->slow_allocation_cycles > 0) - b->slow_allocation_cycles--; - - if (vmballoon_send_get_target(b, &target)) { - /* update target, adjust size */ - b->target = target; - - if (b->size < target) - vmballoon_inflate(b); - else if (b->size > target) - vmballoon_deflate(b); - } - - queue_delayed_work(vmballoon_wq, dwork, round_jiffies_relative(HZ)); -} - -/* - * DEBUGFS Interface - */ -#ifdef CONFIG_DEBUG_FS - -static int vmballoon_debug_show(struct seq_file *f, void *offset) -{ - struct vmballoon *b = f->private; - struct vmballoon_stats *stats = &b->stats; - - /* format size info */ - seq_printf(f, - "target: %8d pages\n" - "current: %8d pages\n", - b->target, b->size); - - /* format rate info */ - seq_printf(f, - "rateNoSleepAlloc: %8d pages/sec\n" - "rateSleepAlloc: %8d pages/sec\n" - "rateFree: %8d pages/sec\n", - VMW_BALLOON_NOSLEEP_ALLOC_MAX, - b->rate_alloc, b->rate_free); - - seq_printf(f, - "\n" - "timer: %8u\n" - "start: %8u (%4u failed)\n" - "guestType: %8u (%4u failed)\n" - "lock: %8u (%4u failed)\n" - "unlock: %8u (%4u failed)\n" - "target: %8u (%4u failed)\n" - "primNoSleepAlloc: %8u (%4u failed)\n" - "primCanSleepAlloc: %8u (%4u failed)\n" - "primFree: %8u\n" - "errAlloc: %8u\n" - "errFree: %8u\n", - stats->timer, - stats->start, stats->start_fail, - stats->guest_type, stats->guest_type_fail, - stats->lock, stats->lock_fail, - stats->unlock, stats->unlock_fail, - stats->target, stats->target_fail, - stats->alloc, stats->alloc_fail, - stats->sleep_alloc, stats->sleep_alloc_fail, - stats->free, - stats->refused_alloc, stats->refused_free); - - return 0; -} - -static int vmballoon_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, vmballoon_debug_show, inode->i_private); -} - -static const struct file_operations vmballoon_debug_fops = { - .owner = THIS_MODULE, - .open = vmballoon_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init vmballoon_debugfs_init(struct vmballoon *b) -{ - int error; - - b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, - &vmballoon_debug_fops); - if (IS_ERR(b->dbg_entry)) { - error = PTR_ERR(b->dbg_entry); - pr_err("failed to create debugfs entry, error: %d\n", error); - return error; - } - - return 0; -} - -static void __exit vmballoon_debugfs_exit(struct vmballoon *b) -{ - debugfs_remove(b->dbg_entry); -} - -#else - -static inline int vmballoon_debugfs_init(struct vmballoon *b) -{ - return 0; -} - -static inline void vmballoon_debugfs_exit(struct vmballoon *b) -{ -} - -#endif /* CONFIG_DEBUG_FS */ - -static int __init vmballoon_init(void) -{ - int error; - - /* - * Check if we are running on VMware's hypervisor and bail out - * if we are not. - */ - if (x86_hyper != &x86_hyper_vmware) - return -ENODEV; - - vmballoon_wq = create_freezeable_workqueue("vmmemctl"); - if (!vmballoon_wq) { - pr_err("failed to create workqueue\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&balloon.pages); - INIT_LIST_HEAD(&balloon.refused_pages); - - /* initialize rates */ - balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX; - balloon.rate_free = VMW_BALLOON_RATE_FREE_MAX; - - INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); - - /* - * Start balloon. - */ - if (!vmballoon_send_start(&balloon)) { - pr_err("failed to send start command to the host\n"); - error = -EIO; - goto fail; - } - - if (!vmballoon_send_guest_id(&balloon)) { - pr_err("failed to send guest ID to the host\n"); - error = -EIO; - goto fail; - } - - error = vmballoon_debugfs_init(&balloon); - if (error) - goto fail; - - queue_delayed_work(vmballoon_wq, &balloon.dwork, 0); - - return 0; - -fail: - destroy_workqueue(vmballoon_wq); - return error; -} -module_init(vmballoon_init); - -static void __exit vmballoon_exit(void) -{ - cancel_delayed_work_sync(&balloon.dwork); - destroy_workqueue(vmballoon_wq); - - vmballoon_debugfs_exit(&balloon); - - /* - * Deallocate all reserved memory, and reset connection with monitor. - * Reset connection before deallocating memory to avoid potential for - * additional spurious resets from guest touching deallocated pages. - */ - vmballoon_send_start(&balloon); - vmballoon_pop(&balloon); -} -module_exit(vmballoon_exit); -- cgit v1.2.3-59-g8ed1b From f5665518c20c01e9045314872878f5788cb3fff2 Mon Sep 17 00:00:00 2001 From: Hans-Christian Egtvedt Date: Wed, 22 Sep 2010 13:04:58 -0700 Subject: MAINTAINERS: change AVR32 and AT32AP maintainer Alter the maintainer of the AVR32 architecture and the AVR32/AT32AP machine support to me. Haavard is moving on to new challenges, and we've found it better to transfer the maintainer part to me. I will have good contact with Haavard anyway. Signed-off-by: Hans-Christian Egtvedt Acked-by: Haavard Skinnemoen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 50b8148448fd..726433a17998 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1220,7 +1220,7 @@ F: drivers/auxdisplay/ F: include/linux/cfag12864b.h AVR32 ARCHITECTURE -M: Haavard Skinnemoen +M: Hans-Christian Egtvedt W: http://www.atmel.com/products/AVR32/ W: http://avr32linux.org/ W: http://avrfreaks.net/ @@ -1228,7 +1228,7 @@ S: Supported F: arch/avr32/ AVR32/AT32AP MACHINE SUPPORT -M: Haavard Skinnemoen +M: Hans-Christian Egtvedt S: Supported F: arch/avr32/mach-at32ap/ -- cgit v1.2.3-59-g8ed1b From eba93fcc34d6c4387ce8fbb53bb7b685f91f3343 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 22 Sep 2010 13:04:59 -0700 Subject: drivers/rtc/rtc-ab3100.c: add missing platform_set_drvdata() in ab3100_rtc_probe() Otherwise, calling platform_get_drvdata() in ab3100_rtc_remove() returns NULL. Signed-off-by: Axel Lin Acked-by:Wan ZongShun Acked-by: Linus Walleij Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ab3100.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c index d26780ea254b..261a07e0fb24 100644 --- a/drivers/rtc/rtc-ab3100.c +++ b/drivers/rtc/rtc-ab3100.c @@ -235,6 +235,7 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) err = PTR_ERR(rtc); return err; } + platform_set_drvdata(pdev, rtc); return 0; } @@ -244,6 +245,7 @@ static int __exit ab3100_rtc_remove(struct platform_device *pdev) struct rtc_device *rtc = platform_get_drvdata(pdev); rtc_device_unregister(rtc); + platform_set_drvdata(pdev, NULL); return 0; } -- cgit v1.2.3-59-g8ed1b From d1908362ae0b97374eb8328fbb471576332f9fb1 Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Wed, 22 Sep 2010 13:05:01 -0700 Subject: vmscan: check all_unreclaimable in direct reclaim path M. Vefa Bicakci reported 2.6.35 kernel hang up when hibernation on his 32bit 3GB mem machine. (https://bugzilla.kernel.org/show_bug.cgi?id=16771). Also he bisected the regression to commit bb21c7ce18eff8e6e7877ca1d06c6db719376e3c Author: KOSAKI Motohiro Date: Fri Jun 4 14:15:05 2010 -0700 vmscan: fix do_try_to_free_pages() return value when priority==0 reclaim failure At first impression, this seemed very strange because the above commit only chenged function return value and hibernate_preallocate_memory() ignore return value of shrink_all_memory(). But it's related. Now, page allocation from hibernation code may enter infinite loop if the system has highmem. The reasons are that vmscan don't care enough OOM case when oom_killer_disabled. The problem sequence is following as. 1. hibernation 2. oom_disable 3. alloc_pages 4. do_try_to_free_pages if (scanning_global_lru(sc) && !all_unreclaimable) return 1; If kswapd is not freozen, it would set zone->all_unreclaimable to 1 and then shrink_zones maybe return true(ie, all_unreclaimable is true). So at last, alloc_pages could go to _nopage_. If it is, it should have no problem. This patch adds all_unreclaimable check to protect in direct reclaim path, too. It can care of hibernation OOM case and help bailout all_unreclaimable case slightly. Signed-off-by: KOSAKI Motohiro Signed-off-by: Minchan Kim Reported-by: M. Vefa Bicakci Reported-by: Reviewed-by: Johannes Weiner Tested-by: Acked-by: Rafael J. Wysocki Acked-by: Rik van Riel Acked-by: KAMEZAWA Hiroyuki Cc: Balbir Singh Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmscan.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index c391c320dbaf..c5dfabf25f11 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1804,12 +1804,11 @@ static void shrink_zone(int priority, struct zone *zone, * If a zone is deemed to be full of pinned pages then just give it a light * scan then give up on it. */ -static bool shrink_zones(int priority, struct zonelist *zonelist, +static void shrink_zones(int priority, struct zonelist *zonelist, struct scan_control *sc) { struct zoneref *z; struct zone *zone; - bool all_unreclaimable = true; for_each_zone_zonelist_nodemask(zone, z, zonelist, gfp_zone(sc->gfp_mask), sc->nodemask) { @@ -1827,8 +1826,38 @@ static bool shrink_zones(int priority, struct zonelist *zonelist, } shrink_zone(priority, zone, sc); - all_unreclaimable = false; } +} + +static bool zone_reclaimable(struct zone *zone) +{ + return zone->pages_scanned < zone_reclaimable_pages(zone) * 6; +} + +/* + * As hibernation is going on, kswapd is freezed so that it can't mark + * the zone into all_unreclaimable. It can't handle OOM during hibernation. + * So let's check zone's unreclaimable in direct reclaim as well as kswapd. + */ +static bool all_unreclaimable(struct zonelist *zonelist, + struct scan_control *sc) +{ + struct zoneref *z; + struct zone *zone; + bool all_unreclaimable = true; + + for_each_zone_zonelist_nodemask(zone, z, zonelist, + gfp_zone(sc->gfp_mask), sc->nodemask) { + if (!populated_zone(zone)) + continue; + if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL)) + continue; + if (zone_reclaimable(zone)) { + all_unreclaimable = false; + break; + } + } + return all_unreclaimable; } @@ -1852,7 +1881,6 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, struct scan_control *sc) { int priority; - bool all_unreclaimable; unsigned long total_scanned = 0; struct reclaim_state *reclaim_state = current->reclaim_state; struct zoneref *z; @@ -1869,7 +1897,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, sc->nr_scanned = 0; if (!priority) disable_swap_token(); - all_unreclaimable = shrink_zones(priority, zonelist, sc); + shrink_zones(priority, zonelist, sc); /* * Don't shrink slabs when reclaiming memory from * over limit cgroups @@ -1931,7 +1959,7 @@ out: return sc->nr_reclaimed; /* top priority shrink_zones still had more to do? don't OOM, then */ - if (scanning_global_lru(sc) && !all_unreclaimable) + if (scanning_global_lru(sc) && !all_unreclaimable(zonelist, sc)) return 1; return 0; @@ -2197,8 +2225,7 @@ loop_again: total_scanned += sc.nr_scanned; if (zone->all_unreclaimable) continue; - if (nr_slab == 0 && - zone->pages_scanned >= (zone_reclaimable_pages(zone) * 6)) + if (nr_slab == 0 && !zone_reclaimable(zone)) zone->all_unreclaimable = 1; /* * If we've done a decent amount of scanning and -- cgit v1.2.3-59-g8ed1b From a0c42bac79731276c9b2f28d54f9e658fcf843a2 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 22 Sep 2010 13:05:03 -0700 Subject: aio: do not return ERESTARTSYS as a result of AIO OCFS2 can return ERESTARTSYS from its write function when the process is signalled while waiting for a cluster lock (and the filesystem is mounted with intr mount option). Generally, it seems reasonable to allow filesystems to return this error code from its IO functions. As we must not leak ERESTARTSYS (and similar error codes) to userspace as a result of an AIO operation, we have to properly convert it to EINTR inside AIO code (restarting the syscall isn't really an option because other AIO could have been already submitted by the same io_submit syscall). Signed-off-by: Jan Kara Reviewed-by: Jeff Moyer Cc: Christoph Hellwig Cc: Zach Brown Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/aio.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/aio.c b/fs/aio.c index 1320b2a05fb2..250b0a73c8a8 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -712,8 +712,16 @@ static ssize_t aio_run_iocb(struct kiocb *iocb) */ ret = retry(iocb); - if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) + if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) { + /* + * There's no easy way to restart the syscall since other AIO's + * may be already running. Just fail this IO with EINTR. + */ + if (unlikely(ret == -ERESTARTSYS || ret == -ERESTARTNOINTR || + ret == -ERESTARTNOHAND || ret == -ERESTART_RESTARTBLOCK)) + ret = -EINTR; aio_complete(iocb, ret, 0); + } out: spin_lock_irq(&ctx->ctx_lock); -- cgit v1.2.3-59-g8ed1b From 85a00d9bbfb4704fbf368944b1cb9fed8f1598c5 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 22 Sep 2010 13:05:04 -0700 Subject: efifb: check that the base address is plausible on pci systems Some Apple machines have identical DMI data but different memory configurations for the video. Given that, check that the address in our table is actually within the range of a PCI BAR on a VGA device in the machine. This also fixes up the return value from set_system(), which has always been wrong, but never resulted in bad behavior since there's only ever been one matching entry in the dmi table. The patch 1) stops people's machines from crashing when we get their display wrong, which seems to be unfortunately inevitable, 2) allows us to support identical dmi data with differing video memory configurations This also adds me as the efifb maintainer, since I've effectively been acting as such for quite some time. Signed-off-by: Peter Jones Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 6 +++++ drivers/video/efifb.c | 61 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 726433a17998..4d4881d909da 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2199,6 +2199,12 @@ W: http://acpi4asus.sf.net S: Maintained F: drivers/platform/x86/eeepc-laptop.c +EFIFB FRAMEBUFFER DRIVER +L: linux-fbdev@vger.kernel.org +M: Peter Jones +S: Maintained +F: drivers/video/efifb.c + EFS FILESYSTEM W: http://aeschi.ch.eu.org/efs/ S: Orphan diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 815f84b07933..c082b616f390 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -13,7 +13,7 @@ #include #include #include - +#include #include